/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyrighted [year] [name of copyright owner]".
*
* Copyright 2014-2015 ForgeRock AS.
*/
package org.forgerock.openam.sts.soap.config;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import org.forgerock.openam.audit.AuditEventPublisher;
import org.forgerock.openam.audit.servlet.Auditor;
import org.forgerock.openam.audit.servlet.AuditorFactory;
import org.forgerock.openam.shared.sts.SharedSTSConstants;
import org.forgerock.openam.sts.AMSTSConstants;
import org.forgerock.openam.sts.DefaultHttpURLConnectionFactory;
import org.forgerock.openam.sts.HttpURLConnectionFactory;
import org.forgerock.openam.sts.HttpURLConnectionWrapperFactory;
import org.forgerock.openam.sts.soap.audit.SoapSTSAuditEventPublisher;
import org.forgerock.openam.sts.soap.bootstrap.SoapSTSAccessTokenProvider;
import org.forgerock.openam.sts.soap.bootstrap.SoapSTSAccessTokenProviderImpl;
import org.forgerock.openam.sts.soap.bootstrap.SoapSTSAgentConfigAccess;
import org.forgerock.openam.sts.soap.bootstrap.SoapSTSAgentConfigAccessImpl;
import org.forgerock.openam.sts.soap.bootstrap.SoapSTSAgentCredentialsAccess;
import org.forgerock.openam.sts.soap.bootstrap.SoapSTSAgentCredentialsAccessImpl;
import org.forgerock.openam.sts.soap.bootstrap.SoapSTSLifecycle;
import org.forgerock.openam.sts.soap.bootstrap.SoapSTSLifecycleImpl;
import org.forgerock.openam.sts.soap.policy.am.OpenAMSessionTokenServerInterceptorProvider;
import org.forgerock.openam.sts.soap.publish.PublishServiceConsumer;
import org.forgerock.openam.sts.soap.publish.PublishServiceConsumerImpl;
import org.forgerock.openam.sts.soap.publish.SoapSTSInstanceLifecycleManager;
import org.forgerock.openam.sts.soap.publish.SoapSTSInstanceLifecycleManagerImpl;
import org.forgerock.openam.sts.soap.publish.SoapSTSInstancePublisher;
import org.forgerock.openam.sts.soap.publish.SoapSTSInstancePublisherImpl;
import org.forgerock.openam.sts.token.AMTokenParser;
import org.forgerock.openam.sts.token.AMTokenParserImpl;
import org.forgerock.openam.sts.token.ThreadLocalAMTokenCache;
import org.forgerock.openam.sts.token.ThreadLocalAMTokenCacheImpl;
import org.forgerock.openam.sts.token.UrlConstituentCatenator;
import org.forgerock.openam.sts.token.UrlConstituentCatenatorImpl;
import org.forgerock.openam.sts.token.validator.PrincipalFromSession;
import org.forgerock.openam.sts.token.validator.PrincipalFromSessionImpl;
import org.forgerock.util.time.TimeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Exposed;
import com.google.inject.Key;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.name.Names;
/**
* Defines the guice bindings needed by the soap-sts 'framework' - i.e. the elements need to exposed published soap-sts
* instances as web-services. Also defines bindings common to all soap-sts instances - i.e. version strings, and rest target
* endpoints. It is a PrivateModule as the Guice Injector created for each soap-sts instance will be a child of the Injector
* created by this module, and only some of the global bindings should be exposed to the child Injector.
*/
public class SoapSTSModule extends PrivateModule {
/*
Note that the correspondence between these values and the properties defined in config.properties must be maintained,
as the Names.bindProperties(binder(), properties) call will automatically bind the property values in the properties
file with @Named annotations corresponding to the keys - and the values defined below are used in the @Named annotations
governing these bindings.
*/
//Note that the PrincipalFromSessionImpl expects the OpenAM Server url to be bound under the AMSTSConstants.AM_DEPLOYMENT_URL.
//If the key in the config store changes, then this mismatch must be managed manually.
public static final String OPENAM_HOME_SERVER_PROPERTY_KEY = AMSTSConstants.AM_DEPLOYMENT_URL;
public static final String AM_SESSION_COOKIE_NAME_PROPERTY_KEY = AMSTSConstants.AM_SESSION_COOKIE_NAME;
public static final String SOAP_STS_AGENT_USERNAME_PROPERTY_KEY = "soap_sts_agent_username";
public static final String SOAP_STS_AGENT_PASSWORD_PROPERTY_KEY = "soap_sts_agent_password";
public static final String AGENT_REALM = AMSTSConstants.REALM;
@Override
protected void configure() {
bind(SoapSTSInstanceLifecycleManager.class).to(SoapSTSInstanceLifecycleManagerImpl.class).in(Scopes.SINGLETON);
bind(SoapSTSInstancePublisher.class).to(SoapSTSInstancePublisherImpl.class).in(Scopes.SINGLETON);
bind(HttpURLConnectionFactory.class).to(DefaultHttpURLConnectionFactory.class);
bind(HttpURLConnectionWrapperFactory.class);
expose(HttpURLConnectionFactory.class);
expose(HttpURLConnectionWrapperFactory.class);
bind(PublishServiceConsumer.class).to(PublishServiceConsumerImpl.class).in(Scopes.SINGLETON);
bind(AMTokenParser.class).to(AMTokenParserImpl.class).in(Scopes.SINGLETON);
bind(SoapSTSAccessTokenProvider.class).to(SoapSTSAccessTokenProviderImpl.class);
// Expose to injectors creating soap-sts instances, as each require access tokens to consume the TGS.
expose(SoapSTSAccessTokenProvider.class);
bind(UrlConstituentCatenator.class).to(UrlConstituentCatenatorImpl.class);
expose(UrlConstituentCatenator.class);
bind(SoapSTSAgentConfigAccess.class).to(SoapSTSAgentConfigAccessImpl.class).in(Scopes.SINGLETON);
bind(SoapSTSLifecycle.class).to(SoapSTSLifecycleImpl.class).in(Scopes.SINGLETON);
// Expose as the STSBroker needs to reference this class to kick off the soap-sts bootstrap process.
expose(SoapSTSLifecycle.class);
bind(SoapSTSAgentCredentialsAccess.class).to(SoapSTSAgentCredentialsAccessImpl.class).in(Scopes.SINGLETON);
Properties properties = new Properties();
try {
properties.load(new InputStreamReader(getClass().getResourceAsStream("/config.properties")));
} catch (Exception e) {
throw new IllegalStateException("Could not load the /config.properties for the soap-sts: " + e, e);
}
Names.bindProperties(binder(), properties);
/*
Expose the session cookie name, as this will be required by the instance module for the various rest authN
and TGS consumers. Note that these consumers have a dependency on a string @Named AMSTSConstants.AM_SESSION_COOKIE_NAME.
If the name in the soap sts property file changes - i.e. if the SoapSTSModule.AM_SESSION_COOKIE_PROPERTY_NAME_KEY changes
from the current value of AMSTSConstants.AM_SESSION_COOKIE_NAME, then the SoapSTSInstanceModule will need a
@Provides method which will reference SoapSTSModule.AM_SESSION_COOKIE_NAME_PROPERTY via the SoapSTSInjectorHolder
to provide the dependency on a string @Named AMSTSConstants.AM_SESSION_COOKIE_NAME via the
SoapSTSModule.AM_SESSION_COOKIE_NAME_PROPERTY_KEY value.
*/
expose(Key.get(String.class, Names.named(SoapSTSModule.AM_SESSION_COOKIE_NAME_PROPERTY_KEY)));
/*
Bind the InterceptorProvider which will provide the Interceptor instances to handle any soap-sts invocations
protected by the OpenAMSessionToken binding. Needed by the SoapSTSLifecycleImpl, to register the custom
OpenAMServerToken Interceptors with cxf.
*/
bind(OpenAMSessionTokenServerInterceptorProvider.class);
/*
Bind the dependencies of the OpenAMSessionTokenServerInterceptorProvider - PrincipalFromSession and the
ThreadLocalTokenCache. Expose the ThreadLocalAMTokenCache, and PrincipalFromSession, as these classes will be
needed by the injectors corresponding to soap-sts instances.
*/
bind(ThreadLocalAMTokenCache.class).to(ThreadLocalAMTokenCacheImpl.class).in(Scopes.SINGLETON);
expose(ThreadLocalAMTokenCache.class);
bind(PrincipalFromSession.class).to(PrincipalFromSessionImpl.class).in(Scopes.SINGLETON);
expose(PrincipalFromSession.class);
bind(AuditEventPublisher.class).to(SoapSTSAuditEventPublisher.class);
expose(AuditEventPublisher.class);
install(new FactoryModuleBuilder().implement(Auditor.class, Auditor.class).build(AuditorFactory.class));
expose(AuditorFactory.class);
bind(TimeService.class).toInstance(TimeService.SYSTEM);
expose(TimeService.class);
}
@Provides
@Singleton
ScheduledExecutorService getScheduledExecutorService() {
return Executors.newSingleThreadScheduledExecutor();
}
@Provides
@Singleton
KeyStore getAMInternalKeyStore() {
try {
final KeyStore soapSTSKeystore = KeyStore.getInstance(SharedSTSConstants.AM_INTERNAL_SOAP_STS_KEYSTORE_TYPE);
soapSTSKeystore.load(getClass().getResourceAsStream("/" + SharedSTSConstants.AM_INTERNAL_SOAP_STS_KEYSTORE),
SharedSTSConstants.AM_INTERNAL_SOAP_STS_KEYSTORE_PW.toCharArray());
return soapSTSKeystore;
} catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) {
throw new IllegalStateException("Could not initialize soap-sts internal keystore. A JCEKS keystore with name "
+ SharedSTSConstants.AM_INTERNAL_SOAP_STS_KEYSTORE + " must be in the WEB-INF/classes directory of " +
"the soap-sts .war. Exception: " + e);
}
}
/*
The following 6 methods provide the String constants corresponding to relatively static values relating to
consumption of the OpenAM rest context. This information is necessary for the STS instances to consume this
context, and is the single point where these values need to be changed.
*/
@Provides
@Singleton
@Named(AMSTSConstants.REST_AUTHN_URI_ELEMENT)
@Exposed
String restAuthnUriElement() {
return "/authenticate";
}
@Provides
@Singleton
@Named (AMSTSConstants.REST_LOGOUT_URI_ELEMENT)
@Exposed
String restLogoutUriElement() {
return "/sessions/?_action=logout";
}
@Provides
@Singleton
@Named (AMSTSConstants.REST_ID_FROM_SESSION_URI_ELEMENT)
@Exposed
String restAMTokenValidationUriElement() {
return "/users/?_action=idFromSession";
}
@Provides
@Singleton
@Named(AMSTSConstants.REST_TOKEN_GENERATION_SERVICE_URI_ELEMENT)
@Exposed
String tokenGenerationServiceUriElement() {
return "/sts-tokengen";
}
@Provides
@Singleton
@Named(AMSTSConstants.SOAP_STS_PUBLISH_SERVICE_URI_ELEMENT)
@Exposed
String soapSTSPublishUriElement() {
return "sts-publish/soap";
}
@Provides
@Singleton
@Named(AMSTSConstants.AM_REST_AUTHN_JSON_ROOT)
@Exposed
String getJsonRoot() {
return "/json";
}
@Provides
@Singleton
@Named(AMSTSConstants.AGENTS_PROFILE_SERVICE_URI_ELEMENT)
@Exposed
String getAgentsProfileServiceUriElement() {
return "/agents";
}
@Provides
@Singleton
@Named (AMSTSConstants.REST_CREATE_ACCESS_AUDIT_EVENT_URI_ELEMENT)
@Exposed
String restAMAuditUriElement() {
return "/global-audit/access/?_action=create";
}
@Inject
@Provides
@Singleton
@Named (AMSTSConstants.REST_CREATE_ACCESS_AUDIT_EVENT_URL)
@Exposed
String restAMAuditUriElement(UrlConstituentCatenator urlConstituentCatenator,
@Named(SoapSTSModule.OPENAM_HOME_SERVER_PROPERTY_KEY) String openamUrl,
@Named(AMSTSConstants.AM_REST_AUTHN_JSON_ROOT) String jsonRoot,
@Named(AMSTSConstants.REST_CREATE_ACCESS_AUDIT_EVENT_URI_ELEMENT) String auditServiceUriElement) {
return urlConstituentCatenator.catenateUrlConstituents(openamUrl, jsonRoot, auditServiceUriElement);
}
@Provides
@Singleton
@Named(AMSTSConstants.CREST_VERSION_SESSION_SERVICE)
@Exposed
String getSessionServiceVersion() {
return "protocol=1.0, resource=1.1";
}
@Provides
@Singleton
@Named(AMSTSConstants.CREST_VERSION_AUTHN_SERVICE)
@Exposed
String getAuthNServiceVersion() {
return "protocol=1.0, resource=2.0";
}
@Provides
@Singleton
@Named(AMSTSConstants.CREST_VERSION_TOKEN_GEN_SERVICE)
@Exposed
String getTokenGenServiceVersion() {
return "protocol=1.0, resource=1.0";
}
@Provides
@Singleton
@Named(AMSTSConstants.CREST_VERSION_USERS_SERVICE)
@Exposed
String getUsersServiceVersion() {
return "protocol=1.0, resource=2.0";
}
@Provides
@Singleton
@Named(AMSTSConstants.CREST_VERSION_SOAP_STS_PUBLISH_SERVICE)
@Exposed
String getSoapPublishServiceVersion() {
return "protocol=1.0, resource=1.0";
}
@Provides
@Singleton
@Named(AMSTSConstants.CREST_VERSION_AGENTS_PROFILE_SERVICE)
@Exposed
String getAgentsProfileServiceVersion() {
return "protocol=1.0, resource=2.0";
}
@Provides
@Singleton
@Named(AMSTSConstants.CREST_VERSION_AUDIT_SERVICE)
@Exposed
String getAuditServiceVersion() {
return "protocol=1.0, resource=1.0";
}
@Provides
@Singleton
@Exposed
Logger getSlf4jLogger() {
return LoggerFactory.getLogger(AMSTSConstants.SOAP_STS_DEBUG_ID);
}
}