I am using Spring Security. I have a Controller in which some methods have to be possible to access by any user regardless if he is authenticated or not, some methods have to be possible to access only to users who are authenticated with a JWT token. I have configured some paterns with acces="permitAll()" but it seems not to work. If I try to access localhost:8080/name-of-the-app/services/public/whatever I get 401 which I return in my MobileJWTAuthenticationEntryPoint.commence method. Can you help me?
This is my context.xml:
<security:global-method-security pre-post-annotations="enabled"/>
<security:http entry-point-ref="mobileJWTAuthenticationEntryPoint"
authentication-manager-ref="mobileJWTAuthenticationManager"
create-session="stateless"
use-expressions="true">
<security:custom-filter ref="mobileJWTAuthenticationFilter" position="FORM_LOGIN_FILTER" />
<security:intercept-url pattern="/services/public/**" access="permitAll()"/>
<security:intercept-url pattern="/services/restAPI/**" access="isAuthenticated()" />
</security:http>
<bean id="mobileJWTAuthenticationEntryPoint" class="co.amleto.server.services.security.MobileJWTAuthenticationEntryPoint"/>
<bean id="mobileJWTAuthenticationFilter" class="co.amleto.server.services.security.MobileJWTAuthenticationFilter" >
<constructor-arg name="authenticationManager" ref="mobileJWTAuthenticationManager"/>
<constructor-arg name="entryPoint" ref="mobileJWTAuthenticationEntryPoint"/>
</bean>
<bean id="mobileJWTAuthenticationProvider" class="co.amleto.server.services.security.MobileJWTAuthenticationProvider"/>
<security:authentication-manager alias="mobileJWTAuthenticationManager">
<security:authentication-provider ref="mobileJWTAuthenticationProvider"/>
</security:authentication-manager>
EDIT: My whole code is inspired by this: http://massimilianosciacco.com/spring-security-jwt-authentication. In the AuthenticationFilter I've switched throws with returns. Now I get blank page regardless which url I hit.
Problem solved. As I've mentioned in the edit, my code is based on the solution from the link added in the OP. Custom filter had wrong code: in every situation exceptions were thrown. The solution was to invoke chain.doFilter(request, response) and return from the doFilter method to allow anonymous url invocation.
Related
I am working on a Spring MVC web application. Last week I started adding Sping Secuirty to my project. The problem I am facing concerns session management.
Here is http part of my spring-security.xml
<http auto-config="true">
<intercept-url pattern="/css" filters="none"/>
<intercept-url pattern="/js" filters="none"/>
<intercept-url pattern="/logout" filters="none"/>
<intercept-url pattern="/loginfailed" filters="none"/>
<intercept-url pattern="/login" filters="none"/>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page="/login" default-target-url="/hello"
authentication-failure-url="/loginfailed" />
<session-management invalid-session-url="/login.jsp?error=sessionExpired" session-authentication-error-url="/login.jsp?error=alreadyLogin">
<concurrency-control max-sessions="1" expired-url="/login.jsp?error=sessionExpiredDuplicateLogin" error-if-maximum-exceeded="false"/>
</session-management>
</http>
Login/logout works fine, but when I try to invalidate user session by trying to login from different browser invalid-session-url="/login.jsp?error=sessionExpired" fails. Browser get redirected, because I see that GET request to login.jsp?error=sessionExpired is being sent. However, web page shows error saying that resource is not available. I suspect that it has something to do with
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>org.springframework.web.servlet.view.JstlView</value>
</property>
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
in my dispatcher-servlet.xml. However, I don't know exactly how to fix this issue. login.jsp is located in WEB-INF/pages/
It seems to me Spring MVC DispatcherServlet couldn't find a mapping for /login.jsp because it's not set as a view that accessible without controller. I'm also assuming you had /login mapped to login.jsp (you did not provide enough info to confirm this), but if this is the case, just use expired-url="/login?error=sessionExpiredDuplicateLogin
You are redirecting to the jsp not the mapped url.
session management tag should be :
<session-management invalid-session-url="/login?error=sessionExpired" session-authentication-error-url="/login?error=alreadyLogin">
<concurrency-control max-sessions="1" expired-url="/login?error=sessionExpiredDuplicateLogin" error-if-maximum-exceeded="false"/>
</session-management>
I use Spring Security for my web application
By default, the authentication mechanism redirect the user on the "home", but it's possible to access directly to one screen of the application by its URL.
Everything is working well if you fill the URL in your web-browser.
BUT, if I have an hyperlink in Excel sheet, with the same URL, I get the login page, and then I'm forward to the "home" whereas I wanted to access my specific screen.
If I open the Excel sheet with OpenOffice, everything is working well ; as if I were filling the URL in the web browser.
Here is my configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:http auto-config="true" access-denied-page="/accessDenied.jsp" use-expressions="true" access-decision-manager-ref="accessDecisionManager" entry-point-ref="entryPoint">
<security:intercept-url pattern="/css/*.css" access="permitAll" />
<security:intercept-url pattern="/images/**" access="permitAll" />
<security:intercept-url pattern="/javascript/*.js" access="permitAll" />
<security:intercept-url pattern="/j_spring_security_check" access="permitAll"/>
<security:intercept-url pattern="/register.*" access="permitAll" />
<security:intercept-url pattern="/registerUser.*" access="permitAll" />
<security:intercept-url pattern="/login.*" access="permitAll" />
<security:intercept-url pattern="/restore/*" access="permitAll" />
<security:intercept-url pattern="/customer/**" access="permitAll" />
<security:intercept-url pattern="/logout.*" access="isAuthenticated()" />
<security:intercept-url pattern="/j_spring_security_logout" access="isAuthenticated()"/>
<security:intercept-url pattern="/index.*" access="isAuthenticated()" />
<security:intercept-url pattern="/admin/**" access="hasRole('ADMIN')" />
<security:intercept-url pattern="/template/*" access="isAuthenticated()" />
<security:intercept-url pattern="/editor/*" access="hasRole('EDITOR')" />
<security:intercept-url pattern="/creator/*" access="hasRole('CREATOR')" />
<security:intercept-url pattern="/task/*" access="hasAnyRole('CREATOR','EDITOR')"/>
<security:intercept-url pattern="/ajax/*" access="hasAnyRole('CREATOR','EDITOR')"/>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:form-login default-target-url="/index.jsp" authentication-failure-url="/login.jsp?login_error=true"/>
<security:logout invalidate-session="true" logout-url="/logout.jsp" logout-success-url="/login.jsp"/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="userEnvironmenttStatisticService" />
</security:authentication-manager>
<security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler" />
</security:global-method-security>
<bean id="userEnvironmenttStatisticService" class="com.epam.crs.security.UserEnvironmenttStatisticService">
<property name="userDetailsService" ref="userDetailsService" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<constructor-arg>
<list>
<ref bean="notDeletedVoter" />
</list>
</constructor-arg>
</bean>
<bean id="notDeletedVoter" class="com.epam.crs.security.NotDeletedVoter" />
<bean id="entryPoint" class="com.epam.crs.security.ParameterizedLoginUrlAuthenticationEntryPoint">
<constructor-arg value="/login.jsp"/>
</bean>
<bean id="customPermissionEvaluator" class="com.epam.crs.security.CustomPermissionEvaluator" />
<bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="customPermissionEvaluator" />
</bean>
</beans>
Anybody can help me?
Maybe you have any idea how to fix it?
I got the same issue on a similar system. Here is how I fixed it and a bit more details behind my investigation.
How I fixed it for my similar app
I updated the entrypoint so it uses forwarding. Your updated code would be:
<bean id="entryPoint" class="com.epam.crs.security.ParameterizedLoginUrlAuthenticationEntryPoint">
<constructor-arg value="/login.jsp"/>
<property name="useForward" value="true" />
</bean>
Note: this requires that your entrypoint derives from LoginUrlAuthenticationEntryPoint
More details..
Typical flow of execution:
This is the typical flow of execution of a Spring Security setup like yours:
Anonymous user hits a secured page.
An AccessDeniedException is thrown and is captured by the ExceptionTranslationFilter. That filter adds the request coming from the anonymous user in the session.
The security entrypoint (that's your ParameterizedLoginUrlAuthenticationEntryPoint bean) then redirects the user to the login page. This redirection is done as a HTTP 302 redirect.
The user enters valid credentials.
The default SavedRequestAwareAuthenticationSuccessHandler is called. This handler loads the saved request (stored in the session in step 2) & redirects the user to that page (again with a HTTP 302 redirect.)
How Excel messes with that
Excel, for reasons that are out of scope, uses a simple http client before passing the url to your default browser.
That http client will pass the first url that returns a HTTP 200 code.
The http client will trigger the 3 first steps in the flow, landing on the login page.
Since the login page emits a HTTP 200, that is the url that Excel's http client will send to your browser.
The browser opens the login page, but it receives a new session id: it does not share the session cookie of Excel's http client.
When the user enters valid credentials, the SuccessHandler is called, just like in step 5, except that there is no saved request in the user's session (that saved request was saved in Excel's http client's session, not in the user's one). The handler defaults to sending the user to the default page: your home page.
Why does forwarding fixes this?
Forwarding simply handles the redirection on the server-side, excluding the browser/client from the process. So in the typical flow example, all of the redirections are done as forwards on the server-side.
Concretely, this means that the URL will not change. This allows Excel's http client to pass the right url to the browser, allowing your user to complete the 5 steps process without any hickups.
I had the same problem and for me this helped me:
http://support.microsoft.com/kb/218153
Install the Microsoft Fix it 50655:
http://go.microsoft.com/?linkid=9769998
Everything is working well if you fill the URL in your webbrowser.
BUT, if I have an hyperlink in Excel sheet, with the same URL, I get
the login page, and then I'm forward to the "home" whereas I wanted to
access my specific screen.
This is simply not determined by spring. Your URL's must be different, or you session expired.
I have found some solutions but none of them worked for me. Below code gives
"Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Unsupported configuration attributes: [admin]"
error. When I change auto-config attribute to "true", again gives same error.
<http auto-config="false">
<intercept-url pattern="/pages/login.xhtml*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/**" access="admin" />
<form-login login-page='/pages/login.xhtml' default-target-url="/**"
authentication-failure-url="/pages/login.xhtml"/>
<logout logout-success-url="/pages/logout.xhtml" />
</http>
<beans:bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
<beans:property name="rolePrefix" value=""/>
</beans:bean>
You need to provide your own decision manager (e.g. org.springframework.security.access.vote.AffirmativeBased) with your custom configured decision voters via access-decision-manager-ref="decisionMangerId" attribute.
But be aware that having no prefix in role voter is not a good idea as it will just try to interpret all security attributes as roles. I strongly recommend to use some prefix, if not the default ROLE_.
Or you can enable expression based parsing via use-expressions="true" and use access="hasRole('admin')" expresion. When going this way, you will also need to change your IS_AUTHENTICATED_ANONYMOUSLY condition with access="permitAll".
It should read:
access="hasRole('admin')"
I am using Webflow 2.3.0.RELEASE and Spring 3.1.2.RELEASE with Spring security and Freemarker.
It all works well except that when I logout the session is not destroyed.
e.g. when I click the logout link on the screen, I can see the logout screen successfully with url like this:
http://localhost/mart/adminflow.html;jsessionid=855454DFGDFG54501DSF548036?execution=e1s1
If I copy this url and paste into a new window, it just works with me still logged in.
I am not too sure what code to share, but I can share.
Any advice/
Thanks
UPDATE 1:
The logout link :
<a class="link_a" href="../j_spring_security_logout">
Security config:
<security:global-method-security secured-annotations="enabled" />
<bean id="preAuthenticatedProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<security:http use-expressions="true" auto-config="false" entry-point-ref="preAuthenticatedProcessingFilterEntryPoint">
<security:custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter" />
<security:logout logout-success-url="logout.htm?_eventId=logout" />
<security:session-management invalid-session-url="logout.htm?_eventId=logout" />
</security:http>
My question is similar to this one, but I can simplify it some. Basically I want to authenticate users through the remember me cookie, but I want everything on the server side to be completely stateless, i.e. never create a HttpSession. I have the following setup:
<security:http use-expressions="true" create-session="stateless" >
<security:intercept-url pattern="/index.jsp" access="hasRole('ROLE_ANONYMOUS')" />
<security:intercept-url pattern="/**" access="hasRole('ROLE_TEST')" />
<security:form-login login-page="/index.jsp" default-target-url="/home" always-use-default-target="true" authentication-failure-url="/index.jsp?login_error=1" />
<security:logout logout-success-url="/index.jsp"/>
<security:remember-me key="MY_KEY" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="testUser" password="testPassword" authorities="ROLE_TEST" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
I authenticate just fine with the username and password above and see the remember me cookie in my browser. That part of it is working great. However, I'm finding it is creating a session during this process. I thought the create-session="stateless" was supposed to prevent this. Am I missing something here?
After working with this more, I found out that it wasn't Spring Security that was creating the session. The index.jsp was creating a new session every time I hit it. I simply added <%# page session="false"> to the top of index.jsp, and now there are no sessions being created.