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 /** 066 * The request does not contain an access token. No error code or 067 * description is specified for this error, just the HTTP status code 068 * is set to 401 (Unauthorized). 069 * 070 * <p>Example: 071 * 072 * <pre> 073 * HTTP/1.1 401 Unauthorized 074 * WWW-Authenticate: Bearer 075 * </pre> 076 */ 077 public static final BearerTokenError MISSING_TOKEN = 078 new BearerTokenError(null, null, HTTPResponse.SC_UNAUTHORIZED); 079 080 /** 081 * The request is missing a required parameter, includes an unsupported 082 * parameter or parameter value, repeats the same parameter, uses more 083 * than one method for including an access token, or is otherwise 084 * malformed. The HTTP status code is set to 400 (Bad Request). 085 */ 086 public static final BearerTokenError INVALID_REQUEST = 087 new BearerTokenError("invalid_request", "Invalid request", 088 HTTPResponse.SC_BAD_REQUEST); 089 090 091 /** 092 * The access token provided is expired, revoked, malformed, or invalid 093 * for other reasons. The HTTP status code is set to 401 094 * (Unauthorized). 095 */ 096 public static final BearerTokenError INVALID_TOKEN = 097 new BearerTokenError("invalid_token", "Invalid access token", 098 HTTPResponse.SC_UNAUTHORIZED); 099 100 101 /** 102 * The request requires higher privileges than provided by the access 103 * token. The HTTP status code is set to 403 (Forbidden). 104 */ 105 public static final BearerTokenError INSUFFICIENT_SCOPE = 106 new BearerTokenError("insufficient_scope", "Insufficient scope", 107 HTTPResponse.SC_FORBIDDEN); 108 109 110 /** 111 * Creates a new OAuth 2.0 bearer token error with the specified code 112 * and description. 113 * 114 * @param code The error code, {@code null} if not specified. 115 * @param description The error description, {@code null} if not 116 * specified. 117 */ 118 public BearerTokenError(final String code, final String description) { 119 120 this(code, description, 0, null, null, null); 121 } 122 123 124 /** 125 * Creates a new OAuth 2.0 bearer token error with the specified code, 126 * description and HTTP status code. 127 * 128 * @param code The error code, {@code null} if not specified. 129 * @param description The error description, {@code null} if not 130 * specified. 131 * @param httpStatusCode The HTTP status code, zero if not specified. 132 */ 133 public BearerTokenError(final String code, final String description, final int httpStatusCode) { 134 135 this(code, description, httpStatusCode, null, null, null); 136 } 137 138 139 /** 140 * Creates a new OAuth 2.0 bearer token error with the specified code, 141 * description, HTTP status code, page URI, realm and scope. 142 * 143 * @param code The error code, {@code null} if not specified. 144 * @param description The error description, {@code null} if not 145 * specified. 146 * @param httpStatusCode The HTTP status code, zero if not specified. 147 * @param uri The error page URI, {@code null} if not 148 * specified. 149 * @param realm The realm, {@code null} if not specified. 150 * @param scope The required scope, {@code null} if not 151 * specified. 152 */ 153 public BearerTokenError(final String code, 154 final String description, 155 final int httpStatusCode, 156 final URI uri, 157 final String realm, 158 final Scope scope) { 159 160 super(AccessTokenType.BEARER, code, description, httpStatusCode, uri, realm, scope); 161 } 162 163 164 @Override 165 public BearerTokenError setDescription(final String description) { 166 167 return new BearerTokenError(super.getCode(), description, super.getHTTPStatusCode(), super.getURI(), getRealm(), getScope()); 168 } 169 170 171 @Override 172 public BearerTokenError appendDescription(final String text) { 173 174 String newDescription; 175 176 if (getDescription() != null) 177 newDescription = getDescription() + text; 178 else 179 newDescription = text; 180 181 return new BearerTokenError(super.getCode(), newDescription, super.getHTTPStatusCode(), super.getURI(), getRealm(), getScope()); 182 } 183 184 185 @Override 186 public BearerTokenError setHTTPStatusCode(final int httpStatusCode) { 187 188 return new BearerTokenError(super.getCode(), super.getDescription(), httpStatusCode, super.getURI(), getRealm(), getScope()); 189 } 190 191 192 @Override 193 public BearerTokenError setURI(final URI uri) { 194 195 return new BearerTokenError(super.getCode(), super.getDescription(), super.getHTTPStatusCode(), uri, getRealm(), getScope()); 196 } 197 198 199 @Override 200 public BearerTokenError setRealm(final String realm) { 201 202 return new BearerTokenError(getCode(), 203 getDescription(), 204 getHTTPStatusCode(), 205 getURI(), 206 realm, 207 getScope()); 208 } 209 210 211 @Override 212 public BearerTokenError setScope(final Scope scope) { 213 214 return new BearerTokenError(getCode(), 215 getDescription(), 216 getHTTPStatusCode(), 217 getURI(), 218 getRealm(), 219 scope); 220 } 221 222 223 /** 224 * Parses an OAuth 2.0 bearer token error from the specified HTTP 225 * response {@code WWW-Authenticate} header. 226 * 227 * @param wwwAuth The {@code WWW-Authenticate} header value to parse. 228 * Must not be {@code null}. 229 * 230 * @return The bearer token error. 231 * 232 * @throws ParseException If the {@code WWW-Authenticate} header value 233 * couldn't be parsed to a Bearer token error. 234 */ 235 public static BearerTokenError parse(final String wwwAuth) 236 throws ParseException { 237 238 TokenSchemeError genericError = TokenSchemeError.parse(wwwAuth, AccessTokenType.BEARER); 239 240 return new BearerTokenError( 241 genericError.getCode(), 242 genericError.getDescription(), 243 genericError.getHTTPStatusCode(), 244 genericError.getURI(), 245 genericError.getRealm(), 246 genericError.getScope() 247 ); 248 } 249}