001package com.nimbusds.oauth2.sdk.auth; 002 003 004import java.util.Collections; 005import java.util.HashSet; 006import java.util.Map; 007import java.util.Set; 008 009import net.jcip.annotations.Immutable; 010 011import com.nimbusds.jose.JWSAlgorithm; 012import com.nimbusds.jwt.SignedJWT; 013 014import com.nimbusds.oauth2.sdk.ParseException; 015import com.nimbusds.oauth2.sdk.id.ClientID; 016import com.nimbusds.oauth2.sdk.http.CommonContentTypes; 017import com.nimbusds.oauth2.sdk.http.HTTPRequest; 018import com.nimbusds.oauth2.sdk.util.URLUtils; 019 020 021/** 022 * Client secret JWT authentication at the Token endpoint. Implements 023 * {@link ClientAuthenticationMethod#CLIENT_SECRET_JWT}. 024 * 025 * <p>Supported signature JSON Web Algorithms (JWAs) by this implementation: 026 * 027 * <ul> 028 * <li>HS256 029 * <li>HS384 030 * <li>HS512 031 * </ul> 032 * 033 * <p>Related specifications: 034 * 035 * <ul> 036 * <li>Assertion Framework for OAuth 2.0 (draft-ietf-oauth-assertions-16) 037 * <li>JSON Web Token (JWT) Bearer Token Profiles for OAuth 2.0 038 * (draft-ietf-oauth-jwt-bearer-10). 039 * </ul> 040 */ 041@Immutable 042public final class ClientSecretJWT extends JWTAuthentication { 043 044 045 /** 046 * Gets the set of supported signature JSON Web Algorithms (JWAs) by 047 * this implementation of client secret JSON Web Token (JWT) 048 * authentication. 049 * 050 * @return The set of supported JSON Web Algorithms (JWAs). 051 */ 052 public static Set<JWSAlgorithm> getSupportedJWAs() { 053 054 Set<JWSAlgorithm> supported = new HashSet<>(); 055 056 supported.add(JWSAlgorithm.HS256); 057 supported.add(JWSAlgorithm.HS384); 058 supported.add(JWSAlgorithm.HS512); 059 060 return Collections.unmodifiableSet(supported); 061 } 062 063 064 /** 065 * Creates a new client secret JWT authentication. 066 * 067 * @param clientAssertion The client assertion, corresponding to the 068 * {@code client_assertion_parameter}, as a 069 * supported HMAC-protected JWT. Must be signed 070 * and not {@code null}. 071 */ 072 public ClientSecretJWT(final SignedJWT clientAssertion) { 073 074 super(ClientAuthenticationMethod.CLIENT_SECRET_JWT, clientAssertion); 075 076 if (! getSupportedJWAs().contains(clientAssertion.getHeader().getAlgorithm())) 077 throw new IllegalArgumentException("The client assertion JWT must be HMAC-signed (HS256, HS384 or HS512)"); 078 } 079 080 081 /** 082 * Parses the specified parameters map for a client secret JSON Web 083 * Token (JWT) authentication. Note that the parameters must not be 084 * {@code application/x-www-form-urlencoded} encoded. 085 * 086 * @param params The parameters map to parse. The client secret JSON 087 * Web Token (JWT) parameters must be keyed under 088 * "client_assertion" and "client_assertion_type". The 089 * map must not be {@code null}. 090 * 091 * @return The client secret JSON Web Token (JWT) authentication. 092 * 093 * @throws ParseException If the parameters map couldn't be parsed to a 094 * client secret JSON Web Token (JWT) 095 * authentication. 096 */ 097 public static ClientSecretJWT parse(final Map<String,String> params) 098 throws ParseException { 099 100 JWTAuthentication.ensureClientAssertionType(params); 101 102 SignedJWT clientAssertion = JWTAuthentication.parseClientAssertion(params); 103 104 ClientSecretJWT clientSecretJWT; 105 106 try { 107 clientSecretJWT = new ClientSecretJWT(clientAssertion); 108 109 } catch (IllegalArgumentException e) { 110 111 throw new ParseException(e.getMessage(), e); 112 } 113 114 // Check that the top level client_id matches the assertion subject + issuer 115 116 ClientID clientID = JWTAuthentication.parseClientID(params); 117 118 if (clientID != null) { 119 120 if (! clientID.equals(clientSecretJWT.getClientID())) 121 throw new ParseException("The client identifier doesn't match the client assertion subject / issuer"); 122 } 123 124 return clientSecretJWT; 125 } 126 127 128 /** 129 * Parses a client secret JSON Web Token (JWT) authentication from the 130 * specified {@code application/x-www-form-urlencoded} encoded 131 * parameters string. 132 * 133 * @param paramsString The parameters string to parse. The client secret 134 * JSON Web Token (JWT) parameters must be keyed 135 * under "client_assertion" and 136 * "client_assertion_type". The string must not be 137 * {@code null}. 138 * 139 * @return The client secret JSON Web Token (JWT) authentication. 140 * 141 * @throws ParseException If the parameters string couldn't be parsed 142 * to a client secret JSON Web Token (JWT) 143 * authentication. 144 */ 145 public static ClientSecretJWT parse(final String paramsString) 146 throws ParseException { 147 148 Map<String,String> params = URLUtils.parseParameters(paramsString); 149 150 return parse(params); 151 } 152 153 154 /** 155 * Parses the specified HTTP POST request for a client secret JSON Web 156 * Token (JWT) authentication. 157 * 158 * @param httpRequest The HTTP POST request to parse. Must not be 159 * {@code null} and must contain a valid 160 * {@code application/x-www-form-urlencoded} encoded 161 * parameters string in the entity body. The client 162 * secret JSON Web Token (JWT) parameters must be 163 * keyed under "client_assertion" and 164 * "client_assertion_type". 165 * 166 * @return The client secret JSON Web Token (JWT) authentication. 167 * 168 * @throws ParseException If the HTTP request header couldn't be parsed 169 * to a client secret JSON Web Token (JWT) 170 * authentication. 171 */ 172 public static ClientSecretJWT parse(final HTTPRequest httpRequest) 173 throws ParseException { 174 175 httpRequest.ensureMethod(HTTPRequest.Method.POST); 176 httpRequest.ensureContentType(CommonContentTypes.APPLICATION_URLENCODED); 177 178 return parse(httpRequest.getQueryParameters()); 179 } 180}