CSRF Token in Master/Slave environment - spring-security

I've implemented a REST service using Spring web services, with CSRF security enabled in spring-security.xml, as below
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<security:http>
<security:csrf/>
</security:http>
</beans>
This application is deployed on two tomcat 7.0 servers in a master/slave setup, with apache used as a load balancer.
Some requests are being rejected by the server, throwing a security exception that the CSRF token is invalid.
I think a request with a valid CSRF token for the master server is being redirected to the slave, and vice versa, which is causing the exception. Can you configure security so that a valid token for either server is accepted by the other?

By default the CSRF Token is stored inside the HttpSession.
This means that you need to have the HttpSession replicated over. One easy way to do this is using Spring Session.
The other question you can ask yourself is "Are you using the rest service from a web browser?" If not, then you can remove CSRF protection.

Related

Resolving Metadata via ArtifactResolutionService

I am attempting to implement SAML login using Spring Security 5.5.3. Unfortunately, the metadata file looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<EntityDescriptor entityID="https://remoteloginsite.org/sso/authentication"
xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
<IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<ArtifactResolutionService index="0" isDefault="true" Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="https://remoteloginsite.org/sso/ArtifactResolver/metaAlias/authentication"/>
</IDPSSODescriptor>
</EntityDescriptor>
Unfortunately, Spring Security's SAML support bombs when attempting to read this metadata file with the following exception:
Caused by: org.springframework.security.saml2.Saml2Exception: Metadata response is missing verification certificates, necessary for verifying SAML assertions
I'm assuming that this simply means that 5.5.3 doesn't support resolving items such as <SingleLogoutService>,<SingleLoginService>, etc, so if I want to do it, I'll have to reach out to the location URL specified by the <ArtifactResolutionService> myself and use the results to manually build a RelyingPartyRegistration myself.
Question 1: Am I correct in the assumptions I've made about the steps I have to take?
Question 2: Does OpenSaml (version 3) provide any shortcuts that would make this any easier?
Thanks for any help.
Unfortunately, the version of Spring Security we used, 5.5.3, was too NEW to support artifact resolution. SAML support in Spring Security is a work in progress. We ended up not being able to use the 5.6.x releases of Spring Security because the Saml2AuthenticationToken did not implement the Serializable interface.
We manged to configure a RelyingPartyRegistration manually to make the first call to the IdP. Unfortunately, the response contained a SAML artifact ID, requiring us to make a second call. The IDP also turned around and made a GET request to us, which the SAML Authentication Processing Filter did not recognize.
So, we ended up creating a new implementation of the AbstractAuthenticationProcessingFilter specifically to accept URI of that callback. We leveraged the SOAP functionality of OpenSAML 3 to manually create an ArtifactResolve object and sent it via SOAP to the Artifact Resolution Service URL. We received back an ArtifactResponse object, which we manually processed for the information we needed, then passed that into an AuthenticationProvider to correctly tie the whole thing into the Spring Security lifecycle.
I can't really provide much of our code, but I hope this explanation helps someone in the future.

How to load custom CSRF token repository in Spring 5.2?

Our application using spring framework need to implement request based CSRF token in order to meet security requirements. Currently we have session based CSRF token provided by HttpSessionCsrfTokenRepository as Spring default. According to instruction I found, by configuring xml like this
<security:csrf token-repository-ref="customRequestCsrfTokenRepository"/>
<bean id="customRequestCsrfTokenRepository" class="com.dev.common_web.security.configuration.CustomCsrfTokenRepository"/>
Custom token repository which implements CsrfTokenRepository interface will be loaded to handle token request.
However when application starts, and running in debug mode, I can see it is spring default HttpSessionCsrfTokenRepository is used to handle loading and generating of token. I have also tried using spring CookieCsrfTokenRepository in xml config like
<security:csrf token-repository-ref="cookieCsrfTokenRepository"/>
<bean id="cookieCsrfTokenRepository" class="org.springframework.security.web.csrf.CookieCsrfTokenRepository"/>
And when application is running, it is again HttpSessionCsrfTokenRepository which is loaded to handle token request. Seems it doesn't matter what is configured as value of "token-repository-ref" in xml, it is always HttpSessionCsrfTokenRepository in use.
How to configure spring to use other csrf token repository instead of the default HttpSessionCsrfTokenRepository? We are using Spring 5.2.
I managed to figure this out :-).
In security.xml of our application, we have also customized csrf request matcher defined in order to disable csrf checking for some of the pages. When now adding customized csrf token repository, these two have to be defined in the same line inside <security:csrf ... />. If they are defined in two lines like this, only one is loaded.
<security:csrf token-repository-ref="customRequestCsrfTokenRepository"/>
<security:csrf request-matcher-ref="customCsrfRequestMatcher"/>
It has to be like this
<security:csrf token-repository-ref="customRequestCsrfTokenRepository" request-matcher-ref="customCsrfRequestMatcher" />

Spring Security 3.1

Could someone help me on this. appreciate your help.
I am using Spring security 3.1 with create-session="stateless" option.
Which throwing "InsufficientAuthenticationException" : "Full authentication is required to access this resource" exception of ExceptionTranslationFilter.
I am not able to understand what I am doing wrong and why I am getting this exception . As this exception stated that the credentials are not proper but I can see the credentials are going through request.Still I am getting 401 unauthorized
Fact is that the user is able to login properly & I get the message on console also. But again it is redirecting to login page due to access denied exception.
Here I am putting the code
Spring-Security.xml
<http entry-point-ref="negotiateSecurityFilterEntryPoint"
create-session="stateless" >
<intercept-url pattern="/user/loginuser" access="ROLE_ANONYMOUS"/>
<intercept-url pattern="/**" access="ROLE_USER"/>
<custom-filter ref="securityContextPersistenceFilter" after="BASIC_AUTH_FILTER" />
<custom-filter ref="ldapAuthFilter" position="CAS_FILTER" />
<custom-filter ref="databaseAuthFilter" position="FORM_LOGIN_FILTER" />
</http>
<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name='securityContextRepository'>
<bean class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
<property name='allowSessionCreation' value='false' />
</bean>
</property>
</bean>
As far as I know, that's exactly what stateless is meant to do.
Once you set create-session parameter as stateless, on every http call the SecurityContextPersistenceFilter won't be even called (by default) or, even if you force it to be called according to your configuration, it won't be any session level security information in the SecurityContextHolder.
This stateless pattern is intended to be used in a Rest style architecture, where authentication and authorization information is sent on every request. Better said, I don't think that stateless session creation pattern should be used unless you are developing a full stateless application
I found a good post about this, Spring Security Session Management, look carefully section 2. When Is The Session Created?
So stateless session creation strategy does not fit to a classic login form pattern.
In your scenario, I guesss that what is happening is that, once the login request is completed and the request is authenticathed, it is probably redirecting to a kind of welcome page using an HTTP 301 or 302 redirect, redirection which again is not carrying authentication info, so ends redirecting again to login page.
If you simply use "ifRequired" as session-creation, or as it is the default value, just don't set it, I bet your login would end successfully and redirect to wherever it should correctly without asking to log in again. And, if you do it like this, avoid setting the SecurityContextPersistenceFilter, it is configured automatically.

SockJS not passing credential information when on a different domain(CORS)

We have a websocket server side implementation using spring 4. It has been configured to use spring security for auth/authz. On the client side, we use sockJS which works perfectly when the client is in the same domain as the server.
Call to websocket is made this way…
socket = new SockJS("http://guest:guest#mydomain.org/MyWebSocketApp/tracker")
This eventually makes a call to http://guest:guest#myinterestingdomain.org/MyWebSocketApp/tracker/info to decide the transport to use. All this is good.
However, when using client from a different domain, I see that the credentials get stripped out. So, when this client is on a different domain, I see that the call being made is:
http://myinterestingdomain.com/MyWebSocketApp/tracker/info. I do not see the credentials being passed. Due to this, I get a 401 error (unauthorized) user. We have the CORS configuration on the server side and also have:
Access-Control-Allow-Credentials "true”
Can someone please help me? I am out of options and I don’t understand why the credentials are getting stripped out? Could this be related to CORS?
Even if XmlHttpRequest.withCredentials=true (done by the SockJS client) and Access-Control-Allow-Credentials=true, you can't pass username and password in the URL for cross domain requests.
In order to use basic authentication, you need to create yourself the Authorization header, but it seems SockJS client does not allow this currently. There is an issue asking for such support, I have added a new comment explaining we need this for Basic Authentication support.
Since Authorization header is not a simple header, a CORS preflight request will be sent before the actual request. But Spring Framework currently does not dispatch OPTIONS requests by default, so even with the Authorization header set on client side, you will also need to enable OPTIONS requests dispatching in Spring Framework.
With web.xml:
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
Or if you are using Servlet 3 without web.xml, add this to your class that extends AbstractAnnotationConfigDispatcherServletInitializer:
#Override
protected void customizeRegistration(Dynamic registration) {
registration.setInitParameter("dispatchOptionsRequest", "true");
}

Acegi Security Issue

I have the following security config (i.e. http channel requirements) for my webapp:
<bean id="channelProcessingFilter" class="org.acegisecurity.securechannel.ChannelProcessingFilter">
<property name="channelDecisionManager"><ref bean="channelDecisionManager"/>
<property name="filterInvocationDefinitionSource">
<value>
...
\A/.*.html\Z=REQUIRES_INSECURE_CHANNEL
</value>
</property>
</bean>
where all *.html URLs require http access (insecure channel). This explains why I’m seeing https requests switch to http. When I change the config to require https access (secure channel), then I can’t get to the page via http.
My questions is: Does anyone know if it’s possible to allow either http or https access?
Turns out that there exists a setting called ANY_CHANNELS in some implementations. Unfortunately, not mine.

Resources