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

SpiNNakerManchester / JavaSpiNNaker / 14610151785

21 Mar 2025 04:17PM UTC coverage: 38.216% (-0.4%) from 38.579%
14610151785

push

github

web-flow
Merge pull request #1222 from SpiNNakerManchester/more_spalloc_rest_calls

More spalloc rest calls

70 of 815 new or added lines in 33 files covered. (8.59%)

36 existing lines in 15 files now uncovered.

9181 of 24024 relevant lines covered (38.22%)

1.15 hits per line

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

54.17
/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.util.Collection;
28
import java.util.List;
29
import java.util.function.Supplier;
30

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

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

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

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

51
        private final List<GrantedAuthority> authorities;
52

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

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

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

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

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

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

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

132
        /**
133
         * Push our special temporary authentication object for the duration of the
134
         * inner code. Used to satisfy Spring method security.
135
         *
136
         * @param <T>
137
         *            The type of the result
138
         * @param inContext
139
         *            The inner code to run with an authentication object applied.
140
         * @return Whatever the inner code returns
141
         */
142
        public <T> T authorize(Supplier<T> inContext) {
143
                var c = SecurityContextHolder.getContext();
3✔
144
                var old = c.getAuthentication();
3✔
145
                c.setAuthentication(new TempAuth());
3✔
146
                try {
147
                        return inContext.get();
3✔
148
                } finally {
149
                        c.setAuthentication(old);
3✔
150
                }
151
        }
152

153
        /**
154
         * A temporarily-installable authentication token. Allows access to
155
         * secured APIs in asynchronous worker threads, provided they provide a
156
         * {@link Permit} (obtained from a service thread) to show that they may
157
         * do so.
158
         */
159
        @SuppressWarnings("serial")
160
        final class TempAuth implements Authentication {
3✔
161
                // The permit already proves we're authenticated
162
                private boolean auth = true;
3✔
163

164
                @Override
165
                public String getName() {
NEW
166
                        return name;
×
167
                }
168

169
                @Override
170
                public Collection<? extends GrantedAuthority> getAuthorities() {
NEW
171
                        return authorities;
×
172
                }
173

174
                @Override
175
                public Object getCredentials() {
176
                        // You can never get the credentials from this
NEW
177
                        return null;
×
178
                }
179

180
                @Override
181
                public Permit getDetails() {
NEW
182
                        return Permit.this;
×
183
                }
184

185
                @Override
186
                public String getPrincipal() {
NEW
187
                        return name;
×
188
                }
189

190
                @Override
191
                public boolean isAuthenticated() {
192
                        return auth;
3✔
193
                }
194

195
                @Override
196
                public void setAuthenticated(boolean isAuthenticated) {
NEW
197
                        if (!isAuthenticated) {
×
NEW
198
                                auth = false;
×
199
                        }
UNCOV
200
                }
×
201

202
                private void writeObject(ObjectOutputStream out)
203
                                throws NotSerializableException {
NEW
204
                        throw new NotSerializableException("not actually serializable");
×
205
                }
206
        }
207
}
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