Skip to content

Instantly share code, notes, and snippets.

@simon04
Created December 30, 2021 14:52
Show Gist options
  • Save simon04/c302d738e7f24b90267a1d341d720d6d to your computer and use it in GitHub Desktop.
Save simon04/c302d738e7f24b90267a1d341d720d6d to your computer and use it in GitHub Desktop.

Revisions

  1. simon04 created this gist Dec 30, 2021.
    90 changes: 90 additions & 0 deletions JwtAuthenticator.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,90 @@
    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;
    }
    }