Spring security with multiple login pages - spring

I am using Spring security to secure login to the application admin section with a username and password. But now my client need to have another login screen for the application clients section, where they will have their own usernames / passwords to login to the clients section. So far I've already implemented the admin section login successfully with the following spring-security.xml settings:
<security:http auto-config="true" use-expressions="true">
<security:form-login login-page="/login"
default-target-url="/admin/dashboard" always-use-default-target="true"
authentication-failure-url="/login/admin?error_msg=wrong username or password" />
<security:intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')" />
<security:logout logout-success-url="/login"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider
user-service-ref="adminServiceImpl">
</security:authentication-provider>
</security:authentication-manager>
I've searched the web a lot trying to find how I can add the client section login screen, intercept-url(s), security authentication provider but couldn't find any info, so can someone please help me with any link to any tutorial / example, guide on how to do so?
Thanks

According to the Spring Security docs:
From Spring Security 3.1 it is now possible to use multiple http
elements to define separate security filter chain configurations for
different request patterns. If the pattern attribute is omitted from
an http element, it matches all requests.
Each element creates a filter chain within the internal FilterChainProxy and the URL pattern that should be mapped to it. The elements will be added in the order they are declared, so the most specific patterns must again be declared first.
So, essentially you need two <http> elements each with a different pattern attribute.
There's a detailed tutorial here: https://blog.codecentric.de/en/2012/07/spring-security-two-security-realms-in-one-application/

I would use only one security:http, but register two UsernamePasswordLoginFilters.
This solution would be appropriate if the two Login-Pages belog to the same security-realm. (So if it does not matter on which Login-Page the user logs in). Of course you can still use roles to restrict the access for different parts of your application for different types of users.
This solution should be quite easy, because you will not need to handle two security:http sections.
The major drawback of this is: that you will have to decide on which of the two login pages a NOT logged in user gets redirected if he try to access an page that requires a login.

Example project of Spring MVC App with multiple login forms.
Three types of pages Normal/Member/Admin.
If you try to access member page you are brought to Member Login form.
If you try to access admin page you go to the Admin Login form.
https://github.com/eric-mckinley/springmultihttploginforms
Done using the ant regex request matcher in the seucrity xml config 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.xsd">
<global-method-security secured-annotations="enabled" />
<http name="member" pattern="/member/*" request-matcher="ant" auto-config="true" use-expressions="false">
<csrf disabled="true"/>
<intercept-url pattern="/member/home" access="ROLE_MEMBER" />
<intercept-url pattern="/member/account" access="ROLE_MEMBER" />
<intercept-url pattern="/member/orders" access="ROLE_MEMBER" />
<form-login login-page="/member-login" always-use-default-target="false"/>
<logout logout-url="/logout" logout-success-url="/home"/>
</http>
<http name="admin" request-matcher="regex" auto-config="true" use-expressions="false">
<csrf disabled="true"/>
<intercept-url pattern="/admin/home" access="ROLE_ADMIN" />
<intercept-url pattern="/admin/users" access="ROLE_ADMIN" />
<form-login login-page="/admin-login" always-use-default-target="false"/>
<logout logout-url="/logout" logout-success-url="/home"/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="password" authorities="ROLE_ADMIN" />
<user name="member" password="password" authorities="ROLE_MEMBER" />
<user name="super" password="password" authorities="ROLE_ADMIN,ROLE_MEMBER" />
</user-service>
</authentication-provider>
</authentication-manager>

http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<!-- <intercept-url pattern="/welcome/**" access="permitAll" /> <intercept-url
pattern="/admin*" access="hasRole('ROLE_ADMIN')" /> -->
<intercept-url access="hasRole('ROLE_USER')" pattern="/main*" />
<intercept-url pattern="/main*" access="hasRole('ROLE_USER')" />
<form-login login-page="/login" default-target-url="/login-success"
authentication-failure-url="/loginError" />
<!-- <session-management invalid-session-url="/login" session-fixation-protection="newSession">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management> -->
<logout logout-success-url="/login" delete-cookies="JSESSIONID" />
<csrf disabled="true" />
<headers>
<frame-options policy="SAMEORIGIN" />
</headers>
</http>
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/mobile/" access="permitAll" />
<intercept-url pattern="/mobile/login" access="permitAll" />
<!-- <intercept-url pattern="/welcome/**" access="permitAll" /> <intercept-url
pattern="/admin*" access="hasRole('ROLE_ADMIN')" /> -->
<intercept-url access="hasRole('ROLE_USER')" pattern="/main*" />
<intercept-url pattern="/main*" access="hasRole('ROLE_USER')" />
<form-login login-page="/mobile/login" default-target-url="/mobile/login-success"
always-use-default-target="true" authentication-failure-url="/mobile/login?error"
username-parameter="username" password-parameter="password" />
<logout delete-cookies="JSESSIONID" logout-success-url="/mobile/login" />
<csrf disabled="true" />
<headers>
<frame-options policy="SAMEORIGIN" />
</headers>
Here I have need two login forms common for all users. I have configured tag element as mentioned above in spring-security.xml.But it is not working. Please suggest me a solution

Related

Spring MVC Security permitAll to / but denyAll to /** not working

I have a Spring4 MVC application that is deployed on Wildfly10 and is configured using xml.
I have the following controller defined:
<mvc:view-controller path="/" view-name="/index" />
<mvc:view-controller path="/index" view-name="/index" />
And in Spring security define access:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/index" access="permitAll" />
...
<intercept-url pattern="/**" access="denyAll" />
<form-login login-page="/login" default-target-url="/dashboard"
always-use-default-target="true" authentication-failure-url="/loginfailed"
authentication-failure-handler-ref="authenticationFailureHandler" />
<logout logout-success-url="/index" />
<access-denied-handler ref="customAccessDeniedHandler"/>
</http>
If I remove the denyAll to /** intercept-url the application works as intended however adding it causes security to redirect root calls to the login page and not the index page!
Is there a way I can have permitAll access to the root (Redirects to /index) of my application and still denyAll to /** thus covering anything else that is not defined?
By Changing the pattern to <intercept-url pattern="/.+" access="denyAll" /> as commented by Vasan got it working. below is an example of the change
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/index" access="permitAll" />
...
<intercept-url pattern="/.+" access="denyAll" />
<form-login login-page="/login" default-target-url="/dashboard"
always-use-default-target="true" authentication-failure-url="/loginfailed"
authentication-failure-handler-ref="authenticationFailureHandler" />
<logout logout-success-url="/index" />
<access-denied-handler ref="customAccessDeniedHandler"/>

Keycloak and Spring Security

Can anyone please show me how to migrate keycloak and spring security. I already follow step in http://keycloak.github.io/docs/userguide/keycloak-server/html/ch08.html#spring-security-adapter. but it dint work. Do i need to write my own provider?
my original spring-security.xml
<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:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd"
>
<http use-expressions="true">
<intercept-url pattern="/index" access="isAuthenticated()" />
<intercept-url pattern="/tasks" access="isAuthenticated()" />
<intercept-url pattern="/dashboard" access="isAuthenticated()" />
<intercept-url pattern="/resetPassword" access="isAuthenticated()" />
<intercept-url pattern="/settings/**" access="isAuthenticated()" />
<intercept-url pattern="/" access="isAuthenticated()" />
<intercept-url pattern="/sam/**" access="hasRole('mym_security_permission-002')" />
<intercept-url pattern="/admin/**" access="hasRole('mym_security_permission-005')" />
<intercept-url pattern="/committee/**" access="isAuthenticated()" />
<intercept-url pattern="/member/**" access="isAuthenticated()" />
<intercept-url pattern="/attachment/download/**" access="isAuthenticated()" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/login"
login-processing-url="/perform_login"
authentication-failure-url="/login?error"
authentication-success-handler-ref="customAuthenticationSuccessHandler"
username-parameter="username"
password-parameter="password"
always-use-default-target="true"
/>
<!--success-handler-ref="customLogoutSuccessHandler" -->
<logout
logout-url="/perform_logout"
delete-cookies="true"
invalidate-session="true"
/>
<!-- enable csrf protection -->
<csrf/>
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
</http>
<authentication-manager alias="authenticationManager" erase-credentials="false">
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>
</beans:beans>
i change this xml to xml that provided by keycloak user guide. And i put keycloak.json in web-inf.
After i make the configuration on keycloak. i try to access my page then error page like below will appear:
We're sorry ...
Invalid parameter: redirect_uri
return url:http://localhost:8080/auth/realms/Meeting/protocol/openid-connect/auth?response_type=code&client_id=mym-apps&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2FApp%2Fsso%2Flogin&state=0%2Fd21c7ae9-b041-43e5-8135-8150e9895ee5&login=true
i already resolved this problem. I just fix my “valid redirect URIs” to http://localhost:8080/app/* and /app/*
please add web orgins in keycloak client

Spring security filter called twice

I just realized that the OAuth2AuthenticationProcessingFilter is called twice when accessing the protected resource /me in my OAuth auth server:
An abstract of my xml config:
<http pattern="/me/**" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint" use-expressions="true"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/me/**"
access="hasRole('ROLE_USER') and #oauth2.clientHasRole('ROLE_CLIENT') and #oauth2.hasScope('read')" />
<!-- Protect the resource with oauth by using the resourceServerFilter-->
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<expression-handler ref="oauthWebExpressionHandler" />
<request-cache ref="requestCache" />
</http>
and
<http access-denied-page="/login?authorization_error=true" disable-url-rewriting="true"
xmlns="http://www.springframework.org/schema/security" use-expressions="true">
<intercept-url pattern="/oauth/**" access="hasRole('ROLE_USER')" />
<!-- /secure/** is protected and for users only. Don't allow oauth2 clients to access protected UI pages.
Put all secured web pages under /secure (e.g. /secure/profile) -->
<intercept-url pattern="/secure/**" access="hasRole('ROLE_USER') and #oauth2.denyOAuthClient()" />
<!-- Allow access to everything else -->
<intercept-url pattern="/**" access="permitAll()" />
<form-login authentication-failure-handler-ref="authenticationFailureHandler"
login-page="/login" login-processing-url="/login.do" authentication-success-handler-ref="customAuthenticationSuccessHandler" />
<!-- See also LogoutFilterPostProcessor -->
<logout logout-url="/logout.do" delete-cookies="JSESSIONID" success-handler-ref="lclSessionCookieDeletingLogoutHandler" />
<anonymous />
<!-- Allow the usage of oauth web expressions (e.g. '#oauth2.denyOAuthClient()') -->
<expression-handler ref="oauthWebExpressionHandler" />
<request-cache ref="requestCache" />
<csrf token-repository-ref="csrfTokenRepository"/>
<remember-me services-ref="persistentTokenBasedRememberMeServices" key="abcdefg"/>
<custom-filter ref="forcePasswordResetFilter" before="REQUEST_CACHE_FILTER" />
</http>
It seems as if the filters from the second <http/> section (e.g. the ForcePasswordResetFilter) are also applied when /me is called - which is not what I'd expect. Any ideas why not only the first <http/> section is considered which matches /me/**?

spring session redirect after timeout

I have configured spring security for login form. Everything works fine except session timeout.
When session timeouts I want to redirect to login page. Instead I am redirected to homepage. Below is part of my security xml .Can anyone suggest anything via xml configuration
<http auto-config="true" use-expressions="true">
<!-- This settings is for IE. Default this setting is on migrateSession.
When IE tries to migrate the session, the auth cookie does not migrate, resulting
in a nice login screen again, after you've logged in. This setting ensures
that the session will not be invalidated, and thus IE will still work as
expected. -->
<session-management session-fixation-protection="none" />
<intercept-url pattern="/login.jsp" access="permitAll" />
<intercept-url pattern="/css/*" access="permitAll" />
<intercept-url pattern="/img/**" access="permitAll" />
<intercept-url pattern="/js/**" access="permitAll" />
<intercept-url pattern="/lib/**" access="permitAll" />
<intercept-url pattern="/fonts/**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<form-login login-page="/login.jsp" login-processing-url="/j_spring_security_check"
default-target-url="/index.html" always-use-default-target="true"
authentication-failure-url="/login?error=true" username-parameter="username"
password-parameter="password" authentication-failure-handler-ref="authenticationFailureHandler" />
<logout logout-success-url="/login.jsp" logout-url="/j_spring_security_logout" invalidate-session="true" />
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
<session-management invalid-session-url="/login.jsp" />
<!-- disable csrf protection -->
<csrf disabled="true" />
</http>
I have added timeout in web.xml as
<session-config>
<session-timeout>1</session-timeout>
</session-config>

spring security redirects to last requested page after login session timeout

I have implemented spring security for login to my web portal. It works fine except for one issue. I have set session timeout to 5 min. Once timeout happpens and then user click any URL, it gets redirected to logout page.
But when user re autheticates, user directly lands on the last access page instead of home page which is default target URL.
Spring security file is as below:
<?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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<http auto-config="true">
<intercept-url pattern="/index.jsp" access="ROLE_ADMIN,ROLE_USER" />
<intercept-url pattern="/home.html" access="ROLE_ADMIN,ROLE_USER" />
<intercept-url pattern="/mdm/accessToken.html" access="ROLE_USER" />
<intercept-url pattern="/mdm/enroll.html" access="ROLE_USER" />
<intercept-url pattern="/mdm/installApp.html" access="ROLE_USER" />
<intercept-url pattern="/mdm/checkStatus.html" access="ROLE_USER" />
<intercept-url pattern="/mdm/searchDevice.html" access="ROLE_USER" />
<intercept-url pattern="/admin/*" access="ROLE_ADMIN" />
<intercept-url pattern="/account/*" access="ROLE_ADMIN" />
<intercept-url pattern="/user/*" access="ROLE_USER" />
<form-login login-page="/login.html" default-target-url="/home.html"
authentication-failure-url="/loginfailed.html" />
<logout logout-url="/logout.html" logout-success-url="/logoutSuccess.html" invalidate-session="true" />
<anonymous username="guest" granted-authority="ROLE_GUEST" />
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
<session-management invalid-session-url="/logout.html" />
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select USER as username, password, 'true' as enabled from TBL_USER_MASTER where user=?"
authorities-by-username-query="select um.USER as username , rm.ROLE_NAME as authorities from TBL_USER_MASTER um,TBL_ROLE_MASTER rm
where um.USER=? and um.role_id=rm.role_id" />
<password-encoder hash="md5"/>
</authentication-provider>
</authentication-manager>
</beans:beans>
Add the always-use-default-target attribute to your form-login tag.
<form-login always-use-default-target="true" />
If set to true, the user will always start at the value given by default-target-url, regardless of how they arrived at the login page. Maps to the alwaysUseDefaultTargetUrl property of UsernamePasswordAuthenticationFilter. Default value is false.
In Grails, this setting solves the problem in Config.groovy
grails.plugin.springsecurity.successHandler.alwaysUseDefault = true

Resources