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