001package com.nimbusds.openid.connect.sdk; 002 003 004import java.net.URI; 005import java.net.URISyntaxException; 006import java.util.Collections; 007import java.util.HashSet; 008import java.util.Map; 009import java.util.Set; 010 011import net.jcip.annotations.Immutable; 012 013import com.nimbusds.oauth2.sdk.*; 014import com.nimbusds.oauth2.sdk.util.URLUtils; 015 016import com.nimbusds.oauth2.sdk.id.State; 017import com.nimbusds.oauth2.sdk.http.HTTPResponse; 018 019 020/** 021 * OpenID Connect authentication error response. 022 * 023 * <p>Standard errors: 024 * 025 * <ul> 026 * <li>OAuth 2.0 authorisation errors: 027 * <ul> 028 * <li>{@link com.nimbusds.oauth2.sdk.OAuth2Error#INVALID_REQUEST} 029 * <li>{@link com.nimbusds.oauth2.sdk.OAuth2Error#UNAUTHORIZED_CLIENT} 030 * <li>{@link com.nimbusds.oauth2.sdk.OAuth2Error#ACCESS_DENIED} 031 * <li>{@link com.nimbusds.oauth2.sdk.OAuth2Error#UNSUPPORTED_RESPONSE_TYPE} 032 * <li>{@link com.nimbusds.oauth2.sdk.OAuth2Error#INVALID_SCOPE} 033 * <li>{@link com.nimbusds.oauth2.sdk.OAuth2Error#SERVER_ERROR} 034 * <li>{@link com.nimbusds.oauth2.sdk.OAuth2Error#TEMPORARILY_UNAVAILABLE} 035 * </ul> 036 * <li>OpenID Connect specific errors: 037 * <ul> 038 * <li>{@link OIDCError#INTERACTION_REQUIRED} 039 * <li>{@link OIDCError#LOGIN_REQUIRED} 040 * <li>{@link OIDCError#ACCOUNT_SELECTION_REQUIRED} 041 * <li>{@link OIDCError#CONSENT_REQUIRED} 042 * <li>{@link OIDCError#INVALID_REQUEST_URI} 043 * <li>{@link OIDCError#INVALID_REQUEST_OBJECT} 044 * <li>{@link OIDCError#REGISTRATION_NOT_SUPPORTED} 045 * <li>{@link OIDCError#REQUEST_NOT_SUPPORTED} 046 * <li>{@link OIDCError#REQUEST_URI_NOT_SUPPORTED} 047 * </ul> 048 * </li> 049 * </ul> 050 * 051 * <p>Example HTTP response: 052 * 053 * <pre> 054 * HTTP/1.1 302 Found 055 * Location: https://client.example.org/cb? 056 * error=invalid_request 057 * &error_description=the%20request%20is%20not%20valid%20or%20malformed 058 * &state=af0ifjsldkj 059 * </pre> 060 * 061 * <p>Related specifications: 062 * 063 * <ul> 064 * <li>OpenID Connect Core 1.0, section 3.1.2.6. 065 * </ul> 066 */ 067@Immutable 068public class AuthenticationErrorResponse 069 extends AuthorizationErrorResponse 070 implements AuthenticationResponse { 071 072 073 /** 074 * The standard errors for an OpenID Connect authentication error 075 * response. 076 */ 077 private static Set<ErrorObject> stdErrors = new HashSet<>(); 078 079 080 static { 081 stdErrors.addAll(AuthorizationErrorResponse.getStandardErrors()); 082 083 stdErrors.add(OIDCError.INTERACTION_REQUIRED); 084 stdErrors.add(OIDCError.LOGIN_REQUIRED); 085 stdErrors.add(OIDCError.ACCOUNT_SELECTION_REQUIRED); 086 stdErrors.add(OIDCError.CONSENT_REQUIRED); 087 stdErrors.add(OIDCError.INVALID_REQUEST_URI); 088 stdErrors.add(OIDCError.INVALID_REQUEST_OBJECT); 089 stdErrors.add(OIDCError.REGISTRATION_NOT_SUPPORTED); 090 stdErrors.add(OIDCError.REQUEST_NOT_SUPPORTED); 091 stdErrors.add(OIDCError.REQUEST_URI_NOT_SUPPORTED); 092 } 093 094 095 /** 096 * Gets the standard errors for an OpenID Connect authentication error 097 * response. 098 * 099 * @return The standard errors, as a read-only set. 100 */ 101 public static Set<ErrorObject> getStandardErrors() { 102 103 return Collections.unmodifiableSet(stdErrors); 104 } 105 106 107 /** 108 * Creates a new OpenID Connect authentication error response. 109 * 110 * @param redirectURI The base redirection URI. Must not be 111 * {@code null}. 112 * @param error The error. Should match one of the 113 * {@link #getStandardErrors standard errors} for an 114 * OpenID Connect authentication error response. 115 * Must not be {@code null}. 116 * @param rt The response type, used to determine the redirect 117 * URI composition. If unknown {@code null}. 118 * @param state The state, {@code null} if not requested. 119 */ 120 public AuthenticationErrorResponse(final URI redirectURI, 121 final ErrorObject error, 122 final ResponseType rt, 123 final State state) { 124 125 super(redirectURI, error, rt, state); 126 } 127 128 129 @Override 130 public URI toURI() 131 throws SerializeException { 132 133 StringBuilder sb = new StringBuilder(getRedirectionURI().toString()); 134 135 if (getResponseType() == null || 136 getResponseType().contains(ResponseType.Value.TOKEN) || 137 getResponseType().contains(OIDCResponseTypeValue.ID_TOKEN)) { 138 139 sb.append("#"); 140 } else { 141 142 sb.append("?"); 143 } 144 145 sb.append(URLUtils.serializeParameters(toParameters())); 146 147 try { 148 return new URI(sb.toString()); 149 150 } catch (URISyntaxException e) { 151 152 throw new SerializeException("Couldn't serialize redirection URI: " + e.getMessage(), e); 153 } 154 } 155 156 157 /** 158 * Parses an OpenID Connect authentication error response from the 159 * specified redirection URI and parameters. 160 * 161 * @param redirectURI The base redirection URI. Must not be 162 * {@code null}. 163 * @param params The response parameters to parse. Must not be 164 * {@code null}. 165 * 166 * @return The OpenID Connect authentication error response. 167 * 168 * @throws ParseException If the parameters couldn't be parsed to an 169 * OpenID Connect authentication error response. 170 */ 171 public static AuthenticationErrorResponse parse(final URI redirectURI, 172 final Map<String,String> params) 173 throws ParseException { 174 175 AuthorizationErrorResponse resp = AuthorizationErrorResponse.parse(redirectURI, params); 176 177 return new AuthenticationErrorResponse(resp.getRedirectionURI(), 178 resp.getErrorObject(), 179 resp.getResponseType(), 180 resp.getState()); 181 } 182 183 184 /** 185 * Parses an OpenID Connect authentication error response from the 186 * specified URI. 187 * 188 * <p>Example URI: 189 * 190 * <pre> 191 * https://client.example.com/cb? 192 * error=invalid_request 193 * &error_description=the%20request%20is%20not%20valid%20or%20malformed 194 * &state=af0ifjsldkj 195 * </pre> 196 * 197 * @param uri The URI to parse. Can be absolute or relative. Must not 198 * be {@code null}. 199 * 200 * @return The OpenID Connect authentication error response. 201 * 202 * @throws ParseException If the URI couldn't be parsed to an OpenID 203 * Connect authentication error response. 204 */ 205 public static AuthenticationErrorResponse parse(final URI uri) 206 throws ParseException { 207 208 AuthorizationErrorResponse resp = AuthorizationErrorResponse.parse(uri); 209 210 return new AuthenticationErrorResponse(resp.getRedirectionURI(), 211 resp.getErrorObject(), 212 resp.getResponseType(), 213 resp.getState()); 214 } 215 216 217 /** 218 * Parses an OpenID Connect authentication error response from the 219 * specified HTTP response. 220 * 221 * <p>Example HTTP response: 222 * 223 * <pre> 224 * HTTP/1.1 302 Found 225 * Location: https://client.example.com/cb? 226 * error=invalid_request 227 * &error_description=the%20request%20is%20not%20valid%20or%20malformed 228 * &state=af0ifjsldkj 229 * </pre> 230 * 231 * @param httpResponse The HTTP response to parse. Must not be 232 * {@code null}. 233 * 234 * @return The OpenID Connect authentication error response. 235 * 236 * @throws ParseException If the HTTP response couldn't be parsed to an 237 * OpenID Connect authentication error response. 238 */ 239 public static AuthenticationErrorResponse parse(final HTTPResponse httpResponse) 240 throws ParseException { 241 242 AuthorizationErrorResponse resp = AuthorizationErrorResponse.parse(httpResponse); 243 244 return new AuthenticationErrorResponse(resp.getRedirectionURI(), 245 resp.getErrorObject(), 246 resp.getResponseType(), 247 resp.getState()); 248 } 249}