001package com.nimbusds.oauth2.sdk.assertions.jwt;
002
003
004import java.security.Provider;
005import java.security.interfaces.ECPrivateKey;
006import java.security.interfaces.RSAPrivateKey;
007import java.util.Collections;
008import java.util.HashSet;
009import java.util.Set;
010
011import com.nimbusds.oauth2.sdk.auth.Secret;
012
013import com.nimbusds.jose.JOSEException;
014import com.nimbusds.jose.JWSAlgorithm;
015import com.nimbusds.jose.JWSHeader;
016import com.nimbusds.jose.crypto.ECDSASigner;
017import com.nimbusds.jose.crypto.MACSigner;
018import com.nimbusds.jose.crypto.RSASSASigner;
019import com.nimbusds.jwt.SignedJWT;
020
021
022/**
023 * Static JWT bearer assertion factory.
024 *
025 * <p>Related specifications:
026 *
027 * <ul>
028 *     <li>Assertion Framework for OAuth 2.0 Client Authentication and
029 *         Authorization Grants (RFC 7521).
030 *     <li>JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and
031 *         Authorization Grants (RFC 7523).
032 * </ul>
033 */
034public class JWTAssertionFactory {
035
036
037        /**
038         * Returns the supported signature JSON Web Algorithms (JWAs).
039         *
040         * @return The supported JSON Web Algorithms (JWAs).
041         */
042        public static Set<JWSAlgorithm> supportedJWAs() {
043
044                Set<JWSAlgorithm> supported = new HashSet<>();
045                supported.addAll(JWSAlgorithm.Family.HMAC_SHA);
046                supported.addAll(JWSAlgorithm.Family.RSA);
047                supported.addAll(JWSAlgorithm.Family.EC);
048                return Collections.unmodifiableSet(supported);
049        }
050
051
052        /**
053         * Creates a new HMAC-protected JWT bearer assertion.
054         *
055         * @param details      The JWT bearer assertion details. Must not be
056         *                     {@code null}.
057         * @param jwsAlgorithm The expected HMAC algorithm (HS256, HS384 or
058         *                     HS512) for the JWT assertion. Must be supported
059         *                     and not {@code null}.
060         * @param secret       The secret. Must be at least 256-bits long.
061         *
062         * @return The JWT bearer assertion.
063         *
064         * @throws JOSEException If the client secret is too short, or HMAC
065         *                       computation failed.
066         */
067        public static SignedJWT create(final JWTAssertionDetails details,
068                                       final JWSAlgorithm jwsAlgorithm,
069                                       final Secret secret)
070                throws JOSEException {
071
072                SignedJWT signedJWT = new SignedJWT(new JWSHeader(jwsAlgorithm), details.toJWTClaimsSet());
073                signedJWT.sign(new MACSigner(secret.getValueBytes()));
074                return signedJWT;
075        }
076
077
078        /**
079         * Creates a new RSA-signed JWT bearer assertion.
080         *
081         * @param details       The JWT bearer assertion details. Must not be
082         *                      be {@code null}.
083         * @param jwsAlgorithm  The expected RSA signature algorithm (RS256,
084         *                      RS384, RS512, PS256, PS384 or PS512) for the
085         *                      JWT assertion. Must be supported and not
086         *                      {@code null}.
087         * @param rsaPrivateKey The RSA private key. Must not be {@code null}.
088         * @param keyID         Optional identifier for the RSA key, to aid key
089         *                      selection on the recipient side. Recommended.
090         *                      {@code null} if not specified.
091         * @param jcaProvider   Optional specific JCA provider, {@code null} to
092         *                      use the default one.
093         *
094         * @return The JWT bearer assertion.
095         *
096         * @throws JOSEException If RSA signing failed.
097         */
098        public static SignedJWT create(final JWTAssertionDetails details,
099                                       final JWSAlgorithm jwsAlgorithm,
100                                       final RSAPrivateKey rsaPrivateKey,
101                                       final String keyID,
102                                       final Provider jcaProvider)
103                throws JOSEException {
104
105                SignedJWT signedJWT = new SignedJWT(
106                        new JWSHeader.Builder(jwsAlgorithm).keyID(keyID).build(),
107                        details.toJWTClaimsSet());
108                RSASSASigner signer = new RSASSASigner(rsaPrivateKey);
109                if (jcaProvider != null) {
110                        signer.getJCAContext().setProvider(jcaProvider);
111                }
112                signedJWT.sign(signer);
113                return signedJWT;
114        }
115
116
117        /**
118         * Creates a new EC-signed JWT bearer assertion.
119         *
120         * @param details      The JWT bearer assertion details. Must not be
121         *                     {@code null}.
122         * @param jwsAlgorithm The expected EC signature algorithm (ES256,
123         *                     ES384 or ES512) for the JWT assertion. Must be
124         *                     supported and not {@code null}.
125         * @param ecPrivateKey The EC private key. Must not be {@code null}.
126         * @param keyID        Optional identifier for the EC key, to aid key
127         *                     selection on the recipient side. Recommended.
128         *                     {@code null} if not specified.
129         * @param jcaProvider  Optional specific JCA provider, {@code null} to
130         *                     use the default one.
131         *
132         * @return The JWT bearer assertion.
133         *
134         * @throws JOSEException If RSA signing failed.
135         */
136        public static SignedJWT create(final JWTAssertionDetails details,
137                                       final JWSAlgorithm jwsAlgorithm,
138                                       final ECPrivateKey ecPrivateKey,
139                                       final String keyID,
140                                       final Provider jcaProvider)
141                throws JOSEException {
142
143                SignedJWT signedJWT = new SignedJWT(
144                        new JWSHeader.Builder(jwsAlgorithm).keyID(keyID).build(),
145                        details.toJWTClaimsSet());
146                ECDSASigner signer = new ECDSASigner(ecPrivateKey);
147                if (jcaProvider != null) {
148                        signer.getJCAContext().setProvider(jcaProvider);
149                }
150                signedJWT.sign(signer);
151                return signedJWT;
152        }
153
154
155        /**
156         * Prevents public instantiation.
157         */
158        private JWTAssertionFactory() {}
159}