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.util.*; 022 023import net.jcip.annotations.Immutable; 024 025import com.nimbusds.common.contenttype.ContentType; 026import com.nimbusds.oauth2.sdk.ParseException; 027import com.nimbusds.oauth2.sdk.SerializeException; 028import com.nimbusds.oauth2.sdk.http.HTTPRequest; 029import com.nimbusds.oauth2.sdk.id.ClientID; 030import com.nimbusds.oauth2.sdk.util.MultivaluedMapUtils; 031import com.nimbusds.oauth2.sdk.util.URLUtils; 032 033 034/** 035 * Client secret post authentication at the Token endpoint. Implements 036 * {@link ClientAuthenticationMethod#CLIENT_SECRET_POST}. 037 * 038 * <p>Related specifications: 039 * 040 * <ul> 041 * <li>OAuth 2.0 (RFC 6749), sections 2.3.1 and 3.2.1. 042 * <li>OpenID Connect Core 1.0, section 9. 043 * </ul> 044 */ 045@Immutable 046public final class ClientSecretPost extends PlainClientSecret { 047 048 049 /** 050 * Creates a new client secret post authentication. 051 * 052 * @param clientID The client identifier. Must not be {@code null}. 053 * @param secret The client secret. Must not be {@code null}. 054 */ 055 public ClientSecretPost(final ClientID clientID, final Secret secret) { 056 057 super(ClientAuthenticationMethod.CLIENT_SECRET_POST, clientID, secret); 058 } 059 060 061 @Override 062 public Set<String> getFormParameterNames() { 063 064 return Collections.unmodifiableSet(new HashSet<String>(Arrays.asList("client_id", "client_secret"))); 065 } 066 067 068 /** 069 * Returns the parameter representation of this client secret post 070 * authentication. Note that the parameters are not 071 * {@code application/x-www-form-urlencoded} encoded. 072 * 073 * <p>Parameters map: 074 * 075 * <pre> 076 * "client_id" = [client-identifier] 077 * "client_secret" = [client-secret] 078 * </pre> 079 * 080 * @return The parameters map, with keys "client_id" and 081 * "client_secret". 082 */ 083 public Map<String,List<String>> toParameters() { 084 085 Map<String,List<String>> params = new HashMap<>(); 086 params.put("client_id", Collections.singletonList(getClientID().getValue())); 087 params.put("client_secret", Collections.singletonList(getClientSecret().getValue())); 088 return params; 089 } 090 091 092 @Override 093 public void applyTo(final HTTPRequest httpRequest) { 094 095 if (httpRequest.getMethod() != HTTPRequest.Method.POST) 096 throw new SerializeException("The HTTP request method must be POST"); 097 098 ContentType ct = httpRequest.getEntityContentType(); 099 100 if (ct == null) 101 throw new SerializeException("Missing HTTP Content-Type header"); 102 103 if (! ct.matches(ContentType.APPLICATION_URLENCODED)) 104 throw new SerializeException("The HTTP Content-Type header must be " + ContentType.APPLICATION_URLENCODED); 105 106 Map<String,List<String>> params = httpRequest.getQueryParameters(); 107 108 params.putAll(toParameters()); 109 110 String queryString = URLUtils.serializeParameters(params); 111 112 httpRequest.setQuery(queryString); 113 } 114 115 116 /** 117 * Parses a client secret post authentication from the specified 118 * parameters map. Note that the parameters must not be 119 * {@code application/x-www-form-urlencoded} encoded. 120 * 121 * @param params The parameters map to parse. The client secret post 122 * parameters must be keyed under "client_id" and 123 * "client_secret". The map must not be {@code null}. 124 * 125 * @return The client secret post authentication. 126 * 127 * @throws ParseException If the parameters map couldn't be parsed to a 128 * client secret post authentication. 129 */ 130 public static ClientSecretPost parse(final Map<String,List<String>> params) 131 throws ParseException { 132 133 String clientIDString = MultivaluedMapUtils.getFirstValue(params, "client_id"); 134 135 if (clientIDString == null) 136 throw new ParseException("Malformed client secret post authentication: Missing client_id parameter"); 137 138 String secretValue = MultivaluedMapUtils.getFirstValue(params, "client_secret"); 139 140 if (secretValue == null) 141 throw new ParseException("Malformed client secret post authentication: Missing client_secret parameter"); 142 143 return new ClientSecretPost(new ClientID(clientIDString), new Secret(secretValue)); 144 } 145 146 147 /** 148 * Parses a client secret post authentication from the specified 149 * {@code application/x-www-form-urlencoded} encoded parameters string. 150 * 151 * @param paramsString The parameters string to parse. The client secret 152 * post parameters must be keyed under "client_id" 153 * and "client_secret". The string must not be 154 * {@code null}. 155 * 156 * @return The client secret post authentication. 157 * 158 * @throws ParseException If the parameters string couldn't be parsed to 159 * a client secret post authentication. 160 */ 161 public static ClientSecretPost parse(final String paramsString) 162 throws ParseException { 163 164 Map<String,List<String>> params = URLUtils.parseParameters(paramsString); 165 166 return parse(params); 167 } 168 169 170 /** 171 * Parses a client secret post authentication from the specified HTTP 172 * POST request. 173 * 174 * @param httpRequest The HTTP POST request to parse. Must not be 175 * {@code null} and must contain a valid 176 * {@code application/x-www-form-urlencoded} encoded 177 * parameters string in the entity body. The client 178 * secret post parameters must be keyed under 179 * "client_id" and "client_secret". 180 * 181 * @return The client secret post authentication. 182 * 183 * @throws ParseException If the HTTP request header couldn't be parsed 184 * to a valid client secret post authentication. 185 */ 186 public static ClientSecretPost parse(final HTTPRequest httpRequest) 187 throws ParseException { 188 189 httpRequest.ensureMethod(HTTPRequest.Method.POST); 190 httpRequest.ensureEntityContentType(ContentType.APPLICATION_URLENCODED); 191 192 return parse(httpRequest.getQueryParameters()); 193 } 194}