/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.picketlink.identity.federation.core.sts; import java.io.File; import java.io.InputStream; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; import javax.xml.namespace.QName; import org.picketlink.identity.federation.PicketLinkLogger; import org.picketlink.identity.federation.PicketLinkLoggerFactory; import org.picketlink.identity.federation.core.ErrorCodes; import org.picketlink.identity.federation.core.config.STSType; import org.picketlink.identity.federation.core.exceptions.ConfigurationException; import org.picketlink.identity.federation.core.exceptions.ProcessingException; import org.picketlink.identity.federation.core.interfaces.ProtocolContext; import org.picketlink.identity.federation.core.interfaces.SecurityTokenProvider; import org.picketlink.identity.federation.core.parsers.sts.STSConfigParser; import org.picketlink.identity.federation.core.wstrust.PicketLinkSTSConfiguration; import org.picketlink.identity.federation.core.wstrust.STSConfiguration; /** * <p> * Generic STS Core. * </p> * <p> * This is a Singleton Class. * </p> * * @see {@code #instance()} * * @author Anil.Saldhana@redhat.com * @since Dec 27, 2010 */ public class PicketLinkCoreSTS { private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); public static final RuntimePermission rte = new RuntimePermission("org.picketlink.sts"); protected STSCoreConfig configuration; private static PicketLinkCoreSTS _instance = null; private static final String SEPARATOR = AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty("file.separator"); } }); private static final String STS_CONFIG_DIR = "picketlink-store" + SEPARATOR + "sts" + SEPARATOR; protected PicketLinkCoreSTS() { } public static PicketLinkCoreSTS instance() { if (_instance == null) _instance = new PicketLinkCoreSTS(); return _instance; } public void initialize(STSCoreConfig config) { if (this.configuration != null) { this.configuration.copy(config); } else this.configuration = config; } public void installDefaultConfiguration(String... configFileName) { String fileName = "core-sts.xml"; if (configFileName != null && configFileName.length > 0) fileName = configFileName[0]; if (configuration == null) { logger.trace("[InstallDefaultConfiguration] Configuration is null. Creating a new configuration"); configuration = new PicketLinkSTSConfiguration(); } try { logger.trace("[InstallDefaultConfiguration] Configuration file name=" + fileName); STSConfiguration config = getConfiguration(fileName); configuration.copy(config); } catch (ConfigurationException e) { throw new RuntimeException(e); } } /** * Issue a security token * * @param protocolContext * @throws ProcessingException * @throws {@link SecurityException} if the caller does not have a runtime permission for "org.picketlink.sts" */ public void issueToken(ProtocolContext protocolContext) throws ProcessingException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(rte); SecurityTokenProvider provider = getProvider(protocolContext); if (provider == null) throw logger.stsNoTokenProviderError(configuration.toString(), protocolContext.toString()); logger.debug("issueToken::provider=" + provider); provider.issueToken(protocolContext); } /** * <p> * Renews the security token contained in the specified request context. This method is used when a previously generated * token has expired, generating a new version of the same token with different expiration semantics. * </p> * * @param protocolContext the {@code ProtocolContext} that contains the token to be renewed. * @throws ProcessingException if an error occurs while renewing the security token. * @throws {@link SecurityException} if the caller does not have a runtime permission for "org.picketlink.sts" */ public void renewToken(ProtocolContext protocolContext) throws ProcessingException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(rte); SecurityTokenProvider provider = null; if (provider == null) provider = getProviderBasedOnQName(protocolContext); if (provider == null) throw logger.stsNoTokenProviderError(configuration.toString(), protocolContext.toString()); logger.debug("renewToken::provider=" + provider); provider.renewToken(protocolContext); } /** * <p> * Cancels the token contained in the specified request context. A security token is usually canceled when one wants to make * sure that the token will not be used anymore. A security token can't be renewed once it has been canceled. * </p> * * @param protocolContext the {@code ProtocolContext} that contains the token to be canceled. * @throws ProcessingException if an error occurs while canceling the security token. * @throws {@link SecurityException} if the caller does not have a runtime permission for "org.picketlink.sts" */ public void cancelToken(ProtocolContext protocolContext) throws ProcessingException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(rte); SecurityTokenProvider provider = null; if (provider == null) provider = getProviderBasedOnQName(protocolContext); if (provider == null) throw logger.stsNoTokenProviderError("", protocolContext.toString()); logger.debug("cancelToken::provider=" + provider); provider.cancelToken(protocolContext); } /** * <p> * Evaluates the validity of the token contained in the specified request context and sets the result in the context itself. * The result can be a status, a new token, or both. * </p> * * @param protocolContext the {@code ProtocolContext} that contains the token to be validated. * @throws ProcessingException if an error occurs while validating the security token. * @throws {@link SecurityException} if the caller does not have a runtime permission for "org.picketlink.sts" */ public void validateToken(ProtocolContext protocolContext) throws ProcessingException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(rte); SecurityTokenProvider provider = null; if (provider == null) provider = getProviderBasedOnQName(protocolContext); if (provider == null) throw logger.stsNoTokenProviderError(configuration.toString(), protocolContext.toString()); logger.debug("validateToken::provider=" + provider); provider.validateToken(protocolContext); } private SecurityTokenProvider getProvider(ProtocolContext protocolContext) { if (configuration == null) throw new RuntimeException(ErrorCodes.STS_CONFIGURATION_NOT_SET); SecurityTokenProvider provider = null; // Special Case: WST Applies To String serviceName = protocolContext.serviceName(); if (serviceName != null) { provider = this.configuration.getProviderForService(serviceName); } if (provider == null) { // lets get the provider based on token type String tokenType = protocolContext.tokenType(); if (tokenType != null) provider = this.configuration.getProviderForTokenType(protocolContext.tokenType()); } return provider; } private SecurityTokenProvider getProviderBasedOnQName(ProtocolContext protocolContext) throws ProcessingException { SecurityTokenProvider provider = null; QName qname = null; if (provider == null) { qname = protocolContext.getQName(); if (qname == null) throw new ProcessingException(ErrorCodes.NULL_VALUE + "QName of the token type"); provider = this.configuration.getProviderForTokenElementNS(protocolContext.family(), qname); } if (provider == null) throw new ProcessingException(ErrorCodes.STS_NO_TOKEN_PROVIDER + qname.getNamespaceURI() + ":" + qname.getLocalPart()); return provider; } /** * <p> * Obtains the STS configuration options. * </p> * * @return an instance of {@code STSConfiguration} containing the STS configuration properties. */ protected STSConfiguration getConfiguration(String fileName) throws ConfigurationException { URL configurationFileURL = null; try { // check the user home for a configuration file generated by the picketlink console. String configurationFilePath = System.getProperty("user.home") + SEPARATOR + STS_CONFIG_DIR + fileName; File configurationFile = new File(configurationFilePath); if (configurationFile.exists()) configurationFileURL = configurationFile.toURI().toURL(); else { // if not configuration file was found in the user home, check the context classloader. configurationFileURL = SecurityActions.loadResource(getClass(), fileName); } // if no configuration file was found, log a warn message and use default configuration values. if (configurationFileURL == null) { logger.stsConfigurationFileNotFoundTCL(fileName); ClassLoader clazzLoader = SecurityActions.getClassLoader(getClass()); configurationFileURL = clazzLoader.getResource(fileName); } // if no configuration file was found, log a warn message and use default configuration values. if (configurationFileURL == null) { logger.stsConfigurationFileNotFoundClassLoader(fileName); try { configurationFileURL = new URL(fileName); } catch (Exception e) { return new PicketLinkSTSConfiguration(); } finally { if (configurationFileURL == null) { logger.stsUsingDefaultConfiguration(fileName); return new PicketLinkSTSConfiguration(); } } } InputStream stream = configurationFileURL.openStream(); STSType stsConfig = (STSType) new STSConfigParser().parse(stream); STSConfiguration configuration = new PicketLinkSTSConfiguration(stsConfig); logger.stsConfigurationFileLoaded(fileName); return configuration; } catch (Exception e) { throw logger.stsConfigurationFileParsingError(e); } } public STSCoreConfig getConfiguration() { return this.configuration; } }