com.identityx.auth.impl.JoseResponseVerifier Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of daon-http-digest-auth Show documentation
Show all versions of daon-http-digest-auth Show documentation
Client library used for adding authentication to http messages as required by IdentityX Rest Services
/*
* Copyright Daon.
*
* 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.identityx.auth.impl;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.identityx.auth.def.IApiKey;
import com.identityx.auth.def.IResponse;
import com.identityx.auth.def.IResponseAuthenticator;
import com.identityx.auth.def.IResponseVerifier;
import com.identityx.auth.impl.keys.PublicApiKey;
import com.identityx.auth.support.DigestVerificationFailedException;
import com.identityx.auth.util.CertValidationResultCache;
import com.identityx.auth.util.CertsUtil;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.RSASSAVerifier;
public class JoseResponseVerifier implements IResponseVerifier {
private String authenticationScheme = JoseRequestAuthenticator.AUTHENTICATION_SCHEME;
private static final Log logger = LogFactory.getLog(JoseResponseVerifier.class);
@Override
public void verify(IResponse response, IResponseAuthenticator responseAuthenticator, IApiKey apiKey, String nonce) throws DigestVerificationFailedException {
if (!response.getHeaders().containsKey(DigestAuthenticator.DATE_HEADER) || !response.getHeaders().containsKey(AuthSettings.AUTHORIZATION_HEADER)) {
throw new DigestVerificationFailedException("The required headers were not present in the response message");
}
if (apiKey == null || !(apiKey instanceof PublicApiKey)) {
throw new IllegalArgumentException("apiKey parameter null or wrong type");
}
try {
String authHeader = response.getHeaders().getFirst(AuthSettings.AUTHORIZATION_HEADER);
JWSPayload jwsPayload = ((JoseResponseAuthenticator)responseAuthenticator).getJWSPayloadFromHeader(authHeader);
String canonicalResponse = responseAuthenticator.buildCanonicalResponse(response);
String canonicalResponseHashHex = DigestAuthenticator.toHex(DigestAuthenticator.hash(canonicalResponse));
if (!jwsPayload.getCanonicalRequestHashHex().equals(canonicalResponseHashHex)) {
String message = "The canonical response in the signature does not match the actual canonical response";
logger.error(message);
throw new DigestVerificationFailedException("Failed to verify the signature of the response object: " + message);
}
PublicApiKey publicApiKey = (PublicApiKey)apiKey;
if (publicApiKey.getCert() == null && jwsPayload.getSigningCerts() == null) {
String msg = "Certs were expected in the server response.";
logger.error(msg);
throw new DigestVerificationFailedException("Failed to verify the signature of the response object: " + msg);
}
//////////////////////////////////////////////////////////////////
List certs = null;
if (jwsPayload.getSigningCerts() == null || jwsPayload.getSigningCerts().isEmpty()) {
// no certs received from the server
certs = new ArrayList();
certs.add(publicApiKey.getCert());
certs.addAll(publicApiKey.getIntermediateCerts());
X509Certificate eeCert = publicApiKey.getCert();
checkServerCertDistinguishedName(eeCert, publicApiKey);
String key = eeCert.getIssuerDN().toString() + eeCert.getSerialNumber().toString();
if (!CertValidationResultCache.getInstance(key).isCached()) {
performCertPathValidation(publicApiKey, certs);
// no exception so far so mark it valid in the cache
CertValidationResultCache.getInstance(key).markPassedValidation();
}
}
else {
// server provides new certs
String signingCerts = jwsPayload.getSigningCerts();
certs = CertsUtil.certsFromString(signingCerts);
X509Certificate eeCert = certs.get(0);
checkServerCertDistinguishedName(eeCert, publicApiKey);
performCertPathValidation(publicApiKey, certs);
publicApiKey.setCert(eeCert);
publicApiKey.getIntermediateCerts().clear();
publicApiKey.getIntermediateCerts().addAll(certs.subList(1, certs.size()));
}
X509Certificate serverCert = certs.get(0);
serverCert.checkValidity();
JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey)serverCert.getPublicKey());
JWSObject jwsObject = ((JoseResponseAuthenticator)responseAuthenticator).getJWSObjectFromHeader(authHeader);
logger.debug("Verifying the JSW token's signature");
if (!jwsObject.verify(verifier)) {
logger.error("Failed to verify the signature of the jws token");
throw new DigestVerificationFailedException("Failed to verify the signature of the response object");
}
} catch (CertPathValidatorException e) {
// make sure after a failure the result is still cached
//CertValidationResultCache.getInstance().resetCache();
throw new DigestVerificationFailedException("Failed to validate the signature of the response object", e);
}
catch (Exception e) {
throw new DigestVerificationFailedException("An error has occurred while verifying the signature of the response object", e);
}
}
public void checkServerCertDistinguishedName(X509Certificate serverCert, PublicApiKey publicApiKey) throws DigestVerificationFailedException {
String incomingDN = serverCert.getSubjectDN().toString();
if (!incomingDN.equals(publicApiKey.getServerCertDN())) {
String message = "The incoming server certificate's DistinguishedName does not match the expected DN: got " + incomingDN + ", expecting " + publicApiKey.getServerCertDN();
logger.error(message);
throw new DigestVerificationFailedException(message);
}
}
protected void performCertPathValidation(PublicApiKey publicApiKey, List certs) throws CertificateException, DigestVerificationFailedException, NoSuchAlgorithmException, CertPathValidatorException, InvalidAlgorithmParameterException, NoSuchProviderException {
// 1. cert should be in date or is that included in the path validation ?
// 2. cert SAN should be the same as the one we store
// 3. Full path validation
if (certs == null || certs.isEmpty()) {
return;
}
// only work with certs that are not self signed
List pathCerts = new ArrayList();
for (X509Certificate icert : certs) {
if (!CertsUtil.isSelfSigned(icert)) {
pathCerts.add(icert);
}
}
if (pathCerts.isEmpty()) {
return;
}
CertificateFactory fact = CertificateFactory.getInstance("X.509");
CertPath certPath = fact.generateCertPath(pathCerts);
PKIXParameters params = null;
TrustAnchor anchor = new TrustAnchor(publicApiKey.getCaCert(), null);
params = new PKIXParameters(Collections.singleton(anchor));
params.setRevocationEnabled(publicApiKey.isRevocationEnabled());
if (publicApiKey.isRevocationEnabled()) {
Properties props = System.getProperties();
props.setProperty("com.sun.security.enableCRLDP", "true");
}
if (publicApiKey.isOcspEnabled()) {
Security.setProperty("ocsp.enable", "true");
}
else {
Security.setProperty("ocsp.enable", "false");
}
CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
cpv.validate(certPath, params);
}
public String getAuthenticationScheme() {
return authenticationScheme;
}
public void setAuthenticationScheme(String authenticationScheme) {
this.authenticationScheme = authenticationScheme;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy