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 audience The identity of the audience, for example the 083 * issuer URI of the authorisation server. Must 084 * 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 audience, 096 final JWSAlgorithm jwsAlgorithm, 097 final Secret clientSecret) 098 throws JOSEException { 099 100 this(new Issuer(clientID), clientID, audience, 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 audience The identity of the audience, for example the 115 * issuer URI of the authorisation server. Must 116 * 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 audience, 129 final JWSAlgorithm jwsAlgorithm, 130 final Secret clientSecret) 131 throws JOSEException { 132 133 this(JWTAssertionFactory.create( 134 new JWTAuthenticationClaimsSet(iss, clientID, new Audience(audience)), 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 && ! clientID.equals(clientSecretJWT.getClientID())) { 192 throw new ParseException("Invalid client secret JWT authentication: The client identifier doesn't match the client assertion subject"); 193 } 194 195 return clientSecretJWT; 196 } 197 198 199 /** 200 * Parses a client secret JSON Web Token (JWT) authentication from the 201 * specified {@code application/x-www-form-urlencoded} encoded 202 * parameters string. 203 * 204 * @param paramsString The parameters string to parse. The client secret 205 * JSON Web Token (JWT) parameters must be keyed 206 * under "client_assertion" and 207 * "client_assertion_type". The string must not be 208 * {@code null}. 209 * 210 * @return The client secret JSON Web Token (JWT) authentication. 211 * 212 * @throws ParseException If the parameters string couldn't be parsed 213 * to a client secret JSON Web Token (JWT) 214 * authentication. 215 */ 216 public static ClientSecretJWT parse(final String paramsString) 217 throws ParseException { 218 219 Map<String,List<String>> params = URLUtils.parseParameters(paramsString); 220 221 return parse(params); 222 } 223 224 225 /** 226 * Parses the specified HTTP POST request for a client secret JSON Web 227 * Token (JWT) authentication. 228 * 229 * @param httpRequest The HTTP POST request to parse. Must not be 230 * {@code null} and must contain a valid 231 * {@code application/x-www-form-urlencoded} encoded 232 * parameters string in the entity body. The client 233 * secret JSON Web Token (JWT) parameters must be 234 * keyed under "client_assertion" and 235 * "client_assertion_type". 236 * 237 * @return The client secret JSON Web Token (JWT) authentication. 238 * 239 * @throws ParseException If the HTTP request header couldn't be parsed 240 * to a client secret JSON Web Token (JWT) 241 * authentication. 242 */ 243 public static ClientSecretJWT parse(final HTTPRequest httpRequest) 244 throws ParseException { 245 246 httpRequest.ensureMethod(HTTPRequest.Method.POST); 247 httpRequest.ensureEntityContentType(ContentType.APPLICATION_URLENCODED); 248 249 return parse(httpRequest.getBodyAsFormParameters()); 250 } 251}