/* * 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.sts; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.impl.builder.StAXOMBuilder; import org.apache.axiom.om.util.UUIDGenerator; import org.apache.axis2.AxisFault; import org.apache.axis2.description.AxisBinding; import org.apache.axis2.description.AxisEndpoint; import org.apache.axis2.description.AxisModule; import org.apache.axis2.description.AxisService; import org.apache.axis2.description.AxisServiceGroup; import org.apache.axis2.description.Parameter; import org.apache.axis2.engine.AxisConfiguration; import org.apache.axis2.engine.AxisEvent; import org.apache.axis2.engine.AxisObserver; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.neethi.Policy; import org.apache.neethi.PolicyEngine; import org.apache.rahas.impl.AbstractIssuerConfig; import org.apache.rahas.impl.SAMLTokenIssuerConfig; import org.apache.rahas.impl.TokenIssuerUtil; import org.apache.ws.security.handler.WSHandlerConstants; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.base.ServerConfiguration; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.RegistryType; import org.wso2.carbon.core.RegistryResources; import org.wso2.carbon.core.deployment.DeploymentInterceptor; import org.wso2.carbon.core.persistence.PersistenceUtils; import org.wso2.carbon.core.util.KeyStoreManager; import org.wso2.carbon.core.util.KeyStoreUtil; import org.wso2.carbon.registry.api.RegistryException; import org.wso2.carbon.registry.core.Collection; import org.wso2.carbon.registry.core.Registry; import org.wso2.carbon.registry.core.Resource; import org.wso2.carbon.registry.core.session.UserRegistry; import org.wso2.carbon.registry.core.utils.RegistryUtils; import org.wso2.carbon.security.SecurityConfigException; import org.wso2.carbon.security.SecurityConstants; import org.wso2.carbon.security.SecurityScenario; import org.wso2.carbon.security.SecurityScenarioDatabase; import org.wso2.carbon.security.config.SecurityServiceAdmin; import org.wso2.carbon.security.keystore.KeyStoreAdmin; import org.wso2.carbon.security.keystore.service.KeyStoreData; import org.wso2.carbon.security.pox.POXSecurityHandler; import org.wso2.carbon.security.util.RampartConfigUtil; import org.wso2.carbon.security.util.ServerCrypto; import org.wso2.carbon.security.util.ServicePasswordCallbackHandler; import org.wso2.carbon.sts.internal.STSServiceDataHolder; import org.wso2.carbon.user.core.UserRealm; import org.wso2.carbon.utils.ServerConstants; import org.wso2.carbon.utils.ServerException; import org.wso2.carbon.utils.deployment.GhostDeployerUtils; import javax.cache.Cache; import javax.cache.CacheManager; import javax.cache.Caching; import javax.security.auth.callback.CallbackHandler; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import java.io.InputStream; import java.security.KeyStore; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; /** * This deployment interceptor will be called whenever STS service being deployed. * * @see AxisObserver */ public class STSDeploymentInterceptor implements AxisObserver { private static final Log log = LogFactory.getLog(DeploymentInterceptor.class); public static final String HOST_NAME = "HostName"; public static final String STS_TIME_TO_LIVE = "STSTimeToLive"; public static final String SECURITY_DISABLE_TOKEN_STORE = "Security.DisableTokenStore"; public static final String SECURITY_KEY_STORE_KEY_PASSWORD = "Security.KeyStore.KeyPassword"; public static final String SECURITY_TOKEN_PERSISTER_CLASS = "Security.TokenPersister.Class"; public static final String SECURITY_TOKEN_PERSISTER_STORAGE_PATH = "Security.TokenPersister.StoragePath"; public static final String SECURITY_TOKEN_PERSISTER_IN_MEMORY_THRESHOLD = "Security.TokenPersister.InMemoryThreshold"; public static final String SECURITY_TOKEN_PERSISTER_PROPERTIES_PROPERTY_NAME = "Security.TokenPersister.Properties.Property.Name"; public static final String SECURITY_TOKEN_PERSISTER_PROPERTIES_PROPERTY_VALUE = "Security.TokenPersister.Properties.Property.Value"; /** * Updates STS service during deployment * * @param config AxisConfiguration * @throws Exception */ public static void updateSTSService(AxisConfiguration config) throws Exception { AxisService service = null; Registry configRegistry = null; Registry governRegistry = null; String keyPassword = null; KeyStoreAdmin admin = null; KeyStoreData[] keystores = null; String privateKeyAlias = null; String keyStoreName = null; String issuerName = null; ServerConfiguration serverConfig = null; int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); configRegistry = STSServiceDataHolder.getInstance().getRegistryService().getConfigSystemRegistry(tenantId); governRegistry = STSServiceDataHolder.getInstance().getRegistryService().getGovernanceSystemRegistry(tenantId); if (configRegistry == null || config.getService(ServerConstants.STS_NAME) == null) { if (log.isDebugEnabled()) { log.debug("configRegistry not set or STS service is unavailable"); } return; } serverConfig = ServerConfiguration.getInstance(); admin = new KeyStoreAdmin(tenantId, governRegistry); if (MultitenantConstants.SUPER_TENANT_ID == tenantId) { keyPassword = serverConfig.getFirstProperty(SECURITY_KEY_STORE_KEY_PASSWORD); keystores = admin.getKeyStores(true); for (int i = 0; i < keystores.length; i++) { if (KeyStoreUtil.isPrimaryStore(keystores[i].getKeyStoreName())) { keyStoreName = keystores[i].getKeyStoreName(); privateKeyAlias = KeyStoreUtil.getPrivateKeyAlias(KeyStoreManager.getInstance( MultitenantConstants.SUPER_TENANT_ID) .getKeyStore(keyStoreName)); break; } } } else { // this is not the proper way to find out the primary key store of the tenant. We need // check a better way TODO String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); if (tenantDomain == null) { tenantDomain = STSServiceDataHolder.getInstance().getRealmService(). getTenantManager().getDomain(tenantId); } if (tenantDomain != null) { // assuming domain always in this format -> example.com keyStoreName = tenantDomain.replace(".", "-") + ".jks"; KeyStore keyStore = KeyStoreManager.getInstance(tenantId).getKeyStore(keyStoreName); if (keyStore != null) { privateKeyAlias = KeyStoreUtil.getPrivateKeyAlias(keyStore); keyPassword = KeyStoreManager.getInstance(tenantId).getKeyStorePassword(keyStoreName); } else { log.warn("No key store is exist as " + keyStoreName + ". STS would be fail"); } } else { throw new Exception("Tenant Domain can not be null"); } } issuerName = serverConfig.getFirstProperty(HOST_NAME); if (issuerName == null) { // HostName not set :-( use wso2wsas-sts issuerName = ServerConstants.STS_NAME; } if (privateKeyAlias != null) { service = config.getService(ServerConstants.STS_NAME); String cryptoProvider = ServerCrypto.class.getName(); Properties props = RampartConfigUtil.getServerCryptoProperties( new String[] { keyStoreName }, keyStoreName, privateKeyAlias); SAMLTokenIssuerConfig stsSamlConfig = new SAMLTokenIssuerConfig(issuerName, cryptoProvider, props); stsSamlConfig.setIssuerKeyAlias(privateKeyAlias); stsSamlConfig.setIssuerKeyPassword(keyPassword); stsSamlConfig.setAddRequestedAttachedRef(true); stsSamlConfig.setAddRequestedUnattachedRef(true); stsSamlConfig.setKeyComputation(2); stsSamlConfig.setProofKeyType(TokenIssuerUtil.BINARY_SECRET); String resourcePath = null; resourcePath = RegistryResources.SERVICE_GROUPS + ServerConstants.STS_NAME + RegistryResources.SERVICES + ServerConstants.STS_NAME + "/trustedServices"; if (configRegistry.resourceExists(resourcePath)) { Resource trustedService = null; Properties properties = null; Iterator iterator = null; trustedService = configRegistry.get(resourcePath); properties = trustedService.getProperties(); if (properties != null && !properties.isEmpty()) { iterator = properties.entrySet().iterator(); while (iterator.hasNext()) { Entry entry = (Entry) iterator.next(); if (RegistryUtils.isHiddenProperty(entry.getKey().toString())) { continue; } stsSamlConfig.addTrustedServiceEndpointAddress((String) entry.getKey(), (String) ((List) entry.getValue()).get(0)); } } } //Set the TTL value read from the carbon.xml String ttl = serverConfig.getFirstProperty(STS_TIME_TO_LIVE); if (StringUtils.isNotBlank(ttl)) { try { stsSamlConfig.setTtl(Long.parseLong(ttl)); if (log.isDebugEnabled()) { log.debug("STSTimeToLive read from carbon.xml " + ttl); } } catch (NumberFormatException e) { log.error("Error while reading STSTimeToLive from carbon.xml", e); } } //set if token store is disabled String tokenStoreDisabled = serverConfig.getFirstProperty(SECURITY_DISABLE_TOKEN_STORE); if (tokenStoreDisabled != null) { stsSamlConfig.setTokenStoreDisabled(Boolean.parseBoolean(tokenStoreDisabled)); } //Set persister configuration reading from carbon.xml String persisterClassName = serverConfig.getFirstProperty(SECURITY_TOKEN_PERSISTER_CLASS); String persistingFilePath = serverConfig.getFirstProperty(SECURITY_TOKEN_PERSISTER_STORAGE_PATH); String inMemoryThreshold = serverConfig.getFirstProperty(SECURITY_TOKEN_PERSISTER_IN_MEMORY_THRESHOLD); if (persisterClassName != null) { stsSamlConfig.setPersisterClassName(persisterClassName); } Map<String, String> propertyMap = new HashMap<>(); if (persistingFilePath != null) { propertyMap.put(AbstractIssuerConfig.LOCAL_PROPERTY_STORAGE_PATH, persistingFilePath); } if (inMemoryThreshold != null) { propertyMap.put(AbstractIssuerConfig.LOCAL_PROPERTY_THRESHOLD, inMemoryThreshold); } if (log.isDebugEnabled()) { if (persisterClassName != null && inMemoryThreshold == null) { log.debug("Although persister is defined, threshold not defined."); } } //allow defining any additional properties related to token persister. String[] persisterPropertyNames = serverConfig.getProperties( SECURITY_TOKEN_PERSISTER_PROPERTIES_PROPERTY_NAME); String[] persisterPropertyValues = serverConfig.getProperties( SECURITY_TOKEN_PERSISTER_PROPERTIES_PROPERTY_VALUE); if (!ArrayUtils.isEmpty(persisterPropertyNames) && !ArrayUtils.isEmpty(persisterPropertyValues) && persisterPropertyNames.length == persisterPropertyValues.length) { for (int i = 0; i < persisterPropertyNames.length; i++) { propertyMap.put(persisterPropertyNames[i], persisterPropertyValues[i]); } } if (!propertyMap.isEmpty()) { stsSamlConfig.setPersisterPropertyMap(propertyMap); } try { // remove param is exists Parameter param = service.getParameter(SAMLTokenIssuerConfig.SAML_ISSUER_CONFIG.getLocalPart()); if (param == null) { // Add new parameter service.addParameter(stsSamlConfig.getParameter()); } } catch (AxisFault e) { log.error("Error while updating " + ServerConstants.STS_NAME + " in STSDeploymentInterceptor", e); } } } /** * {@inheritDoc} */ @Override public void serviceUpdate(AxisEvent event, AxisService service) { if (event.getEventType() == AxisEvent.SERVICE_DEPLOY && ServerConstants.STS_NAME.equals(service.getName())) { try { updateSTSService(service.getAxisConfiguration()); } catch (Exception e) { log.error("Error while updating " + ServerConstants.STS_NAME + " in STSDeploymentInterceptor", e); } } } /** * {@inheritDoc} */ @Override public void init(AxisConfiguration arg0) { // Nothing to implement } /** * {@inheritDoc} */ @Override public void moduleUpdate(AxisEvent arg0, AxisModule arg1) { // Nothing to implement } /** * {@inheritDoc} */ @Override public void serviceGroupUpdate(AxisEvent event, AxisServiceGroup group) { // Nothing to implement } /** * {@inheritDoc} */ @Override public void addParameter(Parameter arg0) throws AxisFault { // Nothing to implement } /** * {@inheritDoc} */ @Override public void deserializeParameters(OMElement arg0) throws AxisFault { // Nothing to implement } /** * {@inheritDoc} */ @Override public Parameter getParameter(String arg0) { // Nothing to return return null; } /** * {@inheritDoc} */ @Override public ArrayList getParameters() { // Nothing to return return null; } /** * {@inheritDoc} */ @Override public boolean isParameterLocked(String arg0) { return false; } /** * {@inheritDoc} */ @Override public void removeParameter(Parameter arg0) throws AxisFault { // Nothing to implement } }