|
9 | 9 | import javax.ws.rs.container.PreMatching; |
10 | 10 | import javax.ws.rs.core.Context; |
11 | 11 | import javax.ws.rs.core.Response; |
| 12 | +import javax.ws.rs.core.UriInfo; |
| 13 | + |
12 | 14 | import java.net.MalformedURLException; |
13 | 15 | import java.net.URL; |
14 | 16 | import java.security.InvalidParameterException; |
|
24 | 26 |
|
25 | 27 | @PreMatching |
26 | 28 | public class KeycloakAuthenticationFilter implements ContainerRequestFilter { |
27 | | - @Context |
28 | | - HttpServletRequest request; |
29 | | - |
30 | | - @Override |
31 | | - |
32 | | - public void filter(ContainerRequestContext requestContext) throws IOException { |
33 | | - if (requestContext.getMethod().equals("GET") || requestContext.getMethod().equals("FETCH") || |
34 | | - requestContext.getMethod().equals("OPTIONS")) { |
35 | | - } else { |
36 | | - String token = requestContext.getHeaderString("Authorization"); |
37 | | - if (token == null || "".equals(token)) { |
38 | | - requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Access denied").build()); |
39 | | - } else { |
40 | | - final JwtValidator validator = new JwtValidator(); |
41 | | - try { |
42 | | - if (token.contains("Bearer")) { |
43 | | - token = token.substring(7); |
44 | | - } |
45 | | - DecodedJWT jwtToken = validator.validate(token.replaceAll("Bearer ", "")); |
46 | | - String email = jwtToken.getClaim("email").asString(); |
47 | | - requestContext.setProperty("username", email); |
48 | | - } catch (InvalidParameterException e) { |
49 | | - requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Access denied").build()); |
50 | | - e.printStackTrace(); |
| 29 | + @Context |
| 30 | + HttpServletRequest request; |
| 31 | + |
| 32 | + @Override |
| 33 | + public void filter(ContainerRequestContext requestContext) throws IOException { |
| 34 | + // Only filter POSTS |
| 35 | + if (requestContext.getMethod().equals("GET") || |
| 36 | + requestContext.getMethod().equals("FETCH") || |
| 37 | + requestContext.getMethod().equals("OPTIONS")) { |
| 38 | + return; |
51 | 39 | } |
52 | | - } |
53 | | - } |
54 | | - } |
55 | 40 |
|
56 | | - public class JwtValidator { |
57 | | - private final List<String> allowedIsses = Collections |
58 | | - .singletonList("https://auth.mint.isi.edu/realms/production"); |
| 41 | + // Special case for getData. |
| 42 | + UriInfo uriInfo = requestContext.getUriInfo(); |
| 43 | + String path = uriInfo.getAbsolutePath().getPath(); |
| 44 | + if (path.endsWith("getData")) |
| 45 | + return; |
| 46 | + |
| 47 | + // All other request must have an authorization token. |
| 48 | + String token = requestContext.getHeaderString("Authorization"); |
| 49 | + if (token != null && !token.equals("")) { |
| 50 | + final JwtValidator validator = new JwtValidator(); |
| 51 | + try { |
| 52 | + // Remove the Bearer part |
| 53 | + if (token.startsWith("Bearer")) { |
| 54 | + token = token.substring(7); |
| 55 | + } |
| 56 | + DecodedJWT jwtToken = validator.validate(token); |
| 57 | + String email = jwtToken.getClaim("email").asString(); |
| 58 | + requestContext.setProperty("username", email); |
| 59 | + return; |
| 60 | + } catch (InvalidParameterException e) { |
| 61 | + e.printStackTrace(); |
| 62 | + } |
| 63 | + } |
59 | 64 |
|
60 | | - private String getKeycloakCertificateUrl(DecodedJWT token) { |
61 | | - return token.getIssuer() + "/protocol/openid-connect/certs"; |
| 65 | + requestContext.abortWith( |
| 66 | + Response.status(Response.Status.UNAUTHORIZED) |
| 67 | + .entity("Access denied").build()); |
62 | 68 | } |
63 | 69 |
|
64 | | - private RSAPublicKey loadPublicKey(DecodedJWT token) throws JwkException, MalformedURLException { |
65 | | - |
66 | | - final String url = getKeycloakCertificateUrl(token); |
67 | | - JwkProvider provider = new UrlJwkProvider(new URL(url)); |
| 70 | + public class JwtValidator { |
| 71 | + private final List<String> allowedIsses = Collections |
| 72 | + .singletonList("https://auth.mint.isi.edu/realms/production"); |
68 | 73 |
|
69 | | - return (RSAPublicKey) provider.get(token.getKeyId()).getPublicKey(); |
70 | | - } |
71 | | - |
72 | | - /** |
73 | | - * Validate a JWT token |
74 | | - * |
75 | | - * @param token |
76 | | - * @return decoded token |
77 | | - */ |
78 | | - public DecodedJWT validate(String token) { |
79 | | - try { |
80 | | - final DecodedJWT jwt = JWT.decode(token); |
81 | | - |
82 | | - if (!allowedIsses.contains(jwt.getIssuer())) { |
83 | | - throw new InvalidParameterException(String.format("Unknown Issuer %s", jwt.getIssuer())); |
| 74 | + private String getKeycloakCertificateUrl(DecodedJWT token) { |
| 75 | + return token.getIssuer() + "/protocol/openid-connect/certs"; |
84 | 76 | } |
85 | 77 |
|
86 | | - RSAPublicKey publicKey = loadPublicKey(jwt); |
| 78 | + private RSAPublicKey loadPublicKey(DecodedJWT token) throws JwkException, MalformedURLException { |
87 | 79 |
|
88 | | - Algorithm algorithm = Algorithm.RSA256(publicKey, null); |
89 | | - JWTVerifier verifier = JWT.require(algorithm) |
90 | | - .withIssuer(jwt.getIssuer()) |
91 | | - .build(); |
| 80 | + final String url = getKeycloakCertificateUrl(token); |
| 81 | + JwkProvider provider = new UrlJwkProvider(new URL(url)); |
92 | 82 |
|
93 | | - verifier.verify(token); |
94 | | - return jwt; |
| 83 | + return (RSAPublicKey) provider.get(token.getKeyId()).getPublicKey(); |
| 84 | + } |
95 | 85 |
|
96 | | - } catch (Exception e) { |
97 | | - throw new InvalidParameterException("JWT validation failed: " + e.getMessage()); |
98 | | - } |
| 86 | + /** |
| 87 | + * Validate a JWT token |
| 88 | + * |
| 89 | + * @param token |
| 90 | + * @return decoded token |
| 91 | + */ |
| 92 | + public DecodedJWT validate(String token) { |
| 93 | + try { |
| 94 | + final DecodedJWT jwt = JWT.decode(token); |
| 95 | + |
| 96 | + if (!allowedIsses.contains(jwt.getIssuer())) { |
| 97 | + throw new InvalidParameterException(String.format("Unknown Issuer %s", jwt.getIssuer())); |
| 98 | + } |
| 99 | + |
| 100 | + RSAPublicKey publicKey = loadPublicKey(jwt); |
| 101 | + |
| 102 | + Algorithm algorithm = Algorithm.RSA256(publicKey, null); |
| 103 | + JWTVerifier verifier = JWT.require(algorithm) |
| 104 | + .withIssuer(jwt.getIssuer()) |
| 105 | + .build(); |
| 106 | + |
| 107 | + verifier.verify(token); |
| 108 | + return jwt; |
| 109 | + |
| 110 | + } catch (Exception e) { |
| 111 | + throw new InvalidParameterException("JWT validation failed: " + e.getMessage()); |
| 112 | + } |
| 113 | + } |
99 | 114 | } |
100 | | - } |
101 | 115 | } |
0 commit comments