package org.hunt.kriimsilm.camunda.jwt; import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.HttpHeaders; import org.camunda.bpm.engine.ProcessEngine; import org.camunda.bpm.engine.rest.security.auth.AuthenticationProvider; import org.camunda.bpm.engine.rest.security.auth.AuthenticationResult; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.SignatureException; import io.jsonwebtoken.UnsupportedJwtException; /** * JWT token authentication provider. * */ public class JwtAuthenticationProvider implements AuthenticationProvider { private static Logger logger = Logger.getLogger(JwtAuthenticationProvider.class.getName()); private static final String TOKEN_PREFIX = "Bearer"; private static PublicKey publicKey; // test purpose public static void setPublicKey(PublicKey publicKey) { JwtAuthenticationProvider.publicKey = publicKey; } @Override public AuthenticationResult extractAuthenticatedUser(HttpServletRequest request, ProcessEngine engine) { String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION); if (authorizationHeader != null && authorizationHeader.startsWith(TOKEN_PREFIX)) { try { try { return doAuthentication(authorizationHeader); } catch (SignatureException | ExpiredJwtException ex) { // lets reset public key and try once again logger.info("Public keys do not match! Reseting Camunda public key ..."); publicKey = null; return doAuthentication(authorizationHeader); } } catch (Exception ex) { logger.severe(ex.getMessage()); return AuthenticationResult.unsuccessful(); } } else { logger.info(HttpHeaders.AUTHORIZATION + " header not found!"); return AuthenticationResult.unsuccessful(); } } @Override public void augmentResponseByAuthenticationChallenge(HttpServletResponse response, ProcessEngine engine) { response.setHeader(HttpHeaders.WWW_AUTHENTICATE, TOKEN_PREFIX); } @SuppressWarnings("unchecked") private AuthenticationResult doAuthentication(final String token) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException, Exception { Claims claims = Jwts.parser().setSigningKey(getPublicKey()) .parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody(); // read groups from jwt token List groups = new ArrayList(); if (claims.containsKey("groups")) { groups.addAll((List) claims.get("groups")); } String user = claims.getSubject(); if (user != null) { AuthenticationResultWithGroups result = new AuthenticationResultWithGroups(user, true); result.getGroupIds().addAll(groups); return result; } else { logger.info("User not found!"); return AuthenticationResult.unsuccessful(); } } /** * Get public key from authentication service (or from memory). * @return * @throws Exception */ public static PublicKey getPublicKey() throws Exception { if (publicKey == null) { byte[] publicKeyBytes = ... // take jwt public key KeyFactory kf = KeyFactory.getInstance("RSA"); publicKey = kf.generatePublic(new X509EncodedKeySpec(publicKeyBytes)); } return publicKey; } }