001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.oauth2.sdk;
019
020
021import java.util.Collections;
022import java.util.HashSet;
023import java.util.Set;
024
025import net.jcip.annotations.Immutable;
026import net.minidev.json.JSONObject;
027
028import com.nimbusds.common.contenttype.ContentType;
029import com.nimbusds.oauth2.sdk.http.HTTPResponse;
030
031
032/**
033 * OAuth 2.0 Token error response.
034 *
035 * <p>Standard token errors:
036 *
037 * <ul>
038 *     <li>{@link OAuth2Error#INVALID_REQUEST}
039 *     <li>{@link OAuth2Error#INVALID_CLIENT}
040 *     <li>{@link OAuth2Error#INVALID_GRANT}
041 *     <li>{@link OAuth2Error#UNAUTHORIZED_CLIENT}
042 *     <li>{@link OAuth2Error#UNSUPPORTED_GRANT_TYPE}
043 *     <li>{@link OAuth2Error#INVALID_SCOPE}
044 * </ul>
045 *
046 * <p>Example HTTP response:
047 *
048 * <pre>
049 * HTTP/1.1 400 Bad Request
050 * Content-Type: application/json
051 * Cache-Control: no-store
052 * Pragma: no-cache
053 * 
054 * {
055 *  "error": "invalid_request"
056 * }
057 * </pre>
058 *
059 * <p>Related specifications:
060 *
061 * <ul>
062 *     <li>OAuth 2.0 (RFC 6749), section 5.2.
063 * </ul>
064 */
065@Immutable
066public class TokenErrorResponse extends TokenResponse implements ErrorResponse {
067
068
069        /**
070         * The standard OAuth 2.0 errors for an Access Token error response.
071         */
072        private static final Set<ErrorObject> STANDARD_ERRORS;
073        
074        
075        static {
076                Set<ErrorObject> errors = new HashSet<>();
077                errors.add(OAuth2Error.INVALID_REQUEST);
078                errors.add(OAuth2Error.INVALID_CLIENT);
079                errors.add(OAuth2Error.INVALID_GRANT);
080                errors.add(OAuth2Error.UNAUTHORIZED_CLIENT);
081                errors.add(OAuth2Error.UNSUPPORTED_GRANT_TYPE);
082                errors.add(OAuth2Error.INVALID_SCOPE);
083                STANDARD_ERRORS = Collections.unmodifiableSet(errors);
084        }
085        
086        
087        /**
088         * Gets the standard OAuth 2.0 errors for an Access Token error 
089         * response.
090         *
091         * @return The standard errors, as a read-only set.
092         */
093        public static Set<ErrorObject> getStandardErrors() {
094        
095                return STANDARD_ERRORS;
096        }
097        
098        
099        /**
100         * The error.
101         */
102        private final ErrorObject error;
103
104
105        /**
106         * Creates a new OAuth 2.0 Access Token error response. No OAuth 2.0
107         * error is specified.
108         */
109        protected TokenErrorResponse() {
110
111                error = null;
112        }
113        
114        
115        /**
116         * Creates a new OAuth 2.0 Access Token error response.
117         *
118         * @param error The error. Should match one of the 
119         *              {@link #getStandardErrors standard errors} for a token 
120         *              error response. Must not be {@code null}.
121         */
122        public TokenErrorResponse(final ErrorObject error) {
123        
124                if (error == null)
125                        throw new IllegalArgumentException("The error must not be null");
126                        
127                this.error = error;
128        }
129
130
131        @Override
132        public boolean indicatesSuccess() {
133
134                return false;
135        }
136        
137
138        @Override
139        public ErrorObject getErrorObject() {
140        
141                return error;
142        }
143        
144        
145        /**
146         * Returns the JSON object for this token error response.
147         *
148         * @return The JSON object for this token error response.
149         */
150        public JSONObject toJSONObject() {
151        
152                JSONObject o = new JSONObject();
153
154                // No error?
155                if (error == null)
156                        return o;
157                
158                o.putAll(error.toJSONObject());
159                
160                return o;
161        }
162        
163        
164        @Override
165        public HTTPResponse toHTTPResponse() {
166
167                int statusCode = (error != null && error.getHTTPStatusCode() > 0) ?
168                        error.getHTTPStatusCode() : HTTPResponse.SC_BAD_REQUEST;
169
170                HTTPResponse httpResponse = new HTTPResponse(statusCode);
171
172                if (error == null)
173                        return httpResponse;
174                
175                httpResponse.setEntityContentType(ContentType.APPLICATION_JSON);
176                httpResponse.setCacheControl("no-store");
177                httpResponse.setPragma("no-cache");
178                
179                httpResponse.setContent(toJSONObject().toString());
180                
181                return httpResponse;
182        }
183
184
185        /**
186         * Parses an OAuth 2.0 Token Error response from the specified JSON
187         * object.
188         *
189         * @param jsonObject The JSON object to parse. Its status code must not
190         *                   be 200 (OK). Must not be {@code null}.
191         *
192         * @return The token error response.
193         *
194         * @throws ParseException If the JSON object couldn't be parsed to an 
195         *                        OAuth 2.0 Token Error response.
196         */
197        public static TokenErrorResponse parse(final JSONObject jsonObject)
198                throws ParseException {
199
200                // No error code?
201                if (! jsonObject.containsKey("error"))
202                        return new TokenErrorResponse();
203                
204                ErrorObject error = ErrorObject.parse(jsonObject).setHTTPStatusCode(HTTPResponse.SC_BAD_REQUEST);
205                
206                return new TokenErrorResponse(error);
207        }
208        
209        
210        /**
211         * Parses an OAuth 2.0 Token Error response from the specified HTTP
212         * response.
213         *
214         * @param httpResponse The HTTP response to parse. Its status code must
215         *                     not be 200 (OK). Must not be {@code null}.
216         *
217         * @return The token error response.
218         *
219         * @throws ParseException If the HTTP response couldn't be parsed to an 
220         *                        OAuth 2.0 Token Error response.
221         */
222        public static TokenErrorResponse parse(final HTTPResponse httpResponse)
223                throws ParseException {
224                
225                httpResponse.ensureStatusCodeNotOK();
226                return new TokenErrorResponse(ErrorObject.parse(httpResponse));
227        }
228}