001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2021, 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.dpop.verifiers; 019 020 021import com.nimbusds.jose.JOSEException; 022import com.nimbusds.jose.JWSAlgorithm; 023import com.nimbusds.jwt.SignedJWT; 024import com.nimbusds.oauth2.sdk.dpop.JWKThumbprintConfirmation; 025import com.nimbusds.oauth2.sdk.id.JWTID; 026import com.nimbusds.oauth2.sdk.util.Receiver; 027import com.nimbusds.oauth2.sdk.util.singleuse.SingleUseChecker; 028import com.nimbusds.openid.connect.sdk.Nonce; 029import net.jcip.annotations.ThreadSafe; 030 031import java.net.URI; 032import java.util.Collections; 033import java.util.Map; 034import java.util.Objects; 035import java.util.Set; 036 037 038/** 039 * DPoP proof JWT verifier for the OAuth 2.0 token endpoint of an authorisation 040 * server. 041 */ 042@ThreadSafe 043public class DPoPTokenRequestVerifier extends DPoPCommonVerifier { 044 045 046 /** 047 * The token endpoint URI. 048 */ 049 private final URI endpointURI; 050 051 052 /** 053 * Creates a new DPoP proof JWT verifier for the OAuth 2.0 token 054 * endpoint. 055 * 056 * @param acceptedJWSAlgs The accepted JWS algorithms. Must be 057 * supported and not {@code null}. 058 * @param endpointURI The token endpoint URI. Any query or 059 * fragment component will be stripped from 060 * it before performing the comparison. Must 061 * not be {@code null}. 062 * @param maxClockSkewSeconds The maximum permitted DPoP proof "iat" 063 * clock skew, in seconds. A proof with 064 * "iat" in the future is accepted if it is 065 * within this skew tolerance. Intended to 066 * prevent rejections due to client and 067 * server system time differences. 068 * @param maxAgeSeconds The maximum accepted DPoP proof "iat" age 069 * relative to the current system time, in 070 * seconds. Intended to limit replay by 071 * bounding how long a proof is valid after 072 * issue. 073 * @param singleUseChecker The single use checker for the DPoP proof 074 * "jti" (JWT ID) claims, {@code null} if 075 * not specified. 076 */ 077 public DPoPTokenRequestVerifier(final Set<JWSAlgorithm> acceptedJWSAlgs, 078 final URI endpointURI, 079 final long maxClockSkewSeconds, 080 final long maxAgeSeconds, 081 final SingleUseChecker<DPoPProofUse> singleUseChecker) { 082 083 super(acceptedJWSAlgs, maxClockSkewSeconds, maxAgeSeconds, singleUseChecker); 084 this.endpointURI = Objects.requireNonNull(endpointURI); 085 } 086 087 088 /** 089 * Creates a new DPoP proof JWT verifier for the OAuth 2.0 token 090 * endpoint. 091 * 092 * @param acceptedJWSAlgs The accepted JWS algorithms. Must be 093 * supported and not {@code null}. 094 * @param endpointURI The token endpoint URI. Any query or 095 * fragment component will be stripped from 096 * it before performing the comparison. Must 097 * not be {@code null}. 098 * @param maxClockSkewSeconds The maximum permitted DPoP proof "iat" 099 * clock skew, in seconds. A proof with 100 * "iat" in the future is accepted if it is 101 * within this skew tolerance. Intended to 102 * prevent rejections due to client and 103 * server system time differences. 104 * @param singleUseChecker The single use checker for the DPoP proof 105 * "jti" (JWT ID) claims, {@code null} if 106 * not specified. 107 */ 108 @Deprecated 109 public DPoPTokenRequestVerifier(final Set<JWSAlgorithm> acceptedJWSAlgs, 110 final URI endpointURI, 111 final long maxClockSkewSeconds, 112 final SingleUseChecker<Map.Entry<DPoPIssuer, JWTID>> singleUseChecker) { 113 114 super(acceptedJWSAlgs, maxClockSkewSeconds, singleUseChecker); 115 this.endpointURI = Objects.requireNonNull(endpointURI); 116 } 117 118 119 /** 120 * Verifies the specified DPoP proof and returns the DPoP JWK SHA-256 121 * thumbprint confirmation. 122 * 123 * @param issuer Unique identifier for the DPoP proof issuer, typically 124 * as its client ID. Must not be {@code null}. 125 * @param proof The DPoP proof JWT. Must not be {@code null}. 126 * 127 * @return The DPoP JWK SHA-256 thumbprint confirmation. 128 * 129 * @throws InvalidDPoPProofException If the DPoP proof is invalid. 130 * @throws InvalidDPoPNonceException If the DPoP proof nonce is invalid 131 * or missing. 132 * @throws JOSEException If an internal JOSE exception is 133 * encountered. 134 */ 135 @Deprecated 136 public JWKThumbprintConfirmation verify(final DPoPIssuer issuer, final SignedJWT proof) 137 throws InvalidDPoPProofException, JOSEException { 138 139 return verify(issuer, proof, (Set<Nonce>) null); 140 } 141 142 143 /** 144 * Verifies the specified DPoP proof and returns the DPoP JWK SHA-256 145 * thumbprint confirmation. 146 * 147 * @param issuer Unique identifier for the DPoP proof issuer, typically 148 * as its client ID. Must not be {@code null}. 149 * @param proof The DPoP proof JWT. Must not be {@code null}. 150 * @param nonce The accepted DPoP proof JWT nonce, {@code null} if 151 * none is expected. 152 * 153 * @return The DPoP JWK SHA-256 thumbprint confirmation. 154 * 155 * @throws InvalidDPoPProofException If the DPoP proof is invalid. 156 * @throws InvalidDPoPNonceException If the DPoP proof nonce is invalid 157 * or missing. 158 * @throws JOSEException If an internal JOSE exception is 159 * encountered. 160 */ 161 public JWKThumbprintConfirmation verify(final DPoPIssuer issuer, final SignedJWT proof, final Nonce nonce) 162 throws InvalidDPoPProofException, JOSEException { 163 164 return verify(issuer, proof, nonce != null ? Collections.singleton(nonce) : null); 165 } 166 167 168 /** 169 * Verifies the specified DPoP proof and returns the DPoP JWK SHA-256 170 * thumbprint confirmation. 171 * 172 * @param issuer Unique identifier for the DPoP proof issuer, typically 173 * a client ID. Must not be {@code null}. 174 * @param proof The DPoP proof JWT. Must not be {@code null}. 175 * @param nonces The accepted DPoP proof JWT nonce values, {@code null} 176 * if none are expected. 177 * 178 * @return The DPoP JWK SHA-256 thumbprint confirmation. 179 * 180 * @throws InvalidDPoPProofException If the DPoP proof is invalid. 181 * @throws InvalidDPoPNonceException If the DPoP proof nonce is invalid 182 * or missing. 183 * @throws JOSEException If an internal JOSE exception is 184 * encountered. 185 */ 186 public JWKThumbprintConfirmation verify(final DPoPIssuer issuer, final SignedJWT proof, final Set<Nonce> nonces) 187 throws InvalidDPoPProofException, JOSEException { 188 189 return verify(issuer, proof, nonces, null); 190 } 191 192 193 /** 194 * Verifies the specified DPoP proof and returns the DPoP JWK SHA-256 195 * thumbprint confirmation. 196 * 197 * @param issuer Unique identifier for the DPoP proof issuer, 198 * typically a client ID. Must not be {@code null}. 199 * @param proof The DPoP proof JWT. Must not be {@code null}. 200 * @param nonces The accepted DPoP proof JWT nonce values, 201 * {@code null} if none are expected. 202 * @param ctxReceiver To access the DPoP proof JWT claims set, 203 * {@code null} if not required. 204 * 205 * @return The DPoP JWK SHA-256 thumbprint confirmation. 206 * 207 * @throws InvalidDPoPProofException If the DPoP proof is invalid. 208 * @throws InvalidDPoPNonceException If the DPoP proof nonce is invalid 209 * or missing. 210 * @throws JOSEException If an internal JOSE exception is 211 * encountered. 212 */ 213 public JWKThumbprintConfirmation verify(final DPoPIssuer issuer, 214 final SignedJWT proof, 215 final Set<Nonce> nonces, 216 final Receiver<DPoPProofContext> ctxReceiver) 217 throws InvalidDPoPProofException, JOSEException { 218 219 try { 220 super.verify("POST", endpointURI, issuer, proof, null, null, nonces, ctxReceiver); 221 } catch (AccessTokenValidationException e) { 222 throw new RuntimeException("Unexpected exception", e); 223 } 224 225 return new JWKThumbprintConfirmation(proof.getHeader().getJWK().computeThumbprint()); 226 } 227}