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}