Java tutorial
/* * Copyright (c) 2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. 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.wso2.carbon.identity.sso.saml.builders; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.opensaml.xml.security.credential.Credential; import org.opensaml.xml.security.credential.CredentialContextSet; import org.opensaml.xml.security.credential.UsageType; import org.opensaml.xml.security.x509.X509Credential; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.base.ServerConfiguration; import org.wso2.carbon.core.util.KeyStoreManager; import org.wso2.carbon.identity.base.IdentityException; import org.wso2.carbon.identity.sso.saml.util.SAMLSSOUtil; import org.wso2.carbon.user.api.UserStoreException; import java.io.FileInputStream; import java.io.IOException; import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAPublicKeySpec; import java.util.Collection; import java.util.Collections; import javax.crypto.SecretKey; /** * X509Credential implementation for signature verification of self issued tokens. The key is * constructed from modulus and exponent */ public class X509CredentialImpl implements X509Credential { private PublicKey publicKey = null; private PrivateKey privateKey = null; private X509Certificate signingCert = null; private static KeyStore superTenantSignKeyStore = null; private static Log log = LogFactory.getLog(X509CredentialImpl.class); private static final String SECURITY_SAML_SIGN_KEY_STORE_LOCATION = "Security.SAMLSignKeyStore.Location"; private static final String SECURITY_SAML_SIGN_KEY_STORE_TYPE = "Security.SAMLSignKeyStore.Type"; private static final String SECURITY_SAML_SIGN_KEY_STORE_PASSWORD = "Security.SAMLSignKeyStore.Password"; private static final String SECURITY_SAML_SIGN_KEY_STORE_KEY_ALIAS = "Security.SAMLSignKeyStore.KeyAlias"; private static final String SECURITY_SAML_SIGN_KEY_STORE_KEY_PASSWORD = "Security.SAMLSignKeyStore.KeyPassword"; /** * Instantiates X509Credential. * This credential object will hold the private key, public key and the cert for the respective tenant domain. * * @param tenantDomain tenant domain */ public X509CredentialImpl(String tenantDomain) throws IdentityException { int tenantId; try { tenantId = SAMLSSOUtil.getRealmService().getTenantManager().getTenantId(tenantDomain); } catch (UserStoreException e) { throw new IdentityException( "Exception occurred while retrieving Tenant ID from tenant domain " + tenantDomain, e); } KeyStoreManager keyStoreManager = KeyStoreManager.getInstance(tenantId); // Get the private key and the cert for the respective tenant domain. if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) { if (isSignKeyStoreConfigured()) { initCredentialForSuperTenantFromSignKeyStore(); } else { initCredentialFromSuperTenantKeyStore(keyStoreManager); } } else { initCredentialForTenant(tenantDomain, keyStoreManager); } if (privateKey == null) { throw new IdentityException("Cannot find the private key for tenant " + tenantDomain); } if (signingCert == null) { throw new IdentityException("Cannot find the certificate."); } publicKey = signingCert.getPublicKey(); } /** * Set private key and X509Certificate from the default KeyStore. * * @param keyStoreManager keyStore Manager. * @throws IdentityException Error in retrieving private key and certificate. */ private void initCredentialFromSuperTenantKeyStore(KeyStoreManager keyStoreManager) throws IdentityException { try { privateKey = keyStoreManager.getDefaultPrivateKey(); signingCert = keyStoreManager.getDefaultPrimaryCertificate(); // This Exception is thrown from the KeyStoreManager. } catch (Exception e) { throw new IdentityException("Error retrieving private key and the certificate for tenant " + MultitenantConstants.SUPER_TENANT_DOMAIN_NAME, e); } } /** * Set private key and X509Certificate from the Sign KeyStore which is defined under Security.SAMLSignKeyStore * in carbon.xml. * * @throws IdentityException Error in keystore. */ private void initCredentialForSuperTenantFromSignKeyStore() throws IdentityException { if (log.isDebugEnabled()) { log.debug("Initializing Key Data for super tenant using separate sign key store."); } try { if (superTenantSignKeyStore == null) { initSuperTenantSignKeyStore(); } String keyAlias = ServerConfiguration.getInstance() .getFirstProperty(SECURITY_SAML_SIGN_KEY_STORE_KEY_ALIAS); char[] keyPassword = ServerConfiguration.getInstance() .getFirstProperty(SECURITY_SAML_SIGN_KEY_STORE_KEY_PASSWORD).toCharArray(); Key privateKey = superTenantSignKeyStore.getKey(keyAlias, keyPassword); Certificate publicKey = superTenantSignKeyStore.getCertificate(keyAlias); if (privateKey instanceof PrivateKey) { this.privateKey = (PrivateKey) privateKey; } else { throw new IdentityException("Configured signing KeyStore private key is invalid."); } if (publicKey instanceof X509Certificate) { this.signingCert = (X509Certificate) publicKey; } else { throw new IdentityException("Configured signing KeyStore X509Certificate is invalid."); } } catch (NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException e) { throw new IdentityException( "Unable to load signing keystore for tenant " + MultitenantConstants.SUPER_TENANT_DOMAIN_NAME, e); } } private void initSuperTenantSignKeyStore() throws IdentityException { String keyStoreLocation = ServerConfiguration.getInstance() .getFirstProperty(SECURITY_SAML_SIGN_KEY_STORE_LOCATION); try (FileInputStream is = new FileInputStream(keyStoreLocation)) { String keyStoreType = ServerConfiguration.getInstance() .getFirstProperty(SECURITY_SAML_SIGN_KEY_STORE_TYPE); KeyStore keyStore = KeyStore.getInstance(keyStoreType); char[] keyStorePassword = ServerConfiguration.getInstance() .getFirstProperty(SECURITY_SAML_SIGN_KEY_STORE_PASSWORD).toCharArray(); keyStore.load(is, keyStorePassword); superTenantSignKeyStore = keyStore; } catch (IOException | CertificateException | NoSuchAlgorithmException e) { throw new IdentityException("Unable to load keystore.", e); } catch (KeyStoreException e) { throw new IdentityException("Unable to get an instance of keystore.", e); } } /** * Set private key and X509Certificate from the tenant KeyStore. * * @param tenantDomain tenant domain. * @param keyStoreManager KeyStore Manager. * @throws IdentityException Error in retrieving private key and certificate. */ private void initCredentialForTenant(String tenantDomain, KeyStoreManager keyStoreManager) throws IdentityException { try { // Derive key store name. String ksName = tenantDomain.trim().replace(".", "-"); // Derive JKS name. String jksName = ksName + ".jks"; privateKey = (PrivateKey) keyStoreManager.getPrivateKey(jksName, tenantDomain); signingCert = (X509Certificate) keyStoreManager.getKeyStore(jksName).getCertificate(tenantDomain); // This Exception is thrown from the KeyStoreManager. } catch (Exception e) { throw new IdentityException( "Error retrieving private key and the certificate for tenant " + tenantDomain, e); } } /** * Check whether separate configurations for sign KeyStore available. * * @return true if necessary configurations are defined for sign KeyStore; false otherwise. */ private boolean isSignKeyStoreConfigured() { String keyStoreLocation = ServerConfiguration.getInstance() .getFirstProperty(SECURITY_SAML_SIGN_KEY_STORE_LOCATION); String keyStoreType = ServerConfiguration.getInstance().getFirstProperty(SECURITY_SAML_SIGN_KEY_STORE_TYPE); String keyStorePassword = ServerConfiguration.getInstance() .getFirstProperty(SECURITY_SAML_SIGN_KEY_STORE_PASSWORD); String keyAlias = ServerConfiguration.getInstance() .getFirstProperty(SECURITY_SAML_SIGN_KEY_STORE_KEY_ALIAS); String keyPassword = ServerConfiguration.getInstance() .getFirstProperty(SECURITY_SAML_SIGN_KEY_STORE_KEY_PASSWORD); return StringUtils.isNotBlank(keyStoreLocation) && StringUtils.isNotBlank(keyStoreType) && StringUtils.isNotBlank(keyStorePassword) && StringUtils.isNotBlank(keyAlias) && StringUtils.isNotBlank(keyPassword); } /** * The key is constructed form modulus and exponent. * * @param modulus * @param publicExponent * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ public X509CredentialImpl(BigInteger modulus, BigInteger publicExponent) throws NoSuchAlgorithmException, InvalidKeySpecException { RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); publicKey = keyFactory.generatePublic(spec); } public X509CredentialImpl(X509Certificate cert) { publicKey = cert.getPublicKey(); signingCert = cert; } /** * Retrieves the publicKey */ @Override public PublicKey getPublicKey() { return publicKey; } public X509Certificate getSigningCert() { return signingCert; } // ********** Not implemented ************************************************************** @Override public X509Certificate getEntityCertificate() { // TODO Auto-generated method stub return null; } @Override public Collection<X509CRL> getCRLs() { // TODO Auto-generated method stub return Collections.emptyList(); } @Override public Collection<X509Certificate> getEntityCertificateChain() { // TODO Auto-generated method stub return Collections.emptyList(); } @Override public CredentialContextSet getCredentalContextSet() { // TODO Auto-generated method stub return null; } @Override public Class<? extends Credential> getCredentialType() { return X509Credential.class; } @Override public String getEntityId() { // TODO Auto-generated method stub return null; } @Override public Collection<String> getKeyNames() { // TODO Auto-generated method stub return Collections.emptyList(); } @Override public PrivateKey getPrivateKey() { return privateKey; } @Override public SecretKey getSecretKey() { // TODO Auto-generated method stub return null; } @Override public UsageType getUsageType() { // TODO Auto-generated method stub return null; } }