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 com.nimbusds.common.contenttype.ContentType; 022import com.nimbusds.oauth2.sdk.http.HTTPResponse; 023import net.jcip.annotations.Immutable; 024import net.minidev.json.JSONObject; 025 026import java.util.Collections; 027import java.util.HashSet; 028import java.util.Objects; 029import java.util.Set; 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) 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 this.error = Objects.requireNonNull(error); 124 } 125 126 127 @Override 128 public boolean indicatesSuccess() { 129 130 return false; 131 } 132 133 134 @Override 135 public ErrorObject getErrorObject() { 136 137 return error; 138 } 139 140 141 /** 142 * Returns the JSON object for this token error response. 143 * 144 * @return The JSON object for this token error response. 145 */ 146 public JSONObject toJSONObject() { 147 148 JSONObject o = new JSONObject(); 149 150 // No error? 151 if (error == null) 152 return o; 153 154 o.putAll(error.toJSONObject()); 155 156 return o; 157 } 158 159 160 @Override 161 public HTTPResponse toHTTPResponse() { 162 163 int statusCode = (error != null && error.getHTTPStatusCode() > 0) ? 164 error.getHTTPStatusCode() : HTTPResponse.SC_BAD_REQUEST; 165 166 HTTPResponse httpResponse = new HTTPResponse(statusCode); 167 168 if (error == null) 169 return httpResponse; 170 171 httpResponse.setEntityContentType(ContentType.APPLICATION_JSON); 172 httpResponse.setCacheControl("no-store"); 173 httpResponse.setPragma("no-cache"); 174 httpResponse.setBody(toJSONObject().toString()); 175 return httpResponse; 176 } 177 178 179 /** 180 * Parses an OAuth 2.0 Token Error response from the specified JSON 181 * object. 182 * 183 * @param jsonObject The JSON object to parse. Its status code must not 184 * be 200 (OK). Must not be {@code null}. 185 * 186 * @return The token error response. 187 * 188 * @throws ParseException If the JSON object couldn't be parsed to an 189 * OAuth 2.0 Token Error response. 190 */ 191 public static TokenErrorResponse parse(final JSONObject jsonObject) 192 throws ParseException { 193 194 // No error code? 195 if (! jsonObject.containsKey("error")) 196 return new TokenErrorResponse(); 197 198 ErrorObject error = ErrorObject.parse(jsonObject).setHTTPStatusCode(HTTPResponse.SC_BAD_REQUEST); 199 200 return new TokenErrorResponse(error); 201 } 202 203 204 /** 205 * Parses an OAuth 2.0 Token Error response from the specified HTTP 206 * response. 207 * 208 * @param httpResponse The HTTP response to parse. Its status code must 209 * not be 200 (OK). Must not be {@code null}. 210 * 211 * @return The token error response. 212 * 213 * @throws ParseException If the HTTP response couldn't be parsed to an 214 * OAuth 2.0 Token Error response. 215 */ 216 public static TokenErrorResponse parse(final HTTPResponse httpResponse) 217 throws ParseException { 218 219 httpResponse.ensureStatusCodeNotOK(); 220 return new TokenErrorResponse(ErrorObject.parse(httpResponse)); 221 } 222}