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