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.
Related
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.
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.
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.
Edit / Delete
What should be pattern for above URL.I am using following but its not working
<intercept-url pattern="/index*" access="permitAll" />
<intercept-url pattern="/register*" access="permitAll" />
<intercept-url pattern="/welcome*" access="hasRole('Techincian')" />
<intercept-url pattern="/my/*" access="hasRole('Techincian')" />
<intercept-url pattern="/my/*\?param=value" access="hasRole('Techincian')" />
<intercept-url pattern="/my/**" access="hasRole('Techincian')" />
should work, but notice that this will match something that is <root of the project>/my/something . The above links are relative and may result in some other url will be not mached. To ensure you start from the root you can use c:url if you are in jsp.
Spring Form .I want to update the request made by customer by changing its status.some of field coming form controller .I want to submit form to controller in order to acess the values
h2>Update Request</h2>
>form:form method="POST" action="/my/update.htm" commandName="servicehistory">
table align="center" border="0">
<tr><td>Request Id: </td>
<td><form:input path="sr.ServiceRequestId" value="${sr.serviceRequestId}"></form:input> < other fields..............
<tr><td><input type="submit" value="Save" /></td></tr>
Controller which access the form value and update the request in database.but it is not happening.GUI displays resource is not available.It was working without Spring Security.
#RequestMapping(value="/my/update.htm",method=RequestMethod.POST)
public ModelAndView update(#ModelAttribute("servicehistory") #Valid ServiceHistories sh1,BindingResult result,ModelMap map)
{
Redirect it to another page after validating the form
return new ModelAndView(("redirect:/displaylist.htm"));
}
>Spring Security which implement security after matching url and user role
< http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin/*" access="hasRole('Technician')" />
<intercept-url pattern="/my/**" access="hasRole('Techincian')" />
This is JSp page that is used to assign the compalint to techincian. After hitting submit, it give number format exceptions.
<c:forEach items="${hlist}" var="history" varStatus="i">
<tr>
<td><form:input path="requests[${i.index}].ServiceRequestId" value="${history.serviceRequestId }"></form:input></td>
<td><form:input path="requests[${i.index}].Description" value="${history.description }"></form:input></td>
<td><form:select multiple="false" path="requests[${i.index}].userto.UserId">
<form:option value="NONE" label="--- Select ---" />
<c:forEach items="${user}" var="u" varStatus="index">
<form:option label="${u.userName}" value="${u.userId}" />
</c:forEach>
</form:select>
</tr>
</c:forEach>
<tr><td> <input type="submit" value="Assign Technicians"></td></tr>
>Controller : I am using Autopopulating list to access list coming from above form.But it gives Number format exception. But it is working for another scenario which is identical to this one.
#ModelAttribute("requestForm")
public RequestForm getRequest()
{
RequestForm rf=new RequestForm();
rf.setRequests(new AutoPopulatingList(ServiceRequests.class));
return rf;
}
#RequestMapping(value="/admin/assigntech.htm",method=RequestMethod.POST)
public String assign(#ModelAttribute("requestForm") RequestForm requestForm,BindingResult result,ModelMap map)
{
List<ServiceRequests> sr=(List<ServiceRequests>)requestForm.getRequests();
System.out.println(sr.size());
System.out.println(sr.get(0).getUserto().getUserId());
return "Welcome";
}
To match everything under a folder like /my/, you should use double star ** because the pattern matching follows Ant standard.
I'm currently trying to implement an login-mechanism to my spring web application and I'm a little bit confused about the security concepts which are used in spring.
If I access a page requiring login, it is correctly redirecing to the login page. After login the actual page is visible (good so far).
Code for this
<security:http use-expressions="true" auto-config="true">
<security:intercept-url pattern="/login" access="permitAll" />
<security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<security:form-login login-page="/login" default-target-url="/welcome"
authentication-failure-url="/loginfailed" />
<security:logout logout-success-url="/logout" />
<security:remember-me/>
</security:http>
However, if I access the same page again I need to login AGAIN. So I need some kind of security-session. I already tried and read lots of things about remember-me and session-management but couldn't find out how to do it.
Can somebody please give me some directions, the appropriate chapter in the spring documentation or a keyword?
Login Form
<form name='f' action="<c:url value='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>
LoginController.java
#RequestMapping(value="/login", method = RequestMethod.GET)
public String login(ModelMap model) {
return "login";
}
#RequestMapping(value="/loginfailed", method = RequestMethod.GET)
public String loginerror(ModelMap model) {
model.addAttribute("error", "true");
return "login";
}
#RequestMapping(value="/logout", method = RequestMethod.GET)
public String logout(ModelMap model) {
return "login";
}
You'll need to this to your security definition in conf file:
<security:remember-me services-alias="rememberMeService" data-source-ref="dataSource" user-service-ref="userService"/>
</security:http>
and create a persistnet logins table
create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null)
But I am now repeating the Official docs
It's quite mysterious why the security session is not maintained for the second request after the login, because your config looks fine. Some logs would be useful to troubleshoot this issue. Enable trace level logging on org.springframework.security and share the logs after reproducing the problem.
A comment would have been enough to say this so far, but I also wanted to clarify the configuration and usage of the remember-me feature, because you had some problem there too.
The remember-me service should work with the simple configuration that you have in your original question. As you didn't specify a data-source-ref on <remember-me>, a simpler and less secure implementation will be applied which doesn't persist the tokens that were issued to the client.
It's not mandatory, but by configuring the data-source-ref you could gain some additional security: you would be able to warn the user if his remember-me token (cookie) had been stolen and used by an attacker to log in to your site with the user's identity. This is worthwhile enough to consider investing the additional effort.
Now the important thing: an under-documented feature of the remember-me service is that the client has to explicitly ask the server to remember his login by sending a request parameter with the name _spring_security_remember_me. So you'll have to insert something like the following snippet into your login form.
<p>
<label for="_spring_security_remember_me">Remember-me</label>
<input id="_spring_security_remember_me"
name="_spring_security_remember_me" type="checkbox"/>
</p>
The remember-me service won't do anything without this. (For the sake of completeness: there is an alternative option to set the alwaysRemember flag on the remember-me service, but that's a bit inconvenient, because this configuration point isn't exposed by the security namespace)