spring security with custom AuthenticationProvider gives access denied error - spring

I am trying to implement custom authentication using Spring security in my application by implementing AuthenticationProvider. The authentication is successful and the user also has the specified role but still I am always getting access denied page. Below is my code. i am new to spring security. Please help. Thanks in advance
Spring-security.xml
<form-login
login-page="/login" login-processing-url="/j_spring_security_check" default-target-url="/welcome" authentication-failure-url="/login?error"
/>
<access-denied-handler error-page="/403" />
<logout logout-success-url="/login?logout" />
<csrf disabled="true"/>
</http>
<authentication-manager id="dao-auth" erase-credentials="false">
<authentication-provider ref="customAuthenticationProvider">
</authentication-provider>
</authentication-manager>
<b:bean id="customAuthenticationProvider" class="com.xom.custom.dataservice.impl.CustomAuthenticationProvider"></b:bean>
CustomAuthenticationProvider
#Override
public Authentication authenticate(Authentication authentication) throws
AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
final User rasUser;
try {
rasUser = checkPrivileges(name, password);
} catch (NoRASUserLoginException exception) {
throw new ServiceException(0, "exception while retrieving user data " + exception);
} catch (SQLException exception) {
throw new ServiceException(0, "exception while retrieving user privilages " + name + exception);
}
// userValue = (UserDetails) rasUser;
if (rasUser == null)
throw new UsernameNotFoundException(name + " not found");
List<SimpleGrantedAuthority> auths = new
java.util.ArrayList<SimpleGrantedAuthority>();
for (String privilege : rasUser.getPermissions()) {
if (privilege != null && privilege.equalsIgnoreCase("RReportAdmin"))
{
auths.add(new
SimpleGrantedAuthority("ROLES_".concat(privilege)));
}
}
auths = auths.stream().distinct().collect(Collectors.toList());
authentication = new UsernamePasswordAuthenticationToken(name, password, auths);
return authentication;
}
Login.jsp
<html>
<head>
<title>Login</title>
</head>
<body onload='document.loginForm.username.focus();'>
<h1>Spring Security Custom Login Form (XML)</h1>
<div id="login-box">
<h3>Login with Username and Password</h3>
<form name='loginForm'
action="<c:url value='/j_spring_security_check' />" method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type='text' name='username'></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>
</form>
</div>
</body>
</html>
logs
2017-11-07 03:47:42,212 DEBUG o.s.s.w.u.m.AntPathRequestMatcher [http-nio-8080-exec-15] Checking match of request : '/admin'; against '/admin'
2017-11-07 03:47:42,214 DEBUG o.s.s.a.i.AbstractSecurityInterceptor [http-nio-8080-exec-15] Secure object: FilterInvocation: URL: /admin; Attributes:[hasRole('ROLES_RReportAdmin')]
2017-11-07 03:47:42,214 DEBUG o.s.s.a.i.AbstractSecurityInterceptor [http-nio-8080-exec-15] Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#e68aaf8b:
Principal: rparwee; Credentials: [PROTECTED]; Authenticated: true;
Details:
org.springframework.security.web.authentication.WebAuthenticationDetails#1c07a:
RemoteIpAddress: 127.0.0.1; SessionId:
EE3501D56ED257409E40A4F8D5F6F794; Granted Authorities:
ROLES_RReportAdmin
2017-11-07 03:47:42,216 DEBUG o.s.s.a.v.AffirmativeBased [http-nio-8080-exec-15] Voter:
org.springframework.security.web.access.expression.WebExpressionVoter#6102b9a6,
returned: -1
2017-11-07 03:47:42,219 TRACE o.s.c.s.AbstractApplicationContext [http-nio-8080-exec-15] Publishing event in WebApplicationContext for
namespace 'mvc-dispatcher-servlet':
org.springframework.security.access.event.AuthorizationFailureEvent[source=FilterInvocation:
URL: /admin]
2017-11-07 03:47:42,219 DEBUG o.s.s.w.a.ExceptionTranslationFilter [http-nio-8080-exec-15] Access is
denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84)
~[spring-security-core-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233)
~[spring-security-core-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124)
~[spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
~[spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]

Please try adding
access="permitAll" in Spring-security.xml for login-page="/login"
Also access="hasRole('ROLE_RReportAdmin')" in /welcome

I got my mistake. Spring check "ROLE" before checking for authorization. In my case i was adding "ROLES".
Code changed from intercept-url pattern="/admin**" access="hasRole('ROLES_RReportAdmin')" to intercept-url pattern="/admin**" access="hasRole('ROLE_RReportAdmin')"

Related

When CSRF enable in Spring Security, Access denied 403

In my Spring application in spring security configuration file when csrf is enable
(<security:csrf/>)
and try to submit login form then Access denied page 403 appear (or)
(Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.) exception (when access-denied-handler not present)
"But if I don't enable CSRF in spring security configuration file then everything work perfectly."
Here my codes when CSRF enable
pom.xml (all the versions)
<properties>
<spring.version>3.2.8.RELEASE</spring.version>
<spring.security.version>3.2.3.RELEASE</spring.security.version>
<jstl.version>1.2</jstl.version>
<mysql.connector.version>5.1.30</mysql.connector.version>
</properties>
spring-security.xml
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/login" access="permitAll"/>
<security:intercept-url pattern="/**" access="isAuthenticated()"/>
<!-- access denied page -->
<security:access-denied-handler error-page="/403"/>
<security:form-login
login-page="/login" default-target-url="/loginSuccess" authentication-failure-url="/loginError?error"/>
<!-- enable csrf protection-->
<security:csrf/>
</security:http>
<!-- Select users and user_roles from database -->
<security:authentication-manager>
<security:authentication-provider>
<!--<security:jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select username,password, enabled from registration where username=?"
authorities-by-username-query="select username, role from registration where username=?"/> -->
<security:user-service>
<security:user name="test" password="test" authorities="ROLE_USER" />
<security:user name="test1" password="test1" authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
Controller
#Controller
public class MainController {
#RequestMapping(value={"/login"})
public ModelAndView loginPage(){
ModelAndView model = new ModelAndView("login");
return model;
}
#RequestMapping(value={"/loginSuccess"},method=RequestMethod.POST)
public ModelAndView loginSuccess(Principal principal,HttpServletRequest request,HttpSession session){
ModelAndView model = new ModelAndView("success");
//Testing.......
String name = principal.getName();
model.addObject("username", name);
session = request.getSession();
session.setAttribute("USER", "system");
return model;
}
login.jsp
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%#page session="true"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>login Page</title>
<!-- <meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body onload='document.loginForm.username.focus();'>
<h1>Spring Security Login Form (Database Authentication)</h1>
<div>
<h3>Login with Username and Password</h3>
<c:if test="${not empty error}">
<div>${error}</div>
</c:if>
<form name="loginForm" action="j_spring_security_check" method="post">
<table>
<tr>
<td>Username</td>
<td><input type="text" name=j_username></td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" name=j_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>
</body>
</html>
403.jsp
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
<h1>HTTP Status 403 - Access is denied</h1>
<c:choose>
<c:when test="${empty username}">
<h2>You do not have permission to access this page!</h2>
</c:when>
<c:otherwise>
<h2>Username : ${username} <br/>You do not have permission to access this page!</h2>
</c:otherwise>
</c:choose>
</body>
</html>
Output:
HTTP Status 403 - Access is denied
Username : ${username}
You do not have permission to access this page!
Please help.
Solution
Controller:
#RequestMapping(value={"/","/loginSuccess"},method=RequestMethod.GET)
public ModelAndView loginSuccess()
web.xml
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
Due to of default page
I think you are doing an ajax request once you submit the form. In that case, you have to pass csrf token in the header.
something like,
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
var headers ={};
headers[header]=token;
var headerObj = {};
headerObj['headers']=headers;
$http.post("http://xyz",request,headerObj);
In order to enable csrf only for a particular url, You can do something like this
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().requireCsrfProtectionMatcher(new RequestMatcher() {
#Override
public boolean matches(HttpServletRequest request) {
return request.getServletPath().contains("/xyz");
}
});
}
}

How to combine token Authenication and CRSF?

I am developing a web application with consist of the following
Rest Web service (Spring 4) | JWT token authentication
Web pages (login.xhtml, index.xhtml) (JSF, primeface) | crsf
The problem I am facing now is weird.
If my spring security is enabled, any access to rest web services need to be authenticated before the access is granted. I am using JWT token authentication for my login. However my web pages will fail after I login. i.e my login is successful but any action after this, results in an invalid crsf token or null request error.
If my spring security is disabled, my rest services does not need to be authenticated to access the web services but my web pages works perfectly fine.
How do I integrate both solutions together?
All my web pages already included the following:
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
ApplicationContext-Security.xml:
<http pattern="/auth/login" security="none" />
<http pattern="/login.xhtml" security="none" />
<http pattern="/index.xhtml" security="none" />
<http pattern="/javax.faces.resource/**" security="none" />
<http pattern="/RES_NOT_FOUND" security="none" />
<http pattern="/img/**" security="none" />
<sec:http auto-config="false" create-session="stateless" entry-point-ref="customEntryPoint" use-expressions="true">
<intercept-url pattern="/admin/**" access="hasRole('ADMIN') or hasRole('HQ')" />
<intercept-url pattern="/audit/**" access="hasRole('ADMIN')" />
<intercept-url pattern="/request/**" access="hasRole('ADMIN') or hasRole('HQ')" />
<intercept-url pattern="/reporting/**" access="hasRole('ADMIN') or hasRole('HQ')" />
<sec:custom-filter ref="customAuthenticationFilter"
before="PRE_AUTH_FILTER" />
<!-- <sec:csrf disabled="true" /> -->
</sec:http>
As you can see i included the <http pattern="/index.xhtml" security="none" /> so that i can allow what feature that is in my index.xhtml to work. But now i can access the index.xhtml directly.
Can someone advise on how to fix this?
===== EDITED. MORE INFO =====
To add on, this is my login page and controller.
login.xhtml:
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>BTS Upload</title>
<h:outputStylesheet library="css" name="bootstrap.min.css" />
<h:outputScript library="js" name="jquery-1.11.1.min.js" />
<h:outputScript library="js" name="bootstrap.min.js" />
</h:head>
<!-- Css here -->
<h:body>
<font color="red"> <h:outputLabel
value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
</font>
<div class="container">
<div class="row">
<div class="col-sm-6 col-md-4 col-md-offset-4">
<h1 class="text-center login-title">Sign in</h1>
<div class="account-wall">
<h:graphicImage class="profile-img" library="images"
name="photo.png" />
<h:form class="form-signin">
<h:outputLabel value="Enter UserName:" />
<h:inputText id="username" value="#{loginAction.username}"
required="true" requiredMessage="Please enter your username"
autofocus="true" class="form-control"></h:inputText>
<h:message for="username" id="msg"
errorStyle="color:red; display:block" />
<br />
<h:outputLabel value="Enter Password:" />
<h:inputSecret id="password" value="#{loginAction.pwd}"
required="true" requiredMessage="Please enter your password"
class="form-control"></h:inputSecret>
<h:message for="password" id="msg1"
errorStyle="color:red; display:block" />
<br />
<br />
<h:commandButton class="btn btn-lg btn-primary btn-block"
action="#{loginAction.login}"
value="Login"></h:commandButton>
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</h:form>
</div>
</div>
</div>
</div>
</h:body>
</html>
Controller:
#ManagedBean(name="loginAction")
#SessionScoped
public class LoginAction extends BaseAction implements Serializable
{
private static final long serialVersionUID = 1094801825228386363L;
private String pwd;
private String msg;
private String username;
#ManagedProperty("#{accessControlService}")
private AccessControlService accessControlService;
public String getPwd()
{
return pwd;
}
public void setPwd(String pwd)
{
this.pwd = pwd;
}
public String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public String getUsername()
{
return username;
}
public void setUsername(String user)
{
this.username = user;
}
//validate login and redirect to the specified website.
public String login()
{
System.out.println();
System.out.println("Call Log in");
if (username.equals("") || pwd.equals(""))
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Username and Password", "Please enter correct username and Password"));
return "login";
}
boolean valid = false;
String token = "";
try
{
token = accessControlService.isAuthorizedUser(username, pwd, PropertiesUtil.LoginType.WEB_BTS.ordinal(), this.getRequest());
}
catch (Exception e)
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Error", e.getLocalizedMessage()));
}
if(token.contains(PropertiesUtil.TOKEN_HEADER))
{
valid = true;
}
if (valid)
{
HttpSession session = this.getSession();
session.setAttribute("username", username);
session.setAttribute("token", token);
return "admin";
}
else
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Username and Password", "Please enter correct username and Password"));
return "login";
}
}
// logout event, invalidate session
public String logout()
{
System.out.println("**********************************************************");
try
{
accessControlService.logout(getUsername(), PropertiesUtil.LoginType.WEB_BTS.ordinal(), getRequest());
HttpSession session = this.getSession();
session.invalidate();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return "login";
}
public AccessControlService getAccessControlService()
{
return accessControlService;
}
public void setAccessControlService(AccessControlService accessControlService)
{
this.accessControlService = accessControlService;
}
}
Firstly you must be sure that you have spring security 4 compatible *-security.xml and *-servlet.xml look at this
From part of security.xml that you posted I can see that you don't have form-login tag. It should be something like this
<security:form-login default-target-url="/index"
login-page="/login"
username-parameter="j_username"
password-parameter="j_password"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/login?login_error=1"/>
Your login jsp needs to have action j_spring_security_check to trigger filter chain:
<form action="<c:url value="/j_spring_security_check"/>" method="POST"> ...
You don't need csrf hidden input because spring automatically injects it into request header and parameters (if you don't disable it) as of spring 4

Spring Security 4 Exception Access is denied

help me.I try to follow online.In The Screen 1, I used the username and password to login. but when i press to the login button then appears The Error Message [Exception error message Access is denied]
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/MH01*" access="permitAll" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/Erro" access="permitAll" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<access-denied-handler error-page="/Erro"/>
<form-login
login-page="/MH01"
authentication-failure-url="/MH01?error"/>
<logout logout-url="/logout" logout-success-url="/MH01?logout" />
<csrf disabled="true"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query= "
SELECT USERNAME, PASSWORD, CASE ENABLED WHEN 1 THEN 'true' ELSE 'false' END 'ENABLED'
FROM TBL_USERS
WHERE USERNAME=?;"
authorities-by-username-query = "
SELECT USERNAME, PASSWORD, CASE ENABLED WHEN 1 THEN 'true' ELSE 'false' END 'ENABLED'
FROM TBL_USERS
WHERE USERNAME=?;"/>
</authentication-provider>
</authentication-manager>
Controller:
List<String> lsMessage = userService.doLogin(userDto);
if(!lsMessage.isEmpty()) {
userDto.setLsMessage(lsMessage);
} else {
SessionController.setDefaut(session);
return "redirect:/" + Common.VMH02;
}
return Common.VMH01;
Error:
2016-05-06 08:38:20 DEBUG FilterSecurityInterceptor:219 - Secure object: FilterInvocation: URL: /MH02; Attributes: [hasRole('ROLE_USER')]
2016-05-06 08:38:20 DEBUG FilterSecurityInterceptor:219 - Secure object: FilterInvocation: URL: /MH02; Attributes: [hasRole('ROLE_USER')]
2016-05-06 08:38:20 DEBUG FilterSecurityInterceptor:348 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#6fa90ed4: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#fffc7f0c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 440EF5F23A36FF1A6DFACFD29BD8EF60; Granted Authorities: ROLE_ANONYMOUS
2016-05-06 08:38:20 DEBUG FilterSecurityInterceptor:348 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#6fa90ed4: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#fffc7f0c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 440EF5F23A36FF1A6DFACFD29BD8EF60; Granted Authorities: ROLE_ANONYMOUS
2016-05-06 08:38:20 DEBUG AffirmativeBased:66 - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#6ec34892, returned: -1
2016-05-06 08:38:20 DEBUG AffirmativeBased:66 - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#6ec34892, returned: -1
2016-05-06 08:38:20 DEBUG ExceptionTranslationFilter:174 - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
Login Form
<h3> Đăng nhập hệ thống</h3>
<table class="table-login">
<tr>
<td class="td-label"><label for="username">Tên đăng nhập</label></td>
<td><form:input type="text" path="username" id="userName" name ="userName"/></td>
</tr>
<tr>
<td class="td-label"><label for="password">Tên đăng nhập</label></td>
<td><form:password path="password" id="pass" /></td>
</tr>
</table>
<div class="btnSearch-div">
Đăng nhập
</div>

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.

j_username cannot be accessed using spring_security_check

I created a login page using spring_security_check.
Here:
<form name='f' action="/sec_test/j_spring_security_check" method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type="text" name="j_username" value=''>
</td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="j_password" />
</td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit"
value="submit" />
</td>
</tr>
<tr>
<td colspan='2'><input name="reset" type="reset" />
</td>
</tr>
</table>
</form>
But I can not have access to j_username afterward.
I've tried:
* request.getParameter("j_username")
* request.getAttribute("j_username")
* request.getAttribute("j_username")
* request.getUserPrincipal().getName()
* request.getRemoteUser()
From all of them, all I'm getting is null!
Any idea what to do?
Spring does authentication for you based on type of the authentication configured in your configuration file. Once authentication is successful it redirects to the login success url(say /login.htm). Because it redirects to /login.htm, you will not get any request parameter (username/user role) unless explicitly set in request in overriden authentication filter.
After successful authentication spring stores the authenticated information in security context, including user roles. You can access this information from SecurityContext. Refer - link
I'd be interested to see your spring config files. Regardless, it appears you are trying to validate the user's credentials when spring security will actually do that for you. If you're unsure how to get started, read up on spring's documentation, including any online tutorials you can find. Here's what my spring security config looks like:
<security:http auto-config="true" use-expressions="true" access-denied-page="/login.html">
<security:form-login
login-page="/login.html"
authentication-failure-url="/loginfail.html"
default-target-url="/authenticate.html"/>
<security:logout
invalidate-session="true"
logout-success-url="/login.html"
logout-url="/logoff.html"/>
</security:http>
<bean id="securityDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/security_DS"/>
<property name="resourceRef" value="true"/>
</bean>
<bean id="encoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder" />
<security:authentication-manager>
<security:authentication-provider>
<security:password-encoder ref="encoder" />
<security:jdbc-user-service
data-source-ref="securityDataSource"
authorities-by-username-query="SELECT l.user_name as username, r.role_name AS authority FROM login l join user_role ur on l.user_id = ur.user_id join role r on ur.role_id = r.role_id WHERE l.user_name = ?"
users-by-username-query="SELECT user_name as username, password_value AS password, active_flg AS enabled FROM login WHERE user_name = ?"
/>
</security:authentication-provider>
</security:authentication-manager>
If you want to have access to the user name after spring has validated the user's credentials, do something like this:
#RequestMapping(value = { "/authenticate.html" }, method = { RequestMethod.GET, RequestMethod.HEAD })
public ModelAndView authenticateUser(final HttpServletRequest httpServletRequest, HttpSession httpSession, Authentication authentication) {
User user = (User) authentication.getPrincipal();
String userName = user.getUsername();
...
You can see that the request will be forwarded to the /authenticate.html method based on the default-target-url that I specified in my spring config.

Resources