How to handle 404 with Spring Security? - spring-security

I found only related topic for c# please don't blame me if I missed the resource.
It looks something like
/project/blablaentered and content with 404.
Effectively I just want to specify my own page when 404 page is thrown.
My security xml:
<security:http auto-config="true" use-expressions="true" >
<security:form-login login-processing-url="/static/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" default-target-url="/home"/>
<security:intercept-url pattern="/home" access="isAuthenticated()" />
<security:intercept-url pattern="/home/try" access="hasRole('ROLE_EDITOR')"/>
<security:access-denied-handler error-page="/accessDenied"/>
</security:http>
UPDATE: Please follow for solution: Custom 404 using Spring DispatcherServlet

The simplest way is probably enable an error-page element inside web.xml as long as you don't mind it being a plain JSP (ie, no controller). This way, URLs outside your DispatcherServlet which will generate a 404 from your servlet container will follow the same path as any URL that Spring is unable to map to a controller based on your configuration.
If this isn't good enough, you can define a #Exception method for a particular controller, or use a HandlerExceptionResolver.

You need add class:
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
// Do nothing
}

Related

Spring Security: Getting error "The server understood the request but refuses to authorize it"

While running the application using Spring Security, I am getting below error on all browsers:
"The server understood the request but refuses to authorize it"
I tried by changing Roles from "ROLE_ADMIN" to "ROLE_USER" in "spring-security.xml" file.
Below is "spring-security.xml"
<http auto-config="true">
<intercept-url pattern ="/admin" access = "hasRole('ROLE-USER')"/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name = "abc" password = "xyz" authorities="hasRole('ROLE-USER')" />
</user-service>
</authentication-provider>
</authentication-manager>
Below is SpringController Class:
#Controller
public class SpringController {
#RequestMapping(value = "/")
public String homePage() {
return "HomePage";
}
#RequestMapping(value="/admin", method=RequestMethod.GET)
public String loginPage() {
return "login";
}
HomePage.jsp and login.jsp pages are loaded property but after passing credentials on login.jsp getting error:
HTTP Status 403 – Forbidden
Type: Status Report
Message: Access is denied
Description: The server understood the request but refuses to
authorize it.
Apache Tomcat/7.0.90
403 is a very generic error code. I was facing the same issue but after making some changes I am able to make it work. Still not sure if the problem was with password encryption or configuration of form-login tag.
<security:http auto-config="true" >
<security:intercept-url pattern="/login*" access="isAnonymous()" />
<security:intercept-url pattern="/**" access="isAuthenticated()"/>
<security:form-login login-page="/login" login-processing-url="/login-user" authentication-failure-url="/login?error=true" />
<security:csrf disabled="true" />
<security:logout logout-success-url="/" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="admin" password="{noop}admin" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider >
</security:authentication-manager>
Ignore the security: prefix in the tags.
{noop} in front of the password ensures that I am not using any encryption for the password.
Controller to show login JSP
#Controller
#RequestMapping("/login")
public class LoginController {
#RequestMapping(value = { "/", "" }, method = { RequestMethod.GET})
public String login(HttpServletRequest request) {
System.out.println("LoginController.login() "+request.getRequestURI());
return "login";
}
}
Form action
<form name='loginForm' action="login-user" method='POST'>
I got this issue but not while using spring. We were hosting two instances of our own in house application on the same server but using two different ports. Login to one instance was okay, however login to the other one from the same browser (another tab) caused the error above to be thrown from tomcat, preceded with this message "CSRF nonce validation failed".
The workaround I did is to login to the other instance from different browser. I know that this is not a fix but it may help if you have a situation similar to mine
This happens because you use normal <form> tags with spring security, while it checks for CSRF attacks.
The solution is:
Add CSRF hidden field with each <form> tag
<form action="..." method="POST">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
Or use spring MVC <form:form> tags which include this hidden field automtically (Recommended)
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:form action="..." method="POST">
</form:form>
This also happened with me when I accidentally launched two instances of my application on different tomcat servers. I resolved it by removing the working directories of the application in my webapps and work folders, and restarting the server.
use <form:form> tags when you're dealing with spring security, instead of manually adding the CSRF token for each forms as below
<form:form action="", method="">
</form:form>

#PreAuthorize and intercept-url priority

I have
<security:http use-expressions="true">
<security:intercept-url pattern="/**/*" access="hasRole('ROLE_USER')"/>
in the Spring Security context configuration file and
#PreAuthorize("permitAll")
#RequestMapping("/public")
public String aMethod() {
// ...
}
in a controller.
What I want is that all the URLs to require authentication except public. Is this possible?
<intercept-url> in XML takes precedence over annotations. <intercept-url> works at URL level and annotations at method level.
If you are going to use spring security and spring <form-login /> then the approach below would serve you better.
<intercept-url pattern="/public/**"
access="permitAll" />
<intercept-url pattern="/restricted/**"
access="hasAnyRole('ROLE_USER', 'ROLE_ADMIN', 'ROLE_SOME')
#PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_SOME')")
#RequestMapping("/restricted/aMethod")
public String aMethod() {
// ...
}
Anything under restricted can be accessed by three different roles. But specific path restricted/aMethod can be accessed by #PreAuthorize("ROLE_ADMIN") and #PreAuthorize("ROLE_SOME") but NOT by #PreAuthorize("ROLE_USER"). By default all three roles can access but when you mark some path with #PreAuthorize("ROLE_ADMIN") then user with ROLE_ADMIN can access that path.
If you think about it, #PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_SOME')") act as narrowed or filtered access from a large set of ROLES to single(or set of roles) ROLE.
As you would notice, none of /restricted paths are accessible by permitAll. Its preferred to have /static/*.css and others under permitAll.
HTH

navigating to spring security login page redirects to invalid-session-url

In order to redirect the user to a url that I desire on session timeout I recently added the following to my spring security file....
<http pattern="/resources/**" security="none"/>
<http pattern="/resources/js/**" security="none"/>
<http pattern="/resources/css/**" security="none"/>
<!-- excluded pages -->
<http pattern="/login.htm" security="none"/>
<http pattern="/j_spring_security_check" security="none"/>
<http pattern="/accessDenied.htm" security="none"/>
<http pattern="/error.htm" security="none"/>
<http use-expressions="true" auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint">
<!-- custom filters -->
<custom-filter position="FORM_LOGIN_FILTER" ref="twoFactorAuthenticationFilter" />
<custom-filter after="SECURITY_CONTEXT_FILTER" ref="securityLoggingFilter"/>
<!-- session management -->
<session-management
invalid-session-url="/sessionExpired.htm"
session-authentication-error-url="/alreadyLoggedIn.htm">
<concurrency-control
max-sessions="1"
expired-url="/sessionExpiredDuplicateLogin.htm"
error-if-maximum-exceeded="false"
session-registry-alias="sessionRegistry"/>
</session-management>
When the session expires on the next click the user is taken to /sessionExpired.htm which is the desired effect HOWEVER i now have an issue when I navigate to the login page (login.htm), i am redirected to invalid-session-url (/sessionExpired.htm).
Obviously this is not what I want to happen. I've been doing some reading on it and one of the suggested solutions seems to be to delete the jsessionid cookie like such and also set invalidate-session to false (I now invalidate session in the controller method for logout.htm) ...
<logout logout-success-url="/logout.htm" invalidate-session="false" delete-cookies="JSESSIONID"/>
which I have tried but doesn't seem to work. Can someone please help me understand what is happening here and how I might resolve? It seems as if when i go to the login page it is trying to remember who I am.
thanks
I had this problem in Tomcat (not sure if only applies to it).
From Tomcat documentation (see here) we can conclude that the path generated for the session cookie has a trailing slash:
Some browsers, such as IE, will send a session cookie for a context with a path of /foo with a request to /foobar. To prevent this, Tomcat will add a trailing slash to the path associated with the session cookie so, in the above example, the cookie path becomes /foo/. However, with a cookie path of /foo/, IE will no longer send the cookie with a request to /foo. This should not be a problem unless there is a servlet mapped to /*. In this case this feature will need to be disabled. The default value for this attribute is true. To disable this feature, set the attribute to false.
On the other side, spring-security's CookieClearingLogoutHandler will generate a cookie path without the trailing slash. The set-cookie response header will be sent to the browser, but the cookie path will not match the path because the trailing slash is missing.
The browser will not clear the existing JSESSIONID cookie because the paths do not match.
I solved my problem implementing a custom implementation of the CookieClearingLogoutHandler.

No visible WebSecurityExpressionHandler instance could be found in the applicationContext

Am trying to implement Section level security using Spring3.1. Using Thymeleaf2.0 for my view part. Here is the configuration i have made to do so,
Jars Used## - All spring3.1 jars and thymeleaf-extras-springsecurity3.jar (version 1.0.0.beta-1)
SpringWebFlow-Servlet.xml
<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
...
<property name="additionalDialects">
<set>
<bean class="org.thymeleaf.extras.springsecurity3.dialect.SpringSecurityDialect"/>
</set>
</property>
...
</bean>
<bean id="webexpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />
spring-security.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/productSelection" access="hasRole('ROLE_ADMIN')"/>
.....
</http>
xxx.html
<div sec:authorize="hasRole('ROLE_ADMIN')">
This only be seen if authenticated user has role ROLE_ADMIN.
</div>
Issue
Getting an Exception stating :
No visible WebSecurityExpressionHandler instance could be found in the applicationContext
In Spring3.1, DefaultWebSecurityExpressionHandler doesn't implement WebSecurityExpressionHandler and the interface is deprecated. Please let me know the workaround as Thymeleaf is trying to search for the instance of WebSecurityExpressionHandler which is not available in ApplicationContext.
You'll need to define the bean in your application (root) context not in your servlet context.
<bean id="webSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"/>
I had same problem moved it from servlet-context.xml to root-context.xml and the bean is picked up.
Depending on your spring setup it can be in another xml file so check your web.xml for the Spring context root.
In your case if spring-security.xml is imported in your Spring root context you can add it there.
The DefaultWebSecurityExpressionHandler class in Spring Security 3.1.0 does not implement the WebSecurityExpressionHandler interface, which was probably an ommission.
This was solved in Spring Security 3.1.1 and newer versions, so you just have to update your Spring Security dependencies.
This question is pretty old but for anybody who found there way here to complement Daniel's answer you can update your dependencies in your pom.xml by changing the following.
<properties>
...
<!-- <spring-security.version>3.1.0.RELEASE</spring-security.version> -->
<spring-security.version>3.1.1.RELEASE</spring-security.version>
</properties>
I blogged about this as well with some more information if anybody is interested

Issue with Spring security's logout

I've got a problem logging out in Spring framework.
First when I want j_spring_security_logout to handle it for me i get 404 j_spring_security_logout not found:
sample-security.xml:
<http>
<intercept-url pattern="/messageList.htm*" access="ROLE_USER,ROLE_GUEST" />
<intercept-url pattern="/messagePost.htm*" access="ROLE_USER" />
<intercept-url pattern="/messageDelete.htm*" access="ROLE_ADMIN" />
<form-login login-page="/login.jsp" default-target-url="/messageList.htm"
authentication-failure-url="/login.jsp?error=true" />
<logout/>
</http>
Sample url link to logout in JSP page:
Logout
When i try to use a custom JSP page i.e. I use login form for this purpose then I get better result at least it gets to login page, but another problem is that you dont't get logged off as you can diretcly type url that should be guarded buy you get past it anyway.
Slightly modified from previous listings:
<http>
<intercept-url pattern="/messageList.htm*" access="ROLE_USER,ROLE_GUEST" />
<intercept-url pattern="/messagePost.htm*" access="ROLE_USER" />
<intercept-url pattern="/messageDelete.htm*" access="ROLE_ADMIN" />
<form-login login-page="/login.jsp" default-target-url="/messageList.htm"
authentication-failure-url="/login.jsp?error=true" />
<logout logout-success-url="/login.jsp" />
</http>
Logout
Thank you for help
I've just had this problem.
You need to make sure in web.xml your security filter matches on the url /j_spring_security_logout
e.g.
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/j_spring_security_logout</url-pattern>
</filter-mapping>
You should do POST request. Something like that:
<form action="${logoutUrl}" method="post" id="logoutForm">
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
<script>
function formSubmit() {
document.getElementById("logoutForm").submit();
}
</script>
<c:if test="${pageContext.request.userPrincipal.name != null}">
<h2>
Welcome : ${pageContext.request.userPrincipal.name} |
Logout
</h2>
</c:if>
I ran into the same problem and after loosing hope, finally I found out the answer by accident.
Of course we learn a lot by reading and using someone else's codes and, by doing this we inherit settings we don't know much about.
And this is what happened to me when programming using Spring Security.
In the Spring Security XML, within the http tag, there is this line:
<logout invalidate-session="true" logout-success-url="/login" logout-url="/logout" />
I got this line during my research from some tutorial or example. And after 2 days struggling with the j_spring_security_logout keyword and getting nothing but error 404, I figured out this.
In the logout tag I am using, there's this logout-url parameter set to "/logout". Then I realized that according to my settings, my spring is expecting to receive /logout instead of /j_spring_security_logout.
Once I updated my code accordingly, it worked like a charm.
Is logout link aware of the context path?
For example, if your context path is "myapp", where does the above mentioned link point?
"http://localhost:8080/myapp/j_spring_security_logout" or "http://localhost:8080/j_spring_security_logout" ?
In fact, the j_spring_security_logout is only valid within the context of the webapp so only the first link would lead to the correct url
I had the same issue.
Seems to be a bug on 3.0.6!
I just downgrade to 3.0.5 and everything works nicely.
Try this link in your page whow content a logout link:
<h:outputLink value="#{request.contextPath}/logout.jsp">Logout</h:outputLink>
and creeate a logout.jsp file in your "webcontent" folder with the following code:
<% response.sendRedirect("/#{request.contextPath}/j_spring_security_logout"); %>
if an eror occured try to change "#{request.contextPath}" to the name of your project
ex: my project name is "security" so i am using in my logout.jsp file:
<% response.sendRedirect("/security/j_spring_security_logout"); %>

Resources