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