Package org.apache.cxf.xkms.crypto.impl

Source Code of org.apache.cxf.xkms.crypto.impl.XkmsCryptoProvider

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.cxf.xkms.crypto.impl;

import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.security.auth.callback.CallbackHandler;

import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.xkms.cache.EHCacheXKMSClientCache;
import org.apache.cxf.xkms.cache.XKMSCacheToken;
import org.apache.cxf.xkms.cache.XKMSClientCache;
import org.apache.cxf.xkms.crypto.CryptoProviderException;
import org.apache.cxf.xkms.handlers.Applications;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.components.crypto.CryptoBase;
import org.apache.ws.security.components.crypto.CryptoType;
import org.apache.ws.security.components.crypto.CryptoType.TYPE;
import org.w3._2002._03.xkms_wsdl.XKMSPortType;

public class XkmsCryptoProvider extends CryptoBase {

    private static final Logger LOG = LogUtils.getL7dLogger(XkmsCryptoProvider.class);

    private final XKMSInvoker xkmsInvoker;
    private Crypto defaultCrypto;
    private XKMSClientCache xkmsClientCache;

    public XkmsCryptoProvider(XKMSPortType xkmsConsumer) {
        this(xkmsConsumer, null);
    }

    public XkmsCryptoProvider(XKMSPortType xkmsConsumer, Crypto defaultCrypto) {
        this(xkmsConsumer, defaultCrypto, new EHCacheXKMSClientCache());
    }
   
    public XkmsCryptoProvider(XKMSPortType xkmsConsumer, Crypto defaultCrypto, XKMSClientCache xkmsClientCache) {
        if (xkmsConsumer == null) {
            throw new IllegalArgumentException("xkmsConsumer may not be null");
        }
        this.xkmsInvoker = new XKMSInvoker(xkmsConsumer);
        this.defaultCrypto = defaultCrypto;
        this.xkmsClientCache = xkmsClientCache;
    }
   
    @Override
    public X509Certificate[] getX509Certificates(CryptoType cryptoType) throws WSSecurityException {
        if (LOG.isLoggable(Level.INFO)) {
            LOG.info(String
                .format("XKMS Runtime: getting public certificate for alias: %s; issuer: %s; subjectDN: %s",
                        cryptoType.getAlias(), cryptoType.getIssuer(), cryptoType.getSubjectDN()));
        }
        X509Certificate[] certs = getX509CertificatesInternal(cryptoType);
        if (certs == null) {
            LOG.severe(String
                .format(
                        "Cannot find certificate for alias: %s, issuer: %s; subjectDN: %s",
                        cryptoType.getAlias(), cryptoType.getIssuer(), cryptoType.getSubjectDN()));
        }
        return certs;
    }

    @Override
    public String getX509Identifier(X509Certificate cert) throws WSSecurityException {
        assertDefaultCryptoProvider();
        return defaultCrypto.getX509Identifier(cert);
    }

    @Override
    public PrivateKey getPrivateKey(X509Certificate certificate, CallbackHandler callbackHandler)
        throws WSSecurityException {
        assertDefaultCryptoProvider();
        return defaultCrypto.getPrivateKey(certificate, callbackHandler);
    }

    @Override
    public PrivateKey getPrivateKey(String identifier, String password) throws WSSecurityException {
        assertDefaultCryptoProvider();
        return defaultCrypto.getPrivateKey(identifier, password);
    }

    @Override
    public boolean verifyTrust(X509Certificate[] certs) {
        return verifyTrust(certs, false);
    }
   
    @Override
    public boolean verifyTrust(X509Certificate[] certs, boolean enableRevocation) {
        if (certs != null) {
            LOG.fine(String.format("Verifying certificate id: %s", certs[0].getSubjectDN()));
        }
       
        XKMSCacheToken cachedToken = null;
        // Try local cache first
        if (certs != null && certs.length > 0 && xkmsClientCache != null) {
            String key = certs[0].getSubjectX500Principal().getName();
            // Try by Subject DN and IssuerSerial
            cachedToken = xkmsClientCache.get(key);
            if (cachedToken == null) {
                key = getKeyForIssuerSerial(certs[0].getIssuerX500Principal().getName(),
                                            certs[0].getSerialNumber());
                cachedToken = xkmsClientCache.get(key);
            }
            if (cachedToken != null && cachedToken.isXkmsValidated()) {
                LOG.fine("Certificate has already been validated by the XKMS service");
                return true;
            }
        }
        if (certs == null || certs[0] == null || !xkmsInvoker.validateCertificate(certs[0])) {
            return false;
        }
       
        // Validate Cached token
        if (cachedToken != null) {
            cachedToken.setXkmsValidated(true);
        }
       
        // Otherwise, Store in the cache as a validated certificate
        storeCertificateInCache(certs[0], null, true);

        return true;
    }

    @Override
    public boolean verifyTrust(PublicKey publicKey) throws WSSecurityException {
        throw new CryptoProviderException("PublicKeys cannot be verified");
    }

    private void assertDefaultCryptoProvider() {
        if (defaultCrypto == null) {
            throw new UnsupportedOperationException("Not supported by this crypto provider");
        }
    }

    private X509Certificate[] getX509CertificatesInternal(CryptoType cryptoType) {
        CryptoType.TYPE type = cryptoType.getType();
        if (type == TYPE.SUBJECT_DN) {
            return getX509CertificatesFromXKMS(Applications.PKIX, cryptoType.getSubjectDN());
        } else if (type == TYPE.ALIAS) {
            return getX509CertificatesFromXKMS(cryptoType);
        } else if (type == TYPE.ISSUER_SERIAL) {
            // Try local Crypto first
            X509Certificate[] localCerts = getCertificateLocally(cryptoType);
            if (localCerts != null) {
                return localCerts;
            }
           
            String key = getKeyForIssuerSerial(cryptoType.getIssuer(), cryptoType.getSerial());
            // Try local cache next
            if (xkmsClientCache != null) {
                XKMSCacheToken cachedToken = xkmsClientCache.get(key);
                if (cachedToken != null && cachedToken.getX509Certificate() != null) {
                    return new X509Certificate[] {cachedToken.getX509Certificate()};
                }
            }
            // Now ask the XKMS Service
            X509Certificate certificate = xkmsInvoker.getCertificateForIssuerSerial(cryptoType
                .getIssuer(), cryptoType.getSerial());
           
            // Store in the cache
            storeCertificateInCache(certificate, key, false);

            return new X509Certificate[] {
                certificate
            };
        }
        throw new IllegalArgumentException("Unsupported type " + type);
    }

    private X509Certificate[] getX509CertificatesFromXKMS(CryptoType cryptoType) {
        Applications appId = null;
        boolean isServiceName = isServiceName(cryptoType);
        if (!isServiceName) {
            X509Certificate[] localCerts = getCertificateLocally(cryptoType);
            if (localCerts != null) {
                return localCerts;
            }
            appId = Applications.PKIX;
        } else {
            appId = Applications.SERVICE_SOAP;
        }
        return getX509CertificatesFromXKMS(appId, cryptoType.getAlias());
    }

    private X509Certificate[] getX509CertificatesFromXKMS(Applications application, String id) {
        LOG.fine(String.format("Getting public certificate from XKMS for application:%s; id: %s",
                               application, id));
        if (id == null) {
            throw new CryptoProviderException("Id is not specified for certificate request");
        }
       
        // Try local cache first
        if (xkmsClientCache != null) {
            XKMSCacheToken cachedToken = xkmsClientCache.get(id.toLowerCase());
            if (cachedToken != null && cachedToken.getX509Certificate() != null) {
                return new X509Certificate[] {cachedToken.getX509Certificate()};
            }
        }
       
        // Now ask the XKMS Service
        X509Certificate cert = xkmsInvoker.getCertificateForId(application, id);
       
        // Store in the cache
        storeCertificateInCache(cert, id.toLowerCase(), false);

        return new X509Certificate[] {
            cert
        };
    }

    /**
     * Try to get certificate locally. First try using the supplied CryptoType. If this
     * does not work, and if the supplied CryptoType is a ALIAS, then try again with SUBJECT_DN
     * in case the supplied Alias is actually a Certificate's Subject DN
     *
     * @param cryptoType
     * @return if found certificate otherwise null returned
     */
    private X509Certificate[] getCertificateLocally(CryptoType cryptoType) {
        // This only applies if we've configured a local Crypto instance...
        if (defaultCrypto == null) {
            return null;
        }
       
        // First try using the supplied CryptoType instance
        X509Certificate[] localCerts = null;
        try {
            localCerts = defaultCrypto.getX509Certificates(cryptoType);
        } catch (Exception e) {
            LOG.info("Certificate is not found in local keystore using desired CryptoType: "
                     + cryptoType.getType().name());
        }
       
        if (localCerts == null && cryptoType.getType() == CryptoType.TYPE.ALIAS) {
            // If none found then try using either the Subject DN. This is because an
            // Encryption username in CXF is configured as an Alias in WSS4J, but may in fact
            // be a Subject DN
            CryptoType newCryptoType = new CryptoType(CryptoType.TYPE.SUBJECT_DN);
            newCryptoType.setSubjectDN(cryptoType.getAlias());
           
            try {
                localCerts = defaultCrypto.getX509Certificates(newCryptoType);
            } catch (Exception e) {
                LOG.info("Certificate is not found in local keystore and will be requested from "
                    + "XKMS (first trying the cache): " + cryptoType.getAlias());
            }
        }
        return localCerts;
    }

    /**
     * Service Aliases contain namespace
     *
     * @param cryptoType
     * @return
     */
    private boolean isServiceName(CryptoType cryptoType) {
        return cryptoType.getAlias().contains("{");
    }
   
    private String getKeyForIssuerSerial(String issuer, BigInteger serial) {
        return issuer + "-" + serial.toString(16);
    }
   
    private void storeCertificateInCache(X509Certificate certificate, String key, boolean validated) {
        // Store in the cache
        if (certificate != null && xkmsClientCache != null) {
            XKMSCacheToken cacheToken = new XKMSCacheToken(certificate);
            cacheToken.setXkmsValidated(validated);
            // Store using a custom key (if any)
            if (key != null) {
                xkmsClientCache.put(key, cacheToken);
            }
            // Store it using IssuerSerial as well
            String issuerSerialKey =
                getKeyForIssuerSerial(certificate.getIssuerX500Principal().getName(),
                                      certificate.getSerialNumber());
            if (!issuerSerialKey.equals(key)) {
                xkmsClientCache.put(issuerSerialKey, cacheToken);
            }
            // Store it using the Subject DN as well
            String subjectDNKey = certificate.getSubjectX500Principal().getName();
            if (!subjectDNKey.equals(key)) {
                xkmsClientCache.put(subjectDNKey, cacheToken);
            }
        }
    }

}
TOP

Related Classes of org.apache.cxf.xkms.crypto.impl.XkmsCryptoProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.