package at.tbbm.manual_input.util; import com.auth0.jwk.Jwk; import com.auth0.jwk.JwkException; import com.auth0.jwk.JwkProvider; import com.auth0.jwk.UrlJwkProvider; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.security.Authenticator; import org.eclipse.jetty.security.DefaultUserIdentity; import org.eclipse.jetty.security.UserAuthentication; import org.eclipse.jetty.server.Authentication; import org.eclipse.jetty.server.UserIdentity; import javax.security.auth.Subject; import java.io.IOException; import java.io.UncheckedIOException; import java.net.URL; import java.security.Principal; import java.security.interfaces.RSAPublicKey; import java.util.regex.Pattern; public record JwtAuthenticator(Pattern skipPattern, JwkProvider provider) implements Authenticator { public JwtAuthenticator(Pattern skipPattern, URL jwks) { this(skipPattern, new UrlJwkProvider(jwks)); } @Override public String getAuthMethod() { return "BEARER"; } @Override public void prepareRequest(ServletRequest request) { } @Override public void setConfiguration(AuthConfiguration configuration) { } @Override public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) { HttpServletRequest httpServletRequest = (HttpServletRequest) request; String requestPath = httpServletRequest.getRequestURI().substring(httpServletRequest.getContextPath().length()); if (skipPattern.matcher(requestPath).matches()) { return Authentication.NOT_CHECKED; } try { DecodedJWT jwt = decodedJWT(httpServletRequest); verify(jwt); return buildUserAuthentication(jwt); } catch (JwkException | JWTVerificationException e) { try { ((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED); } catch (IOException e2) { throw new UncheckedIOException(e2); } return Authentication.UNAUTHENTICATED; } } private DecodedJWT decodedJWT(HttpServletRequest httpServletRequest) { String token = httpServletRequest.getHeader(HttpHeader.AUTHORIZATION.asString()).substring("Bearer ".length()); return JWT.decode(token); } private void verify(DecodedJWT jwt) throws JwkException { Jwk jwk = provider.get(jwt.getKeyId()); Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null); JWT.require(algorithm).build().verify(jwt); } private UserAuthentication buildUserAuthentication(DecodedJWT jwt) { Principal email = () -> jwt.getClaims().get("email").asString(); UserIdentity identity = new DefaultUserIdentity(new Subject(), email, new String[]{"role1", "role2"}); return new UserAuthentication(getAuthMethod(), identity); } @Override public boolean secureResponse(ServletRequest request, ServletResponse response, boolean mandatory, Authentication.User validatedUser) { return true; } }