Shibboleth Choosing Authentication Mechanism Based on SP - single-sign-on

I am Using Shibboleth as IDP
For starters, how do i configure IDP to pick an authentication mechanism based on sp
like
SP1- Database Authentication
SP2- External Authentication
SP3- LDAP Authentication

We can configure the behaviour required in replying party.xml
<bean parent="RelyingPartyByName" c:relyingPartyIds="https://sp.example.org">
<property name="profileConfigurations">
<list>
<!-- Your refs or beans here. -->
</list>
</property>
</bean>
And
we can specify the desired authentication mechanism as
<bean parent="SAML2.SSO" p:authenticationFlows="#{{'Password'}}" />
which will be like
<bean parent="RelyingPartyByName" c:relyingPartyIds="https://sp.example.org">
<property name="profileConfigurations">
<list>
<bean parent="SAML2.SSO" p:authenticationFlows="#{{'Password'}}" />
</list>
</property>
</bean>

Related

Spring SAML - Using multiple IDP certificates from keystore instead of metadata XML

I was able to integrate my application (SP) with Okta (IDP).
I will be only performing IDP-initiated logins.
But Okta will not be my only IDP and I do not want to keep adding new IDP metadata XML's to my applications (because that means I need to edit my spring XML file and add a new IDP and restart the server).
So I just want to import the IDP x509certificates (public key) into my keystore and use them to verify my SAML responses. Is that possible?
Or in other words, I want to register an IDP at runtime without making any changes to my application or restarting it.
If yes, can you provide resources on how to do that?
Currently I have provided Okta's metadata XML like below in my application's spring xml file.
<bean id="metadata" class="org.springframework.security.saml.metadata.MetadataManager">
<constructor-arg>
<list>
<bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
<constructor-arg>
<value type="java.io.File">C:\\DEV\\idp_metadata\\metadata.xml</value>
</constructor-arg>
<property name="parserPool" ref="parserPool" />
</bean>
</list>
</constructor-arg>
</bean>
Thanks,
Abhishek
I completed the changes to my application to make it dependent on an IDP's certificate present in a keystore.
But with a caveat, if a new IDP certificate is added in future, it requires a server restart.
I changed the securityProfile to pkix instead of the default metaIOP
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<constructor-arg>
<bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
<constructor-arg>
<bean class="java.util.Timer" />
</constructor-arg>
<constructor-arg>
<bean class="org.opensaml.util.resource.FilesystemResource">
<constructor-arg value="${path.to.SP.metadata}" />
</bean>
</constructor-arg>
<property name="parserPool" ref="parserPool" />
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="local" value="true" />
<property name="securityProfile" value="pkix" />
<property name="sslSecurityProfile" value="pkix" />
<property name="requireArtifactResolveSigned" value="false" />
<property name="requireLogoutRequestSigned" value="false" />
<property name="requireLogoutResponseSigned" value="false" />
<property name="idpDiscoveryEnabled" value="false" />
<property name="supportUnsolicitedResponse" value="true" />
</bean>
</constructor-arg>
</bean>
Added the certificate to a .jks file: keytool -importcert -file certificate.txt -keystore keystore.jks -alias "Alias"
Implemented a SAMLContextProviderLB and injected pkixresolver
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderLB">
<property name="scheme" value="${saml.loadBalancer.scheme}" />
<property name="serverName" value="${saml.loadBalancer.serverName}" />
<property name="serverPort" value="${saml.loadBalancer.serverPort}" />
<property name="includeServerPortInRequestURL" value="${saml.loadBalancer.includeServerPortInRequestURL}" />
<property name="contextPath" value="/contextPath" />
<property name="pkixResolver">
<bean class="org.springframework.security.saml.trust.PKIXInformationResolver">
<constructor-arg index="0" ref="metadataCredResolver" />
<constructor-arg index="1" ref="metadata" />
<constructor-arg index="2" ref="trustedKeyManager" />
</bean>
</property>
<property name="storageFactory">
<bean class="org.springframework.security.saml.storage.EmptyStorageFactory" />
</property>
</bean>
<bean id="metadataCredResolver" class="org.springframework.security.saml.trust.MetadataCredentialResolver">
<constructor-arg index="0" ref="metadata" />
<constructor-arg index="1" ref="trustedKeyManager" />
<property name="useXmlMetadata" value="false" />
</bean>
<bean id="trustedKeyManager" class="org.springframework.security.saml.key.JKSKeyManager">
<constructor-arg value="${saml.trust.jks.filePath}" />
<constructor-arg type="java.lang.String" value="${saml.trust.jks.password}" />
<constructor-arg>
<map>
<entry key="${saml.trust.jks.defaultKey.name}" value="${saml.trust.jks.defaultKey.password}" />
</map>
</constructor-arg>
<constructor-arg type="java.lang.String" value="${saml.trust.jks.defaultKey.name}" />
</bean>
Implemented a few classes to override the need of a metadata XML.
SAMLProcessorImpl and WebSSOProfileConsumerImpl
I remove the dependency on getPeerEntityID / getPeerEntityMetadata.getEntityID() and replace it with response.getIssuer().getValue() because both have to be the same for SAML to work.
The trust certificates are obtained from the keystore which is loaded once during startup.
In my next update I will try to figure out how to perform a timed refresh of the .jks file to load new certificates.

spring-social Facebook login doesn't set Authentication object

I'm using Facebook login to authenticate in my application. I use the authentication filter.
The authentication goes OK, but when it redirects back to homepage the filter doesn't seem to set the Authentication object, so calling SecurityContextHolder.getContext().getAuthentication() returns null. This only happens the first time when the user authorizes our app. It doesn't happen after that.
Currently to get the Authentication object set, the user has to 'login with facebook' twice. The second time it doesn't actually do any logins, the filter looks like it's picking up the cookie and does the authentication and doesn't even need to go to Facebook anymore.
So my question is why do I need to go through the filter twice? Or how can I avoid that?
Configuration looks like this:
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<constructor-arg value="/login"/>
<property name="useForward" value="true"/>
</bean>
<bean class="com.gigi.web.SpringDataUserDetailsService" id="userService"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="userService"/>
<security:authentication-provider ref="socialAuthenticationProvider" />
</security:authentication-manager>
<bean class="org.springframework.social.security.SocialAuthenticationFilter" id="socialAuthenticationFilter">
<constructor-arg ref="authenticationManager" />
<constructor-arg ref="userIdSource" />
<constructor-arg ref="usersConnectionRepository" />
<constructor-arg ref="connectionRegistry" />
<property name="postLoginUrl" value="/home" />
<property name="defaultFailureUrl" value="/login?error&social" />
<property name="signupUrl" value="/user/signup" />
</bean>
<bean class="org.springframework.social.connect.web.ProviderSignInUtils">
<constructor-arg ref="connectionRegistry"/>
<constructor-arg ref="usersConnectionRepository"/>
</bean>
<bean id="userIdSource" class="org.springframework.social.security.AuthenticationNameUserIdSource" />
<bean id="socialAuthenticationProvider"
class="org.springframework.social.security.SocialAuthenticationProvider">
<constructor-arg ref="usersConnectionRepository" />
<constructor-arg ref="userService" />
</bean>
<bean id="userSocialConnectionService" class="com.gigi.web.UserSocialConnectionController"></bean>
<bean id="usersConnectionRepository" class="com.gigi.social.SpringDataUsersConnectionRepository">
<constructor-arg ref="connectionRegistry" />
</bean>
<bean id="connectionRegistry"
class="org.springframework.social.security.SocialAuthenticationServiceRegistry">
<property name="authenticationServices">
<list>
<bean class="org.springframework.social.facebook.security.FacebookAuthenticationService">
<constructor-arg value="${facebook.app.id}" />
<constructor-arg value="${facebook.app.secret}" />
<constructor-arg value="${facebook.app.namespace}" />
</bean>
</list>
</property>
</bean>
It looks like spring doesn't handle that on it's own, which kinda makes sense though I feel like it should be possible for the config, rather than having to write code for it. Anyway, here's how we've done it:
#RequestMapping("/signup")
public String signUp(WebRequest request) {
Connection<?> connection = providerSignInUtils.getConnectionFromSession(request);
User user = usersConnectionRepository.createUser(connection);
getRepository().save(user);
providerSignInUtils.doPostSignUp(user.getId().toString(), request);
// the following will automatically log in the user after sign up
SecurityContextHolder.getContext().setAuthentication(new SocialAuthenticationToken(connection, user, null, user.getAuthorities()));
return "redirect:/home";
}

Error with Spring ldap pooling

i build async jersey web services, and now i need to make some operations with ldap.
I have configure Spring beam.xml in this mode:
<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="${ldap.url}" />
<property name="base" value="${ldap.base}" />
<property name="userDn" value="${ldap.userDn}" />
<property name="password" value="${ldap.password}" />
<property name="pooled" value="false" />
</bean>
<bean id="contextSource"
class="org.springframework.ldap.pool.factory.PoolingContextSource">
<property name="contextSource" ref="contextSourceTarget" />
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="ldapTreeBuilder" class="com.me.ldap.LdapTreeBuilder">
<constructor-arg ref="ldapTemplate" />
</bean>
<bean id="personDao" class="com.me.ldap.PersonDaoImpl">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
But when i try to use ldap i have this error:
Error creating bean with name 'contextSource' defined in class path resource [config/Beans.xml]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool/KeyedPoolableObjectFactory
In my project i have commons-pool2-2.2.jar lib, but still i have this error..i try to add commons-pool2-2.2.jar in TOMCAT_PATH/lib but not works..
UPDATE:
If i put commons-pool-1.6.jar it works.. but if i want to use pool2 how i can do? only i must change class inn commons-pool2-2.2.jar?
Updated Answer:
Since at least Spring LDAP 2.3.2 you can now use commons-pool2. Spring LDAP now provides two classes:
For commons-pool 1.x:
org.springframework.ldap.pool.factory.PoolingContextSource
For commons-pool 2.x:
org.springframework.ldap.pool2.factory.PooledContextSource
Details can be found here:
https://github.com/spring-projects/spring-ldap/issues/351#issuecomment-586551591
Original Answer:
Unfortunately Spring-Ldap uses commons-pool and not commons-pool2. As you have found the class org.apache.commons.pool.KeyedPoolableObjectFactory does not exist in commons-pool2 (it has a different package structure), hence the error.
There is a Jira issue for the Spring-ldap project asking them to upgrade/support commons-pool2:
https://jira.spring.io/browse/LDAP-316
Until that has been completed you will have to use commons-pool 1.6.

How I change ValidationMessages.properties with Hibernate Validator?

I am trying modify default ValidationMessages.properties to other. But I not get it.
My setup:
In Spring.
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>text</value>
<value>error</value>
</list>
</property>
</bean>
<bean name="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource">
<ref bean="messageSource"/>
</property>
</bean>
In text.properties and tex_XX.properties.
edit.profile.password.size=Password must be between {min} and {max}
Annotation example.
#Size(min=4, max=8, message="{edit.profile.password.size}")
You should have Hibernate Validator 4.1 or higher on the classpath even if you use a different validation provider.

How do i change the property of jaxrs endpoint to support "mtom"

I created a RESTful web service, and I want to send binary files to this service without SOAP.
There are some information on CXF website:
XOP
But I can't find a way to get the CXF JAX-RS endpoints, and set an mtom-enabled property.
My Spring config is:
<jaxrs:server id="fis" address="http://172.20.41.40:8080/fis">
<jaxrs:serviceBeans>
<ref bean="FaultInfoResource" />
<ref bean="ExplorationResultResource" />
</jaxrs:serviceBeans>
</jaxrs:server>
<bean id="FaultInfoService" parent="baseService" class="com.dfe.demo.FaultInfoService">
</bean>
<bean id="FaultInfoResource" class="com.dfe.demo.FaultInfoResource">
<property name="faultInfoService" ref="FaultInfoService"/>
</bean>
<bean id="ExplorationResultService" parent="baseService" class="com.dfe.demo.ExplorationResultService">
</bean>
<bean id="ExplorationResultResource" class="com.dfe.demo.ExplorationResultResource">
<property name="explorationResultService" ref="ExplorationResultService"/>
</bean>
And my server class is:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"com/dfe/iss/config/applicationContext.xml","com/dfe/demo/yearlyplan/cxf-servlet.xml"});
JAXRSServerFactoryBean fib = (JAXRSServerFactoryBean) ctx.getBean("fis");
fib.create();
Try this:
<beans>
<jaxrs:server id="bookstore1">
<jaxrs:properties>
<entry key="mtom-enabled" value="true"/>
</jaxrs:properties>
</jaxrs:server>
</beans>