Spring SAML configuration is breaking other http connections - spring-security

I am using Spring SAML to implement single sign on in my application. Evreything is integrated and works properly from SSO perspective.
Another service of my application which also uses HTTP client post via Axis started failing with the following error
{http://xml.apache.org/axis/}stackTrace:javax.net.ssl.SSLPeerUnverifiedException: SSL peer failed hostname validation for name: null
I have looked into the answer provided the link
Spring Security SAML + HTTPS to another page and follow the same but to no avail.
Below is the configuration for TLSProtocolSocketFactory
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.apache.commons.httpclient.protocol.Protocol"/>
<property name="targetMethod" value="registerProtocol"/>
<property name="arguments">
<list>
<value>https</value>
<bean class="org.apache.commons.httpclient.protocol.Protocol">
<constructor-arg value="https"/>
<constructor-arg>
<bean class="org.springframework.security.saml.trust.httpclient.TLSProtocolSocketFactory">
<constructor-arg ref="keyManager"/>
<constructor-arg><null/></constructor-arg>
<constructor-arg value="allowAll"/>
</bean>
</constructor-arg>
<constructor-arg value="443"/>
</bean>
</list>
</property>
</bean>
I have imported the cert of the other service in samlKeystore.jks as well.
Any help in the issue will be apreciated

I think this may be what you're looking for: Source
You are using bean TLSProtocolConfigurer which changes trusted certificates and hostname verification of the HTTPS protocol in the HTTP Client. You can revert behaviour of the HTTP Client back to defaults by removing this bean. You will then need to make sure that certificates used by entities from which you load metadata (https://idp.ssocircle.com/idp-meta.xml) are trusted in your cacerts, or use an endpoints without https (http://idp.ssocircle.com/idp-meta.xml).
Alternatively, you can disable hostname verification by setting property sslHostnameVerification to allowAll on bean TLSProtocolConfigurer. You will also need to make sure that the HTTPS certificate of https://www.somepage.com (or its CA) is included in the samlKeystore.jks (see Spring SAML manual).
You can find more details on the TLSProtocolConfigurer bean in the Spring SAML manual, chapter HTTP-based metadata provider with SSL.

The issue is in checkNames() function of PKIXX509CredentialTrustEngine where we are checking the trustedNames collection only for null instead of "null or Empty".Even though we are passing the value for trustedNames as null in TLSProtocolSocketFactory's getPKIXResolver() method to create StaticPKIXValidationInformatonResolver, the constructor of this class reinitialized the trustedNames collection to an empty collection.Changing the line from if(trustedNames == null) to if(trustedNames == null || trustedNames.isEmpty()) fixed the problem for me.

Related

SAML Configuration

I have integrated SAML 2.0 in my system and I have several questions about SAML configurations file.
In my Service Provider file I have
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>.
In the customer's IDP file we don't have any NameIDFormat definition.
What is de default NameIDFormat if the client didn't defined it?
In my spring saml configuration file
<bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
<property name="contextProvider" ref="${saml.security.context.provider}" />
<property name="defaultProfileOptions">
<bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
<property name="includeScoping" value="false" />
<property name="nameID" value="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" />
<property name="allowCreate" value="true" />
</bean>
</property>
</bean>
But the client told us that the policy 'persitent' is not supported for him.
If I modify the defaultProfileOptions and I delete the nameID property, the default value for the client would be
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified (I remember that in SP file the NameIDFormat is urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified and in IDP file we don't have the NameIDFormat definition)?
From SAML specification point of view NameID format
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
should be used if no NameID format is specified. However you don't need to send anyone, the SAML IdP sould then choose one of your SP's supported NameID formats (provided in the SAML SP meta data).
From SAML spec point of view NameID format
urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
is intended to be used for the use case of 'account-linking' (linkage of 2 identities in 2 different identity silos, one on IdP side, on on SP side)
As your use-case seems to be SSO only, the intended NameID format would
urn:oasis:names:tc:SAML:2.0:nameid-format:transient

Oauth 1.0a consumer code equesting an access token twice

I've setup a consumer app, and most of the oauth workflow looks correct, but for some reason after the callback url is invoked by the provider, it tries to get an access token TWICE. The first time works
http://localhost:8080/app/ws/oauth/token
[OAuth oauth_consumer_key="itd79n64zlwv5hhv", oauth_nonce="cac26978-c36c-4a8b-8f3e-3e779ff927ab", oauth_signature="5c8BM9qQoijXC2f5IXpQGtSQsys%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1458938403", oauth_token="5451cf20-7eed-4797-819c-ee2316981654", oauth_verifier="c56de555-79df-455e-ab87-f5f11b953fef", oauth_version="1.0"]
response is a 200, payload includes oauth_token=a95d6305-4261-4c1d-a9b0-43411a0c2f2c&oauth_token_secret=573702d2-70ca-412c-84e5-868e9ee07169
but then, it calls the URL again.
http://localhost:8080/app/ws/oauth/token
[OAuth oauth_consumer_key="itd79n64zlwv5hhv", oauth_nonce="6c013ef9-2f3c-49dd-84fb-97db73b5fb39", oauth_signature="5RTQE5XtcqUwEFVvYQjExhH1eio%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1458938403", oauth_token="5451cf20-7eed-4797-819c-ee2316981654", oauth_verifier="c56de555-79df-455e-ab87-f5f11b953fef", oauth_version="1.0"
which causes an exception on the server since the request token has been removed and the access token has already been issued.
When stepping through the code, I can see that the OAuthConsumerContextFilter stores the access token fine after the first call.
Somehow the filter chain ends up bring it back to readResource in CoreOAuthConsumerSupport with the request token.
I built the consumer app using spring-boot.
from: applicationContext.xml
<bean id="oscarService" class="com.mdumontier.oscar.labline.service.OscarService">
<property name="oscarRestTemplate">
<bean class="org.springframework.security.oauth.consumer.client.OAuthRestTemplate">
<constructor-arg ref="oscar" />
</bean>
</property>
</bean>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="marissa" password="wombat" authorities="ROLE_USER" />
<security:user name="sam" password="kangaroo" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<security:http auto-config='true' >
</security:http>
<oauth:consumer resource-details-service-ref="resourceDetails" oauth-failure-page="/oauth_error.jsp">
<oauth:url pattern="/oscar/**" resources="oscar"/>
</oauth:consumer>
<oauth:resource-details-service id="resourceDetails">
<oauth:resource id="oscar"
key="itd79n64zlwv5hhv"
secret="d3psvmrn8k1xws9x"
request-token-url="http://localhost:8080/app/ws/oauth/initiate"
user-authorization-url="http://localhost:8080/app/ws/oauth/authorize"
access-token-url="http://localhost:8080/app/ws/oauth/token"/>
</oauth:resource-details-service>
Spring Boot automatically registers any Beans which implement Filter in the main application filter chain. See: https://stackoverflow.com/a/28428154 for a bit more detail.
The oauth:consumer helper registers both OAuth filters as beans, and seems to not have been updated in a while. I couldn't even get the XML config to work properly under the latest Spring Boot. Anyway, this means that both will be run twice, and in the case of the OAuthConsumerContextFilter this is destructive since it will run outside the security sub-chain and fail every time.
To fix this you have two options.
One, hint to Spring Boot to avoid this behavior by providing a FilterRegistrationBean for each filter it's automatically picking up, like so:
#Bean
public FilterRegistrationBean registration(OAuthConsumerContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
Two, bypass the XML config entirely and use Java config. I've posted a complete working code sample of getting on OAuth 1 consumer in Spring Boot using Java config in this answer: https://stackoverflow.com/a/42143001/2848158
Within the Java config, you would have to either repeat the FilterRegistrationBean trick, or just not register those filters as beans in the first place but rather create and register instances directly with the Security filter chain.

spring-messaging xml config with stomp and spring-sessions

I'm trying to set up WebSockets with spring-messaging using stomp, and using redis-backed sessions with spring-session. Our application context is wired via xml, and spring-session is working with the non-websocket portion of the application. The relevant config for websocket is as follows
<websocket:message-broker application-destination-prefix="/streaming" >
<websocket:stomp-endpoint path="/data">
<websocket:sockjs session-cookie-needed="false" />
</websocket:stomp-endpoint>
<websocket:stomp-broker-relay prefix="/topic" relay-host="${jms_hostname}" relay-port="${jms_stomp_port}" />
<websocket:client-inbound-channel>
<websocket:interceptors>
<ref bean="sessionRepoMessageInterceptor"/>
<ref bean="authenticationValidationInterceptor" />
<ref bean="selectorValidationInterceptor" />
<ref bean="selectorQuotingInterceptor" /> <!-- comes after we have validated the selector, we now shim it so JMS understands it -->
</websocket:interceptors>
</websocket:client-inbound-channel>
</websocket:message-broker>
I have defined what I think are the necessary beans for spring-session's integration with web sockets here:
<bean id="redisSessionBackedWebsocketHandler" class="org.springframework.session.web.socket.server.">
</bean>
<bean id="sessionRepoMessageInterceptor" class="org.springframework.session.web.socket.server.SessionRepositoryMessageInterceptor">
</bean>
<bean id="webSocketRegistryListener" class="org.springframework.session.web.socket.handler.WebSocketRegistryListener">
</bean>
but I'm not sure where I would wire them in to the web socket configuration, and have not been able to find any doc on how to do it this way.
Thoughts?
The Spring Session WebSocket contains the config just only for the Java & Annotation variant.
And according to the Spring Session Docs the AbstractSessionWebSocketMessageBrokerConfigurer does the stuff for seamless integration between Spring Session and Spring WebSockets. However there we can see some paragraph, what it does:
To hook in the Spring Session support, we need to ensure ...
To be honest it isn't so easy to configure that stuff from XML.
Feel free to follow with the issue: https://github.com/spring-projects/spring-session/issues/101

jasper server 5.6 active directory authentication not working

I'm authentication jasper server 5.6 to ldap active directory.ldapAuthenticationProvider bean configurations are ok.(userDnPatterns working).but server couldn't search in usersearch bean.this is my userSearch configuration.Am I correctly put values to constructor-arg ?
<bean id="userSearch"
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0"><value>(sAMAccountName={0})</value></constructor-arg>
<constructor-arg index="1"><value>sAMAccountName={0},ou=IT Service Accounts</value></constructor-arg>
<constructor-arg index="2"><ref local="ldapContextSource"/></constructor-arg>
<property name="searchSubtree"><value>true</value></property>
</bean>
Thanks !
You should not use "sAMAccountName" as first parameter (index=0), as that parameter is the Directory search base.
If you want to use the default search base, leave the value blank.
Now, the second parameter, tells jasper (or any app that uses the FilterBasedLdapUserSearch method) how to search for the user, and what user should the app use to finally bind to the directory.
The fiter you specified on "index=1" would only work if AD has users DN's in the form:
DN: sAMAccountName=user,ou=IT Service Accounts, .....
Now, AD's default user DN's are more like: "CN=Full Name,CN=Users,....", so, in your case, you should be using only (sAMAccountName={0}) in the "FilterBasedLdapUserSearch" method, and then modify "LdapAuthenticationProvider" method to specify "userDnPatterns", like this:
<bean id="ldapAuthenticationProvider"
class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
<constructor-arg><bean class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
<constructor-arg><ref local="ldapContextSource"/></constructor-arg>
<property name="userDnPatterns"/>
<list> <value>CN={0},ou=IT Service Accounts</value> </list> </bean> </bean>
Of course, you should match this more closely to your setup, this is only an example.

Spring social linkedin not sending "state" parameter with oAuth2

I am trying to implement Linkedin social login in a Spring Application; I am using the most recent release spring-social-linkedin-1.0.0.RC4 and spring-social-1.0.3.RELEASE.
I manage to get to the point where authorization link is sent to Linkedin:
https://www.linkedin.com/uas/oauth2/authorization?client_id=....&response_type=code&redirect_uri=....
but the request is sent without the mandatory "state" request parameter, so it always results in an error from Linkedin. I double checked that simply adding the missing parameter to te url by hand results in the correct login page from linkedin, so I know client id is right.
Here's the code I use to connect to Linkedin:
User principal = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
ConnectionRepository repository = usersConnectionRepository.createConnectionRepository(principal.getUsername());
Connection<LinkedIn> connection = repository.findPrimaryConnection(LinkedIn.class);
return connection.getApi();
And the configuration for connectionFactoryLocator, where placeholders are resolved correctly:
<bean id="connectionFactoryLocator"
class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
<property name="connectionFactories">
<list>
<bean
class="org.springframework.social.linkedin.connect.LinkedInConnectionFactory">
<constructor-arg value="${linkedin.api.key}" />
<constructor-arg value="${linkedin.api.secret}" />
</bean>
</list>
</property>
</bean>
Everything else is configured by the book and it's pretty standard spring social + jdbc setup.
I think "state" and "scope" parameters should be configured in the same way as "api.key" and "api.secret" (which are correctly set in the request), but I can't find how.
Did someone manage to get this right?
I found out: the simplest way to do it is to use an Interceptor and add it to the ConnectController. You will be able to add any parameter you like there.
Or upgrade to spring social 1.1.0 which has automatic state parameter handling (it's currently at RC1 stage).

Resources