001package com.nimbusds.openid.connect.sdk;
002
003
004import java.net.MalformedURLException;
005import java.net.URL;
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 *           &amp;error_description=the%20request%20is%20not%20valid%20or%20malformed
058 *           &amp;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<ErrorObject>();
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 URL 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 URL 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 URL(sb.toString());
149
150                } catch (MalformedURLException 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 URL 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         * &amp;error_description=the%20request%20is%20not%20valid%20or%20malformed
194         * &amp;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 URL 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         * &amp;error_description=the%20request%20is%20not%20valid%20or%20malformed
228         * &amp;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}