• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SpiNNakerManchester / JavaSpiNNaker / 6310285782

26 Sep 2023 08:47AM UTC coverage: 36.367% (-0.5%) from 36.866%
6310285782

Pull #658

github

dkfellows
Merge branch 'master' into java-17
Pull Request #658: Update Java version to 17 and JEE to 9

1675 of 1675 new or added lines in 266 files covered. (100.0%)

8368 of 23010 relevant lines covered (36.37%)

0.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

52.08
/SpiNNaker-allocserv/src/main/java/uk/ac/manchester/spinnaker/alloc/security/Permit.java
1
/*
2
 * Copyright (c) 2021 The University of Manchester
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package uk.ac.manchester.spinnaker.alloc.security;
17

18
import static java.util.stream.Collectors.toUnmodifiableList;
19
import static uk.ac.manchester.spinnaker.alloc.security.Grants.GRANT_ADMIN;
20
import static uk.ac.manchester.spinnaker.alloc.security.Grants.GRANT_READER;
21
import static uk.ac.manchester.spinnaker.alloc.security.Grants.GRANT_USER;
22
import static uk.ac.manchester.spinnaker.alloc.security.Grants.GRANT_NMPI_EXEC;
23
import static uk.ac.manchester.spinnaker.alloc.security.TrustLevel.USER;
24

25
import java.io.NotSerializableException;
26
import java.io.ObjectOutputStream;
27
import java.io.Serial;
28
import java.util.Collection;
29
import java.util.List;
30
import java.util.function.Supplier;
31

32
import org.springframework.security.core.Authentication;
33
import org.springframework.security.core.GrantedAuthority;
34
import org.springframework.security.core.context.SecurityContext;
35
import org.springframework.security.core.context.SecurityContextHolder;
36
import org.springframework.web.socket.WebSocketSession;
37

38
/**
39
 * Encodes what a user is permitted to do. Abstracts over several types of
40
 * security context.
41
 */
42
public final class Permit {
43
        /** Is the user an admin? */
44
        public final boolean admin;
45

46
        /** Is the user an nmpi exec user? */
47
        public final boolean nmpiexec;
48

49
        /** What is the name of the user? */
50
        public final String name;
51

52
        private final List<GrantedAuthority> authorities;
53

54
        private static final List<String> STDAUTH =
1✔
55
                        List.of(GRANT_ADMIN, GRANT_READER, GRANT_USER, GRANT_NMPI_EXEC);
1✔
56

57
        /**
58
         * Build a permit.
59
         *
60
         * @param context
61
         *            The originating security context.
62
         */
63
        public Permit(jakarta.ws.rs.core.SecurityContext context) {
×
64
                authorities = STDAUTH.stream().filter(context::isUserInRole)
×
65
                                .map(SimpleGrantedAuthority::new).collect(toUnmodifiableList());
×
66
                admin = is(authorities, GRANT_ADMIN);
×
67
                nmpiexec = is(authorities, GRANT_NMPI_EXEC);
×
68
                name = context.getUserPrincipal().getName();
×
69
        }
×
70

71
        private static boolean is(List<GrantedAuthority> auths, String grant) {
72
                return auths.stream().map(GrantedAuthority::getAuthority)
1✔
73
                                .anyMatch(grant::equals);
1✔
74
        }
75

76
        /**
77
         * Build a permit.
78
         *
79
         * @param context
80
         *            The originating security context.
81
         */
82
        public Permit(SecurityContext context) {
1✔
83
                authorities = context.getAuthentication().getAuthorities().stream()
1✔
84
                                .collect(toUnmodifiableList());
1✔
85
                admin = is(authorities, GRANT_ADMIN);
1✔
86
                nmpiexec = is(authorities, GRANT_NMPI_EXEC);
1✔
87
                name = context.getAuthentication().getName();
1✔
88
        }
1✔
89

90
        /**
91
         * Build a permit for a service user. The service user can create jobs and
92
         * read job details, but cannot do much with jobs owned by other users.
93
         * <em>Only used by the legacy interface.</em>
94
         *
95
         * @param serviceUser
96
         *            The user name. Must exist in order to be actually used.
97
         */
98
        public Permit(String serviceUser) {
1✔
99
                authorities = USER.getGrants().collect(toUnmodifiableList());
1✔
100
                admin = false;
1✔
101
                nmpiexec = false;
1✔
102
                name = serviceUser;
1✔
103
        }
1✔
104

105
        /**
106
         * The permit used for web socket handling. Note that websockets never have
107
         * access to admin facilities (and shouldn't ever need them), even if their
108
         * creating user does.
109
         *
110
         * @param session
111
         *            The originating websocket context.
112
         */
113
        public Permit(WebSocketSession session) {
×
114
                authorities = USER.getGrants().collect(toUnmodifiableList());
×
115
                admin = false;
×
116
                nmpiexec = is(authorities, GRANT_NMPI_EXEC);
×
117
                name = session.getPrincipal().getName();
×
118
        }
×
119

120
        /**
121
         * Can something owned by a given user can be shown to the user that this
122
         * permit is for?
123
         *
124
         * @param owner
125
         *            The owner of the object.
126
         * @return True exactly if the object (or subset of properties) may be
127
         *         shown.
128
         */
129
        public boolean unveilFor(String owner) {
130
                return admin || owner.equals(name);
1✔
131
        }
132

133
        /**
134
         * Push our special temporary authentication object for the duration of the
135
         * inner code. Used to satisfy Spring method security.
136
         *
137
         * @param <T>
138
         *            The type of the result
139
         * @param inContext
140
         *            The inner code to run with an authentication object applied.
141
         * @return Whatever the inner code returns
142
         */
143
        public <T> T authorize(Supplier<T> inContext) {
144
                /**
145
                 * A temporarily-installable authentication token. Allows access to
146
                 * secured APIs in asynchronous worker threads, provided they provide a
147
                 * {@link Permit} (obtained from a service thread) to show that they may
148
                 * do so.
149
                 */
150
                @SuppressWarnings("serial")
151
                final class TempAuth implements Authentication {
1✔
152
                        // The permit already proves we're authenticated
153
                        private boolean auth = true;
1✔
154

155
                        @Override
156
                        public String getName() {
157
                                return name;
×
158
                        }
159

160
                        @Override
161
                        public Collection<? extends GrantedAuthority> getAuthorities() {
162
                                return authorities;
×
163
                        }
164

165
                        @Override
166
                        public Object getCredentials() {
167
                                // You can never get the credentials from this
168
                                return null;
×
169
                        }
170

171
                        @Override
172
                        public Permit getDetails() {
173
                                return Permit.this;
×
174
                        }
175

176
                        @Override
177
                        public String getPrincipal() {
178
                                return name;
×
179
                        }
180

181
                        @Override
182
                        public boolean isAuthenticated() {
183
                                return auth;
×
184
                        }
185

186
                        @Override
187
                        public void setAuthenticated(boolean isAuthenticated) {
188
                                if (!isAuthenticated) {
×
189
                                        auth = false;
×
190
                                }
191
                        }
×
192

193
                        @Serial
194
                        private void writeObject(ObjectOutputStream out)
195
                                        throws NotSerializableException {
196
                                throw new NotSerializableException("not actually serializable");
×
197
                        }
198
                }
199

200
                var c = SecurityContextHolder.getContext();
1✔
201
                var old = c.getAuthentication();
1✔
202
                c.setAuthentication(new TempAuth());
1✔
203
                try {
204
                        return inContext.get();
1✔
205
                } finally {
206
                        c.setAuthentication(old);
1✔
207
                }
208
        }
209
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc