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