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.net.URI; 022 023import net.jcip.annotations.Immutable; 024 025import net.minidev.json.JSONObject; 026 027import com.nimbusds.oauth2.sdk.http.HTTPResponse; 028import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 029 030 031/** 032 * Error object, used to encapsulate OAuth 2.0 and other errors. 033 * 034 * <p>Example error object as HTTP response: 035 * 036 * <pre> 037 * HTTP/1.1 400 Bad Request 038 * Content-Type: application/json;charset=UTF-8 039 * Cache-Control: no-store 040 * Pragma: no-cache 041 * 042 * { 043 * "error" : "invalid_request" 044 * } 045 * </pre> 046 */ 047@Immutable 048public class ErrorObject { 049 050 051 /** 052 * The error code, may not always be defined. 053 */ 054 private final String code; 055 056 057 /** 058 * Optional error description. 059 */ 060 private final String description; 061 062 063 /** 064 * Optional HTTP status code, 0 if not specified. 065 */ 066 private final int httpStatusCode; 067 068 069 /** 070 * Optional URI of a web page that includes additional information 071 * about the error. 072 */ 073 private final URI uri; 074 075 076 /** 077 * Creates a new error with the specified code. 078 * 079 * @param code The error code, {@code null} if not specified. 080 */ 081 public ErrorObject(final String code) { 082 083 this(code, null, 0, null); 084 } 085 086 087 /** 088 * Creates a new error with the specified code and description. 089 * 090 * @param code The error code, {@code null} if not specified. 091 * @param description The error description, {@code null} if not 092 * specified. 093 */ 094 public ErrorObject(final String code, final String description) { 095 096 this(code, description, 0, null); 097 } 098 099 100 /** 101 * Creates a new error with the specified code, description and HTTP 102 * status code. 103 * 104 * @param code The error code, {@code null} if not specified. 105 * @param description The error description, {@code null} if not 106 * specified. 107 * @param httpStatusCode The HTTP status code, zero if not specified. 108 */ 109 public ErrorObject(final String code, final String description, 110 final int httpStatusCode) { 111 112 this(code, description, httpStatusCode, null); 113 } 114 115 116 /** 117 * Creates a new error with the specified code, description, HTTP 118 * status code and page URI. 119 * 120 * @param code The error code, {@code null} if not specified. 121 * @param description The error description, {@code null} if not 122 * specified. 123 * @param httpStatusCode The HTTP status code, zero if not specified. 124 * @param uri The error page URI, {@code null} if not 125 * specified. 126 */ 127 public ErrorObject(final String code, final String description, 128 final int httpStatusCode, final URI uri) { 129 130 this.code = code; 131 this.description = description; 132 this.httpStatusCode = httpStatusCode; 133 this.uri = uri; 134 } 135 136 137 /** 138 * Gets the error code. 139 * 140 * @return The error code, {@code null} if not specified. 141 */ 142 public String getCode() { 143 144 return code; 145 } 146 147 148 /** 149 * Gets the error description. 150 * 151 * @return The error description, {@code null} if not specified. 152 */ 153 public String getDescription() { 154 155 return description; 156 } 157 158 159 /** 160 * Sets the error description. 161 * 162 * @param description The error description, {@code null} if not 163 * specified. 164 * 165 * @return A copy of this error with the specified description. 166 */ 167 public ErrorObject setDescription(final String description) { 168 169 return new ErrorObject(getCode(), description, getHTTPStatusCode(), getURI()); 170 } 171 172 173 /** 174 * Appends the specified text to the error description. 175 * 176 * @param text The text to append to the error description, 177 * {@code null} if not specified. 178 * 179 * @return A copy of this error with the specified appended 180 * description. 181 */ 182 public ErrorObject appendDescription(final String text) { 183 184 String newDescription; 185 186 if (getDescription() != null) 187 newDescription = getDescription() + text; 188 else 189 newDescription = text; 190 191 return new ErrorObject(getCode(), newDescription, getHTTPStatusCode(), getURI()); 192 } 193 194 195 /** 196 * Gets the HTTP status code. 197 * 198 * @return The HTTP status code, zero if not specified. 199 */ 200 public int getHTTPStatusCode() { 201 202 return httpStatusCode; 203 } 204 205 206 /** 207 * Sets the HTTP status code. 208 * 209 * @param httpStatusCode The HTTP status code, zero if not specified. 210 * 211 * @return A copy of this error with the specified HTTP status code. 212 */ 213 public ErrorObject setHTTPStatusCode(final int httpStatusCode) { 214 215 return new ErrorObject(getCode(), getDescription(), httpStatusCode, getURI()); 216 } 217 218 219 /** 220 * Gets the error page URI. 221 * 222 * @return The error page URI, {@code null} if not specified. 223 */ 224 public URI getURI() { 225 226 return uri; 227 } 228 229 230 /** 231 * Sets the error page URI. 232 * 233 * @param uri The error page URI, {@code null} if not specified. 234 * 235 * @return A copy of this error with the specified page URI. 236 */ 237 public ErrorObject setURI(final URI uri) { 238 239 return new ErrorObject(getCode(), getDescription(), getHTTPStatusCode(), uri); 240 } 241 242 243 /** 244 * Returns a JSON object representation of this error object. 245 * 246 * <p>Example: 247 * 248 * <pre> 249 * { 250 * "error" : "invalid_grant", 251 * "error_description" : "Invalid resource owner credentials" 252 } 253 * </pre> 254 * 255 * @return The JSON object. 256 */ 257 public JSONObject toJSONObject() { 258 259 JSONObject o = new JSONObject(); 260 261 if (code != null) { 262 o.put("error", code); 263 } 264 265 if (description != null) { 266 o.put("error_description", description); 267 } 268 269 if (uri != null) { 270 o.put("error_uri", uri.toString()); 271 } 272 273 return o; 274 } 275 276 277 /** 278 * @see #getCode 279 */ 280 @Override 281 public String toString() { 282 283 return code != null ? code : "null"; 284 } 285 286 287 @Override 288 public int hashCode() { 289 290 return code != null ? code.hashCode() : "null".hashCode(); 291 } 292 293 294 @Override 295 public boolean equals(final Object object) { 296 297 return object instanceof ErrorObject && 298 this.toString().equals(object.toString()); 299 } 300 301 302 /** 303 * Parses an error object from the specified JSON object. 304 * 305 * @param jsonObject The JSON object to parse. Must not be 306 * {@code null}. 307 * 308 * @return The error object. 309 */ 310 public static ErrorObject parse(final JSONObject jsonObject) { 311 312 String code = null; 313 String description = null; 314 URI uri = null; 315 316 try { 317 if (jsonObject.containsKey("error")) { 318 code = JSONObjectUtils.getString(jsonObject, "error"); 319 } 320 321 if (jsonObject.containsKey("error_description")) { 322 description = JSONObjectUtils.getString(jsonObject, "error_description"); 323 } 324 325 if (jsonObject.containsKey("error_uri")) { 326 uri = JSONObjectUtils.getURI(jsonObject, "error_uri"); 327 } 328 } catch (ParseException e) { 329 // ignore and continue 330 } 331 332 return new ErrorObject(code, description, 0, uri); 333 } 334 335 336 /** 337 * Parses an error object from the specified HTTP response. 338 * 339 * @param httpResponse The HTTP response to parse. Must not be 340 * {@code null}. 341 * 342 * @return The error object. 343 */ 344 public static ErrorObject parse(final HTTPResponse httpResponse) { 345 346 JSONObject jsonObject; 347 348 try { 349 jsonObject = httpResponse.getContentAsJSONObject(); 350 351 } catch (ParseException e) { 352 353 return new ErrorObject(null, null, httpResponse.getStatusCode()); 354 } 355 356 ErrorObject intermediary = parse(jsonObject); 357 358 return new ErrorObject( 359 intermediary.getCode(), 360 intermediary.description, 361 httpResponse.getStatusCode(), 362 intermediary.getURI()); 363 } 364}