001package com.nimbusds.oauth2.sdk; 002 003 004import java.net.MalformedURLException; 005import java.net.URL; 006import java.util.LinkedHashMap; 007import java.util.Map; 008 009import net.jcip.annotations.Immutable; 010 011import com.nimbusds.oauth2.sdk.id.ClientID; 012 013 014/** 015 * Authorisation code grant. Used in access token requests with an 016 * authorisation code. This class is immutable. 017 * 018 * <p>Related specifications: 019 * 020 * <ul> 021 * <li>OAuth 2.0 (RFC 6749), section 4.1.3. 022 * </ul> 023 * 024 * @author Vladimir Dzhuvinov 025 */ 026@Immutable 027public final class AuthorizationCodeGrant extends AuthorizationGrant { 028 029 030 /** 031 * The associated grant type. 032 */ 033 public static final GrantType GRANT_TYPE = GrantType.AUTHORIZATION_CODE; 034 035 036 /** 037 * The authorisation code received from the authorisation server. 038 */ 039 private final AuthorizationCode code; 040 041 042 /** 043 * The conditionally required redirection URI in the initial 044 * authorisation request. 045 */ 046 private final URL redirectURI; 047 048 049 /** 050 * The conditionally required client ID. 051 */ 052 private final ClientID clientID; 053 054 055 /** 056 * Creates a new authorisation code grant. This constructor is 057 * intended for an authenticated access token requests (doesn't require 058 * the client identifier to be specified). 059 * 060 * @param code The authorisation code. Must not be {@code null}. 061 * @param redirectURI The redirection URI of the original authorisation 062 * request. Required if the {redirect_uri} 063 * parameter was included in the authorisation 064 * request, else {@code null}. 065 */ 066 public AuthorizationCodeGrant(final AuthorizationCode code, 067 final URL redirectURI) { 068 069 super(GRANT_TYPE); 070 071 if (code == null) 072 throw new IllegalArgumentException("The authorisation code must not be null"); 073 074 this.code = code; 075 076 this.redirectURI = redirectURI; 077 078 this.clientID = null; 079 } 080 081 082 /** 083 * Creates a new authorisation code grant. This constructor is 084 * intended for an unauthenticated access token request and requires 085 * the client identifier to be specified. 086 * 087 * @param code The authorisation code. Must not be {@code null}. 088 * @param redirectURI The redirection URI of the original authorisation 089 * request, {@code null} if the {@code redirect_uri} 090 * parameter was not included in the authorisation 091 * request. 092 * @param clientID The client identifier. Must not be {@code null}. 093 */ 094 public AuthorizationCodeGrant(final AuthorizationCode code, 095 final URL redirectURI, 096 final ClientID clientID) { 097 098 super(GrantType.AUTHORIZATION_CODE); 099 100 if (code == null) 101 throw new IllegalArgumentException("The authorisation code must not be null"); 102 103 this.code = code; 104 105 this.redirectURI = redirectURI; 106 107 if (clientID == null) 108 throw new IllegalArgumentException("The client identifier must not be null"); 109 110 this.clientID = clientID; 111 } 112 113 114 /** 115 * Gets the authorisation code. 116 * 117 * @return The authorisation code. 118 */ 119 public AuthorizationCode getAuthorizationCode() { 120 121 return code; 122 } 123 124 125 /** 126 * Gets the redirection URI of the original authorisation request. 127 * 128 * @return The redirection URI, {@code null} if the 129 * {@code redirect_uri} parameter was not included in the 130 * original authorisation request. 131 */ 132 public URL getRedirectionURI() { 133 134 return redirectURI; 135 } 136 137 138 /** 139 * Gets the client identifier. 140 * 141 * @return The client identifier, {@code null} if not specified 142 * (implies an authenticated access token request). 143 */ 144 public ClientID getClientID() { 145 146 return clientID; 147 } 148 149 150 @Override 151 public Map<String,String> toParameters() { 152 153 Map<String,String> params = new LinkedHashMap<String,String>(); 154 155 params.put("grant_type", GRANT_TYPE.getValue()); 156 157 params.put("code", code.getValue()); 158 159 if (redirectURI != null) 160 params.put("redirect_uri", redirectURI.toString()); 161 162 if (clientID != null) 163 params.put("client_id", clientID.getValue()); 164 165 return params; 166 } 167 168 169 /** 170 * Parses an authorisation code grant from the specified parameters. 171 * 172 * <p>Example: 173 * 174 * <pre> 175 * grant_type=authorization_code 176 * code=SplxlOBeZQQYbYS6WxSbIA 177 * redirect_uri=https://Fclient.example.com/cb 178 * </pre> 179 * 180 * @param params The parameters. 181 * 182 * @return The authorisation code grant. 183 * 184 * @throws ParseException If parsing failed. 185 */ 186 public static AuthorizationCodeGrant parse(final Map<String,String> params) 187 throws ParseException { 188 189 // Parse grant type 190 String grantTypeString = params.get("grant_type"); 191 192 if (grantTypeString == null) 193 throw new ParseException("Missing \"grant_type\" parameter", OAuth2Error.INVALID_REQUEST); 194 195 GrantType grantType = new GrantType(grantTypeString); 196 197 if (! grantType.equals(GRANT_TYPE)) 198 throw new ParseException("The \"grant_type\" must be " + GRANT_TYPE, OAuth2Error.INVALID_GRANT); 199 200 201 // Parse authorisation code 202 String codeString = params.get("code"); 203 204 if (codeString == null || codeString.trim().isEmpty()) 205 throw new ParseException("Missing or empty \"code\" parameter", OAuth2Error.INVALID_REQUEST); 206 207 AuthorizationCode code = new AuthorizationCode(codeString); 208 209 210 // Parse optional redirection URI 211 String redirectURIString = params.get("redirect_uri"); 212 213 URL redirectURI = null; 214 215 if (redirectURIString != null) { 216 217 try { 218 redirectURI = new URL(redirectURIString); 219 220 } catch (MalformedURLException e) { 221 222 throw new ParseException("Invalid \"redirect_uri\" parameter: " + e.getMessage(), OAuth2Error.INVALID_REQUEST, e); 223 } 224 } 225 226 227 // Parse optional client ID 228 String clientIDString = params.get("client_id"); 229 230 ClientID clientID = null; 231 232 if (clientIDString != null && clientIDString.trim().length() > 0) 233 clientID = new ClientID(clientIDString); 234 235 if (clientID == null) 236 return new AuthorizationCodeGrant(code, redirectURI); 237 else 238 return new AuthorizationCodeGrant(code, redirectURI, clientID); 239 } 240}