1 package de.dlr.shepard.common.filters;
2
3 import static org.mockito.ArgumentMatchers.any;
4 import static org.mockito.Mockito.never;
5 import static org.mockito.Mockito.verify;
6 import static org.mockito.Mockito.when;
7
8 import de.dlr.shepard.auth.security.JWTPrincipal;
9 import de.dlr.shepard.auth.security.UserLastSeenCache;
10 import de.dlr.shepard.auth.security.Userinfo;
11 import de.dlr.shepard.auth.security.UserinfoService;
12 import de.dlr.shepard.auth.users.entities.User;
13 import de.dlr.shepard.auth.users.services.UserService;
14 import de.dlr.shepard.common.exceptions.ShepardProcessingException;
15 import io.quarkus.test.InjectMock;
16 import io.quarkus.test.component.QuarkusComponentTest;
17 import jakarta.inject.Inject;
18 import jakarta.ws.rs.container.ContainerRequestContext;
19 import jakarta.ws.rs.core.HttpHeaders;
20 import jakarta.ws.rs.core.SecurityContext;
21 import jakarta.ws.rs.core.UriInfo;
22 import java.io.IOException;
23 import java.net.URISyntaxException;
24 import java.security.Principal;
25 import org.junit.jupiter.api.BeforeEach;
26 import org.junit.jupiter.api.Test;
27 import org.mockito.ArgumentCaptor;
28 import org.mockito.Captor;
29
30 @QuarkusComponentTest
31 public class UserFilterTest {
32
33 @InjectMock
34 ContainerRequestContext requestContext;
35
36 @InjectMock
37 SecurityContext securityContext;
38
39 @InjectMock
40 UserService userService;
41
42 @InjectMock
43 UserinfoService userinfoService;
44
45 @InjectMock
46 UserLastSeenCache userLastSeenCache;
47
48 @InjectMock
49 UriInfo uriInfo;
50
51 @Inject
52 UserFilter filter;
53
54 @Captor
55 ArgumentCaptor<JWTPrincipal> userCaptor;
56
57 @BeforeEach
58 public void prepareSpy() throws IllegalAccessException {
59 when(requestContext.getSecurityContext()).thenReturn(securityContext);
60 }
61
62 @Test
63 public void testFilterPublic_publicRoute() throws URISyntaxException, IOException {
64 String relativePath = "/versionz";
65 when(uriInfo.getPath()).thenReturn(relativePath);
66 when(requestContext.getUriInfo()).thenReturn(uriInfo);
67 filter.filter(requestContext);
68 verify(requestContext, never()).abortWith(any());
69 }
70
71 @Test
72 public void testFilterPublic_privateRoute() throws URISyntaxException, IOException {
73 String relativePath = "/versionsz";
74 when(uriInfo.getPath()).thenReturn(relativePath);
75 when(requestContext.getUriInfo()).thenReturn(uriInfo);
76 filter.filter(requestContext);
77 verify(requestContext).abortWith(any());
78 }
79
80 @Test
81 public void testFilter_Successful() throws IOException, ShepardProcessingException {
82 Principal p = new JWTPrincipal("bob", "MyKeyId");
83 Userinfo ui = new Userinfo("bob", "name", "john.doe@example.com", "John", "Doe", "doe_jo");
84 User u = new User("bob", "John", "Doe", "john.doe@example.com");
85
86 when(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)).thenReturn("Bearer abc");
87 String relativePath = "/projects";
88 when(uriInfo.getPath()).thenReturn(relativePath);
89 when(requestContext.getUriInfo()).thenReturn(uriInfo);
90
91 when(securityContext.getUserPrincipal()).thenReturn(p);
92 when(userinfoService.fetchUserinfo("Bearer abc")).thenReturn(ui);
93 when(userService.createOrUpdateUser(u)).thenReturn(u);
94
95 filter.filter(requestContext);
96 verify(userService).createOrUpdateUser(u);
97 verify(userLastSeenCache).cacheKey("bob");
98 verify(requestContext, never()).abortWith(any());
99 }
100
101 @Test
102 public void testFilter_SuccessfulUsernameConversion() throws IOException, ShepardProcessingException {
103 Principal p = new JWTPrincipal("bob", "MyKeyId");
104 Userinfo ui = new Userinfo("f:123:bob", "name", "john.doe@example.com", "John", "Doe", "doe_jo");
105 User u = new User("bob", "John", "Doe", "john.doe@example.com");
106
107 when(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)).thenReturn("Bearer abc");
108 when(securityContext.getUserPrincipal()).thenReturn(p);
109 when(userinfoService.fetchUserinfo("Bearer abc")).thenReturn(ui);
110 when(userService.createOrUpdateUser(u)).thenReturn(u);
111 String relativePath = "/projects";
112 when(uriInfo.getPath()).thenReturn(relativePath);
113 when(requestContext.getUriInfo()).thenReturn(uriInfo);
114
115 filter.filter(requestContext);
116 verify(userService).createOrUpdateUser(u);
117 verify(userLastSeenCache).cacheKey("bob");
118 verify(requestContext, never()).abortWith(any());
119 }
120
121 @Test
122 public void testFilter_GracePeriod() throws IOException {
123 Principal p = new JWTPrincipal("bob", "MyKeyId");
124
125 when(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)).thenReturn("Bearer abc");
126 when(securityContext.getUserPrincipal()).thenReturn(p);
127 when(userLastSeenCache.isKeyCached("bob")).thenReturn(true);
128 String relativePath = "/projects";
129 when(uriInfo.getPath()).thenReturn(relativePath);
130 when(requestContext.getUriInfo()).thenReturn(uriInfo);
131
132 filter.filter(requestContext);
133 verify(userService, never()).createOrUpdateUser(any());
134 verify(userLastSeenCache, never()).cacheKey(any());
135 }
136
137 @Test
138 public void testFilter_NoPrincipal() throws IOException {
139 when(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)).thenReturn("Bearer abc");
140 when(securityContext.getUserPrincipal()).thenReturn(null);
141 String relativePath = "/projects";
142 when(uriInfo.getPath()).thenReturn(relativePath);
143 when(requestContext.getUriInfo()).thenReturn(uriInfo);
144
145 filter.filter(requestContext);
146 verify(userService, never()).createOrUpdateUser(any());
147 verify(userLastSeenCache, never()).cacheKey(any());
148 verify(requestContext).abortWith(any());
149 }
150
151 @Test
152 public void testFilter_InvalidPrincipal() throws IOException {
153 Principal p = new Principal() {
154 @Override
155 public String getName() {
156 return "myName";
157 }
158 };
159
160 when(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)).thenReturn("Bearer abc");
161 when(securityContext.getUserPrincipal()).thenReturn(p);
162 String relativePath = "/projects";
163 when(uriInfo.getPath()).thenReturn(relativePath);
164 when(requestContext.getUriInfo()).thenReturn(uriInfo);
165
166 filter.filter(requestContext);
167 verify(userService, never()).createOrUpdateUser(any());
168 verify(userLastSeenCache, never()).cacheKey(any());
169 verify(requestContext).abortWith(any());
170 }
171
172 @Test
173 public void testFilter_noHeader() throws IOException {
174 Principal p = new JWTPrincipal("bob", "MyKeyId");
175
176 when(securityContext.getUserPrincipal()).thenReturn(p);
177 when(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)).thenReturn(null);
178 String relativePath = "/projects";
179 when(uriInfo.getPath()).thenReturn(relativePath);
180 when(requestContext.getUriInfo()).thenReturn(uriInfo);
181
182 filter.filter(requestContext);
183 verify(userService, never()).createOrUpdateUser(any());
184 verify(userLastSeenCache, never()).cacheKey(any());
185 }
186
187 @Test
188 public void testFilter_invalidHeader() throws IOException {
189 Principal p = new JWTPrincipal("bob", "MyKeyId");
190
191 when(securityContext.getUserPrincipal()).thenReturn(p);
192 when(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)).thenReturn("invalid");
193 String relativePath = "/projects";
194 when(uriInfo.getPath()).thenReturn(relativePath);
195 when(requestContext.getUriInfo()).thenReturn(uriInfo);
196
197 filter.filter(requestContext);
198 verify(userService, never()).createOrUpdateUser(any());
199 verify(userLastSeenCache, never()).cacheKey(any());
200 }
201
202 @Test
203 public void testFilter_ProcessingException() throws IOException, ShepardProcessingException {
204 Principal p = new JWTPrincipal("bob", "MyKeyId");
205
206 when(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)).thenReturn("Bearer abc");
207 when(securityContext.getUserPrincipal()).thenReturn(p);
208 when(userinfoService.fetchUserinfo("Bearer abc")).thenThrow(new ShepardProcessingException("Message"));
209 String relativePath = "/projects";
210 when(uriInfo.getPath()).thenReturn(relativePath);
211 when(requestContext.getUriInfo()).thenReturn(uriInfo);
212
213 filter.filter(requestContext);
214 verify(userService, never()).createOrUpdateUser(any());
215 verify(userLastSeenCache, never()).cacheKey(any());
216 verify(requestContext).abortWith(any());
217 }
218
219 @Test
220 public void testFilter_InconsistentUsernames() throws IOException, ShepardProcessingException {
221 Principal p = new JWTPrincipal("bob", "MyKeyId");
222 Userinfo ui = new Userinfo("claus", "name", "john.doe@example.com", "John", "Doe", "doe_jo");
223
224 when(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)).thenReturn("Bearer abc");
225 when(securityContext.getUserPrincipal()).thenReturn(p);
226 when(userinfoService.fetchUserinfo("Bearer abc")).thenReturn(ui);
227 String relativePath = "/projects";
228 when(uriInfo.getPath()).thenReturn(relativePath);
229 when(requestContext.getUriInfo()).thenReturn(uriInfo);
230
231 filter.filter(requestContext);
232 verify(userService, never()).createOrUpdateUser(any());
233 verify(userLastSeenCache, never()).cacheKey(any());
234 verify(requestContext).abortWith(any());
235 }
236
237 @Test
238 public void testFilter_UpdatedFailed() throws IOException, ShepardProcessingException {
239 Principal p = new JWTPrincipal("bob", "MyKeyId");
240 Userinfo ui = new Userinfo("bob", "name", "john.doe@example.com", "John", "Doe", "doe_jo");
241 User u = new User("bob", "John", "Doe", "john.doe@example.com");
242
243 when(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)).thenReturn("Bearer abc");
244 when(securityContext.getUserPrincipal()).thenReturn(p);
245 when(userinfoService.fetchUserinfo("Bearer abc")).thenReturn(ui);
246 when(userService.createOrUpdateUser(u)).thenReturn(null);
247 String relativePath = "/projects";
248 when(uriInfo.getPath()).thenReturn(relativePath);
249 when(requestContext.getUriInfo()).thenReturn(uriInfo);
250
251 filter.filter(requestContext);
252 verify(userLastSeenCache, never()).cacheKey(any());
253 verify(requestContext).abortWith(any());
254 }
255 }