1 package de.dlr.shepard.common.filters;
2
3 import de.dlr.shepard.auth.security.JWTPrincipal;
4 import de.dlr.shepard.auth.security.UserLastSeenCache;
5 import de.dlr.shepard.auth.security.Userinfo;
6 import de.dlr.shepard.auth.security.UserinfoService;
7 import de.dlr.shepard.auth.users.entities.User;
8 import de.dlr.shepard.auth.users.services.UserService;
9 import de.dlr.shepard.common.exceptions.ApiError;
10 import de.dlr.shepard.common.exceptions.ShepardProcessingException;
11 import io.quarkus.logging.Log;
12 import jakarta.annotation.Priority;
13 import jakarta.enterprise.context.ApplicationScoped;
14 import jakarta.inject.Inject;
15 import jakarta.ws.rs.Priorities;
16 import jakarta.ws.rs.container.ContainerRequestContext;
17 import jakarta.ws.rs.container.ContainerRequestFilter;
18 import jakarta.ws.rs.core.HttpHeaders;
19 import jakarta.ws.rs.core.Response;
20 import jakarta.ws.rs.core.Response.Status;
21 import jakarta.ws.rs.ext.Provider;
22 import java.io.IOException;
23
24 @Provider
25 @Priority(Priorities.AUTHENTICATION + 1)
26 @ApplicationScoped
27 public class UserFilter implements ContainerRequestFilter {
28
29 @Inject
30 UserLastSeenCache userLastSeenCache;
31
32 @Inject
33 UserService userService;
34
35 @Inject
36 UserinfoService userInfoService;
37
38 @Override
39 public void filter(ContainerRequestContext requestContext) throws IOException {
40 if (PublicEndpointRegistry.isRequestPathPublic(requestContext)) return;
41 var principal = requestContext.getSecurityContext().getUserPrincipal();
42 if (!(principal instanceof JWTPrincipal)) {
43 Log.warnf("Unknown principal %s", principal);
44 abort(requestContext, "User could not be read from the request context");
45 return;
46 }
47 var jwtPrincipal = (JWTPrincipal) principal;
48 var header = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
49 if (header != null && header.startsWith("Bearer ") && !userLastSeenCache.isKeyCached(jwtPrincipal.getUsername())) {
50 User user;
51 Userinfo userinfo;
52 try {
53 userinfo = userInfoService.fetchUserinfo(header);
54 } catch (ShepardProcessingException e) {
55 abort(requestContext, "User info could not be retrieved");
56 return;
57 }
58 user = parseUserFromUserinfo(userinfo);
59 if (!jwtPrincipal.getUsername().equals(user.getUsername())) {
60 Log.warn("The usernames from the access token and the userinfo response do not match");
61 abort(requestContext, "The usernames from the access token and the userinfo response do not match");
62 return;
63 }
64 var created = userService.createOrUpdateUser(user);
65 if (created == null) {
66 Log.warn("The user could not be updated or created");
67 abort(requestContext, "The user could not be updated or created");
68 return;
69 }
70 userLastSeenCache.cacheKey(jwtPrincipal.getUsername());
71 }
72 }
73
74 private void abort(ContainerRequestContext requestContext, String reason) {
75 requestContext.abortWith(
76 Response.status(Status.UNAUTHORIZED)
77 .entity(new ApiError(Status.UNAUTHORIZED.getStatusCode(), "AuthenticationException", reason))
78 .build()
79 );
80 }
81
82 private User parseUserFromUserinfo(Userinfo userinfo) {
83
84
85 var splitted = userinfo.getSub().split(":");
86 String username = splitted[splitted.length - 1];
87
88 User user = new User(username, userinfo.getGivenName(), userinfo.getFamilyName(), userinfo.getEmail());
89 return user;
90 }
91 }