CSRF needs to be disabled for /login spring security - spring

All of my REST interfaces work fine with csrf protection enabled but I need to disable csrf for /login otherwise I get an 403 Forbidden. I use spring security, the login path is available through spring security.
http.csrf().disable()
How to disable csrf protection for particular pages in my website?
Or if it is not a problem to disable CSRF on the login page the problem would also be fixed
EDIT:
.csrf().ignoringAntMatchers("/login")
The login route always needs an login body so there should be no CSRF attack potential, isn't?

if you don't use spring mvc form tags , you can't use spring security csrf support automatically, probably you use plain html form tags that's why you get http 403, you need to manually include csrf token in your form submission.
Either you need to use spring mvc form tags like this
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
…
<form:form action="" method="POST">
…
</form:form>
or adding csrf token in your plain html form submission manually.
<form action="" method="POST">
<input type="hidden" name="${_csrf.parameterName}" value = "${_csrf.token}" />
…
</form>

Try this out:
Change in Spring-Security.xml:
<security:http use-expressions="true" authentication-manager-ref="authenticationManager">
<security:intercept-url pattern="/auth/**" access="hasAnyRole('ROLE_USER')" />
<security:form-login login-page="/login" authentication-success-handler-ref="loginSuccessHandler" authentication-failure-url="/login" login-processing-url="/j_spring_security_check" />
<security:logout invalidate-session="true" logout-url="/logout" success-handler-ref="logoutSuccessHandler" />
<security:csrf request-matcher-ref="csrfSecurityRequestMatcher" />
</security:http>
CsrfSecurityRequestMatcher
public class CsrfSecurityRequestMatcher implements RequestMatcher {
private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("/ext/**", null);
#Override
public boolean matches(HttpServletRequest request) {
if(allowedMethods.matcher(request.getMethod()).matches()){
return false;
}
return !unprotectedMatcher.matches(request);
}
}

Related

Failed to evaluate expression with spring security

I have a Spring rest service, and I'm trying to add security to it. I followed this tutorial, but when I try to access the service directly I get the following error:
There was an unexpected error (type=Internal Server Error,
status=500). Failed to evaluate expression 'ROLE_USER'
Here's my security configuration:
webSecurityConfig.xml
<http entry-point-ref="restAuthenticationEntryPoint">
<intercept-url pattern="/**" access="ROLE_USER"/>
<form-login
authentication-success-handler-ref="mySuccessHandler"
authentication-failure-handler-ref="myFailureHandler"
/>
<logout />
</http>
<beans:bean id="mySuccessHandler"
class="com.eficid.cloud.security.rest.AuthenticationSuccessHandler"/>
<beans:bean id="myFailureHandler" class=
"org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"/>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="temp" password="temp" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
SpringSecurityConfig:
public class SpringSecurityConfig {
public SpringSecurityConfig() {
super();
}
}
I'm also getting this error when trying to use curl to log in:
{
"timestamp":1460399841286,
"status":403,"error":"Forbidden",
"message":"Could not verify the provided CSRF token because your session was not found.",
"path":"/spring-security-rest/login"
}
Do I need to add the csrf token manually to the command? The service has a self-signed certificate, if that makes any difference.
If you don't need CRF to be enabled, then you can disable it in webSecurityConfig.xml file like below:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/login.html" access="hasRole('ANONYMOUS')" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<!-- This form is a default form that used to login
<http-basic/>
-->
<form-login login-page="/login.html"/>
<csrf disabled="true"/>
</http>
If CSRF is enabled, you have to include a _csrf.token in the page you want to login or logout.The below code needs to be added to the form:
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
You need hasRole('ROLE_USER') in the intercept-url element.
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
See the docs for the other expressions, that you can use.
Spring security blocks POST requests.
To enable it you can either:
Add after all you forms requests :
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" class="form-control" />
(For example:
<form id="computerForm" action="addComputer" method="POST">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" class="form-control" />
)
Or if you use anotation, you can allow POST directly in your code by adding the csrf().disable on your WebSecurityConfigurerAdapter (I havent found the xml equivalent yet) :
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.and().formLogin()
.csrf().disable()
;}

is Spring Security custom login method cancels redirec?

So basiclly redirect to /index.xhtml doesn't work after login. I can't figure out how to fix it but I think what is the problem with my code, if someone could help I'd be glad.
I have login() method, which in my opinion lacks something:
public String login() {
try {
Authentication request = new UsernamePasswordAuthenticationToken(this.getUsername(), this.getPassword());
Authentication result = authenticationManager.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
} catch (BadCredentialsException badCredentialsException) {
//handle exception
} catch (DisabledException disabledException) {
//handle exception
}
return "loggedin";
}
Also in my securityContext:
<sec:http auto-config="true" use-expressions="true" request-matcher="regex" create-session="always">
<access-denied-handler error-page="/?accessDenied=true"/>
<form-login login-page="/login.xhtml" default-target-url="/index.xhtml" always-use-default-target="true"/>
<logout invalidate-session="true" delete-cookies="true" logout-success-url="/"/>
</sec:http>
Am I right that redirect doesn't work is because I have custom login method that doesn't use the .xml settings?
How can I fix that?
EDIT:
<h:form prependId="false">
<h:panelGroup id="loginRender" layout="block">
<h:panelGroup layout="block">
<h:inputText id="j_username" required="true" value="#{loginBean.username}"></h:inputText>
<h:outputText value="LOGIN"></h:outputText>
<h:inputSecret id="j_password" required="true" value="#{loginBean.password}"></h:inputSecret>
<h:outputText value="PASSWORD"></h:outputText>
<h:commandButton id="login_button" value="LOG IN" action="#{loginBean.login}"> <!-- Login button, with login() action -->
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
When using spring security's form login you're not supposed to handle the login yourself.
Spring's form login handler will handle the login operation for you. The login handler is pretty configurable and will most likely serve your needs.
<security:http>
<security:form-login login-page="/login.xhtml" login-processing-url="/login"
password-parameter="username" username-parameter="password"
default-target-url="/index.xhtml" authentication-failure-url="/login.xhtml?error"/>
</security:http>
The login-page attribute tells spring what the login page of your application is. It will redirect unauthenticated users to this page when they access a secured page. The login-processing-url attribute specifies the url to which the login form will POST the login credentials. The username-parameterand password-parameter attributes tell spring which parameters the contain the username and password. After a successful login spring will redirect the user to the default-target-url page. After a failed login attempt the user will be redirected to the authentication-failure-url.
It's not necessary configure all this if you're happy with the default values of these attributes. All this and more is pretty well explained in the documentation so you really should take at look at it.
UPDATE
The login form on your index.xhtml page should look like this given the example form-login configuration above. The action of your form must match the value of the login-processing-url. Spring security will handle login request when the form is submitted.
<form name='loginForm' action="/login" method='POST'>
<input type='text' name='username' placeholder="username">
<input type='text' name='password' placeholder="password">
</form>

HTTP Status 405 - Request method 'POST' not supported occurs when try to submit spring security's custom login form

I am using spring, spring security. My application have custom login page a jsp page where i am trying to post username, password and csrf token, and in backend i have a controller to capture and authenticate login details. I am using tomcat. I am using spring security for login authentication. Getting the following error when i submitting login form the file HTTP Status 405 - Request method 'POST' not supported Any ideas?
Login Page:
<div id="login-box">
<h3>Login with Username and Password</h3>
<c:if test="${not empty error}">
<div class="error">${error}</div>
</c:if>
<c:if test="${not empty msg}">
<div class="msg">${msg}</div>
</c:if>
<form name='loginForm' action="<c:url value='/login' />" method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit"
value="submit" /></td>
</tr>
</table>
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
</div>
Controller Class:
#Controller
public class HelloController {
#RequestMapping(value = { "/", "/welcome**" }, method = RequestMethod.GET)
public ModelAndView welcomePage() {
ModelAndView model = new ModelAndView();
model.addObject("title", "Spring Security Custom Login Form");
model.addObject("message", "This is welcome page!");
model.setViewName("hello");
return model;
}
#RequestMapping(value = "/admin**", method = RequestMethod.GET)
public ModelAndView adminPage() {
ModelAndView model = new ModelAndView();
model.addObject("title", "Spring Security Custom Login Form");
model.addObject("message", "This is protected page!");
model.setViewName("admin");
return model;
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
Spring-Security Config:
<http auto-config="true">
<intercept-url pattern="/admin**" access="ROLE_USER" />
<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>
<user name="mkyong" password="123456" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
Ok the problem I see here is in the jsp form. The form action is not correct, spring security tries to do login processing with some other action by default. i.e. /j_spring_security_check and even the field names are not correct in your mail.
Username field : j_username
Password field : j_password
So you need to do three things to get this working.
Rename action in form declaration in jsp to action="
Rename username field to j_username
Rename password field to j_password
Spring security does provide flexibilities to rename all, but lets get the basic one working first. No other changes are expected
EDIT:
I missed reading the username and password customization.
Just do one thing (Have added login-processing-url property):
<http auto-config="true">
<intercept-url pattern="/admin**" access="ROLE_USER" />
<form-login
login-page="/login"
default-target-url="/welcome"
authentication-failure-url="/login?error"
login-processing-url="/login"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/login?logout" />
<!-- enable csrf protection -->
<csrf/>
First of all you redirect to login page with
model.setViewName("login");
Do you use spring security? If yes, I don't see in your code anything related to the spring security filter.
I suggest you to have a look over there
mykong example
or obviously to
spring-reference
Your controller accept only GET request, your form use POST. First of all I will try to change this configuration.
#RequestMapping(value = "/login", method = RequestMethod.POST)
You can also avoid to specify the option method, which should mean GET and POST.

Spring 4 mvc login intercepting

I am new at Spring mvc. I am working on a webpage on which users will be able to log in after they have registered and activated themselves.
I sucessfully implemented the Login part, it works fine.
I would like to check if the user has already activated his/her accout via email before the login process launches. Is it possible?
I have tried to solve it with a Login interceptor, but it seems the default "/j_spring_security_check" can not be intercepted. Except this link the interceptor works with all of the url-s.
Is it possible to intercept this default link?
My spring-security.xml
...
<http use-expressions="true">
<intercept-url pattern="/admin**" access="hasRole('ADMIN')" />
<access-denied-handler error-page="/403" />
<form-login login-page="/login"
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="loginService" />
</authentication-manager>
LoginService
#Service("loginService")
public class LoginServiceImpl implements UserDetailsService {
//It is a regular UserDetailsService nothing extra stuff and works fine
...
}
Login.jsp
....
<div id="login-box">
<span style="color: red">${message}</span>
<c:url value="/j_spring_security_check" var="loginUrl"/>
<form name='f' action="${loginUrl}" method="post">
<p>
<label for="username">Email</label>
<input type="text" id="username" name="username"/>
</p>
<p>
<label for="password">Password</label>
<input type="password" id="password" name="password"/>
</p>
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
<button type="submit" class="btn">Log in</button>
</form>
</div>
...
mvc-dispatcher-servlet.xml
...
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/j_spring_security_check"/>
<bean id="logininterceptor" class="org.psi.controller.LoginInterCeptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
...
LoginInterceptor
public class LoginInterCeptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//Do some check
System.out.println("some check");
return true;
}
}
Any other possible solution are welcome.
I would accomplish this by using either the locked or enabled property on the UserDetails object and let Spring handle the rest rather than trying to intercept the request. When the user confirms their email via the link you send them, flip the flag in the database to indicate the the user is either enabled or not locked.
Alternatively, if you really want to go the intercept route, what I might do is have the login form point to something other than j_spring_security_check, intercept whatever that is, and then (if desired) forward the request to j_spring_security_check. I'm not sure if you can actually override that url.

Call to j_spring_security_logout not working

I'm trying to setup the logut of my application with j_spring_security_logout but for some reason it's not working, I keep getting a 404 error.
I'm calling the function like this:
<img border="0" id="logout" src="./img/logout.png" />
I have in WebContent/jsp/ my application main page, and the login and logout pages are in WebContent/login/.
I've also checked this other post Problem with Spring security's logout but the solution given there is not working for me.
Here you can see my web.xml
<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>/*</url-pattern>
</filter-mapping>
And here my spring-security.xml
<http auto-config="true">
<intercept-url pattern="/*" access="ROLE_USER" />
<form-login login-page="/login/login.jsp"
authentication-failure-url="/login/errorLogin.jsp"/>
<logout logout-success-url="/" logout-url="/login/logout.jsp" />
</http>
<beans:bean id="myAuthenticationProvider"
class="myapp.web.authentication.WSAuthenticationProvider">
</beans:bean>
<authentication-manager>
<authentication-provider ref="myAuthenticationProvider"/>
</authentication-manager>
Thanks in advance.
the logout-url refers to a virtual URL, you need not have any resource by that name. You can do either this:
<logout logout-success-url="/" logout-url="/j_spring_security_logout" />
and the link on your page like this
<c:url value="/j_spring_security_logout" var="logoutUrl" />
Log Out
OR this:
<logout logout-success-url="/" logout-url="/logout" />
and the link as follows:
<c:url value="/logout" var="logoutUrl" />
Log Out
You were mixing both thats why you were getting 404 error.
check whether csrf is enabled. If csrf enabled, need to use post method to logout, add csrf token as hidden field. then use JavaScript to post the form to logout
With spring security 4 Logout has to be done through form button. CSRF token has to be submitted along. j_spring_security_logout does not work any longer. After spending one day i got following to be working.
Step 1: In your JSP page
<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}" method="post">
<input type="submit" value="Logout"/>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
Step 2
<security:http use-expressions="true">
<security:form-login login-page="/login" authentication-failure-url="/login?error=true" />
<security:logout logout-success-url="/login" invalidate-session="true" logout-url="/logout" />
</security:http>
Step 3 In your login controller
//Logout mapping
#RequestMapping("/logout")
public String showLoggedout(){
return "logout";
}
Step 4 You must have one logout.jsp
Important to see that it will land onto login page after logout.
<security:form-login login-page="/login" authentication-failure-url="/login?error=true" />
So this login page must be there with corresponding mappping to login.jsp or whatever to map in your controller.
also heres what your controller should look like
#RequestMapping("/logout")
public String logoutUrl(){
return "logout";
}
first set security-context.xml the following code...
<security:logout logout-success-url="/"
invalidate-session="true" />
then add this code to your jsp file..
<script>
function formSubmit() {
document.getElementById("logoutForm").submit();
}
</script>
<c:url var="logoutUrl" value="/logout" />
Logout
</li>
<form action="${logoutUrl}" method="post" id="logoutForm">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
In JAVA-BASED Spring MVC config, you have to configure it in your security config class:
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.servletApi().rolePrefix("");
http
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
This answer is doubled from, and is working on my case:
Spring Security Java Config not generating logout url

Resources