001package com.nimbusds.oauth2.sdk; 002 003 004import java.net.URL; 005import java.util.Map; 006 007import org.apache.commons.lang3.StringUtils; 008 009import com.nimbusds.oauth2.sdk.id.State; 010import com.nimbusds.oauth2.sdk.http.HTTPResponse; 011import com.nimbusds.oauth2.sdk.util.URLUtils; 012 013 014/** 015 * The base abstract class for authorisation success and error responses. 016 * 017 * <p>Related specifications: 018 * 019 * <ul> 020 * <li>OAuth 2.0 (RFC 6749), section 3.1. 021 * </ul> 022 */ 023public abstract class AuthorizationResponse implements Response { 024 025 026 /** 027 * The base redirection URI. 028 */ 029 private final URL redirectURI; 030 031 032 /** 033 * The optional state parameter to be echoed back to the client. 034 */ 035 private final State state; 036 037 038 /** 039 * Creates a new authorisation response. 040 * 041 * @param redirectURI The base redirection URI. Must not be 042 * {@code null}. 043 * @param state The state, {@code null} if not requested. 044 */ 045 protected AuthorizationResponse(final URL redirectURI, final State state) { 046 047 if (redirectURI == null) 048 throw new IllegalArgumentException("The redirection URI must not be null"); 049 050 this.redirectURI = redirectURI; 051 052 this.state = state; 053 } 054 055 056 /** 057 * Gets the base redirection URI. 058 * 059 * @return The base redirection URI (without the appended error 060 * response parameters). 061 */ 062 public URL getRedirectionURI() { 063 064 return redirectURI; 065 } 066 067 068 /** 069 * Gets the optional state. 070 * 071 * @return The state, {@code null} if not requested. 072 */ 073 public State getState() { 074 075 return state; 076 } 077 078 079 /** 080 * Returns the parameters of this authorisation response. 081 * 082 * <p>Example parameters (authorisation success): 083 * 084 * <pre> 085 * access_token = 2YotnFZFEjr1zCsicMWpAA 086 * state = xyz 087 * token_type = example 088 * expires_in = 3600 089 * </pre> 090 * 091 * @return The parameters as a map. 092 * 093 * @throws SerializeException If this response couldn't be serialised 094 * to a parameters map. 095 */ 096 public abstract Map<String,String> toParameters() 097 throws SerializeException; 098 099 100 /** 101 * Returns the URI representation (redirection URI + fragment / query 102 * string) of this authorisation response. 103 * 104 * <p>Example URI: 105 * 106 * <pre> 107 * http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA 108 * &state=xyz 109 * &token_type=example 110 * &expires_in=3600 111 * </pre> 112 * 113 * @return The URI representation of this authorisation response. 114 * 115 * @throws SerializeException If this response couldn't be serialised 116 * to a URI. 117 */ 118 public abstract URL toURI() 119 throws SerializeException; 120 121 122 /** 123 * Returns the HTTP response for this authorisation response. 124 * 125 * <p>Example HTTP response (authorisation success): 126 * 127 * <pre> 128 * HTTP/1.1 302 Found 129 * Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA 130 * &state=xyz 131 * &token_type=example 132 * &expires_in=3600 133 * </pre> 134 * 135 * @return The HTTP response matching this authorisation response. 136 * 137 * @throws SerializeException If the response couldn't be serialised to 138 * an HTTP response. 139 */ 140 @Override 141 public HTTPResponse toHTTPResponse() 142 throws SerializeException { 143 144 HTTPResponse response = new HTTPResponse(HTTPResponse.SC_FOUND); 145 146 response.setLocation(toURI()); 147 148 return response; 149 } 150 151 152 /** 153 * Parses an authorisation response. 154 * 155 * @param redirectURI The base redirection URI. Must not be 156 * {@code null}. 157 * @param params The response parameters to parse. Must not be 158 * {@code null}. 159 * 160 * @return The authorisation success or error response. 161 * 162 * @throws ParseException If the parameters couldn't be parsed to an 163 * authorisation success or error response. 164 */ 165 public static AuthorizationResponse parse(final URL redirectURI, final Map<String,String> params) 166 throws ParseException { 167 168 if (StringUtils.isNotBlank(params.get("error"))) 169 return AuthorizationErrorResponse.parse(redirectURI, params); 170 171 else 172 return AuthorizationSuccessResponse.parse(redirectURI, params); 173 } 174 175 176 /** 177 * Parses an authorisation response. 178 * 179 * <p>Use a relative URI if the host, port and path details are not 180 * known: 181 * 182 * <pre> 183 * URL relUrl = new URL("http://?code=Qcb0Orv1...&state=af0ifjsldkj"); 184 * AuthorizationResponse = AuthorizationResponse.parse(relURL); 185 * </pre> 186 * 187 * @param uri The URL to parse. May be absolute or relative, with a 188 * fragment or query string containing the authorisation 189 * response parameters. Must not be {@code null}. 190 * 191 * @return The authorisation success or error response. 192 * 193 * @throws ParseException If no authorisation response parameters were 194 * found in the URL. 195 */ 196 public static AuthorizationResponse parse(final URL uri) 197 throws ParseException { 198 199 Map<String,String> params; 200 201 if (uri.getRef() != null) 202 params = URLUtils.parseParameters(uri.getRef()); 203 204 else if (uri.getQuery() != null) 205 params = URLUtils.parseParameters(uri.getQuery()); 206 207 else 208 throw new ParseException("Missing URL fragment or query string"); 209 210 211 return parse(URLUtils.getBaseURL(uri), params); 212 } 213 214 215 /** 216 * Parses an authorisation response. 217 * 218 * <p>Example HTTP response (authorisation success): 219 * 220 * <pre> 221 * HTTP/1.1 302 Found 222 * Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz 223 * </pre> 224 * 225 * @param httpResponse The HTTP response to parse. Must not be 226 * {@code null}. 227 * 228 * @throws ParseException If the HTTP response couldn't be parsed to an 229 * authorisation response. 230 */ 231 public static AuthorizationResponse parse(final HTTPResponse httpResponse) 232 throws ParseException { 233 234 if (httpResponse.getStatusCode() != HTTPResponse.SC_FOUND) 235 throw new ParseException("Unexpected HTTP status code, must be 302 (Found): " + 236 httpResponse.getStatusCode()); 237 238 URL location = httpResponse.getLocation(); 239 240 if (location == null) 241 throw new ParseException("Missing redirection URL / HTTP Location header"); 242 243 return parse(location); 244 } 245}