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