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