is Spring Security custom login method cancels redirec? - spring

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>

Related

CSRF needs to be disabled for /login spring security

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);
}
}

Spring security redirecting to login page for authenticated urls

I am new to spring. I am creating a spring mvc app. I have a admin url "/admin/".If I login with user credentials with ROLE_ADMIN then I can access the admin page. Right now this scenario is working fine. But If I have not logged in with ROLE_ADMIN and I try to access /admin/ url spring security is redirecting me to /login page.
Here what I want to not expose to outer world that /admin/(or admin url exists) url need authentication. And I want to show default exception page or home page if someone who is not authorized try to access /admin/ url.
Also I need to have custom "/login" url like "/custom_url/" instead of "/login"
But right now I don't have any idea how to achieve this. Any help is appreciated.
applicationContext.xml
</bean>
<security:http auto-config="true">
<security:intercept-url pattern="/admin/**"
access="hasRole('ROLE_ADMIN')" />
<security:form-login
login-page="/login"
default-target-url="/admin"
always-use-default-target="true"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<security:logout logout-success-url="/" invalidate-session="true" logout-
url="/logout" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource"
authorities-by-username-query="SELECT
username, authority From authorities WHERE username = ?"
users-by-username-query="SELECT
username, password, enabled FROM users WHERE username = ?" />
</security:authentication-provider>
</security:authentication-manager>
Login Controller
#RequestMapping("/login")
public String login(#RequestParam(value="error", required = false) String
error, #RequestParam(value="logout",
required = false) String logout, Model model) {
if (error!=null) {
model.addAttribute("error", "Invalid username and password");
}
if(logout!=null) {
model.addAttribute("msg", "You have been logged out successfully.");
}
return "login";
}
login.jsp
<c:if test="${not empty msg}">
<div class="msg">${msg}</div>
</c:if>
<form name="loginForm" action="<c:url
value="/j_spring_security_check" />" method="post">
<c:if test="${not empty error}">
<div class="error" style="color: #ff0000;">${error}</div>
</c:if>
<div class="form-group">
<label for="username">User: </label>
<input type="text" id="username" name="username"
class="form-control" />
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" id="password" name="password"
class="form-control" />
</div>
<input type="submit" value="Submit" class="btn btn-default">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
I am using Spring security 4.
Change the authentication-failure-url="/login?error" to authentication-failure-url="/". This will redirect you to Home page.
The correct xml-snippet in applicationContext.xml is as following:
<security:form-login
login-page="/login"
default-target-url="/admin"
always-use-default-target="true"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/"
username-parameter="username"
password-parameter="password" />
Note: You can change value of authentication-failure-url attribute to an exception page as per need.

JSF 2 + Primefaces 5 + Spring Security How to do an AJAX login

I have the following configuration in Spring Security:
http.requestMatchers().antMatchers("/admin/**", "/login", "/logout").and()
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.and().formLogin().loginPage("/main.xhtml")
.loginProcessingUrl("/login").defaultSuccessUrl("/admin.xhtml").and()
.exceptionHandling().accessDeniedPage("/denied.xhtml");
In a login controller (JSF backing bean) I have:
public void doLogin() throws ServletException, IOException {
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest)context.getRequest()).getRequestDispatcher("/login");
dispatcher.forward((ServletRequest)context.getRequest(), (ServletResponse)context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
}
I am using Primefaces for frontend components.
This is the login form:
<h:form id="form" prependId="false">
<p:messages id="errorMessages" showDetail="false" autoUpdate="true" />
<p:outputLabel for="username" value="Username" />
<p:inputText id="username" required="true" label="username" />
<p:outputLabel for="password" value="Password" />
<p:inputText id="password" required="true" label="password" />
<p:commandButton id="login" value="Login" update="errorMessages"
action="#{loginController.doLogin}" />
</h:form>
The problem is that the previous configuration forwards completely the response from Spring Security when trying to log in, so the login doesn't work. For it to work I would need to add ajax="false" in the p:commandButton but this would cause the whole page to reload in case of a login failure. Reloading the whole page breaks the user experience, for example, in my case users would need to scroll down to the login form if there's a login error.
How can I configure in either JSF or Spring Security so that I can do an AJAX login? Also, in this process, how could I show authentication failure messages from Spring Security?

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.

Resources