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.util.URLUtils; 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 five minutes 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(JWTAssertionFactory.create( 101 new JWTAuthenticationClaimsSet(clientID, new Audience(endpoint.toString())), 102 jwsAlgorithm, 103 clientSecret)); 104 } 105 106 107 /** 108 * Creates a new client secret JWT authentication. 109 * 110 * @param clientAssertion The client assertion, corresponding to the 111 * {@code client_assertion_parameter}, as a 112 * supported HMAC-protected JWT. Must be signed 113 * and not {@code null}. 114 */ 115 public ClientSecretJWT(final SignedJWT clientAssertion) { 116 117 super(ClientAuthenticationMethod.CLIENT_SECRET_JWT, clientAssertion); 118 119 if (! JWSAlgorithm.Family.HMAC_SHA.contains(clientAssertion.getHeader().getAlgorithm())) 120 throw new IllegalArgumentException("The client assertion JWT must be HMAC-signed (HS256, HS384 or HS512)"); 121 } 122 123 124 /** 125 * Parses the specified parameters map for a client secret JSON Web 126 * Token (JWT) authentication. Note that the parameters must not be 127 * {@code application/x-www-form-urlencoded} encoded. 128 * 129 * @param params The parameters map to parse. The client secret JSON 130 * Web Token (JWT) parameters must be keyed under 131 * "client_assertion" and "client_assertion_type". The 132 * map must not be {@code null}. 133 * 134 * @return The client secret JSON Web Token (JWT) authentication. 135 * 136 * @throws ParseException If the parameters map couldn't be parsed to a 137 * client secret JSON Web Token (JWT) 138 * authentication. 139 */ 140 public static ClientSecretJWT parse(final Map<String,List<String>> params) 141 throws ParseException { 142 143 JWTAuthentication.ensureClientAssertionType(params); 144 145 SignedJWT clientAssertion = JWTAuthentication.parseClientAssertion(params); 146 147 ClientSecretJWT clientSecretJWT; 148 149 try { 150 clientSecretJWT = new ClientSecretJWT(clientAssertion); 151 152 } catch (IllegalArgumentException e) { 153 154 throw new ParseException(e.getMessage(), e); 155 } 156 157 // Check that the top level client_id matches the assertion subject + issuer 158 159 ClientID clientID = JWTAuthentication.parseClientID(params); 160 161 if (clientID != null) { 162 163 if (! clientID.equals(clientSecretJWT.getClientID())) 164 throw new ParseException("Invalid client secret JWT authentication: The client identifier doesn't match the client assertion subject / issuer"); 165 } 166 167 return clientSecretJWT; 168 } 169 170 171 /** 172 * Parses a client secret JSON Web Token (JWT) authentication from the 173 * specified {@code application/x-www-form-urlencoded} encoded 174 * parameters string. 175 * 176 * @param paramsString The parameters string to parse. The client secret 177 * JSON Web Token (JWT) parameters must be keyed 178 * under "client_assertion" and 179 * "client_assertion_type". The string must not be 180 * {@code null}. 181 * 182 * @return The client secret JSON Web Token (JWT) authentication. 183 * 184 * @throws ParseException If the parameters string couldn't be parsed 185 * to a client secret JSON Web Token (JWT) 186 * authentication. 187 */ 188 public static ClientSecretJWT parse(final String paramsString) 189 throws ParseException { 190 191 Map<String,List<String>> params = URLUtils.parseParameters(paramsString); 192 193 return parse(params); 194 } 195 196 197 /** 198 * Parses the specified HTTP POST request for a client secret JSON Web 199 * Token (JWT) authentication. 200 * 201 * @param httpRequest The HTTP POST request to parse. Must not be 202 * {@code null} and must contain a valid 203 * {@code application/x-www-form-urlencoded} encoded 204 * parameters string in the entity body. The client 205 * secret JSON Web Token (JWT) parameters must be 206 * keyed under "client_assertion" and 207 * "client_assertion_type". 208 * 209 * @return The client secret JSON Web Token (JWT) authentication. 210 * 211 * @throws ParseException If the HTTP request header couldn't be parsed 212 * to a client secret JSON Web Token (JWT) 213 * authentication. 214 */ 215 public static ClientSecretJWT parse(final HTTPRequest httpRequest) 216 throws ParseException { 217 218 httpRequest.ensureMethod(HTTPRequest.Method.POST); 219 httpRequest.ensureEntityContentType(ContentType.APPLICATION_URLENCODED); 220 221 return parse(httpRequest.getQueryParameters()); 222 } 223}