com.nimbusds.oauth2.sdk.auth.PrivateKeyJWT Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oauth2-oidc-sdk Show documentation
Show all versions of oauth2-oidc-sdk Show documentation
OAuth 2.0 SDK with OpenID Connection extensions for developing client
and server applications.
/*
* oauth2-oidc-sdk
*
* Copyright 2012-2016, Connect2id Ltd and contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License 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.nimbusds.oauth2.sdk.auth;
import com.nimbusds.common.contenttype.ContentType;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.util.Base64;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.assertions.jwt.JWTAssertionFactory;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import com.nimbusds.oauth2.sdk.id.Audience;
import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.id.Issuer;
import com.nimbusds.oauth2.sdk.util.URLUtils;
import net.jcip.annotations.Immutable;
import java.net.URI;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.RSAPrivateKey;
import java.util.*;
/**
* Private key JWT authentication at the Token endpoint. Implements
* {@link ClientAuthenticationMethod#PRIVATE_KEY_JWT}.
*
* Supported signature JSON Web Algorithms (JWAs) by this implementation:
*
*
* - RS256
*
- RS384
*
- RS512
*
- PS256
*
- PS384
*
- PS512
*
- ES256
*
- ES256K
*
- ES384
*
- ES512
*
*
* Example {@link com.nimbusds.oauth2.sdk.TokenRequest} with private key JWT
* authentication:
*
*
* POST /token HTTP/1.1
* Host: server.example.com
* Content-Type: application/x-www-form-urlencoded
*
* grant_type=authorization_code&
* code=i1WsRn1uB1&
* client_id=s6BhdRkqt3&
* client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
* client_assertion=PHNhbWxwOl...[omitted for brevity]...ZT
*
*
* Related specifications:
*
*
* - Assertion Framework for OAuth 2.0 Client Authentication and
* Authorization Grants (RFC 7521).
*
- JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and
* Authorization Grants (RFC 7523)
*
*/
@Immutable
public final class PrivateKeyJWT extends JWTAuthentication {
/**
* Returns the supported signature JSON Web Algorithms (JWAs).
*
* @return The supported JSON Web Algorithms (JWAs).
*/
public static Set supportedJWAs() {
Set supported = new HashSet<>();
supported.addAll(JWSAlgorithm.Family.RSA);
supported.addAll(JWSAlgorithm.Family.EC);
return Collections.unmodifiableSet(supported);
}
/**
* Creates a new private key JWT authentication. The expiration
* time (exp) is set to 1 minute from the current system time.
* Generates a default identifier (jti) for the JWT. The issued-at
* (iat) and not-before (nbf) claims are not set.
*
* @param clientID The client identifier. Must not be {@code null}.
* @param endpoint The endpoint URI where the client will submit
* the JWT authentication, for example the token
* endpoint. Must not be {@code null}.
* @param jwsAlgorithm The expected RSA (RS256, RS384, RS512, PS256,
* PS384 or PS512) or EC (ES256, ES384, ES512)
* signature algorithm for the JWT assertion. Must
* be supported and not {@code null}.
* @param privateKey The signing private RSA or EC key. Must not be
* {@code null}.
* @param keyID Optional identifier for the key, to aid key
* selection on the recipient side. Recommended.
* {@code null} if not specified.
* @param jcaProvider Optional specific JCA provider, {@code null} to
* use the default one.
*
* @throws JOSEException If RSA signing failed.
*/
public PrivateKeyJWT(final ClientID clientID,
final URI endpoint,
final JWSAlgorithm jwsAlgorithm,
final PrivateKey privateKey,
final String keyID,
final Provider jcaProvider)
throws JOSEException {
this(new JWTAuthenticationClaimsSet(clientID, new Audience(endpoint.toString())),
jwsAlgorithm,
privateKey,
keyID,
null,
null,
jcaProvider);
}
/**
* Creates a new private key JWT authentication. The expiration
* time (exp) is set to 1 minute from the current system time.
* Generates a default identifier (jti) for the JWT. The issued-at
* (iat) and not-before (nbf) claims are not set.
*
* @param iss The issuer. May be different from the client
* identifier. Must not be {@code null}.
* @param clientID The client identifier. Must not be {@code null}.
* @param endpoint The endpoint URI where the client will submit
* the JWT authentication, for example the token
* endpoint. Must not be {@code null}.
* @param jwsAlgorithm The expected RSA (RS256, RS384, RS512, PS256,
* PS384 or PS512) or EC (ES256, ES384, ES512)
* signature algorithm for the JWT assertion. Must
* be supported and not {@code null}.
* @param privateKey The signing private RSA or EC key. Must not be
* {@code null}.
* @param keyID Optional identifier for the key, to aid key
* selection on the recipient side. Recommended.
* {@code null} if not specified.
* @param jcaProvider Optional specific JCA provider, {@code null} to
* use the default one.
*
* @throws JOSEException If RSA signing failed.
*/
public PrivateKeyJWT(final Issuer iss,
final ClientID clientID,
final URI endpoint,
final JWSAlgorithm jwsAlgorithm,
final PrivateKey privateKey,
final String keyID,
final Provider jcaProvider)
throws JOSEException {
this(new JWTAuthenticationClaimsSet(iss, clientID, new Audience(endpoint.toString())),
jwsAlgorithm,
privateKey,
keyID,
null,
null,
jcaProvider);
}
/**
* Creates a new private key JWT authentication. The expiration
* time (exp) is set to 1 minute from the current system time.
* Generates a default identifier (jti) for the JWT. The issued-at
* (iat) and not-before (nbf) claims are not set.
*
* @param clientID The client identifier. Must not be {@code null}.
* @param endpoint The endpoint URI where the client will submit
* the JWT authentication, for example the token
* endpoint. Must not be {@code null}.
* @param jwsAlgorithm The expected RSA (RS256, RS384, RS512, PS256,
* PS384 or PS512) or EC (ES256, ES384, ES512)
* signature algorithm for the JWT assertion. Must
* be supported and not {@code null}.
* @param privateKey The signing private RSA or EC key. Must not be
* {@code null}.
* @param keyID Optional identifier for the key, to aid key
* selection on the recipient side. Recommended.
* {@code null} if not specified.
* @param x5c Optional X.509 certificate chain for the public
* key, {@code null} if not specified.
* @param x5t256 Optional X.509 certificate SHA-256 thumbprint,
* {@code null} if not specified.
* @param jcaProvider Optional specific JCA provider, {@code null} to
* use the default one.
*
* @throws JOSEException If RSA signing failed.
*/
public PrivateKeyJWT(final ClientID clientID,
final URI endpoint,
final JWSAlgorithm jwsAlgorithm,
final PrivateKey privateKey,
final String keyID,
final List x5c,
final Base64URL x5t256,
final Provider jcaProvider)
throws JOSEException {
this(new JWTAuthenticationClaimsSet(clientID, new Audience(endpoint.toString())),
jwsAlgorithm,
privateKey,
keyID,
x5c,
x5t256,
jcaProvider);
}
/**
* Creates a new private key JWT authentication. The expiration
* time (exp) is set to 1 minute from the current system time.
* Generates a default identifier (jti) for the JWT. The issued-at
* (iat) and not-before (nbf) claims are not set.
*
* @param iss The issuer. May be different from the client
* identifier. Must not be {@code null}.
* @param clientID The client identifier. Must not be {@code null}.
* @param endpoint The endpoint URI where the client will submit
* the JWT authentication, for example the token
* endpoint. Must not be {@code null}.
* @param jwsAlgorithm The expected RSA (RS256, RS384, RS512, PS256,
* PS384 or PS512) or EC (ES256, ES384, ES512)
* signature algorithm for the JWT assertion. Must
* be supported and not {@code null}.
* @param privateKey The signing private RSA or EC key. Must not be
* {@code null}.
* @param keyID Optional identifier for the key, to aid key
* selection on the recipient side. Recommended.
* {@code null} if not specified.
* @param x5c Optional X.509 certificate chain for the public
* key, {@code null} if not specified.
* @param x5t256 Optional X.509 certificate SHA-256 thumbprint,
* {@code null} if not specified.
* @param jcaProvider Optional specific JCA provider, {@code null} to
* use the default one.
*
* @throws JOSEException If RSA signing failed.
*/
public PrivateKeyJWT(final Issuer iss,
final ClientID clientID,
final URI endpoint,
final JWSAlgorithm jwsAlgorithm,
final PrivateKey privateKey,
final String keyID,
final List x5c,
final Base64URL x5t256,
final Provider jcaProvider)
throws JOSEException {
this(new JWTAuthenticationClaimsSet(iss, clientID, new Audience(endpoint.toString())),
jwsAlgorithm,
privateKey,
keyID,
x5c,
x5t256,
jcaProvider);
}
/**
* Creates a new private key JWT authentication.
*
* @param jwtAuthClaimsSet The JWT authentication claims set. Must not
* be {@code null}.
* @param jwsAlgorithm The expected RSA (RS256, RS384, RS512,
* PS256, PS384 or PS512) or EC (ES256, ES384,
* ES512) signature algorithm for the JWT
* assertion. Must be supported and not
* {@code null}.
* @param privateKey The signing private RSA or EC key. Must not
* be {@code null}.
* @param keyID Optional identifier for the key, to aid key
* selection on the recipient side.
* Recommended. {@code null} if not specified.
* @param jcaProvider Optional specific JCA provider, {@code null}
* to use the default one.
*
* @throws JOSEException If RSA signing failed.
*/
public PrivateKeyJWT(final JWTAuthenticationClaimsSet jwtAuthClaimsSet,
final JWSAlgorithm jwsAlgorithm,
final PrivateKey privateKey,
final String keyID,
final Provider jcaProvider)
throws JOSEException {
this(jwtAuthClaimsSet, jwsAlgorithm, privateKey, keyID, null, null, jcaProvider);
}
/**
* Creates a new private key JWT authentication.
*
* @param jwtAuthClaimsSet The JWT authentication claims set. Must not
* be {@code null}.
* @param jwsAlgorithm The expected RSA (RS256, RS384, RS512,
* PS256, PS384 or PS512) or EC (ES256, ES384,
* ES512) signature algorithm for the JWT
* assertion. Must be supported and not
* {@code null}.
* @param privateKey The signing private RSA or EC key. Must not
* be {@code null}.
* @param keyID Optional identifier for the key, to aid key
* selection on the recipient side.
* Recommended. {@code null} if not specified.
* @param x5c Optional X.509 certificate chain for the
* public key, {@code null} if not specified.
* @param x5t256 Optional X.509 certificate SHA-256
* thumbprint, {@code null} if not specified.
* @param jcaProvider Optional specific JCA provider, {@code null}
* to use the default one.
*
* @throws JOSEException If RSA signing failed.
*/
public PrivateKeyJWT(final JWTAuthenticationClaimsSet jwtAuthClaimsSet,
final JWSAlgorithm jwsAlgorithm,
final PrivateKey privateKey,
final String keyID,
final List x5c,
final Base64URL x5t256,
final Provider jcaProvider)
throws JOSEException {
this(JWTAssertionFactory.create(jwtAuthClaimsSet, jwsAlgorithm, privateKey, keyID, x5c, x5t256, jcaProvider));
}
/**
* Creates a new RSA private key JWT authentication. The expiration
* time (exp) is set to 1 minute from the current system time.
* Generates a default identifier (jti) for the JWT. The issued-at
* (iat) and not-before (nbf) claims are not set.
*
* @param clientID The client identifier. Must not be
* {@code null}.
* @param endpoint The endpoint URI where the client will submit
* the JWT authentication, for example the token
* endpoint. Must not be {@code null}.
* @param jwsAlgorithm The expected RSA signature algorithm (RS256,
* RS384 or RS512) for the private key JWT
* assertion. Must be supported and not
* {@code null}.
* @param rsaPrivateKey The RSA private key. Must not be {@code null}.
* @param keyID Optional identifier for the RSA key, to aid
* key selection at the authorisation server.
* Recommended. {@code null} if not specified.
* @param jcaProvider Optional specific JCA provider, {@code null} to
* use the default one.
*
* @throws JOSEException If RSA signing failed.
*/
@Deprecated
public PrivateKeyJWT(final ClientID clientID,
final URI endpoint,
final JWSAlgorithm jwsAlgorithm,
final RSAPrivateKey rsaPrivateKey,
final String keyID,
final Provider jcaProvider)
throws JOSEException {
this(new JWTAuthenticationClaimsSet(clientID, new Audience(endpoint.toString())),
jwsAlgorithm,
rsaPrivateKey,
keyID,
jcaProvider);
}
/**
* Creates a new RSA private key JWT authentication.
*
* @param jwtAuthClaimsSet The JWT authentication claims set. Must not
* be {@code null}.
* @param jwsAlgorithm The expected RSA signature algorithm (RS256,
* RS384 or RS512) for the private key JWT
* assertion. Must be supported and not
* {@code null}.
* @param rsaPrivateKey The RSA private key. Must not be
* {@code null}.
* @param keyID Optional identifier for the RSA key, to aid
* key selection at the authorisation server.
* Recommended. {@code null} if not specified.
* @param jcaProvider Optional specific JCA provider, {@code null}
* to use the default one.
*
* @throws JOSEException If RSA signing failed.
*/
@Deprecated
public PrivateKeyJWT(final JWTAuthenticationClaimsSet jwtAuthClaimsSet,
final JWSAlgorithm jwsAlgorithm,
final RSAPrivateKey rsaPrivateKey,
final String keyID,
final Provider jcaProvider)
throws JOSEException {
this(JWTAssertionFactory.create(jwtAuthClaimsSet, jwsAlgorithm, rsaPrivateKey, keyID, null, null, jcaProvider));
}
/**
* Creates a new EC private key JWT authentication. The expiration
* time (exp) is set to 1 minute from the current system time.
* Generates a default identifier (jti) for the JWT. The issued-at
* (iat) and not-before (nbf) claims are not set.
*
* @param clientID The client identifier. Must not be
* {@code null}.
* @param endpoint The endpoint URI where the client will submit
* the JWT authentication, for example the token
* endpoint. Must not be {@code null}.
* @param jwsAlgorithm The expected EC signature algorithm (ES256,
* ES384 or ES512) for the private key JWT
* assertion. Must be supported and not
* {@code null}.
* @param ecPrivateKey The EC private key. Must not be {@code null}.
* @param keyID Optional identifier for the EC key, to aid key
* selection at the authorisation server.
* Recommended. {@code null} if not specified.
* @param jcaProvider Optional specific JCA provider, {@code null} to
* use the default one.
*
* @throws JOSEException If RSA signing failed.
*/
@Deprecated
public PrivateKeyJWT(final ClientID clientID,
final URI endpoint,
final JWSAlgorithm jwsAlgorithm,
final ECPrivateKey ecPrivateKey,
final String keyID,
final Provider jcaProvider)
throws JOSEException {
this(new JWTAuthenticationClaimsSet(clientID, new Audience(endpoint.toString())),
jwsAlgorithm,
ecPrivateKey,
keyID,
jcaProvider);
}
/**
* Creates a new EC private key JWT authentication.
*
* @param jwtAuthClaimsSet The JWT authentication claims set. Must not
* be {@code null}.
* @param jwsAlgorithm The expected ES signature algorithm (ES256,
* ES384 or ES512) for the private key JWT
* assertion. Must be supported and not
* {@code null}.
* @param ecPrivateKey The EC private key. Must not be
* {@code null}.
* @param keyID Optional identifier for the EC key, to aid
* key selection at the authorisation server.
* Recommended. {@code null} if not specified.
* @param jcaProvider Optional specific JCA provider, {@code null}
* to use the default one.
*
* @throws JOSEException If RSA signing failed.
*/
@Deprecated
public PrivateKeyJWT(final JWTAuthenticationClaimsSet jwtAuthClaimsSet,
final JWSAlgorithm jwsAlgorithm,
final ECPrivateKey ecPrivateKey,
final String keyID,
final Provider jcaProvider)
throws JOSEException {
this(JWTAssertionFactory.create(jwtAuthClaimsSet, jwsAlgorithm, ecPrivateKey, keyID, null, null, jcaProvider));
}
/**
* Creates a new private key JWT authentication.
*
* @param clientAssertion The client assertion, corresponding to the
* {@code client_assertion} parameter, as a
* supported RSA or ECDSA-signed JWT. Must be
* signed and not {@code null}.
*/
public PrivateKeyJWT(final SignedJWT clientAssertion) {
super(ClientAuthenticationMethod.PRIVATE_KEY_JWT, clientAssertion);
JWSAlgorithm alg = clientAssertion.getHeader().getAlgorithm();
if (! JWSAlgorithm.Family.RSA.contains(alg) && ! JWSAlgorithm.Family.EC.contains(alg))
throw new IllegalArgumentException("The client assertion JWT must be RSA or ECDSA-signed (RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384 or ES512)");
}
/**
* Parses the specified parameters map for a private key JSON Web Token
* (JWT) authentication. Note that the parameters must not be
* {@code application/x-www-form-urlencoded} encoded.
*
* @param params The parameters map to parse. The private key JSON
* Web Token (JWT) parameters must be keyed under
* "client_assertion" and "client_assertion_type". The
* map must not be {@code null}.
*
* @return The private key JSON Web Token (JWT) authentication.
*
* @throws ParseException If the parameters map couldn't be parsed to a
* private key JSON Web Token (JWT)
* authentication.
*/
public static PrivateKeyJWT parse(final Map> params)
throws ParseException {
JWTAuthentication.ensureClientAssertionType(params);
SignedJWT clientAssertion = JWTAuthentication.parseClientAssertion(params);
PrivateKeyJWT privateKeyJWT;
try {
privateKeyJWT = new PrivateKeyJWT(clientAssertion);
}catch (IllegalArgumentException e) {
throw new ParseException(e.getMessage(), e);
}
// Check that the top level client_id matches the assertion subject + issuer
ClientID clientID = JWTAuthentication.parseClientID(params);
if (clientID != null) {
if (! clientID.equals(privateKeyJWT.getClientID()))
throw new ParseException("Invalid private key JWT authentication: The client identifier doesn't match the client assertion subject");
}
return privateKeyJWT;
}
/**
* Parses a private key JSON Web Token (JWT) authentication from the
* specified {@code application/x-www-form-urlencoded} encoded
* parameters string.
*
* @param paramsString The parameters string to parse. The private key
* JSON Web Token (JWT) parameters must be keyed
* under "client_assertion" and
* "client_assertion_type". The string must not be
* {@code null}.
*
* @return The private key JSON Web Token (JWT) authentication.
*
* @throws ParseException If the parameters string couldn't be parsed
* to a private key JSON Web Token (JWT)
* authentication.
*/
public static PrivateKeyJWT parse(final String paramsString)
throws ParseException {
Map> params = URLUtils.parseParameters(paramsString);
return parse(params);
}
/**
* Parses the specified HTTP POST request for a private key JSON Web
* Token (JWT) authentication.
*
* @param httpRequest The HTTP POST request to parse. Must not be
* {@code null} and must contain a valid
* {@code application/x-www-form-urlencoded} encoded
* parameters string in the entity body. The private
* key JSON Web Token (JWT) parameters must be
* keyed under "client_assertion" and
* "client_assertion_type".
*
* @return The private key JSON Web Token (JWT) authentication.
*
* @throws ParseException If the HTTP request header couldn't be parsed
* to a private key JSON Web Token (JWT)
* authentication.
*/
public static PrivateKeyJWT parse(final HTTPRequest httpRequest)
throws ParseException {
httpRequest.ensureMethod(HTTPRequest.Method.POST);
httpRequest.ensureEntityContentType(ContentType.APPLICATION_URLENCODED);
return parse(httpRequest.getBodyAsFormParameters());
}
}