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.jose.JOSEException; 027import com.nimbusds.jose.JWSAlgorithm; 028import com.nimbusds.jwt.SignedJWT; 029 030import com.nimbusds.oauth2.sdk.ParseException; 031import com.nimbusds.oauth2.sdk.assertions.jwt.JWTAssertionFactory; 032import com.nimbusds.oauth2.sdk.http.CommonContentTypes; 033import com.nimbusds.oauth2.sdk.http.HTTPRequest; 034import com.nimbusds.oauth2.sdk.id.Audience; 035import com.nimbusds.oauth2.sdk.id.ClientID; 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 Set<JWSAlgorithm> supported = new HashSet<>(); 072 supported.addAll(JWSAlgorithm.Family.HMAC_SHA); 073 return Collections.unmodifiableSet(supported); 074 } 075 076 077 /** 078 * Creates a new client secret JWT authentication. The expiration 079 * time (exp) is set to five minutes from the current system time. 080 * Generates a default identifier (jti) for the JWT. The issued-at 081 * (iat) and not-before (nbf) claims are not set. 082 * 083 * @param clientID The client identifier. Must not be 084 * {@code null}. 085 * @param tokenEndpoint The token endpoint URI of the authorisation 086 * server. Must not be {@code null}. 087 * @param jwsAlgorithm The expected HMAC algorithm (HS256, HS384 or 088 * HS512) for the client secret JWT assertion. 089 * Must be supported and not {@code null}. 090 * @param clientSecret The client secret. Must be at least 256-bits 091 * long. 092 * 093 * @throws JOSEException If the client secret is too short, or HMAC 094 * computation failed. 095 */ 096 public ClientSecretJWT(final ClientID clientID, 097 final URI tokenEndpoint, 098 final JWSAlgorithm jwsAlgorithm, 099 final Secret clientSecret) 100 throws JOSEException { 101 102 this(JWTAssertionFactory.create( 103 new JWTAuthenticationClaimsSet(clientID, new Audience(tokenEndpoint.toString())), 104 jwsAlgorithm, 105 clientSecret)); 106 } 107 108 109 /** 110 * Creates a new client secret JWT authentication. 111 * 112 * @param clientAssertion The client assertion, corresponding to the 113 * {@code client_assertion_parameter}, as a 114 * supported HMAC-protected JWT. Must be signed 115 * and not {@code null}. 116 */ 117 public ClientSecretJWT(final SignedJWT clientAssertion) { 118 119 super(ClientAuthenticationMethod.CLIENT_SECRET_JWT, clientAssertion); 120 121 if (! JWSAlgorithm.Family.HMAC_SHA.contains(clientAssertion.getHeader().getAlgorithm())) 122 throw new IllegalArgumentException("The client assertion JWT must be HMAC-signed (HS256, HS384 or HS512)"); 123 } 124 125 126 /** 127 * Parses the specified parameters map for a client secret JSON Web 128 * Token (JWT) authentication. Note that the parameters must not be 129 * {@code application/x-www-form-urlencoded} encoded. 130 * 131 * @param params The parameters map to parse. The client secret JSON 132 * Web Token (JWT) parameters must be keyed under 133 * "client_assertion" and "client_assertion_type". The 134 * map must not be {@code null}. 135 * 136 * @return The client secret JSON Web Token (JWT) authentication. 137 * 138 * @throws ParseException If the parameters map couldn't be parsed to a 139 * client secret JSON Web Token (JWT) 140 * authentication. 141 */ 142 public static ClientSecretJWT parse(final Map<String,List<String>> params) 143 throws ParseException { 144 145 JWTAuthentication.ensureClientAssertionType(params); 146 147 SignedJWT clientAssertion = JWTAuthentication.parseClientAssertion(params); 148 149 ClientSecretJWT clientSecretJWT; 150 151 try { 152 clientSecretJWT = new ClientSecretJWT(clientAssertion); 153 154 } catch (IllegalArgumentException e) { 155 156 throw new ParseException(e.getMessage(), e); 157 } 158 159 // Check that the top level client_id matches the assertion subject + issuer 160 161 ClientID clientID = JWTAuthentication.parseClientID(params); 162 163 if (clientID != null) { 164 165 if (! clientID.equals(clientSecretJWT.getClientID())) 166 throw new ParseException("Invalid client secret JWT authentication: The client identifier doesn't match the client assertion subject / issuer"); 167 } 168 169 return clientSecretJWT; 170 } 171 172 173 /** 174 * Parses a client secret JSON Web Token (JWT) authentication from the 175 * specified {@code application/x-www-form-urlencoded} encoded 176 * parameters string. 177 * 178 * @param paramsString The parameters string to parse. The client secret 179 * JSON Web Token (JWT) parameters must be keyed 180 * under "client_assertion" and 181 * "client_assertion_type". The string must not be 182 * {@code null}. 183 * 184 * @return The client secret JSON Web Token (JWT) authentication. 185 * 186 * @throws ParseException If the parameters string couldn't be parsed 187 * to a client secret JSON Web Token (JWT) 188 * authentication. 189 */ 190 public static ClientSecretJWT parse(final String paramsString) 191 throws ParseException { 192 193 Map<String,List<String>> params = URLUtils.parseParameters(paramsString); 194 195 return parse(params); 196 } 197 198 199 /** 200 * Parses the specified HTTP POST request for a client secret JSON Web 201 * Token (JWT) authentication. 202 * 203 * @param httpRequest The HTTP POST request to parse. Must not be 204 * {@code null} and must contain a valid 205 * {@code application/x-www-form-urlencoded} encoded 206 * parameters string in the entity body. The client 207 * secret JSON Web Token (JWT) parameters must be 208 * keyed under "client_assertion" and 209 * "client_assertion_type". 210 * 211 * @return The client secret JSON Web Token (JWT) authentication. 212 * 213 * @throws ParseException If the HTTP request header couldn't be parsed 214 * to a client secret JSON Web Token (JWT) 215 * authentication. 216 */ 217 public static ClientSecretJWT parse(final HTTPRequest httpRequest) 218 throws ParseException { 219 220 httpRequest.ensureMethod(HTTPRequest.Method.POST); 221 httpRequest.ensureContentType(CommonContentTypes.APPLICATION_URLENCODED); 222 223 return parse(httpRequest.getQueryParameters()); 224 } 225}