my thought is to create a website where you can authenticate in two different ways: from a typical login (SpringSecurity) and from a CAS server.
A user reaching any protected page should be redirected to /login page, where Username and Password are needed to proceed further. Then we have a choice: clicking on "Login" button will authenticate the user ONLY for this site; otherwise clicking on "Login with CAS" will redirect the User on the Login of the CAS-server (or maybe, better: directly submit Username and Password to the CAS server) and then redirected to the web application.
Either from local or CAS, a user successfully logged in must have access to the site. How can I do this? For now, I only got the local authentication - and it's working.
spring-security.xml
<http auto-config="true">
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/static/**" access="permitAll" />
<intercept-url pattern="/srv/**" access="permitAll" />
<intercept-url pattern="/admin" access="hasAnyRole('ROLE_ADMIN')" />
<intercept-url pattern="/**" access="hasAnyRole('ROLE_USER', 'ROLE_ADMIN')" />
<...>
</http>
<form-login login-page='/login'
default-target-url="/home"
authentication-success-handler-ref="authSuccessHandler"
authentication-failure-url="/login?error=true" />
<logout logout-success-url="/login" />
<session-management invalid-session-url="/login">
<concurrency-control expired-url="/login" />
</session-management>
</http>
<authentication-manager>
<authentication-provider ref="authProvider"/>
</authentication-manager>
I'm not using SpringBoot; i got SpringSecurity 4.0.3 and Spring Framework 4.3.7
Related
I'm experiencing a strange behaviour trying to secure my login form.
My app is developed over Spring Framework and Spring Security and deployed on a Tomcat server.
Everything works fine using only http, but when I use https 8443 port for my login page, after a successfull login and a redirect lo http://localhost:8080/mens/index I get redirected to login page at https://localhost:8443/mens/login.html
This is (part of) the configuration of my spring-security.xml:
<!-- enable use-expressions -->
<http auto-config="true" use-expressions="true">
<custom-filter position="SWITCH_USER_FILTER" ref="switchUserProcessingFilter" />
<intercept-url pattern="/j_spring_security_switch_user" access="hasRole('ROLE_SUPERVISOR')"/>
<session-management invalid-session-url="/login.html?invalidSession=1" session-fixation-protection="newSession">
<concurrency-control max-sessions="10" error-if-maximum-exceeded="true"/>
</session-management>
<intercept-url pattern="/login.html" access="hasRole('ROLE_ANONYMOUS')" requires-channel="https"/>
<intercept-url pattern="/resources/**" access="permitAll" requires-channel="any"/>
<intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" requires-channel="http"/>
<intercept-url pattern="/rest/**" access="hasRole('ROLE_USER')" requires-channel="http"/>
<intercept-url pattern="/index" access="hasRole('ROLE_USER')" requires-channel="http"/>
<intercept-url pattern="/upload/**" access="hasRole('ROLE_USER')" requires-channel="http"/>
<headers>
<xss-protection block="false"/>
<frame-options disabled="true"/>
<cache-control/>
</headers>
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/login.html"
default-target-url="/index"
always-use-default-target="true"
authentication-failure-url="/login.html?error=1"
username-parameter="username"
password-parameter="password"/>
<logout logout-success-url="/login.html?logout=1" invalidate-session="false" delete-cookies="JSESSIONID"/>
<!-- enable csrf protection -->
<!-- <csrf disabled="true" /> -->
</http>
Alternatively, I tried to use a channelProcessingFilter instead of the requires-channel attribute:
<http auto-config="true" use-expressions="true">
<custom-filter position="CHANNEL_FILTER" ref="channelProcessingFilter"/>
<custom-filter position="SWITCH_USER_FILTER" ref="switchUserProcessingFilter" />
<intercept-url pattern="/j_spring_security_switch_user" access="hasRole('ROLE_SUPERVISOR')"/>
<session-management invalid-session-url="/login.html?invalidSession=1" session-fixation-protection="newSession">
<concurrency-control max-sessions="10" error-if-maximum-exceeded="true"/>
</session-management>
<intercept-url pattern="/login.html" access="hasRole('ROLE_ANONYMOUS')"/>
<intercept-url pattern="/resources/**" access="permitAll"/>
<intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/rest/**" access="hasRole('ROLE_USER')"/>
<intercept-url pattern="/index" access="hasRole('ROLE_USER')"/>
<intercept-url pattern="/upload/**" access="hasRole('ROLE_USER')"/>
<headers>
<xss-protection block="false"/>
<frame-options disabled="true"/>
<cache-control/>
</headers>
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/login.html"
default-target-url="/index"
always-use-default-target="true"
authentication-failure-url="/login.html?error=1"
username-parameter="username"
password-parameter="password"/>
<logout logout-success-url="/login.html?logout=1" invalidate-session="false" delete-cookies="JSESSIONID"/>
<!-- enable csrf protection -->
<!-- <csrf disabled="true" /> -->
</http>
<beans:bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter">
<beans:property name="channelDecisionManager" ref="channelDecisionManager"/>
<beans:property name="securityMetadataSource">
<filter-security-metadata-source request-matcher="regex">
<intercept-url pattern="\A/login.*\Z" access="REQUIRES_SECURE_CHANNEL"/>
<intercept-url pattern="\A/login.html.*\Z" access="REQUIRES_SECURE_CHANNEL"/>
<intercept-url pattern="\A/.*\Z" access="ANY_CHANNEL"/>
</filter-security-metadata-source>
</beans:property>
</beans:bean>
<beans:bean id="channelDecisionManager" class="org.springframework.security.web.access.channel.ChannelDecisionManagerImpl">
<beans:property name="channelProcessors">
<beans:list>
<beans:ref bean="secureChannelProcessor"/>
<beans:ref bean="insecureChannelProcessor"/>
<beans:ref bean="anyChannelProcessor"/>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="secureChannelProcessor" class="com.mycompany.mens.springsecurity.MensSecureChannelProcessor"/>
<beans:bean id="insecureChannelProcessor" class="com.mycompany.mens.springsecurity.MensInsecureChannelProcessor"/>
<beans:bean id="anyChannelProcessor" class="com.mycompany.mens.springsecurity.MensAnyChannelProcessor">
<beans:property name="entryPoint" ref="mensRetryWithHttpEntryPoint"/>
</beans:bean>
<beans:bean name="mensRetryWithHttpEntryPoint" class="com.mycompany.mens.springsecurity.MensRetryWithHttpEntryPoint"/>
Debugging I found that authentication is successfull, entry point redirects the flow to index page on http port 8080, but after that something is redirecting me to login form another time.
Any suggestion?
Thank you very much in advance, I really appreciate your help!
Your login page requires HTTPS:
<intercept-url pattern="/login.html" access="hasRole('ROLE_ANONYMOUS')" requires-channel="https"/>
but your index page requires HTTP:
<intercept-url pattern="/index" access="hasRole('ROLE_USER')" requires-channel="http"/>
that's the reason, why you lose your session cookie, see Spring Security - Frequently Answered Questions (FAQ):
2.3.
I'm using Tomcat (or some other servlet container) and have enabled HTTPS for my login page, switching back to HTTP afterwards. It doesn't work - I just end up back at the login page after authenticating.
This happens because sessions created under HTTPS, for which the session cookie is marked as “secure”, cannot subsequently be used under HTTP. The browser will not send the cookie back to the server and any session state will be lost (including the security context information). Starting a session in HTTP first should work as the session cookie won't be marked as secure (you will also have to disable Spring Security's Session Fixation Protection support to prevent it from creating a new secure session on login (you can always create a new session yourself at a later stage). Note that switching between HTTP and HTTPS is not a good idea in general, as any application which uses HTTP at all is vulnerable to man-in-the-middle attacks. To be truly secure, the user should begin accessing your site in HTTPS and continue using it until they log out. Even clicking on an HTTPS link from a page accessed over HTTP is potentially risky. If you need more convincing, check out a tool like sslstrip.
I'm new to Spring Security and I'm developing a web app which requires authentication and authorization using Spring Security 3.2, the authentication part is working fine but the authorization is not. Below is my spring security configuration xml snippet.
<authentication-manager>
<authentication-provider>
<password-encoder ref="encoder" />
<jdbc-user-service data-source-ref="myDataSource"
users-by-username-query=" SELECT email_address as username , password, enabled FROM users WHERE email_address = ? "
authorities-by-username-query=" SELECT u.email_address as username ,
r.role_name FROM users u
INNER JOIN user_roles ur
ON ur.user_id = u.user_id
INNER JOIN roles r
ON r.role_id = ur.role_id
WHERE u.email_address = ? "/>
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11" />
</beans:bean>
<http pattern="/resources/**" security="none" />
<http auto-config="true" use-expressions="true" create-session="ifRequired">
<form-login login-page="/" default-target-url="/admin/dashboard"
authentication-failure-url="/login-error" always-use-default-target="true" />
<!-- Security zones -->
<intercept-url pattern="/" access="isAnonymous()" />
<intercept-url pattern="/admin*" access="hasRole('ROLE_ADMIN')" />
<session-management invalid-session-url="/"
session-fixation-protection="newSession">
<concurrency-control max-sessions="1"
error-if-maximum-exceeded="true" />
</session-management>
<logout logout-success-url="/" delete-cookies="JSESSIONID"
invalidate-session="true" />
<access-denied-handler error-page="/403" />
</http>
With this configuration everything works fine apart from authorization. I have two users viz tim#abc.com (role=ADMIN) and bob#abc.com(role=USER), but when I try to login with bob#abc.com then also I'm able to view the admin/dashboard page which should not happen.
I've referred many tutorials and spring doc as well but not able to find the exact problem. Please help.
Change the pattern to "/admin/*"
<intercept-url access="hasRole('ROLE_ADMIN')" />
Your default-target-url="/admin/dashboard" seems to be confusing as for every user it will redirect to /admin/dashboard after login. You may get http UnAuthorized response when you login with bob#abc.com.
I created a spring mvc application with spring security. I tried to set authentication for all url with spring security.
Springsecurity.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<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" />
<!-- enable csrf protection -->
<csrf />
</http>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService" >
<password-encoder hash="bcrypt" />
</authentication-provider>
</authentication-manager>
When I giving intercept-url to /** the page doesnot loading. It makes a timeout.
But when giving intercept-url to /admin it works perfectly. Why this happens?
Your intercept pattern for all request is OK, but you need to include an exception for your login page, try adding
<http security="none" pattern="/login"/>
UPDATE with respect to the comment
The approach above completely switches off Spring security for the given URL. As you're using CSFR, it means that spring security filter should attend to this URL as well, but not for the sake of the authentication, rather for the sake of including the unpredictable token that can secure from session fixation attacks. In any case, here's a way to process the URL with spring security, without prompting for authentication. Instead of using the above, use the following
<intercept-url pattern="/login" access="isAnonymous()"/>
inside the
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/login" access="isAnonymous()"/>
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
...
I have this spring security configuration:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/home.jsp" access="permitAll" />
<intercept-url pattern="/loginFailed" access="permitAll" />
<intercept-url pattern="/logOut" access="permitAll" />
<intercept-url pattern="/*" access="isAuthenticated()" />
<form-login login-page="/home.jsp" default-target-url="/index"
authentication-failure-url="/loginFailed" />
<logout logout-success-url="/logOut"/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="N_a" password="12" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
If I type url, that need access="isAuthenticated() I redirect to home.jsp.
I want to see 403 error.
How to change it ?
You are using a form-based login and as such, when not authenticated, you will be prompted with the login-page. This is what you have configured and this is how, by default, Spring Security works.
If you want to override this you need to explicitly configure an AuthenticationEntryPoint to be precise the Http403ForbiddenEntryPoint. This basically always gives a 403 if someone isn't authenticated or doesn't have access. This disables the ability to be prompted with a login-form to give a user the change to login after all.
<beans:bean id="entryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<http auto-config="true" use-expressions="true" entry-point-ref="entryPoint">
<!-- Your other elements here -->
</http>
use access-denied-handler tag in http tag.
http://www.mkyong.com/spring-security/customize-http-403-access-denied-page-in-spring-security/
or use access-denied-page property.
<http auto-config="true" access-denied-page="/403"></http>
I have below spring security configuration. When I add session-management attribute after first successfull login and logout, I can't login again. It redirects me to authentication-failure-url. If I remove it, it works fine. I can rejoin successfully. What am I doing wrong with session-management?
<http auto-config='false' use-expressions="true">
<intercept-url pattern="/login" access="permitAll"/>
<intercept-url pattern="/j_spring_security_check" access="permitAll"/>
<logout logout-success-url="/login.xhtml" invalidate-session="true" delete-cookies="JSESSIONID"/>
<form-login login-page="/login.xhtml"
login-processing-url="/j_spring_security_check"
default-target-url="/pages/index.xhtml"
always-use-default-target="true"
authentication-failure-url="/login.xhtml?error=true"/>
<custom-filter before="FORM_LOGIN_FILTER" ref="customAjaxControlFilter" />
<session-management invalid-session-url="/login.xhtml">
<concurrency-control error-if-maximum-exceeded="true" max-sessions="1" expired-url="/login.xhtml"/>
</session-management>
</http>
Make sure you have added the listener to your web.xml file. It is essential to make sure that the Spring Security session registry is notified when a session is destroyed. Without it, the session information will not be removed from the registry.
<listener>
<listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class>
</listener>