Spring Security logins fail when migrating Spring mvc projects to Spring boot - spring

I migrated a working Spring mvc project to Spring boot. Refer to Section 81.3 of this document and this question. Modules are working properly, but SpringSecurity can not login.
In the open when the home page will jump to the login page, and then log in after the home page and login page repeatedly redirects are 302 HTTP response, and then an error ERR_TOO_MANY_REDIRECTS.
After debugging, when I log on Custom UserDetailsService can correctly find and return UserDetails, custom SimpleUrlAuthenticationSuccessHandler also called onAuthenticationSuccess normally, but in the filter chain in a call FilterSecurityInterceptor this filter, SpringSecurity login status is cleared, I And does not call logout of the HTTP request.
I carefully check that in the set create-session = "stateless" clear the login status is normal, but it seems that my application can not be properly re-authorized. After the request has been SecurityContextHolder.getContext().GetAuthentication().GetPrincipal() has been anonymousUesr (Cookies correctly passed loginKey = b3668242-574a-498e-bd03-243e28dc805c; SESSIONID_HAP = 98963370-8561-40a2-9898-a5e80f7d1186).
This project is more complex, the following is an important part of the configuration and code, and their role is basically the original and the equivalent.
SpringBootConfigure.java SpringBoot enter point.
#SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
#ImportResource({"classpath:/spring/applicationContext*.xml","classpath:/spring/appServlet/servlet*.xml"})
public class SpringBootConfigure {
...
}
spring security xml config
<http access-decision-manager-ref="accessDecisionManager">
<csrf disabled="true"/>
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/login.html" access="permitAll" />
<intercept-url pattern="/verifiCode" access="permitAll" />
<intercept-url pattern="/common/**" access="permitAll" />
<intercept-url pattern="/boot/**" access="permitAll" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<access-denied-handler error-page="/403.html"/>
<form-login login-page='/login' authentication-success-handler-ref="successHandler"
authentication-failure-handler-ref="loginFailureHandler"/>
<custom-filter ref="captchaVerifierFilter" before="FORM_LOGIN_FILTER"/>
<logout logout-url="/logout"/>
<headers defaults-disabled="true">
<cache-control/>
</headers>
</http>
<beans:bean id="loginFailureHandler" class="com.hand.hap.security.LoginFailureHandler"/>
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.web.access.expression.WebExpressionVoter"/>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder ref="passwordManager"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="captchaVerifierFilter" class="com.hand.hap.security.CaptchaVerifierFilter">
<beans:property name="captchaField" value="verifiCode"/>
</beans:bean>
<beans:bean id="successHandler" class="com.hand.hap.security.CustomAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/index"/>
</beans:bean>

Related

Spring security custom session timeout url

Currently I'm working on spring security app, where I need user to be redirected to a custom lock page when session is expired which only contains a password field. (username might be placed in a hidden field inside the login form.) I need to pass username extracted from UserDetails instance and redirect to this custom URL once login session timed out.
I tried to use concurrency-control -> expired-url but it did not give me successful result.
I will be very helpful if you could give some guidence to achieve this.
Is this possible to achieve since I will need to have customized behavior on authentication-failure-url too? (when a given password is incorrect).
Update 1:
My current configuration:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.2.xsd">
<http auto-config="true" create-session="always" use-expressions="true" entry-point-ref="authEntryPoint" >
<form-login
login-page="/login"
default-target-url="/home"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password"
always-use-default-target="true"/>
<logout invalidate-session="true" logout-success-url="/login" delete-cookies="JSESSIONID"/>
<session-management session-fixation-protection="newSession" invalid-session-url="/"
session-authentication-error-url="/login">
<concurrency-control session-registry-alias="sessionRegistry" max-sessions="10"
expired-url="/lock-screen" error-if-maximum-exceeded="true"/>
</session-management>
<intercept-url pattern="/" access="hasRole('ROLE_LOGIN')"/>
<intercept-url pattern="/profile" access="hasRole('ROLE_LOGIN')"/>
<intercept-url pattern="/home" access="hasRole('ROLE_LOGIN')"/>
<access-denied-handler error-page="/403"/>
</http>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="10"/>
</beans:bean>
<beans:bean id="authEntryPoint" class="com.myapp.admin.security.web.authentication.AjaxSupportedLoginUrlAuthenticationEntryPoint"
scope="singleton">
<beans:constructor-arg name="loginFormUrl" value="/login"/>
</beans:bean>
I'm expecting something like this:
user Login screen:
https://i.stack.imgur.com/vTPkF.png
Lock screen after logged in user being inactive for while:
https://i.stack.imgur.com/DY9kG.png

spring security session times out

I am using spring security 4.1, the issue that i face is when i try to login i am sent back to the session expired page several times. I have tried multiple things like adding my own HttpSessionListener also by adding
org.springframework.security.web.session.HttpSessionEventPublisher
but the session keeps expiring. I read in one of the questions the explanation for such behavior
"It's possible for Spring Security to invalidate session in some cases (for example, after logging in, the user gets a new HttpSession)."
I used Fiddler tool to see what is happening, i see user is authenticated but is redirected to session expired page instantly. I want to allow same user to login as many times as he wants. I also read in some places that it will help to move to spring 3.x but i assume it might be for cases when older version of spring was used.
please suggest. Thank You
<http auto-config="true" use-expressions="true"
authentication-manager-ref="authenticationManager">
<session-management
invalid-session-url="/login?eventType=sessionTimedOut"
session-fixation-protection="none"
/>
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/*" access="hasAnyAuthority('FF_USER','FF_ADMIN')" />
<form-login login-page="/login"
authentication-success-handler-ref="authenticationSuccessHandler"
authentication-failure-handler-ref="customAuthenticationFailureHandler"
login-processing-url="/j_spring_security_check"
username-parameter="j_username"
password-parameter="j_password"
/>
<logout invalidate-session="false" logout-success-url="/login?eventType=logout"
logout-url="/j_spring_security_logout" delete-cookies="JSESSIONID"/>
<csrf token-repository-ref="csrfTokenRepository" />
</http>
<beans:bean id="csrfTokenRepository"
class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository">
<beans:property name="headerName" value="X-XSRF-TOKEN" />
</beans:bean>
<beans:bean id="authenticationSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/home"/>
<beans:property name="alwaysUseDefaultTargetUrl" value="true"/>
</beans:bean>
<beans:bean id="customAuthenticationFailureHandler" class="*.*.CustomAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login?eventType=error"></beans:property>
<beans:property name="baseFailureUrl" value="/login?eventType=error"></beans:property>
</beans:bean>
<beans:bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<beans:constructor-arg>
<beans:list>
<beans:ref bean="ldapAuthenticationProvider" />
</beans:list>
</beans:constructor-arg>
<beans:property name="eraseCredentialsAfterAuthentication"
value="true" />
</beans:bean>
<http>
<logout delete-cookies="JSESSIONID" />
</http>
Unfortunately this can't be guaranteed to work with every servlet container, so you will need to test it in your environment[8].
So you need to add a customer logout handler that implements LogoutHandler to LogoutFilter handlers.
<http auto-config="true" use-expressions="true" authentication-manager-ref="authenticationManager">
...
<custom-filter ref="logoutFilter" position="LOGOUT_FILTER" />
...
</http>
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg name="logoutSuccessUrl" value="/login?eventType=logout" />
<!-- implement LogoutHandler, Websphere log out -->
<constructor-arg name="handlers" ref="{customer logout }" />
<property name="filterProcessesUrl" value="/j_spring_security_logout" />
</bean>

Spring Security Pre-Authentication / Login

I did a proof of concept with Spring Security in order to perform pre authentication by using the PRE_AUTH_FILTER filter. It worked OK, but I'd like to know if I can redirect to the login page if the this filter does not work, because I get HTTP 403.
I mean, if the initial request does not contain the SM_USER field in the header, how can I redirect to the login page? I need to consider these two scenarios (when it contains the field - SM_USER -, and when not) and I was not able to get it working. Any ideas about it?
Pra-authentication works smoothly with login authentication in Spring Security. You just setup a working login form configuration, and add the PRE_AUTH_FILTER filter.
Spring only redirects to login page, if after passing the authentication filters, it detects that user is not authenticated when he should be. So if the request contains the expected field in header, the user will be authenticated by the PRE_AUTH_FILTER filter, and will not go to the login page. But if it does not contain one, Spring security will detect a lack of authentication and redirect to login page.
These are my settings:
<http auto-config="true" use-expressions="true" entry-point-ref="http403EntryPoint">
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/logout" access="permitAll" />
<intercept-url pattern="/accessdenied" access="permitAll" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<custom-filter before="PRE_AUTH_FILTER" ref="siteminderFilter" />
<form-login login-page="/login" default-target-url="/list" authentication-failure-url="/accessdenied" />
<logout logout-success-url="/logout" />
</http>
<beans:bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<beans:property name="principalRequestHeader" value="SM_USER"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="exceptionIfHeaderMissing" value="false" />
</beans:bean>
<beans:bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<beans:property name="preAuthenticatedUserDetailsService">
<beans:bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<beans:property name="userDetailsService" ref="customUserDetailsService"/>
</beans:bean>
</beans:property>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="employeeDAO" />
<authentication-provider ref="preauthAuthProvider" />
</authentication-manager>
<beans:bean id="customUserDetailsService" class="com.test.security.CustomUserDetailsService"></beans:bean>
<beans:bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"></beans:bean>

creating <intercept-url pattern> dynamically with spring security 3

Hi I am new to Spring security 3 but with the help of this site I successfully developed Authentication and Authorization. Now I want to remove intercept-url pattern from my context-security.xml. I am looking to fetch authorities for specific user form database and create dynamically. Here i did...
in context-security.xml
<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<custom-filter before="FIRST" ref="requestMappings"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="accessDecisionManager" ref="accessDecisionManager" />
<beans:property name="objectDefinitionSource" ref="requestMappings" />
</beans:bean>
<beans:bean id="requestMappings" class="com.nmmc.common.security.repository.RequestMappingFactoryBean" />
<http auto-config="true" once-per-request="false">
<!-- Restrict URLs based on role -->
<intercept-url pattern="/login.works" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/login/validate.works" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/css/*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<form-login login-page="/login.works" login-processing-url="/j_spring_security_check"
default-target-url="/login/validate.works"
authentication-failure-url="/login.works" />
<logout logout-url="/j_spring_security_logout"
logout-success-url="/login.works" invalidate-session="true" />
<session-management invalid-session-url="/login.works"
session-fixation-protection="none">
<concurrency-control max-sessions="50"
error-if-maximum-exceeded="true" />
</session-management>
</http>
<authentication-manager>
<authentication-provider ref="customAuthenticationProvider"></authentication-provider>
</authentication-manager>
<beans:bean id="customAuthenticationProvider"
class="com.nmmc.common.security.repository.CustomAuthenticationProvider"></beans:bean>
in RequestMappingFactoryBean
import org.springframework.beans.factory.FactoryBean;
public class RequestMappingFactoryBean implements FactoryBean{
private final static String EOL = System.getProperty("line.separator");
public Object getObject() throws Exception
{
StringBuffer sb = new StringBuffer();
sb.append("CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON");
sb.append(EOL);
sb.append("PATTERN_TYPE_APACHE_ANT");
sb.append(EOL);
sb.append("/**login.works=IS_AUTHENTICATED_ANONYMOUSLY");
sb.append(EOL);
sb.append("/user/**=ROLE_ADMIN");
return sb.toString();
}
public Class getObjectType()
{
return String.class;
}
public boolean isSingleton()
{
return true;
}
}
Also when I remove ref from
<custom-filter before="FIRST" ref="requestMappings"/>
then it gives error that ref must be define also if i define it and run my app it gives error like
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Security namespace does not support decoration of element [custom-filter]
thats why i define as given.
Is there any changes in my code to run it?
Read the first answer at How to dynamically decide <intercept-url> access attribute value in Spring Security?
It has an outline of the solution.

Infinite loop using Spring Security - Login page is protected even though it should allow anonymous access

I have a Spring application (Spring version 2.5.6.SEC01, Spring Security version 2.0.5) with the following setup:
web.xml
<welcome-file-list>
<welcome-file>
index.jsp
</welcome-file>
</welcome-file-list>
The index.jsp page is in the WebContent directory and simply contains a redirect:
<c:redirect url="/login.htm"/>
In the appname-servlet.xml, there is a view resolver to point to the jsp pages in WEB-INF/jsp
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
In the security-config.xml file, I have the following configuration:
<http>
<!-- Restrict URLs based on role -->
<intercept-url pattern="/WEB-INF/jsp/login.jsp*" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/WEB-INF/jsp/header.jsp*" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/WEB-INF/jsp/footer.jsp*" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/login*" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/index.jsp" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/logoutSuccess*" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/css/**" filters="none" />
<intercept-url pattern="/images/**" filters="none" />
<intercept-url pattern="/**" access="ROLE_ANONYMOUS" />
<form-login login-page="/login.jsp"/>
</http>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource" />
</authentication-provider>
However, I can't even navigate to the login page and get the following error in the log:
WARNING: The login page is being
protected by the filter chain, but you
don't appear to have anonymous
authentication enabled. This is almost
certainly an error.
I've tried changing the ROLE_ANONYMOUS to IS_AUTHENTICATED_ANONYMOUSLY, changing the login-page to index.jsp, login.htm, and adding different intercept-url values, but I can't get it so the login page is accesible and security applies to the other pages. What do I have to change to avoid this loop?
The problem was I was missing the
<anonymous />
tag in the http section of the security-config.xml file so I wasn't able to get to the login page anonymously. Once I added this, I was able to get to the login page and authenticate.
You should set auto-config attribute:
<http auto-config="true">
<intercept-url ... />
...
</http>
EDIT:
To avoid problems with multiple UserDetailsService you probably can replace your <authentication-provider> declaration by something like this:
<authentication-provider user-service-ref = "userService" />
<jdbc-user-service id = "userService" data-source-ref="dataSource" />
<intercept-url pattern="/login*" access="ROLE_ANONYMOUS" />
you could have replaced that with
<intercept-url pattern="/login*" filter="none" />
because spring security is right, it doesn't make any sense to protect the login page
you can use another sec:http section
<sec:http pattern="/login" security="none" />
or you can use
<sec:intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" />

Resources