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.auth; 019 020 021import java.net.URI; 022import java.util.*; 023 024import net.jcip.annotations.Immutable; 025 026import com.nimbusds.common.contenttype.ContentType; 027import com.nimbusds.jose.JOSEException; 028import com.nimbusds.jose.JWSAlgorithm; 029import com.nimbusds.jwt.SignedJWT; 030import com.nimbusds.oauth2.sdk.ParseException; 031import com.nimbusds.oauth2.sdk.assertions.jwt.JWTAssertionFactory; 032import com.nimbusds.oauth2.sdk.http.HTTPRequest; 033import com.nimbusds.oauth2.sdk.id.Audience; 034import com.nimbusds.oauth2.sdk.id.ClientID; 035import com.nimbusds.oauth2.sdk.id.Issuer; 036import com.nimbusds.oauth2.sdk.util.URLUtils; 037 038 039/** 040 * Client secret JWT authentication at the Token endpoint. Implements 041 * {@link ClientAuthenticationMethod#CLIENT_SECRET_JWT}. 042 * 043 * <p>Supported signature JSON Web Algorithms (JWAs) by this implementation: 044 * 045 * <ul> 046 * <li>HS256 047 * <li>HS384 048 * <li>HS512 049 * </ul> 050 * 051 * <p>Related specifications: 052 * 053 * <ul> 054 * <li>Assertion Framework for OAuth 2.0 Client Authentication and 055 * Authorization Grants (RFC 7521). 056 * <li>JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and 057 * Authorization Grants (RFC 7523). 058 * </ul> 059 */ 060@Immutable 061public final class ClientSecretJWT extends JWTAuthentication { 062 063 064 /** 065 * Returns the supported signature JSON Web Algorithms (JWAs). 066 * 067 * @return The supported JSON Web Algorithms (JWAs). 068 */ 069 public static Set<JWSAlgorithm> supportedJWAs() { 070 071 return Collections.unmodifiableSet(new HashSet<>(JWSAlgorithm.Family.HMAC_SHA)); 072 } 073 074 075 /** 076 * Creates a new client secret JWT authentication. The expiration 077 * time (exp) is set to five minutes from the current system time. 078 * Generates a default identifier (jti) for the JWT. The issued-at 079 * (iat) and not-before (nbf) claims are not set. 080 * 081 * @param clientID The client identifier. Must not be 082 * {@code null}. 083 * @param endpoint The endpoint URI where the client will submit 084 * the JWT authentication, for example the token 085 * endpoint. Must not be {@code null}. 086 * @param jwsAlgorithm The expected HMAC algorithm (HS256, HS384 or 087 * HS512) for the client secret JWT assertion. 088 * Must be supported and not {@code null}. 089 * @param clientSecret The client secret. Must be at least 256-bits 090 * long. 091 * 092 * @throws JOSEException If the client secret is too short, or HMAC 093 * computation failed. 094 */ 095 public ClientSecretJWT(final ClientID clientID, 096 final URI endpoint, 097 final JWSAlgorithm jwsAlgorithm, 098 final Secret clientSecret) 099 throws JOSEException { 100 101 this(new Issuer(clientID), clientID, endpoint, jwsAlgorithm, clientSecret); 102 } 103 104 105 /** 106 * Creates a new client secret JWT authentication. The expiration 107 * time (exp) is set to five minutes from the current system time. 108 * Generates a default identifier (jti) for the JWT. The issued-at 109 * (iat) and not-before (nbf) claims are not set. 110 * 111 * @param iss The issuer. May be different from the client 112 * identifier. Must not be {@code null}. 113 * @param clientID The client identifier. Must not be 114 * {@code null}. 115 * @param endpoint The endpoint URI where the client will submit 116 * the JWT authentication, for example the token 117 * endpoint. Must not be {@code null}. 118 * @param jwsAlgorithm The expected HMAC algorithm (HS256, HS384 or 119 * HS512) for the client secret JWT assertion. 120 * Must be supported and not {@code null}. 121 * @param clientSecret The client secret. Must be at least 256-bits 122 * long. 123 * 124 * @throws JOSEException If the client secret is too short, or HMAC 125 * computation failed. 126 */ 127 public ClientSecretJWT(final Issuer iss, 128 final ClientID clientID, 129 final URI endpoint, 130 final JWSAlgorithm jwsAlgorithm, 131 final Secret clientSecret) 132 throws JOSEException { 133 134 this(JWTAssertionFactory.create( 135 new JWTAuthenticationClaimsSet(iss, clientID, new Audience(endpoint.toString())), 136 jwsAlgorithm, 137 clientSecret)); 138 } 139 140 141 /** 142 * Creates a new client secret JWT authentication. 143 * 144 * @param clientAssertion The client assertion, corresponding to the 145 * {@code client_assertion_parameter}, as a 146 * supported HMAC-protected JWT. Must be signed 147 * and not {@code null}. 148 */ 149 public ClientSecretJWT(final SignedJWT clientAssertion) { 150 151 super(ClientAuthenticationMethod.CLIENT_SECRET_JWT, clientAssertion); 152 153 if (! JWSAlgorithm.Family.HMAC_SHA.contains(clientAssertion.getHeader().getAlgorithm())) 154 throw new IllegalArgumentException("The client assertion JWT must be HMAC-signed (HS256, HS384 or HS512)"); 155 } 156 157 158 /** 159 * Parses the specified parameters map for a client secret JSON Web 160 * Token (JWT) authentication. Note that the parameters must not be 161 * {@code application/x-www-form-urlencoded} encoded. 162 * 163 * @param params The parameters map to parse. The client secret JSON 164 * Web Token (JWT) parameters must be keyed under 165 * "client_assertion" and "client_assertion_type". The 166 * map must not be {@code null}. 167 * 168 * @return The client secret JSON Web Token (JWT) authentication. 169 * 170 * @throws ParseException If the parameters map couldn't be parsed to a 171 * client secret JSON Web Token (JWT) 172 * authentication. 173 */ 174 public static ClientSecretJWT parse(final Map<String,List<String>> params) 175 throws ParseException { 176 177 JWTAuthentication.ensureClientAssertionType(params); 178 179 SignedJWT clientAssertion = JWTAuthentication.parseClientAssertion(params); 180 181 ClientSecretJWT clientSecretJWT; 182 try { 183 clientSecretJWT = new ClientSecretJWT(clientAssertion); 184 } catch (IllegalArgumentException e) { 185 throw new ParseException(e.getMessage(), e); 186 } 187 188 // Check that the top level client_id matches the assertion subject + issuer 189 190 ClientID clientID = JWTAuthentication.parseClientID(params); 191 192 if (clientID != null) { 193 194 if (! clientID.equals(clientSecretJWT.getClientID())) 195 throw new ParseException("Invalid client secret JWT authentication: The client identifier doesn't match the client assertion subject"); 196 } 197 198 return clientSecretJWT; 199 } 200 201 202 /** 203 * Parses a client secret JSON Web Token (JWT) authentication from the 204 * specified {@code application/x-www-form-urlencoded} encoded 205 * parameters string. 206 * 207 * @param paramsString The parameters string to parse. The client secret 208 * JSON Web Token (JWT) parameters must be keyed 209 * under "client_assertion" and 210 * "client_assertion_type". The string must not be 211 * {@code null}. 212 * 213 * @return The client secret JSON Web Token (JWT) authentication. 214 * 215 * @throws ParseException If the parameters string couldn't be parsed 216 * to a client secret JSON Web Token (JWT) 217 * authentication. 218 */ 219 public static ClientSecretJWT parse(final String paramsString) 220 throws ParseException { 221 222 Map<String,List<String>> params = URLUtils.parseParameters(paramsString); 223 224 return parse(params); 225 } 226 227 228 /** 229 * Parses the specified HTTP POST request for a client secret JSON Web 230 * Token (JWT) authentication. 231 * 232 * @param httpRequest The HTTP POST request to parse. Must not be 233 * {@code null} and must contain a valid 234 * {@code application/x-www-form-urlencoded} encoded 235 * parameters string in the entity body. The client 236 * secret JSON Web Token (JWT) parameters must be 237 * keyed under "client_assertion" and 238 * "client_assertion_type". 239 * 240 * @return The client secret JSON Web Token (JWT) authentication. 241 * 242 * @throws ParseException If the HTTP request header couldn't be parsed 243 * to a client secret JSON Web Token (JWT) 244 * authentication. 245 */ 246 public static ClientSecretJWT parse(final HTTPRequest httpRequest) 247 throws ParseException { 248 249 httpRequest.ensureMethod(HTTPRequest.Method.POST); 250 httpRequest.ensureEntityContentType(ContentType.APPLICATION_URLENCODED); 251 252 return parse(httpRequest.getQueryParameters()); 253 } 254}