Disable caching for static resources in spring security 4.2 - spring-security

I have this declaration in my spring xml configuration:
<security:headers>
I believe this ensures that the following header is sent with all responses:
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
I don't want this header to be sent with static resources. So I tried this:
<security:headers>
<security:header ref="cacheStaticsHeaders" />
</security:headers>
<bean id="cacheStaticsHeaders" class="org.springframework.security.web.header.writers.DelegatingRequestMatcherHeaderWriter">
<constructor-arg>
<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
<constructor-arg value="/images/**"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.web.header.writers.StaticHeadersWriter">
<constructor-arg name="headers">
<list>
<bean class="org.springframework.security.web.header.Header">
<constructor-arg name="headerName" value="cache-control"></constructor-arg>
<constructor-arg name="headerValues" value="max-age=31536000"/>
</bean>
<bean class="org.springframework.security.web.header.Header">
<constructor-arg name="headerName" value="Expires"></constructor-arg>
<constructor-arg name="headerValues" value="31536000"/>
</bean>
</list>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
However,now I see two headers for static resources:
Cache-Control:max-age=31536000 cache-control: public
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
How do I fix this? I first asked this question here but didn't get a response.

Related

HttpServletRequest returns null session after authenticated IDP and redirected to SP

I'm setting up OKTA SAML 2.0 integration with Struts 1.0 in Wildfly 8.1.0. Earlier I had the same setup in JBoss 7 server in which everything works fine. I just replicated the same in Wildfly 8 but after the authentication is completed in OKTA and the web page is redirecting to my application in which
request.getSession(false)
returns null.
Here is my SecurityFilter.java
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
}
JBoss-WEb.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<!-- local -->
<context-root>application</context-root>
<!-- production
<context-root>/</context-root> -->
</jboss-web>
SecurityContext.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:annotation-config/>
<context:component-scan base-package="org.springframework.security.saml"/>
<security:http entry-point-ref="samlEntryPoint" use-expressions="false">
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
<security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
<security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
</security:http>
<bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map request-matcher="ant">
<security:filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/>
<!--<security:filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFiler"/> -->
<security:filter-chain pattern="/saml/login/**" filters="samlEntryPoint"/>
<security:filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter"/>
<security:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/>
<security:filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/>
<security:filter-chain pattern="/saml/discovery/**" filters="samlIDPDiscovery"/>
</security:filter-chain-map>
</bean>
<bean id="successRedirectHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/login.do?method=home"/>
</bean>
<bean id="failureRedirectHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="useForward" value="false"/>
</bean>
<bean id="successLogoutHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
<property name="defaultTargetUrl" value="/"/>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="samlAuthenticationProvider"/>
<security:authentication-provider>
<security:user-service id="adminInterfaceService">
<security:user name="admin" password="admin" authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger"/>
<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
<constructor-arg value="classpath:security/samlKeystore.jks"/>
<constructor-arg type="java.lang.String" value="nalle123"/>
<constructor-arg>
<map>
<entry key="apollo" value="nalle123"/>
</map>
</constructor-arg>
<constructor-arg type="java.lang.String" value="apollo"/>
</bean>
<bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
<property name="defaultProfileOptions">
<bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
<property name="includeScoping" value="false"/>
</bean>
</property>
</bean>
<bean id="samlIDPDiscovery" class="org.springframework.security.saml.SAMLDiscovery">
<property name="idpSelectionPath" value="/idpSelection.jsp"/>
</bean>
<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.MetadataGenerator">
<property name="extendedMetadata">
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="idpDiscoveryEnabled" value="true"/>
</bean>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="metadataDisplayFilter" class="org.springframework.security.saml.metadata.MetadataDisplayFilter"/>
<bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
<constructor-arg>
<list>
<bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
<constructor-arg>
<value type="java.io.File">classpath:security/idp.xml</value>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
</bean>
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl"/>
<bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
<property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
</bean>
<bean id="samlWebSSOHoKProcessingFilter" class="org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
<property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
</bean>
<bean id="logoutHandler"
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
<property name="invalidateHttpSession" value="false"/>
</bean>
<bean id="samlLogoutFilter" class="org.springframework.security.saml.SAMLLogoutFilter">
<constructor-arg index="0" ref="successLogoutHandler"/>
<constructor-arg index="1" ref="logoutHandler"/>
<constructor-arg index="2" ref="logoutHandler"/>
</bean>
<bean id="samlLogoutProcessingFilter" class="org.springframework.security.saml.SAMLLogoutProcessingFilter">
<constructor-arg index="0" ref="successLogoutHandler"/>
<constructor-arg index="1" ref="logoutHandler"/>
</bean>
<bean id="processor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<constructor-arg>
<list>
<ref bean="redirectBinding"/>
<ref bean="postBinding"/>
<ref bean="artifactBinding"/>
<ref bean="soapBinding"/>
<ref bean="paosBinding"/>
</list>
</constructor-arg>
</bean>
<!-- SAML 2.0 WebSSO Assertion Consumer -->
<bean id="webSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl"/>
<!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer -->
<bean id="hokWebSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>
<!-- SAML 2.0 Web SSO profile -->
<bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl"/>
<!-- SAML 2.0 Holder-of-Key Web SSO profile -->
<bean id="hokWebSSOProfile" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>
<!-- SAML 2.0 ECP profile -->
<bean id="ecpprofile" class="org.springframework.security.saml.websso.WebSSOProfileECPImpl"/>
<!-- SAML 2.0 Logout Profile -->
<bean id="logoutprofile" class="org.springframework.security.saml.websso.SingleLogoutProfileImpl"/>
<!-- Bindings, encoders and decoders used for creating and parsing messages -->
<bean id="postBinding" class="org.springframework.security.saml.processor.HTTPPostBinding">
<constructor-arg ref="parserPool"/>
<constructor-arg ref="velocityEngine"/>
</bean>
<bean id="redirectBinding" class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding">
<constructor-arg ref="parserPool"/>
</bean>
<bean id="artifactBinding" class="org.springframework.security.saml.processor.HTTPArtifactBinding">
<constructor-arg ref="parserPool"/>
<constructor-arg ref="velocityEngine"/>
<constructor-arg>
<bean class="org.springframework.security.saml.websso.ArtifactResolutionProfileImpl">
<constructor-arg>
<bean class="org.apache.commons.httpclient.HttpClient">
<constructor-arg>
<bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"/>
</constructor-arg>
</bean>
</constructor-arg>
<property name="processor">
<bean class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<constructor-arg ref="soapBinding"/>
</bean>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="soapBinding" class="org.springframework.security.saml.processor.HTTPSOAP11Binding">
<constructor-arg ref="parserPool"/>
</bean>
<bean id="paosBinding" class="org.springframework.security.saml.processor.HTTPPAOS11Binding">
<constructor-arg ref="parserPool"/>
</bean>
<!-- Initialization of OpenSAML library-->
<bean class="org.springframework.security.saml.SAMLBootstrap"/>
<!-- Initialization of the velocity engine -->
<bean id="velocityEngine" class="org.springframework.security.saml.util.VelocityFactory" factory-method="getEngine"/>
<!-- XML parser pool needed for OpenSAML parsing -->
<bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" init-method="initialize">
<property name="builderFeatures">
<map>
<entry key="http://apache.org/xml/features/dom/defer-node-expansion" value="false"/>
</map>
</property>
</bean>
<bean id="parserPoolHolder" class="org.springframework.security.saml.parser.ParserPoolHolder"/>
</beans>
If the authentication is redirected to
http://localhost:8080/application
then there is value in the session
but when I try the same in production URL
http://www.myproductionsite.com:8080/
then I'm getting null pointer exception at
request.getSession(false);
You would have encountered this issue in Chrome v80 and above. Chrome now requires the session cookie to have samesite=NONE attribute if our application allows other domains such as Okta to POST data on the path /saml/SSO. This feature exists to protect applications against CSRF
If the cookie doesn't have the samesite=NONE attribute, Chrome will not include this cookie with the request Okta posts making your application see this request as a completely new request explaining the request.getSession(false) value to be null
Please see more here - https://support.okta.com/help/s/article/FAQ-How-Chrome-80-Update-for-SameSite-by-default-Potentially-Impacts-Your-Okta-Environment?language=en_US
There are different options to provide the sameSite attribute. The cleanest I think is by using spring session and providing a cookie serializer bean or using the latest release of spring session.
See this link for more options - Same-Site cookie in Spring Security

How to add X-FRAME-OPTIONS to some pages in Spring Security headers (Spring version 4.2.0)?

I have enabled Spring Security headers. By default X-FRAME-OPTIONS is DENY. But for some responses I should enable X-FRAME-OPTIONS as SAMEORIGIN. I have tried adding request matcher. But it adding both as X-Frame-Options (DENY, SAMEORIGIN). How to avoid default one (DENY) for request matcher?
My code is like this:
<security:headers disabled="false">
<security:header ref="xFrameOptionsHeaderWriter"/>
<security:content-security-policy policy-directives="script-src 'self' 'unsafe-inline' 'unsafe-eval'" />
<security:cache-control disabled="true"/>
</security:headers>
<bean id="xFrameOptionsHeaderWriter" class="org.springframework.security.web.header.writers.DelegatingRequestMatcherHeaderWriter">
<constructor-arg>
<bean class="org.springframework.security.web.util.matcher.NegatedRequestMatcher">
<constructor-arg>
<bean class="org.springframework.security.web.util.matcher.OrRequestMatcher">
<constructor-arg>
<list>
<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
<constructor-arg value="/**/flows/javax.faces.resource/dynamiccontent.properties/**" />
</bean>
</list>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter">
<constructor-arg value="SAMEORIGIN"/>
</bean>
</constructor-arg>
</bean>
Spring Security's header element adds a new HTTP header, but doesn't replace a HTTP header, see Spring Security Reference:
41.1.16 <header>
Add additional headers to the response, both the name and value need to be specified.
You have to disable the frame options, see Spring Security Reference:
41.1.13 <frame-options>
When enabled adds the X-Frame-Options header to the response, this allows newer browsers to do some security checks and prevent clickjacking attacks.
Your modified Spring Security headers configuration:
<security:headers disabled="false">
<security:frame-options disabled="true"/>
<security:header ref="xFrameOptionsHeaderWriter"/>
<security:content-security-policy policy-directives="script-src 'self' 'unsafe-inline' 'unsafe-eval'" />
<security:cache-control disabled="true"/>
</security:headers>

spring ldap security without xml

This documentation explains how to configure Spring-Security LDAP:
http://docs.spring.io/spring-security/site/docs/3.2.4.CI-SNAPSHOT/reference/htmlsingle/#ldap
3.4.5. Spring Bean Configuration
<bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://monkeymachine:389/dc=springframework,dc=org"/>
<property name="userDn" value="cn=manager,dc=springframework,dc=org"/>
<property name="password" value="password"/>
</bean>
<bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="contextSource"/>
<property name="userDnPatterns">
<list><value>uid={0},ou=people</value></list>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean
class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="contextSource"/>
<constructor-arg value="ou=groups"/>
<property name="groupRoleAttribute" value="ou"/>
</bean>
</constructor-arg>
</bean>
how can we achieve this without xml?
Here we have a sample which uses a local ldif file:
https://github.com/spring-projects/spring-security/blob/master/samples/ldap-jc/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
I've modified SecurityConfig.java as follows:
public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(ldap_url);
contextSource.setUrl(ldap_user);
contextSource.setPassword(ldap_password);
DefaultLdapAuthoritiesPopulator ldapAuthoritiesPopulator = new DefaultLdapAuthoritiesPopulator(contextSource, "ou=groups");
ldapAuthoritiesPopulator.setGroupRoleAttribute("ou");
LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth.ldapAuthentication();
ldapAuthenticationProviderConfigurer
.userDnPatterns("uid={0},ou=people")
.groupSearchBase("ou=groups")
.contextSource(contextSource)
.ldapAuthoritiesPopulator(ldapAuthoritiesPopulator);
}
}
but when I login using the web form, I get this error:
java.lang.NullPointerException
at java.util.Hashtable.<init>(Hashtable.java:296)
at org.springframework.ldap.core.support.AbstractContextSource.getAuthenticatedEnv(AbstractContextSource.java:499)
at org.springframework.ldap.core.support.AbstractContextSource.doGetContext(AbstractContextSource.java:114)
at org.springframework.ldap.core.support.AbstractContextSource.getContext(AbstractContextSource.java:110)
at org.springframework.security.ldap.authentication.BindAuthenticator.bindWithDn(BindAuthenticator.java:112)
Is there a similar documentation to http://docs.spring.io/spring-security/site/docs/3.2.4.CI-SNAPSHOT/reference/htmlsingle/#ldap explaining how to achieve this without spring xml?
You need to call
contextSource.afterPropertiesSet()
if you are using the class outside an application context (see the source and Javadoc for Spring LDAP's AbstractContextSource for more information). Either that or you can just make it an #Bean and Spring will call the method and initialize it for you.
Also
contextSource.setUrl(ldap_user);
doesn't look right. Shouldn't that be setUserDn ?

ldap spring security http basic auth

Can you please give me some links or solutions to manage my problem?
The problem is the follows. I have an LDAP server. How can I make http basic authorization through this LDAP server?
Thanks in advance.
You need to set up two different fetures of Spring Security:
LDAP Authentication. Actual config described here.
HTTP Basic Authentication. This feature is described here.
Thanks. I made such a config:
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/index.jsp" access="isAuthenticated()"/>
<security:http-basic/>
</security:http>
Then, BasicAuthenticationFilter
<bean id="basicAuthenticationFilter"
class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<property name="authenticationEntryPoint" ref="BauthenticationEntryPoint"/>
<property name="authenticationManager" ref="BauthenticationManager"/>
</bean>
Entry point and manager were descrbed like that:
<bean id="BauthenticationEntryPoint" class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
<property name="realmName" value="Name Of Your Realm"/>
</bean>
<bean id="BauthenticationManager" class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref local="ldapAuthProvider"/>
</list>
</property>
</bean>
And finally
<bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="contextSource"/>
<property name="userDnPatterns">
<list>
<value>sAMAccountName={0}</value>
</list>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean
class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="contextSource"/>
<constructor-arg value=""/>
</bean>
</constructor-arg>
</bean>
When I try to access /index.jsp I shown an stadart http auth window that requesting me my username and password. When I type it into form and press Enter nothing goes on - an auth window just reloads and nothing more.
Where I made a mistake?
Thanks.

Spring Security and LDAP MD5 authentication

I need to do spring security authentication where users whose passwords are stored in LDAP MD5 Hex encoding format using password comparison. For LDAP SHA encoding I can use LDAPShaPasswordEncoder. Which encoder should I use for LDAP MD5 encoding ?
<bean id="ldapAuthenticationProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator">
<constructor-arg ref="contextSource" />
<property name="passwordEncoder">
<bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
</property>
<property name="userDnPatterns">
<list>
<value>uid={0},ou=people</value>
</list>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean
class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="contextSource" />
<constructor-arg value="ou=groups" />
<property name="groupSearchFilter" value="(member={0})" />
<property name="rolePrefix" value="ROLE_" />
<property name="searchSubtree" value="true" />
<property name="convertToUpperCase" value="true" />
</bean>
</constructor-arg>
</bean>
There isn't one that supports MD5. You'd have to implement PasswordEncoder yourself. You can use LdapShaPasswordEncoder as a guide. It should be pretty straightforward, especially without salt involved.
You should probably start looking at migrating to a more secure system which includes salt in the hashes. For example, perhaps your directory can support multiple formats and you can use SSHA for new users or password changes.

Resources