All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.launchkey.sdk.crypto.jwt.Jose4jJWTService Maven / Gradle / Ivy

Go to download

SDK for interacting with the LaunchKey distributed authentication and authorization platform

The newest version!
/**
 * Copyright 2016 LaunchKey, Inc. All rights reserved.
 * 

* Licensed under the MIT License. * You may not use this file except in compliance with the License. * A copy of the License is located in the "LICENSE.txt" file accompanying * this file. This file is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.launchkey.sdk.crypto.jwt; import org.jose4j.jwa.AlgorithmConstraints; import org.jose4j.jws.AlgorithmIdentifiers; import org.jose4j.jws.JsonWebSignature; import org.jose4j.jwt.JwtClaims; import org.jose4j.jwt.MalformedClaimException; import org.jose4j.jwt.NumericDate; import org.jose4j.jwt.consumer.*; import org.jose4j.jwx.JsonWebStructure; import org.jose4j.lang.JoseException; import java.security.PublicKey; import java.security.interfaces.RSAPrivateKey; import java.util.Date; import java.util.HashMap; import java.util.Map; public class Jose4jJWTService implements JWTService { private final String apiIdentifier; private final Map privateKeys; private final String currentPrivateKeyId; private final int requestExpireSeconds; /** * @param apiIdentifier JWT identifier for the Platform API. Used as the apiIdentifier for encoding and the * issuer for decoding. * @param privateKeys Mapped list of RSA Private Key by key ID of the RSA public/private key pairs that will be * used to generate digital encoding and decoding as well as obtaining the RSA Public Key of the RSA public/private * key pair of the Platform API which will be used to verify digital signatures when decoding. * @param currentPrivateKeyId Public key fingerprint of the RSA private key that wi8ll be used to encode requests. * @param requestExpireSeconds The number of seconds from the issue ("iss") time to use for the expiration ("exp") * time when encoding. */ public Jose4jJWTService( String apiIdentifier, Map privateKeys, String currentPrivateKeyId, int requestExpireSeconds ) { this.apiIdentifier = apiIdentifier; this.privateKeys = privateKeys; this.currentPrivateKeyId = currentPrivateKeyId; this.requestExpireSeconds = requestExpireSeconds; } @Override public String encode( String jti, String issuer, String subject, Date currentTime, String method, String path, String contentHashAlgorithm, String contentHash ) throws JWTError { JwtClaims jwtClaims = new JwtClaims(); jwtClaims.setJwtId(jti); jwtClaims.setIssuer(issuer); jwtClaims.setSubject(subject); jwtClaims.setAudience(apiIdentifier); NumericDate now = NumericDate.fromMilliseconds(currentTime.getTime()); jwtClaims.setIssuedAt(now); jwtClaims.setNotBefore(now); NumericDate exp = NumericDate.fromMilliseconds(currentTime.getTime()); exp.addSeconds((long) requestExpireSeconds); jwtClaims.setExpirationTime(exp); Map request = new HashMap(); //noinspection SpellCheckingInspection request.put("meth", method); request.put("path", path); if (contentHashAlgorithm != null) { request.put("func", contentHashAlgorithm); request.put("hash", contentHash); } jwtClaims.setClaim("request", request); JsonWebSignature jws = new JsonWebSignature(); jws.setKeyIdHeaderValue(currentPrivateKeyId); jws.setKey(privateKeys.get(currentPrivateKeyId)); jws.setPayload(jwtClaims.toJson()); jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); String jwt; try { jwt = jws.getCompactSerialization(); } catch (JoseException e) { throw new JWTError("An error occurred encoding the JWT", e); } return jwt; } @Override public JWTClaims decode(PublicKey publicKey, String expectedAudience, String expectedTokenId, Date currentTime, String jwt) throws JWTError { JWTClaims claims; try { AlgorithmConstraints algorithmConstraints = new AlgorithmConstraints( AlgorithmConstraints.ConstraintType.WHITELIST, AlgorithmIdentifiers.RSA_USING_SHA256, AlgorithmIdentifiers.RSA_USING_SHA384, AlgorithmIdentifiers.RSA_USING_SHA512 ); NumericDate evaluationTime = NumericDate.fromMilliseconds(currentTime.getTime()); JwtConsumerBuilder builder = new JwtConsumerBuilder() .setVerificationKey(publicKey) .setEvaluationTime(evaluationTime) .setAllowedClockSkewInSeconds(5) .setExpectedAudience(expectedAudience) .setExpectedIssuer(apiIdentifier) .setRequireIssuedAt() .setRequireNotBefore() .setRequireExpirationTime() .setJwsAlgorithmConstraints(algorithmConstraints); if (expectedTokenId != null) { builder.setRequireJwtId() .registerValidator(new JwtIdValidator(expectedTokenId)) .build(); } JwtConsumer jwtConsumer = builder.build(); JwtClaims libraryClaims = jwtConsumer.processToClaims(jwt); Map requestClaims = libraryClaims.getClaimValue("request", Map.class); claims = new JWTClaims( libraryClaims.getJwtId(), libraryClaims.getIssuer(), libraryClaims.getSubject(), libraryClaims.getAudience().get(0), (int) libraryClaims.getIssuedAt().getValue(), (int) libraryClaims.getNotBefore().getValue(), (int) libraryClaims.getExpirationTime().getValue(), requestClaims == null ? null : requestClaims.get("func"), requestClaims == null ? null : requestClaims.get("hash"), requestClaims == null ? null : requestClaims.get("meth"), requestClaims == null ? null : requestClaims.get("path") ); } catch (InvalidJwtException e) { throw new JWTError("An error occurred parsing the JWT", e); } catch (MalformedClaimException e) { throw new JWTError("An error occurred parsing a claim", e); } return claims; } @Override public JWTData getJWTData(String jwt) throws JWTError { String keyId = null; JWTData jwtData; try { JwtConsumer consumer = new JwtConsumerBuilder() .setSkipAllValidators() .setSkipSignatureVerification() .build(); JwtContext jwtContext = consumer.process(jwt); for (JsonWebStructure joseObject : jwtContext.getJoseObjects()) { keyId = joseObject.getKeyIdHeaderValue(); if (keyId != null) { break; } } if (keyId == null) { throw new JWTError("No kid found!", null); } JwtClaims claims = consumer.processToClaims(jwt); jwtData = new JWTData( claims.getIssuer(), claims.getSubject(), claims.getAudience().get(0), keyId ); } catch (InvalidJwtException e) { throw new JWTError("An error occurred parsing the JWT", e); } catch (MalformedClaimException e) { throw new JWTError("An error occurred parsing the JWT", e); } return jwtData; } /** * Validator to assert JWT ID (tid) is the expected value */ public class JwtIdValidator implements Validator { private final String expected; public JwtIdValidator(String expected) { this.expected = expected; } @Override public String validate(JwtContext jwtContext) throws MalformedClaimException { String jti = jwtContext.getJwtClaims().getJwtId(); return jti != null && jti.equals(expected) ? null : "Mismatched JWT ID"; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy