Use of custom authenticationManager and daoAuthenticationProvider beans - spring

i am running small spring mvc 3 application (Spitter from spring in action 3 book ) which is downloaded from github . In spring security file they have written beans for authenticationManager and daoAuthenticationProvider like this
<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-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/home*" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>
<intercept-url pattern="/spitters/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" />
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
<form-login login-processing-url="/static/j_spring_security_check"
login-page="/login" authentication-failure-url="/login?login_error=t" />
<logout logout-success-url="/home"/>
</http>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService" />
</beans:bean>
<beans:bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="daoAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
<password-encoder hash="md5" />
</authentication-provider>
</authentication-manager>
or this link https://github.com/karolgornicki/spitter/blob/master/src/main/webapp/WEB-INF/spring-security.xml
What is the use of these two beans authenticationManager and daoAuthenticationProvider . After commenting also this application works perfectly .

I think the AuthenticationManager delegates the fetching of persistent user information to one or more AuthenticationProviders. The authentication-providers (DaoAuthenticationProvider, JaasAuthenticationProvider, LdapAuthenticationProvider, OpenIDAuthenticationProvider for example) specialize in accessing specific user-info repositories. Something else is mentioned in this part of the reference manual. It says:
You may want to register additional AuthenticationProvider beans with the ProviderManager and you can do this using the element with the ref attribute, where the value of the attribute is the name of the provider bean you want to add.
In other words, you can specify multiple AuthenticationProviders, for example one that looks for users in an LDAP database and another that looks in an SQL database.

Related

Spring service returns 200 but getting 404 in postman

I am new into Spring REST, what I am trying to do is creating REST endpoints for a project. Also I am implementing JWT Spring Security into the service as per project requirement.
The first REST endpoint is /LOGIN, after user credentials are verified through this service a token is assigned to the client in the header. This token will hold the session for any further REST call authentication. This service is doing its work as expected.
The next REST service to be called is GET_CURRENT_USER, which does the work of validating the token and then further jobs. I am using the token in postman to call the GET_CURRENT_USER service, the service code works just fine and I am returning code 200 and the expected JSON through my service.
But at postman I am getting a 404 not found error. What I have tried:
Removed CORS filters
Added index.jsp to project, I get the index page in postman and not the 404 (but that doesn't help).
Tracing further calls after GET_CURRENT_USER, but that leads so many further calls and can't trace what exactly overrides my response with 404.
Tried to play with GET and POST methods in code and POSTMAN but no luck. I am using all the headers required and other stuff.
Can't figure out where could the problem located. I cannot share code, but can answer all questions related.
Any help will be appreciated.
The 404 error went away when I provided default index.jsp, which was missing in my project. But it didn't solved my problem as I needed Rest response(JSON) in result. What I learnt from long code-debugging of DispatcheServlet and Filter chains etc.. that in case we need JSON response after rest call, and we don't intend to send any view-response(like jsps), we should implement AuthenticationSuccessHandler and return void.
Initially my spring-secuyrity.xml was as follows:
<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.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<global-method-security pre-post-annotations="enabled" />
<http pattern="/abc/login" security="none"/>
<http pattern="/abc/**" entry-point-ref="jwtAuthenticationEntryPoint" create-session="stateless">
<csrf disabled="true"/>
<custom-filter before="FORM_LOGIN_FILTER" ref="jwtAuthorizationTokenFilter"/>
</http>
<beans:bean id="jwtAuthorizationTokenFilter" class="com.abc.xyz.controller.JwtAuthorizationTokenFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="<MyUserDetailsService>">
<password-encoder ref="encoder" />
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder"/>
<class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="10" />
</beans:bean>
</beans:beans>
I changed it to as follows:
<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.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<global-method-security pre-post-annotations="enabled" />
<http pattern="/abc/login" security="none"/>
<http pattern="/abc/**" entry-point-ref="jwtAuthenticationEntryPoint" create-session="stateless">
<csrf disabled="true"/>
<custom-filter before="FORM_LOGIN_FILTER" ref="jwtAuthorizationTokenFilter"/>
</http>
<beans:bean id="jwtAuthorizationTokenFilter" class="com.abc.xyz.controller.JwtAuthorizationTokenFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationSuccessHandler" ref="authSuccessHandler" />
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="<MyUserDetailsService>">
<password-encoder ref="encoder" />
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="10" />
</beans:bean>
<!-- Auth Success handler -->
<beans:bean id="authSuccessHandler" class="com.abc.xyz.controller.JwtAuthenticationSuccessHandler" />
</beans:beans>
JWT:
#Component
public class JwtAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
// Not to do anything
}
}
In the above code where we are setting 2 bean properties, that need not required to be in the JwtAuthorizationTokenFilter
The JwtAuthorizationTokenFilter extends to AbstractAuthenticationProcessingFilter
and I believe with reflection it sets authenticationManager, successHandler of the AbstractAuthenticationProcessingFilter
These are the following 2 methods I see in the AbstractAuthenticationProcessingFilter
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void setAuthenticationSuccessHandler(
AuthenticationSuccessHandler successHandler) {
Assert.notNull(successHandler, "successHandler cannot be null");
this.successHandler = successHandler;
}

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

How to change login to work on get instead of post spring security

I have following spring security configuration, How do i change to it login to work based on http GET instead of POST, so that login url will be something like:
*http://localhost/myapp/j_security_check?j_username=test&j_password=test*
This is my configuration xml file
<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-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http access-denied-page="/WEB-INF/pages/accessdenied.jsp" auto-config="true" use-expressions="true">
<intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" method="GET"/>
<intercept-url pattern="/user" access="hasRole('ROLE_USER')"/>
<form-login
always-use-default-target="true"
authentication-failure-url="/loginfailed"
default-target-url="/landing"
login-page="/login" />
<logout
invalidate-session="true"
logout-success-url="/login?logout" />
<form-login
login-page="/login"
default-target-url="/welcome"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/login?logout" /> -->
</http>
<beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService" ></beans:property>
</beans:bean>
<beans:bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager" >
<beans:property name="providers">
<beans:list>
<beans:ref local="daoAuthenticationProvider"/>
</beans:list>
</beans:property>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
</authentication-provider>
</authentication-manager>'
</beans:beans>
For more information, If you want to send your form with method post through spring security. You need to add this token to your form.
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />

Rolevoter not working

I tried to implement a role hierarchy but it doesn't want to work. everything else works perfectly except that. Here is my spring-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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"
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-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Enable method-level security via annotations -->
<global-method-security secured-annotations="enabled" pre-post-annotations="enabled"/>
<!-- Configure form-based authentication -->
<http auto-config="true" use-expressions="true" entry-point-ref="securityEntryPoint" >
<intercept-url pattern="/resources/script/jquery-ui/**" access="permitAll" />
<intercept-url pattern="/resources/script/jquery*" access="permitAll" />
[....]
<intercept-url pattern="/**" access="isAuthenticated()" />
<session-management invalid-session-url="/login.jsp?info=invalid" >
<concurrency-control max-sessions="1" session-registry-alias="sessionRegistry" expired-url="/login.jsp?info=expired" />
</session-management>
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=credentials" />
<logout logout-url="/logout" invalidate-session="true" logout-success-url="/login.jsp" />
</http>
<!-- Configure a spring security logger listener for logging authentication attempts. -->
<beans:bean id="loggerListener" class="org.springframework.security.access.event.LoggerListener"/>
<!-- Configure a delegating entry point -->
<beans:bean id="securityEntryPoint" class="org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint">
<!-- Requests of type text/html or application/xhtml+xml should be handled by form-based authentication -->
<beans:constructor-arg>
<beans:map>
<beans:entry>
<beans:key>
<beans:bean class="com.test.security.AcceptHeaderRequestMatcher"/>
</beans:key>
<beans:bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/login.jsp" />
</beans:bean>
</beans:entry>
</beans:map>
</beans:constructor-arg>
<!-- Otherwise use BASIC authentication by default -->
<beans:property name="defaultEntryPoint">
<beans:bean class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
<beans:property name="realmName" value="test Web Service" />
</beans:bean>
</beans:property>
</beans:bean>
<!-- Configure an authentication manager via our defaultUserService -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="defaultUserService">
<password-encoder hash="md5" />
</authentication-provider>
</authentication-manager>
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<beans:property name="decisionVoters">
<beans:list>
<beans:ref bean="roleVoter" />
<beans:ref bean="authenticatedVoter" />
</beans:list>
</beans:property>
<beans:bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<beans:constructor-arg ref="roleHierarchy" />
<beans:property name="rolePrefix" value="" />
</beans:bean>
<beans:bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<beans:property name="hierarchy">
<beans:value>
PERM_READ_ALL_USER_LIST > PERM_READ_USER_LIST
</beans:value>
</beans:property>
</beans:bean>
If i try to access a resource for which PERM_READ_USER_LIST is required, #PreAuthorize("hasRole('PERM_READ_USER_LIST')"), with a user who has the PERM_READ_ALL_USER_LIST it doesn't work, but if he has PERM_READ_USER_LIST, it works. So obviously the rolevoter is not doing its job but I don't get why...
Thank you.
You have to specify the hirarchy explicite for the MethodSecurityExpressionHandler.
See this Stack Overflow question and answer for more details.
How to use role-hierarchy in Spring Security 3 with Spring EL?

WARNING: Possible error: Filters are both instances of org.springframework.security.web.session.SessionManagementFilter

I'm developing a web application using Spring MVC and Spring security. Actually I do not have an error but a warning instead. It looks like this warning will come up with an error soon:)
When I try to deploy my application, it is deployed successfully but a warning appears:
"WARNING: Possible error: Filters at position 7 and 8 are both instances of org.springframework.security.web.session.SessionManagementFilter"
I have both sessionManagementFilter and preAuthenticationFilter in my spring-security xml.
I've googled the problem but it looks like there is not anybody that gets the same warning. What is this warning? Will it cause an error and how can I fix it? I cannot solve the issue, I'll be appreciated if someone helps me. Thank you.
My spring-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http create-session="never" use-expressions="true" auto-config="false" entry-point-ref="preAuthenticatedProcessingFilterEntryPoint">
<custom-filter ref="sessionManagementFilter" before="SESSION_MANAGEMENT_FILTER" />
<intercept-url pattern="/restricted/**" access="isAuthenticated()" />
<custom-filter position="PRE_AUTH_FILTER" ref="myPreAuthFilter" />
<session-management>
<concurrency-control max-sessions="1" error-if-maximum-exceeded="false" expired-url="/invalid-session.xhtml?concurrent=true" />
</session-management>
<logout logout-url="/cikis" invalidate-session="true" delete-cookies="JSESSIONID" success-handler-ref="myLogoutHandler" />
</http>
<beans:bean id="myLogoutHandler" class="com.test.MyLogoutHandler" />
<beans:bean id="userDetailsServiceImpl" class="com.test.UserDetailsServiceImpl" />
<beans:bean id="preAuthenticatedProcessingFilterEntryPoint" class="com.test.ForbiddenURLEntryPoint" />
<beans:bean id="preAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<beans:property name="preAuthenticatedUserDetailsService" ref="userDetailsServiceImpl" />
</beans:bean>
<beans:bean id="myPreAuthFilter" class="com.test.MyPreAuthenticationFilter">
<beans:property name="authenticationManager" ref="appControlAuthenticationManager" />
</beans:bean>
<beans:bean id="sessionManagementFilter" class="org.springframework.security.web.session.SessionManagementFilter">
<beans:constructor-arg name="securityContextRepository" ref="httpSessionSecurityContextRepository" />
<beans:property name="invalidSessionStrategy" ref="jsfRedirectStrategy" />
</beans:bean>
<beans:bean id="jsfRedirectStrategy" class="com.test.JsfRedirectStrategy"/>
<beans:bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/>
<authentication-manager alias="appControlAuthenticationManager">
<authentication-provider ref="preAuthenticationProvider" />
</authentication-manager>
</beans:beans>
Spring security includes SessionManagementFilter by default on startup.
If you want to specify your own SESSION_MANAGEMENT_FILTER you have to disable session-fixation-protection, just type:
<http create-session="never" use-expressions="true" auto-config="false" entry-point-ref="preAuthenticatedProcessingFilterEntryPoint">
<session-management session-fixation-protection="none"/>
<custom-filter ref="sessionManagementFilter" before="SESSION_MANAGEMENT_FILTER" />
<...>
</http>

Resources