Reputation: 21
I want to authenticate a user using openAm and share the session to communicate to other microservices without authenticating the user again. Session details are stored in an external database. I am using spring security saml sample application with all the java configuration to achieve this. There are two sessions being generated . One before logging to the IDP and one after entering the credentials. If I check at openAm, user is logged in but in the application, i am getting SAMLException specifying InResponseToField of the Response doesnt correspond to sent message 12345(random id). How to integrate spring session with saml?
Security config file of my sample application
package com.vdenotaris.spring.boot.security.saml.web.config;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SAMLUserDetailsServiceImpl samlUserDetailsServiceImpl;
@Bean
public VelocityEngine velocityEngine() {
return VelocityFactory.getEngine();
}
@Bean(initMethod = "initialize")
public StaticBasicParserPool parserPool() {
return new StaticBasicParserPool();
}
@Bean(name = "parserPoolHolder")
public ParserPoolHolder parserPoolHolder() {
return new ParserPoolHolder();
}
@Bean
public MultiThreadedHttpConnectionManager multiThreadedHttpConnectionManager() {
return new MultiThreadedHttpConnectionManager();
}
@Bean
public HttpClient httpClient() {
return new HttpClient(multiThreadedHttpConnectionManager());
}
@Bean
public SAMLAuthenticationProvider samlAuthenticationProvider() {
SAMLAuthenticationProvider samlAuthenticationProvider = new SAMLAuthenticationProvider();
samlAuthenticationProvider.setUserDetails(samlUserDetailsServiceImpl);
samlAuthenticationProvider.setForcePrincipalAsString(false);
return samlAuthenticationProvider;
}
@Bean
public SAMLContextProviderImpl contextProvider() {
return new SAMLContextProviderImpl();
}
@Bean
public static SAMLBootstrap sAMLBootstrap() {
return new SAMLBootstrap();
}
@Bean
public SAMLDefaultLogger samlLogger() {
return new SAMLDefaultLogger();
}
@Bean
public WebSSOProfileConsumer webSSOprofileConsumer() {
return new WebSSOProfileConsumerImpl();
}
@Bean
public WebSSOProfileConsumerHoKImpl hokWebSSOprofileConsumer() {
return new WebSSOProfileConsumerHoKImpl();
}
@Bean
public WebSSOProfile webSSOprofile() {
return new WebSSOProfileImpl();
}
@Bean
public WebSSOProfileConsumerHoKImpl hokWebSSOProfile() {
return new WebSSOProfileConsumerHoKImpl();
}
@Bean
public WebSSOProfileECPImpl ecpprofile() {
return new WebSSOProfileECPImpl();
}
@Bean
public SingleLogoutProfile logoutprofile() {
return new SingleLogoutProfileImpl();
}
@Bean
public KeyManager keyManager() {
DefaultResourceLoader loader = new DefaultResourceLoader();
Resource storeFile = loader
.getResource("classpath:/saml/keystore.jks");
String storePass = "password";
Map<String, String> passwords = new HashMap<String, String>();
passwords.put("mydomain", "password");
String defaultKey = "mydomain";
return new JKSKeyManager(storeFile, storePass, passwords, defaultKey);
}
@Bean
public TLSProtocolConfigurer tlsProtocolConfigurer() {
return new TLSProtocolConfigurer();
}
@Bean
public ProtocolSocketFactory socketFactory() {
return new TLSProtocolSocketFactory(keyManager(), null, "default");
}
@Bean
public Protocol socketFactoryProtocol() {
return new Protocol("https", socketFactory(), 443);
}
@Bean
public MethodInvokingFactoryBean socketFactoryInitialization() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setTargetClass(Protocol.class);
methodInvokingFactoryBean.setTargetMethod("registerProtocol");
Object[] args = {"https", socketFactoryProtocol()};
methodInvokingFactoryBean.setArguments(args);
return methodInvokingFactoryBean;
}
@Bean
public WebSSOProfileOptions defaultWebSSOProfileOptions() {
WebSSOProfileOptions webSSOProfileOptions = new WebSSOProfileOptions();
webSSOProfileOptions.setIncludeScoping(false);
return webSSOProfileOptions;
}
// Entry point to initialize authentication, default values taken from
// properties file
@Bean
public SAMLEntryPoint samlEntryPoint() {
SAMLEntryPoint samlEntryPoint = new SAMLEntryPoint();
samlEntryPoint.setDefaultProfileOptions(defaultWebSSOProfileOptions());
return samlEntryPoint;
}
@Bean
public ExtendedMetadata extendedMetadata() {
ExtendedMetadata extendedMetadata = new ExtendedMetadata();
extendedMetadata.setIdpDiscoveryEnabled(true);
extendedMetadata.setSignMetadata(false);
return extendedMetadata;
}
@Bean
public SAMLDiscovery samlIDPDiscovery() {
SAMLDiscovery idpDiscovery = new SAMLDiscovery();
idpDiscovery.setIdpSelectionPath("/saml/idpSelection");
return idpDiscovery;
}
@Bean
@Qualifier("idp-ssocircle")
public ExtendedMetadataDelegate ssoCircleExtendedMetadataProvider()
throws MetadataProviderException {
String idpSSOCircleMetadataURL = "http://openam.com:8080/OpenAM/saml2/jsp/exportmetadata.jsp";
Timer backgroundTaskTimer = new Timer(true);
HTTPMetadataProvider httpMetadataProvider = new HTTPMetadataProvider(
backgroundTaskTimer, httpClient(), idpSSOCircleMetadataURL);
httpMetadataProvider.setParserPool(parserPool());
ExtendedMetadataDelegate extendedMetadataDelegate =
new ExtendedMetadataDelegate(httpMetadataProvider, extendedMetadata());
extendedMetadataDelegate.setMetadataTrustCheck(true);
extendedMetadataDelegate.setMetadataRequireSignature(false);
return extendedMetadataDelegate;
}
@Bean
@Qualifier("metadata")
public CachingMetadataManager metadata() throws MetadataProviderException {
List<MetadataProvider> providers = new ArrayList<MetadataProvider>();
providers.add(ssoCircleExtendedMetadataProvider());
return new CachingMetadataManager(providers);
}
// Filter automatically generates default SP metadata
@Bean
public MetadataGenerator metadataGenerator() {
MetadataGenerator metadataGenerator = new MetadataGenerator();
metadataGenerator.setEntityId("http://localhost:8080/spring-boot-security-saml2-sample/saml/web/metadata");
metadataGenerator.setExtendedMetadata(extendedMetadata());
metadataGenerator.setIncludeDiscoveryExtension(false);
metadataGenerator.setKeyManager(keyManager());
return metadataGenerator;
}
// The filter is waiting for connections on URL suffixed with filterSuffix
// and presents SP metadata there
@Bean
public MetadataDisplayFilter metadataDisplayFilter() {
return new MetadataDisplayFilter();
}
// Handler deciding where to redirect user after successful login
@Bean
public SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler() {
SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler =
new SavedRequestAwareAuthenticationSuccessHandler();
successRedirectHandler.setDefaultTargetUrl("/");
return successRedirectHandler;
}
// Handler deciding where to redirect user after failed login
@Bean
public SimpleUrlAuthenticationFailureHandler authenticationFailureHandler() {
SimpleUrlAuthenticationFailureHandler failureHandler =
new SimpleUrlAuthenticationFailureHandler();
failureHandler.setUseForward(true);
failureHandler.setDefaultFailureUrl("/error");
return failureHandler;
}
@Bean
public SAMLWebSSOHoKProcessingFilter samlWebSSOHoKProcessingFilter() throws Exception {
SAMLWebSSOHoKProcessingFilter samlWebSSOHoKProcessingFilter = new SAMLWebSSOHoKProcessingFilter();
samlWebSSOHoKProcessingFilter.setAuthenticationSuccessHandler(successRedirectHandler());
samlWebSSOHoKProcessingFilter.setAuthenticationManager(authenticationManager());
samlWebSSOHoKProcessingFilter.setAuthenticationFailureHandler(authenticationFailureHandler());
return samlWebSSOHoKProcessingFilter;
}
@Bean
public SAMLProcessingFilter samlWebSSOProcessingFilter() throws Exception {
SAMLProcessingFilter samlWebSSOProcessingFilter = new SAMLProcessingFilter();
samlWebSSOProcessingFilter.setAuthenticationManager(authenticationManager());
samlWebSSOProcessingFilter.setAuthenticationSuccessHandler(successRedirectHandler());
samlWebSSOProcessingFilter.setAuthenticationFailureHandler(authenticationFailureHandler());
return samlWebSSOProcessingFilter;
}
@Bean
public MetadataGeneratorFilter metadataGeneratorFilter() {
return new MetadataGeneratorFilter(metadataGenerator());
}
@Bean
public SimpleUrlLogoutSuccessHandler successLogoutHandler() {
SimpleUrlLogoutSuccessHandler successLogoutHandler = new SimpleUrlLogoutSuccessHandler();
successLogoutHandler.setDefaultTargetUrl("/");
return successLogoutHandler;
}
@Bean
public SecurityContextLogoutHandler logoutHandler() {
SecurityContextLogoutHandler logoutHandler =
new SecurityContextLogoutHandler();
logoutHandler.setInvalidateHttpSession(true);
logoutHandler.setClearAuthentication(true);
return logoutHandler;
}
@Bean
public SAMLLogoutProcessingFilter samlLogoutProcessingFilter() {
return new SAMLLogoutProcessingFilter(successLogoutHandler(),
logoutHandler());
}
@Bean
public SAMLLogoutFilter samlLogoutFilter() {
return new SAMLLogoutFilter(successLogoutHandler(),
new LogoutHandler[] { logoutHandler() },
new LogoutHandler[] { logoutHandler() });
}
private ArtifactResolutionProfile artifactResolutionProfile() {
final ArtifactResolutionProfileImpl artifactResolutionProfile =
new ArtifactResolutionProfileImpl(httpClient());
artifactResolutionProfile.setProcessor(new SAMLProcessorImpl(soapBinding()));
return artifactResolutionProfile;
}
@Bean
public HTTPArtifactBinding artifactBinding(ParserPool parserPool, VelocityEngine velocityEngine) {
return new HTTPArtifactBinding(parserPool, velocityEngine, artifactResolutionProfile());
}
@Bean
public HTTPSOAP11Binding soapBinding() {
return new HTTPSOAP11Binding(parserPool());
}
@Bean
public HTTPPostBinding httpPostBinding() {
return new HTTPPostBinding(parserPool(), velocityEngine());
}
@Bean
public HTTPRedirectDeflateBinding httpRedirectDeflateBinding() {
return new HTTPRedirectDeflateBinding(parserPool());
}
@Bean
public HTTPSOAP11Binding httpSOAP11Binding() {
return new HTTPSOAP11Binding(parserPool());
}
@Bean
public HTTPPAOS11Binding httpPAOS11Binding() {
return new HTTPPAOS11Binding(parserPool());
}
// Processor
@Bean
public SAMLProcessorImpl processor() {
Collection<SAMLBinding> bindings = new ArrayList<SAMLBinding>();
bindings.add(httpRedirectDeflateBinding());
bindings.add(httpPostBinding());
bindings.add(artifactBinding(parserPool(), velocityEngine()));
bindings.add(httpSOAP11Binding());
bindings.add(httpPAOS11Binding());
return new SAMLProcessorImpl(bindings);
}
@Bean
public FilterChainProxy samlFilter() throws Exception {
List<SecurityFilterChain> chains = new ArrayList<SecurityFilterChain>();
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"),
samlEntryPoint()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/logout/**"),
samlLogoutFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"),
metadataDisplayFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"),
samlWebSSOProcessingFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSOHoK/**"),
samlWebSSOHoKProcessingFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SingleLogout/**"),
samlLogoutProcessingFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/discovery/**"),
samlIDPDiscovery()));
return new FilterChainProxy(chains);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.authenticationEntryPoint(samlEntryPoint());
http
.csrf()
.disable();
http
.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class)
.addFilterAfter(samlFilter(), BasicAuthenticationFilter.class)
.addFilterBefore(sessionRepositoryFilter(sessionRepository(), httpSessionStrategy()),
ChannelProcessingFilter.class)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/publicUrl").permitAll()
.antMatchers("/app/**").permitAll()
.antMatchers("/error").permitAll()
.antMatchers("/saml/**").permitAll()
.antMatchers("/landing").authenticated();
http
.logout()
.logoutSuccessUrl("/");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(samlAuthenticationProvider());
}
@Bean
public HttpSessionStrategy httpSessionStrategy()
{
return new HeaderHttpSessionStrategy();
}
@Bean
public SessionRepositoryFilter<ExpiringSession> sessionRepositoryFilter(
SessionRepository<ExpiringSession> sessionRepository, HttpSessionStrategy httpSessionStrategy)
{
SessionRepositoryFilter<ExpiringSession> sessionRepositoryFilter = new SessionRepositoryFilter<>(
sessionRepository);
sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
return sessionRepositoryFilter;
}
@Bean
public SessionRepository<ExpiringSession> sessionRepository()
{
return new JPASessionRepository(1800);
}
}
JPA Session repository which implements SessionRepository is :
package com.security.repositories.session;
public class JPASessionRepository implements SessionRepository<ExpiringSession>
{
private static final Logger LOG = LogManager.getLogger(JPASessionRepository.class);
private int maxInactiveInterval = -1;
@Autowired
private SpringSessionRepository springSessionRepository;
public JPASessionRepository()
{
}
public JPASessionRepository(int maxInactiveInterval)
{
this.maxInactiveInterval = maxInactiveInterval;
}
@Override
public ExpiringSession createSession()
{
ExpiringSession result = new MapSession();
result.setMaxInactiveIntervalInSeconds(maxInactiveInterval);
return result;
}
@Transactional
@Override
public void save(ExpiringSession session)
{
springSessionRepository.save(convertToDomain(session));
}
@Transactional
@Override
public ExpiringSession getSession(String id)
{
SessionEntity sessionEntity = springSessionRepository.findOne(id);
ExpiringSession saved = null;
if(sessionEntity != null)
{
saved = convertToSession(sessionEntity);
}
if (saved == null)
{
return null;
}
if (saved.isExpired())
{
delete(saved.getId());
return null;
}
return saved;
}
@Override
public void delete(String id)
{
SessionEntity currentSession = springSessionRepository.findOne(id);
if (null != currentSession)
{
springSessionRepository.delete(id);
}
}
private SessionEntity convertToDomain(ExpiringSession session)
{
SessionEntity sessionEntity = new SessionEntity();
sessionEntity.setId(session.getId());
sessionEntity.setLastAccessedTime(session.getLastAccessedTime());
sessionEntity.setCreationTime(session.getCreationTime());
sessionEntity.setData(serializeAttributes(session));
return sessionEntity;
}
byte[] serializeAttributes(ExpiringSession session)
{
Map<String, Object> attributes = new HashMap<>();
for (String attrName : session.getAttributeNames())
{
attributes.put(attrName, session.getAttribute(attrName));
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer;
try
{
ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
objectOutputStream.writeObject(new SessionAttributes(attributes));
buffer = out.toByteArray();
objectOutputStream.close();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
return buffer;
}
private ExpiringSession convertToSession(SessionEntity sessionEntity)
{
MapSession mapSession = new MapSession();
mapSession.setId(sessionEntity.getId());
mapSession.setLastAccessedTime(sessionEntity.getLastAccessedTime());
mapSession.setCreationTime(sessionEntity.getCreationTime());
mapSession.setMaxInactiveIntervalInSeconds(this.maxInactiveInterval);
SessionAttributes attributes = deserializeAttributes(sessionEntity);
if (attributes != null)
{
for (Map.Entry<String, Object> attribute : attributes.getAttributes().entrySet())
{
mapSession.setAttribute(attribute.getKey(), attribute.getValue());
}
}
return mapSession;
}
private SessionAttributes deserializeAttributes(SessionEntity sessionEntity)
{
SessionAttributes attributes = null;
if (sessionEntity.getData() != null && sessionEntity.getData().length > 0)
{
try
{
ObjectInputStream objectInputStream = new ObjectInputStream(
new ByteArrayInputStream(sessionEntity.getData()));
Object obj = objectInputStream.readObject();
attributes = (SessionAttributes) obj;
objectInputStream.close();
}
catch (IOException | ClassNotFoundException e)
{
LOG.warn(e);
//FIXME:How should this exception be handled?
}
}
return attributes;
}
public Integer getDefaultMaxInactiveInterval()
{
return maxInactiveInterval;
}
public void setDefaultMaxInactiveInterval(int maxInactiveInterval)
{
this.maxInactiveInterval = maxInactiveInterval;
}
public SpringSessionRepository getSpringSessionRepository()
{
return springSessionRepository;
}
public void setSpringSessionRepository(SpringSessionRepository springSessionRepository)
{
this.springSessionRepository = springSessionRepository;
}
}
SP Metadata
<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="http___localhost_8080_spring-boot-security-saml2-sample_saml_web_metadata" entityID="http://localhost:8080/spring-boot-security-saml2-sample/saml/web/metadata"><md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>x509 certificate data</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:KeyDescriptor use="encryption"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>--x509 certificate</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8080/saml/SingleLogout"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8080/saml/SingleLogout"/><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</md:NameIDFormat><md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8080/saml/SSO" index="0" isDefault="true"/><md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="http://localhost:8080/saml/SSO" index="1"/></md:SPSSODescriptor></md:EntityDescriptor>
IDP metadata:-
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://localhost:8081/OpenAM">
<IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
sample certificate
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<ArtifactResolutionService index="0" isDefault="true" Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8081/OpenAM/ArtifactResolver/metaAlias/idp"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8081/OpenAM/IDPSloRedirect/metaAlias/idp" ResponseLocation="http://localhost:8081/OpenAM/IDPSloRedirect/metaAlias/idp"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8081/OpenAM/IDPSloPOST/metaAlias/idp" ResponseLocation="http://localhost:8081/OpenAM/IDPSloPOST/metaAlias/idp"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8081/OpenAM/IDPSloSoap/metaAlias/idp"/>
<ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8081/OpenAM/IDPMniRedirect/metaAlias/idp" ResponseLocation="http://localhost:8081/OpenAM/IDPMniRedirect/metaAlias/idp"/>
<ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8081/OpenAM/IDPMniPOST/metaAlias/idp" ResponseLocation="http://localhost:8081/OpenAM/IDPMniPOST/metaAlias/idp"/>
<ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8081/OpenAM/IDPMniSoap/metaAlias/idp"/>
<NameIDFormat>
urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
</NameIDFormat>
<NameIDFormat>
urn:oasis:names:tc:SAML:2.0:nameid-format:transient
</NameIDFormat>
<NameIDFormat>
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
</NameIDFormat>
<NameIDFormat>
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
</NameIDFormat>
<NameIDFormat>
urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName
</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos</NameIDFormat>
<NameIDFormat>
urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
</NameIDFormat>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8081/OpenAM/SSORedirect/metaAlias/idp"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8081/OpenAM/SSOPOST/metaAlias/idp"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8081/OpenAM/SSOSoap/metaAlias/idp"/>
<NameIDMappingService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8081/OpenAM/NIMSoap/metaAlias/idp"/>
<AssertionIDRequestService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8081/OpenAM/AIDReqSoap/IDPRole/metaAlias/idp"/>
<AssertionIDRequestService Binding="urn:oasis:names:tc:SAML:2.0:bindings:URI" Location="http://localhost:8081/OpenAM/AIDReqUri/IDPRole/metaAlias/idp"/>
</IDPSSODescriptor>
</EntityDescriptor>
Please help me resolve the issue
Upvotes: 2
Views: 2920
Reputation: 1012
This error is usually caused by a mismatch of the EntityIDs in some way. It looks like your metadata is configured correctly, so I did some looking and found this.
Make sure that application uses the same HttpSession during sending of the request and reception of the response. Typically, this problem arises when the auhentication request is initialized from localhost address or http scheme, while response is received at a public host name or https scheme. E.g., when initializing authentication from URL https://host:port/app/saml/login, the response must be received at https://host;port/app/saml/SSO, not http://host:port/app/saml/SSO or https://localhost:port/app/saml/SSO.
The checking of the InResponseToField can be disabled by re-configuring the context provider as follows:
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl">
<property name="storageFactory">
<bean class="org.springframework.security.saml.storage.EmptyStorageFactory"/>
</property>
</bean>
You should note that this should only be used for development purposes. You should probably use Spring Profiles to enable this configuration locally only because it's less secure.
Upvotes: 2