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.token; 019 020 021import java.net.URI; 022 023import net.jcip.annotations.Immutable; 024 025import com.nimbusds.oauth2.sdk.ParseException; 026import com.nimbusds.oauth2.sdk.Scope; 027import com.nimbusds.oauth2.sdk.http.HTTPResponse; 028 029 030/** 031 * OAuth 2.0 bearer token error. Used to indicate that access to a resource 032 * protected by a Bearer access token is denied, due to the request or token 033 * being invalid, or due to the access token having insufficient scope. 034 * 035 * <p>Standard bearer access token errors: 036 * 037 * <ul> 038 * <li>{@link #MISSING_TOKEN} 039 * <li>{@link #INVALID_REQUEST} 040 * <li>{@link #INVALID_TOKEN} 041 * <li>{@link #INSUFFICIENT_SCOPE} 042 * </ul> 043 * 044 * <p>Example HTTP response: 045 * 046 * <pre> 047 * HTTP/1.1 401 Unauthorized 048 * WWW-Authenticate: Bearer realm="example.com", 049 * error="invalid_token", 050 * error_description="The access token expired" 051 * </pre> 052 * 053 * <p>Related specifications: 054 * 055 * <ul> 056 * <li>OAuth 2.0 Bearer Token Usage (RFC 6750), section 3.1. 057 * <li>Hypertext Transfer Protocol (HTTP/1.1): Authentication (RFC 7235), 058 * section 4.1. 059 * </ul> 060 */ 061@Immutable 062public class BearerTokenError extends TokenSchemeError { 063 064 065 private static final long serialVersionUID = -5209789923955060584L; 066 067 /** 068 * The request does not contain an access token. No error code or 069 * description is specified for this error, just the HTTP status code 070 * is set to 401 (Unauthorized). 071 * 072 * <p>Example: 073 * 074 * <pre> 075 * HTTP/1.1 401 Unauthorized 076 * WWW-Authenticate: Bearer 077 * </pre> 078 */ 079 public static final BearerTokenError MISSING_TOKEN = 080 new BearerTokenError(null, null, HTTPResponse.SC_UNAUTHORIZED); 081 082 083 /** 084 * The request is missing a required parameter, includes an unsupported 085 * parameter or parameter value, repeats the same parameter, uses more 086 * than one method for including an access token, or is otherwise 087 * malformed. The HTTP status code is set to 400 (Bad Request). 088 */ 089 public static final BearerTokenError INVALID_REQUEST = 090 new BearerTokenError("invalid_request", "Invalid request", 091 HTTPResponse.SC_BAD_REQUEST); 092 093 094 /** 095 * The access token provided is expired, revoked, malformed, or invalid 096 * for other reasons. The HTTP status code is set to 401 097 * (Unauthorized). 098 */ 099 public static final BearerTokenError INVALID_TOKEN = 100 new BearerTokenError("invalid_token", "Invalid access token", 101 HTTPResponse.SC_UNAUTHORIZED); 102 103 104 /** 105 * The request requires higher privileges than provided by the access 106 * token. The HTTP status code is set to 403 (Forbidden). 107 */ 108 public static final BearerTokenError INSUFFICIENT_SCOPE = 109 new BearerTokenError("insufficient_scope", "Insufficient scope", 110 HTTPResponse.SC_FORBIDDEN); 111 112 113 /** 114 * Creates a new OAuth 2.0 bearer token error with the specified code 115 * and description. 116 * 117 * @param code The error code, {@code null} if not specified. 118 * @param description The error description, {@code null} if not 119 * specified. 120 */ 121 public BearerTokenError(final String code, final String description) { 122 123 this(code, description, 0, null, null, null); 124 } 125 126 127 /** 128 * Creates a new OAuth 2.0 bearer token error with the specified code, 129 * description and HTTP status code. 130 * 131 * @param code The error code, {@code null} if not specified. 132 * @param description The error description, {@code null} if not 133 * specified. 134 * @param httpStatusCode The HTTP status code, zero if not specified. 135 */ 136 public BearerTokenError(final String code, final String description, final int httpStatusCode) { 137 138 this(code, description, httpStatusCode, null, null, null); 139 } 140 141 142 /** 143 * Creates a new OAuth 2.0 bearer token error with the specified code, 144 * description, HTTP status code, page URI, realm and scope. 145 * 146 * @param code The error code, {@code null} if not specified. 147 * @param description The error description, {@code null} if not 148 * specified. 149 * @param httpStatusCode The HTTP status code, zero if not specified. 150 * @param uri The error page URI, {@code null} if not 151 * specified. 152 * @param realm The realm, {@code null} if not specified. 153 * @param scope The required scope, {@code null} if not 154 * specified. 155 */ 156 public BearerTokenError(final String code, 157 final String description, 158 final int httpStatusCode, 159 final URI uri, 160 final String realm, 161 final Scope scope) { 162 163 super(AccessTokenType.BEARER, code, description, httpStatusCode, uri, realm, scope); 164 } 165 166 167 @Override 168 public BearerTokenError setDescription(final String description) { 169 170 return new BearerTokenError(super.getCode(), description, super.getHTTPStatusCode(), super.getURI(), getRealm(), getScope()); 171 } 172 173 174 @Override 175 public BearerTokenError appendDescription(final String text) { 176 177 String newDescription; 178 179 if (getDescription() != null) 180 newDescription = getDescription() + text; 181 else 182 newDescription = text; 183 184 return new BearerTokenError(super.getCode(), newDescription, super.getHTTPStatusCode(), super.getURI(), getRealm(), getScope()); 185 } 186 187 188 @Override 189 public BearerTokenError setHTTPStatusCode(final int httpStatusCode) { 190 191 return new BearerTokenError(super.getCode(), super.getDescription(), httpStatusCode, super.getURI(), getRealm(), getScope()); 192 } 193 194 195 @Override 196 public BearerTokenError setURI(final URI uri) { 197 198 return new BearerTokenError(super.getCode(), super.getDescription(), super.getHTTPStatusCode(), uri, getRealm(), getScope()); 199 } 200 201 202 @Override 203 public BearerTokenError setRealm(final String realm) { 204 205 return new BearerTokenError(getCode(), 206 getDescription(), 207 getHTTPStatusCode(), 208 getURI(), 209 realm, 210 getScope()); 211 } 212 213 214 @Override 215 public BearerTokenError setScope(final Scope scope) { 216 217 return new BearerTokenError(getCode(), 218 getDescription(), 219 getHTTPStatusCode(), 220 getURI(), 221 getRealm(), 222 scope); 223 } 224 225 226 /** 227 * Parses an OAuth 2.0 bearer token error from the specified HTTP 228 * response {@code WWW-Authenticate} header. 229 * 230 * @param wwwAuth The {@code WWW-Authenticate} header value to parse. 231 * Must not be {@code null}. 232 * 233 * @return The bearer token error. 234 * 235 * @throws ParseException If the {@code WWW-Authenticate} header value 236 * couldn't be parsed to a Bearer token error. 237 */ 238 public static BearerTokenError parse(final String wwwAuth) 239 throws ParseException { 240 241 TokenSchemeError genericError = TokenSchemeError.parse(wwwAuth, AccessTokenType.BEARER); 242 243 return new BearerTokenError( 244 genericError.getCode(), 245 genericError.getDescription(), 246 genericError.getHTTPStatusCode(), 247 genericError.getURI(), 248 genericError.getRealm(), 249 genericError.getScope() 250 ); 251 } 252}