
org.italiangrid.voms.util.CachingCertificateValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of voms-api-java Show documentation
Show all versions of voms-api-java Show documentation
Java APIs to validate and request VOMS attribute certificates
/**
* Copyright (c) Istituto Nazionale di Fisica Nucleare, 2006-2014.
*
* 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 org.italiangrid.voms.util;
import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.italiangrid.voms.VOMSError;
import eu.emi.security.authn.x509.ProxySupport;
import eu.emi.security.authn.x509.RevocationParameters;
import eu.emi.security.authn.x509.StoreUpdateListener;
import eu.emi.security.authn.x509.ValidationErrorListener;
import eu.emi.security.authn.x509.ValidationResult;
import eu.emi.security.authn.x509.X509CertChainValidatorExt;
import eu.emi.security.authn.x509.impl.CertificateUtils;
import eu.emi.security.authn.x509.impl.FormatMode;
/**
* A Certificate validator that caches validation results for a configurable
* period of time. The cache is keyed by the fingerprint of the certificate at
* the top of the chain (likely the EEC).
*
*
* @author andreaceccanti
*
*/
public class CachingCertificateValidator implements X509CertChainValidatorExt {
/**
* Simple concurrent cache for validation results
*/
protected final ConcurrentMap validationResultsCache;
/**
* The wrapped CANL certificate validator
*/
protected final X509CertChainValidatorExt validator;
/**
* The cache entry lifetime for this validator
*/
protected final long cacheEntryLifetimeMsec;
/**
* Builds a caching validator wrapping the validator passed as argument.
*
* @param val
* The CANL validator to be wrapped.
* @param maxCacheEntryLifetime
* the maximum cache entry lifetime (in msecs)
*/
public CachingCertificateValidator(X509CertChainValidatorExt val,
long maxCacheEntryLifetime) {
cacheEntryLifetimeMsec = maxCacheEntryLifetime;
validator = val;
validationResultsCache = new ConcurrentHashMap();
}
/**
* Checks whether the {@link CachedValidationResult} passed as argument has
* expired with respect to the {@link #cacheEntryLifetimeMsec} defined for
* this validator and the reference time passed as argument.
*
* @param cvr
* a {@link CachedValidationResult} object
* @param referenceTime
* the reference time (msecs since the epoch)
* @return true
when expired, false
otherwise
*/
public boolean cachedValidationResultHasExpired(CachedValidationResult cvr,
long referenceTime) {
return (referenceTime - cvr.getTimestamp() > cacheEntryLifetimeMsec);
}
/**
* Gets a validation result from the memory cache
*
* @param certFingerprint
* the certificate fingerprint for the certificate at the top of the
* chain
* @return the validation result, if found. null
otherwise.
*/
protected ValidationResult getCachedResult(String certFingerprint) {
CachedValidationResult cvr = validationResultsCache.get(certFingerprint);
if (cvr == null)
return null;
if (!cachedValidationResultHasExpired(cvr, System.currentTimeMillis())) {
return cvr.getResult();
}
validationResultsCache.remove(certFingerprint, cvr);
return null;
}
/**
* Obvious sanity checks on input certificate chain
*
* @param certChain
* the chain to be checked
*/
private void certChainSanityChecks(X509Certificate[] certChain) {
if (certChain == null)
throw new IllegalArgumentException("Cannot validate a null cert chain.");
if (certChain.length == 0)
throw new IllegalArgumentException(
"Cannot validate a cert chain of length 0.");
}
/**
* Validates a certificate chain using the wrapped validator, caching the
* result for future validation calls.
*
* @param certChain
* the certificate chain that will be validated
* @return a possibly cached {@link ValidationResult}
* @see eu.emi.security.authn.x509.X509CertChainValidator#validate(java.security.cert.X509Certificate[])
*/
public ValidationResult validate(X509Certificate[] certChain) {
certChainSanityChecks(certChain);
String certFingerprint = null;
try {
certFingerprint = FingerprintHelper
.getFingerprint(certChain[certChain.length - 1]);
} catch (Throwable t) {
String errorMsg = String.format("Error computing fingerprint for "
+ "certificate: %s. Cause: %s",
CertificateUtils.format(certChain[0], FormatMode.COMPACT_ONE_LINE),
t.getMessage());
throw new VOMSError(errorMsg, t);
}
ValidationResult res = getCachedResult(certFingerprint);
if (res == null) {
res = validator.validate(certChain);
validationResultsCache.putIfAbsent(certFingerprint,
new CachedValidationResult(certFingerprint, res));
}
return res;
}
/**
* @see eu.emi.security.authn.x509.X509CertChainValidatorExt#dispose()
*/
public void dispose() {
validator.dispose();
}
/**
* @return the proxy support information
* @see eu.emi.security.authn.x509.X509CertChainValidatorExt#getProxySupport()
*/
public ProxySupport getProxySupport() {
return validator.getProxySupport();
}
/**
* @param certPath
* the certificate path that will be validated
* @return the {@link ValidationResult}
* @see eu.emi.security.authn.x509.X509CertChainValidator#validate(java.security.cert.CertPath)
*/
public ValidationResult validate(CertPath certPath) {
return validator.validate(certPath);
}
/**
* @return revocation parameters for the wrapped validator
* @see eu.emi.security.authn.x509.X509CertChainValidatorExt#getRevocationCheckingMode()
*/
public RevocationParameters getRevocationCheckingMode() {
return validator.getRevocationCheckingMode();
}
/**
* @return trusted issuers from the wrapped validator
* @see eu.emi.security.authn.x509.X509CertChainValidator#getTrustedIssuers()
*/
public X509Certificate[] getTrustedIssuers() {
return validator.getTrustedIssuers();
}
/**
* @param listener
* the {@link ValidationErrorListener} to be added to this validator
*
* @see eu.emi.security.authn.x509.X509CertChainValidator#addValidationListener(eu.emi.security.authn.x509.ValidationErrorListener)
*/
public void addValidationListener(ValidationErrorListener listener) {
validator.addValidationListener(listener);
}
/**
* @param listener
* the {@link ValidationErrorListener} that must be removed from
* this validator
* @see eu.emi.security.authn.x509.X509CertChainValidator#removeValidationListener(eu.emi.security.authn.x509.ValidationErrorListener)
*/
public void removeValidationListener(ValidationErrorListener listener) {
validator.removeValidationListener(listener);
}
/**
* @param listener
* the {@link StoreUpdateListener} that must be added to this
* validator
*
* @see eu.emi.security.authn.x509.X509CertChainValidator#addUpdateListener(eu.emi.security.authn.x509.StoreUpdateListener)
*/
public void addUpdateListener(StoreUpdateListener listener) {
validator.addUpdateListener(listener);
}
/**
* @param listener
* the {@link StoreUpdateListener} that must be removed from this
* validator
*
* @see eu.emi.security.authn.x509.X509CertChainValidator#removeUpdateListener(eu.emi.security.authn.x509.StoreUpdateListener)
*/
public void removeUpdateListener(StoreUpdateListener listener) {
validator.removeUpdateListener(listener);
}
}
/**
* A validation result cache entry.
*
* @author cecco
*
*/
class CachedValidationResult {
/**
* Default constructor.
*
* @param certificateFingerprint
* the certificate fingerprint for this entry
* @param res
* the validation result
*/
public CachedValidationResult(String certificateFingerprint,
ValidationResult res) {
certFingerprint = certificateFingerprint;
result = res;
timestamp = System.currentTimeMillis();
}
/** The certificate fingerprint for this cache entry **/
private String certFingerprint;
/** The validation result for this cache entry **/
private ValidationResult result;
/** The cache entry creation timestamp **/
private long timestamp;
/**
* Returns the validation result for this entry.
*
* @return a {@link ValidationResult}
*/
public ValidationResult getResult() {
return result;
}
/**
* Sets the validation result for this entry
*
* @param result
* a {@link ValidationResult}
*/
public void setResult(ValidationResult result) {
this.result = result;
}
/**
* Returns this entry creation timestamp.
*
* @return the timestamp expressed as milliseconds since epoch
*/
public long getTimestamp() {
return timestamp;
}
/**
* Sets this entry creation timestamp (in milliseconds since the epoch).
*
* @param timestamp
* the timestamp
*/
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/**
* Returns the certificate fingerprint for this entry.
*
* The certificate fingerprint is the SHA1 hash of the DER encoding of the
* certificate.
*
*
*
* @return the fingerprint for this entry
* @see FingerprintHelper
*/
public String getCertFingerprint() {
return certFingerprint;
}
/**
*
* Sets the certificate finger for this entry. The certificate fingerprint is
* the SHA1 hash of the DER encoding of the certificate.
*
* It can be computed with the
* {@link FingerprintHelper#getFingerprint(X509Certificate)} method.
*
* @param certFingerprint
* a certificate fingerprint describing a certificate
*/
public void setCertFingerprint(String certFingerprint) {
this.certFingerprint = certFingerprint;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((certFingerprint == null) ? 0 : certFingerprint.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CachedValidationResult other = (CachedValidationResult) obj;
if (certFingerprint == null) {
if (other.certFingerprint != null)
return false;
} else if (!certFingerprint.equals(other.certFingerprint))
return false;
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy