View Javadoc

1   package com.atlassian.asap.nimbus.serializer;
2   
3   import com.atlassian.asap.api.AlgorithmType;
4   import com.atlassian.asap.api.Jwt;
5   import com.atlassian.asap.api.JwtClaims;
6   import com.atlassian.asap.api.SigningAlgorithm;
7   import com.atlassian.asap.core.SecurityProvider;
8   import com.atlassian.asap.core.exception.SigningException;
9   import com.atlassian.asap.core.exception.UnsupportedAlgorithmException;
10  import com.atlassian.asap.core.serializer.JwtSerializer;
11  import com.google.common.annotations.VisibleForTesting;
12  import com.nimbusds.jose.JOSEException;
13  import com.nimbusds.jose.JWSAlgorithm;
14  import com.nimbusds.jose.JWSHeader;
15  import com.nimbusds.jose.JWSObject;
16  import com.nimbusds.jose.JWSSigner;
17  import com.nimbusds.jose.Payload;
18  import com.nimbusds.jose.crypto.ECDSASigner;
19  import com.nimbusds.jose.crypto.RSASSASigner;
20  import net.minidev.json.JSONObject;
21  import org.slf4j.Logger;
22  import org.slf4j.LoggerFactory;
23  
24  import java.security.PrivateKey;
25  import java.security.Provider;
26  import java.security.interfaces.ECPrivateKey;
27  import java.security.interfaces.RSAPrivateKey;
28  
29  /**
30   * A serializer of JWT implemented using the Nimbus library.
31   */
32  public class NimbusJwtSerializer implements JwtSerializer {
33      private static final Logger logger = LoggerFactory.getLogger(NimbusJwtSerializer.class);
34  
35      private final Provider provider;
36  
37      public NimbusJwtSerializer() {
38          this(SecurityProvider.getProvider());
39      }
40  
41      public NimbusJwtSerializer(Provider provider) {
42          this.provider = provider;
43      }
44  
45      @Override
46      public String serialize(Jwt jwt, PrivateKey privateKey) throws SigningException, UnsupportedAlgorithmException {
47          JWSObject jwsObject = getSignedJwsObject(jwt, privateKey);
48  
49          return jwsObject.serialize();
50      }
51  
52      @VisibleForTesting
53      JWSObject getSignedJwsObject(Jwt jwt, PrivateKey privateKey) throws UnsupportedAlgorithmException {
54          SigningAlgorithm algorithm = jwt.getHeader().getAlgorithm();
55          JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.parse(algorithm.name())) // fails if algorithm is None
56                  .keyID(jwt.getHeader().getKeyId())
57                  .build();
58          Payload payload = new Payload(toJsonPayload(jwt.getClaims()));
59          JWSObject jwsObject = new JWSObject(header, payload);
60          try {
61              jwsObject.sign(getSigner(algorithm, privateKey));
62          } catch (JOSEException e) {
63              logger.error("Unexpected error when signing JWT token", e);
64              throw new SigningException();
65          }
66          return jwsObject;
67      }
68  
69      private JWSSigner getSigner(SigningAlgorithm algorithm, PrivateKey privateKey) throws UnsupportedAlgorithmException {
70          if ((algorithm.type() == AlgorithmType.RSA || algorithm.type() == AlgorithmType.RSASSA_PSS) && privateKey instanceof RSAPrivateKey) {
71              return createRSASSASignerForKey((RSAPrivateKey) privateKey);
72          } else if (algorithm.type() == AlgorithmType.ECDSA && privateKey instanceof ECPrivateKey) {
73              return createECDSASignerForKey((ECPrivateKey) privateKey);
74          } else {
75              throw new UnsupportedAlgorithmException(String.format("Unsupported algorithm %s or signing key type", algorithm.name()));
76          }
77      }
78  
79      @VisibleForTesting
80      protected JWSSigner createRSASSASignerForKey(RSAPrivateKey privateKey) {
81          final RSASSASigner rsassaSigner = new RSASSASigner(privateKey);
82          rsassaSigner.getJCAContext().setProvider(provider);
83          return rsassaSigner;
84      }
85  
86      @VisibleForTesting
87      protected JWSSigner createECDSASignerForKey(ECPrivateKey privateKey) throws UnsupportedAlgorithmException {
88          try {
89              final ECDSASigner ecdsaSigner = new ECDSASigner(privateKey);
90              ecdsaSigner.getJCAContext().setProvider(provider);
91              return ecdsaSigner;
92          } catch (JOSEException e) {
93              throw new UnsupportedAlgorithmException(String.format("Unsupported algorithm %s or signing key type", privateKey.getAlgorithm()));
94          }
95      }
96  
97      private static JSONObject toJsonPayload(JwtClaims claims) {
98          return (JSONObject) Jsr353NimbusTranslator.jsr353ToNimbus(claims.getJson());
99      }
100 }