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