Created
December 30, 2021 14:52
-
-
Save simon04/c302d738e7f24b90267a1d341d720d6d to your computer and use it in GitHub Desktop.
Jetty Authenticator for JWT/JWKS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment