All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nimbusds.oauth2.sdk.token.DPoPTokenError Maven / Gradle / Ivy

Go to download

OAuth 2.0 SDK with OpenID Connection extensions for developing client and server applications.

There is a newer version: 11.19.1
Show newest version
/*
 * oauth2-oidc-sdk
 *
 * Copyright 2012-2016, Connect2id Ltd and contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
 * this file except in compliance with the License. You may obtain a copy of the
 * License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package com.nimbusds.oauth2.sdk.token;


import java.net.URI;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.jcip.annotations.Immutable;

import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
import com.nimbusds.oauth2.sdk.util.CollectionUtils;


/**
 * OAuth 2.0 DPoP token error. Used to indicate that access to a resource
 * protected by a DPoP access token is denied, due to the request, token or
 * DPoP proof being invalid, or due to the access token having insufficient
 * scope.
 *
 * 

Standard DPoP access token errors: * *

    *
  • {@link #MISSING_TOKEN} *
  • {@link #INVALID_REQUEST} *
  • {@link #INVALID_TOKEN} *
  • {@link #INSUFFICIENT_SCOPE} *
  • {@link #USE_DPOP_NONCE} *
* *

Example HTTP response: * *

 * HTTP/1.1 401 Unauthorized
 * WWW-Authenticate: DPoP realm="example.com",
 *                   error="invalid_token",
 *                   error_description="The access token expired"
 * 
* *

Related specifications: * *

    *
  • OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer * (DPoP) (RFC 9449), section 7.1. *
  • Hypertext Transfer Protocol (HTTP/1.1): Authentication (RFC 7235), * section 4.1. *
*/ @Immutable public class DPoPTokenError extends TokenSchemeError { private static final long serialVersionUID = 7399517620661603486L; /** * Regex pattern for matching the JWS algorithms parameter of a * WWW-Authenticate header. */ static final Pattern ALGS_PATTERN = Pattern.compile("algs=\"([^\"]+)"); /** * The request does not contain an access token. No error code or * description is specified for this error, just the HTTP status code * is set to 401 (Unauthorized). * *

Example: * *

	 * HTTP/1.1 401 Unauthorized
	 * WWW-Authenticate: DPoP
	 * 
*/ public static final DPoPTokenError MISSING_TOKEN = new DPoPTokenError(null, null, HTTPResponse.SC_UNAUTHORIZED); /** * The request is missing a required parameter, includes an unsupported * parameter or parameter value, repeats the same parameter, uses more * than one method for including an access token, or is otherwise * malformed. The HTTP status code is set to 400 (Bad Request). */ public static final DPoPTokenError INVALID_REQUEST = new DPoPTokenError("invalid_request", "Invalid request", HTTPResponse.SC_BAD_REQUEST); /** * The access token provided is expired, revoked, malformed, or invalid * for other reasons. The HTTP status code is set to 401 * (Unauthorized). */ public static final DPoPTokenError INVALID_TOKEN = new DPoPTokenError("invalid_token", "Invalid access token", HTTPResponse.SC_UNAUTHORIZED); /** * The request requires higher privileges than provided by the access * token. The HTTP status code is set to 403 (Forbidden). */ public static final DPoPTokenError INSUFFICIENT_SCOPE = new DPoPTokenError("insufficient_scope", "Insufficient scope", HTTPResponse.SC_FORBIDDEN); /** * The request has a DPoP proof that is invalid. The HTTP status code * is set to 401 (Unauthorized). */ public static final DPoPTokenError INVALID_DPOP_PROOF = new DPoPTokenError("invalid_dpop_proof", "Invalid DPoP proof", HTTPResponse.SC_UNAUTHORIZED); /** * The request is missing a required DPoP nonce. The HTTP status code * is set to 401 (Unauthorized). */ public static final DPoPTokenError USE_DPOP_NONCE = new DPoPTokenError("use_dpop_nonce", "Use of DPoP nonce required", HTTPResponse.SC_UNAUTHORIZED); /** * The acceptable JWS algorithms, {@code null} if not specified. */ private final Set jwsAlgs; /** * Creates a new OAuth 2.0 DPoP token error with the specified code * and description. * * @param code The error code, {@code null} if not specified. * @param description The error description, {@code null} if not * specified. */ public DPoPTokenError(final String code, final String description) { this(code, description, 0, null, null, null); } /** * Creates a new OAuth 2.0 DPoP token error with the specified code, * description and HTTP status code. * * @param code The error code, {@code null} if not specified. * @param description The error description, {@code null} if not * specified. * @param httpStatusCode The HTTP status code, zero if not specified. */ public DPoPTokenError(final String code, final String description, final int httpStatusCode) { this(code, description, httpStatusCode, null, null, null); } /** * Creates a new OAuth 2.0 DPoP token error with the specified code, * description, HTTP status code, page URI, realm and scope. * * @param code The error code, {@code null} if not specified. * @param description The error description, {@code null} if not * specified. * @param httpStatusCode The HTTP status code, zero if not specified. * @param uri The error page URI, {@code null} if not * specified. * @param realm The realm, {@code null} if not specified. * @param scope The required scope, {@code null} if not * specified. */ public DPoPTokenError(final String code, final String description, final int httpStatusCode, final URI uri, final String realm, final Scope scope) { this(code, description, httpStatusCode, uri, realm, scope, null); } /** * Creates a new OAuth 2.0 DPoP token error with the specified code, * description, HTTP status code, page URI, realm and scope. * * @param code The error code, {@code null} if not specified. * @param description The error description, {@code null} if not * specified. * @param httpStatusCode The HTTP status code, zero if not specified. * @param uri The error page URI, {@code null} if not * specified. * @param realm The realm, {@code null} if not specified. * @param scope The required scope, {@code null} if not * specified. * @param jwsAlgs The acceptable JWS algorithms, {@code null} if * not specified. */ public DPoPTokenError(final String code, final String description, final int httpStatusCode, final URI uri, final String realm, final Scope scope, final Set jwsAlgs) { super(AccessTokenType.DPOP, code, description, httpStatusCode, uri, realm, scope); this.jwsAlgs = jwsAlgs; } @Override public DPoPTokenError setDescription(final String description) { return new DPoPTokenError( getCode(), description, getHTTPStatusCode(), getURI(), getRealm(), getScope(), getJWSAlgorithms() ); } @Override public DPoPTokenError appendDescription(final String text) { String newDescription; if (getDescription() != null) newDescription = getDescription() + text; else newDescription = text; return new DPoPTokenError( getCode(), newDescription, getHTTPStatusCode(), getURI(), getRealm(), getScope(), getJWSAlgorithms() ); } @Override public DPoPTokenError setHTTPStatusCode(final int httpStatusCode) { return new DPoPTokenError( getCode(), getDescription(), httpStatusCode, getURI(), getRealm(), getScope(), getJWSAlgorithms() ); } @Override public DPoPTokenError setURI(final URI uri) { return new DPoPTokenError( getCode(), getDescription(), getHTTPStatusCode(), uri, getRealm(), getScope(), getJWSAlgorithms() ); } @Override public DPoPTokenError setRealm(final String realm) { return new DPoPTokenError( getCode(), getDescription(), getHTTPStatusCode(), getURI(), realm, getScope(), getJWSAlgorithms() ); } @Override public DPoPTokenError setScope(final Scope scope) { return new DPoPTokenError( getCode(), getDescription(), getHTTPStatusCode(), getURI(), getRealm(), scope, getJWSAlgorithms() ); } /** * Returns the acceptable JWS algorithms. * * @return The acceptable JWS algorithms, {@code null} if not * specified. */ public Set getJWSAlgorithms() { return jwsAlgs; } /** * Sets the acceptable JWS algorithms. * * @param jwsAlgs The acceptable JWS algorithms, {@code null} if not * specified. * * @return A copy of this error with the specified acceptable JWS * algorithms. */ public DPoPTokenError setJWSAlgorithms(final Set jwsAlgs) { return new DPoPTokenError( getCode(), getDescription(), getHTTPStatusCode(), getURI(), getRealm(), getScope(), jwsAlgs ); } /** * Returns the {@code WWW-Authenticate} HTTP response header code for * this DPoP access token error response. * *

Example: * *

	 * DPoP realm="example.com", error="invalid_token", error_description="Invalid access token"
	 * 
* * @return The {@code Www-Authenticate} header value. */ @Override public String toWWWAuthenticateHeader() { String header = super.toWWWAuthenticateHeader(); if (CollectionUtils.isEmpty(getJWSAlgorithms())) { return header; } StringBuilder sb = new StringBuilder(header); if (header.contains("=")) { sb.append(','); } sb.append(" algs=\""); String delim = ""; for (JWSAlgorithm alg: getJWSAlgorithms()) { sb.append(delim); delim = " "; sb.append(alg.getName()); } sb.append("\""); return sb.toString(); } /** * Parses an OAuth 2.0 DPoP token error from the specified HTTP * response {@code WWW-Authenticate} header. * * @param wwwAuth The {@code WWW-Authenticate} header value to parse. * Must not be {@code null}. * * @return The DPoP token error. * * @throws ParseException If the {@code WWW-Authenticate} header value * couldn't be parsed to a DPoP token error. */ public static DPoPTokenError parse(final String wwwAuth) throws ParseException { TokenSchemeError genericError = TokenSchemeError.parse(wwwAuth, AccessTokenType.DPOP); Set jwsAlgs = null; Matcher m = ALGS_PATTERN.matcher(wwwAuth); if (m.find()) { String algsString = m.group(1); jwsAlgs = new HashSet<>(); for (String algName: algsString.split("\\s+")) { jwsAlgs.add(JWSAlgorithm.parse(algName)); } } return new DPoPTokenError( genericError.getCode(), genericError.getDescription(), genericError.getHTTPStatusCode(), genericError.getURI(), genericError.getRealm(), genericError.getScope(), jwsAlgs ); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy