In a Spring MVC 3.1 application I'm trying to implement a remember-me feature (with info saved in the database).
Here's what I currently have :
I created a persistent_logins table.
I have this in my security context file :
<form-login login-page="/login"
authentication-failure-url="/login?err=true"
default-target-url="/"
username-parameter="username"
password-parameter="password"
login-processing-url="/validatelogin" />
<remember-me key="some_random_key"
token-validity-seconds="31536000"
data-source-ref="dataSource" />
In my login.jsp, I have :
<form action="/validatelogin" method="post">
username : <input type='text' id='username' name='username' value='${SPRING_SECURITY_LAST_EXCEPTION.authentication.principal}' />
<br />
password : <input type='password' id='password' name='password' />
<br /><br />
remember me : <input type="checkbox" name="_spring_security_remember_me" />
<br /><br />
<input type="submit" value="submit" />
</form>
In the "<form-login>" bean, I've been able to rename the default "j_password" and "j_username" fields that have to be used in the jsp, using username-parameter and password-parameter. But I don't find a way to rename the "_spring_security_remember_me" checkbox field.
Any idea on how to rename it?
That is set using the parameter property of RememberMeServices.
Sadly this isn't settable using the namespace config. Here are a couple of ways you could set it:
Create a custom RememberMeServices and use it using <remember-me services-ref="myRememberMeServices">. Set the property on your bean.
Use a BeanPostProcessor (see 1.8) to set the property on the default RememberMeServices.
You should use BeanPostProcessor to set correct property:
Let's consider that you want to call your property "myRememberMeProperty"
Then your code should look like this:
public class MyBeanPostProcessor implements BeanPostProcessor {
String myRememberMeProperty;
public Object postProcessAfterInitialization(Object bean, String name) {
if (bean instanceof AbstractRememberMeServices) {
AbstractRememberMeServices rememberMe = (AbstractRememberMeServices) bean;
rememberMe.setParameter(getMyRememberMeProperty());
}
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String name) {
return bean;
}
public void setMyRememberMeProperty(String myRememberMeProperty){
this.myRememberMeProperty = myRememberMeProperty;
}
public String getMyRememberMeProperty(){
return this.myRememberMeProperty;
}
}
<bean id="myBeanPostProcessor"
class="x.y.z.MyBeanPostProcessor">
<property name="myRememberMeProperty" value="myRememberMeProperty" />
</bean>
Hope it helps.
Related
I am trying to integrating spring and JSF(Primefaces).I configured the spring controller as component using #component annotation to be worked as JSF bean but it is not calling the action method of commandbutton.
XHTML File:
<h:form id="productForm" >
<h:panelGrid columns="1">
<p:outputLabel for="name" value="Name: " />
<p:inputText id="name" value="#{cust.customerForm.name}" />
<p:outputLabel for="address" value="address" />
<p:inputNumber id="address" value="#{cust.customerForm.address}" />
<p:outputLabel for="email" value="Email: " />
<p:inputNumber id="email" value="#{cust.customerForm.email}" />
<p:outputLabel for="mobile" value="Mobile: " />
<p:inputNumber id="mobile" value="#{cust.customerForm.mobile}" />
<p:commandButton value="Save" action="#{cust.save}" />
</h:panelGrid>
</h:form>
Spring controller used as JSF Bean:
#Scope(value="session")
#Component(value = "cust")
#ELBeanName(value = "cust")
#Controller
#RequestMapping("/customer")
public class CustomerController {
#Autowired
private CustomerRepository customerRepo;
private List<Customer> customerList;
private Customer customerForm;
public List<Customer> getCustomerList() {
return customerList;
}
public Customer getCustomerForm() {
return customerForm;
}
public void setCustomerForm(Customer customerForm) {
this.customerForm = customerForm;
}
public String save(){
System.out.println("save called:::::::::::");
return("Customer");
}
}
kindly help me out in figuring out what wrong I am doing.
You need to configure the org.springframework.web.jsf.el.SpringBeanFacesELResolver in your faces-config.xml. Otherwise JSF can't find spring beans.
When combining JSF and Spring Boot, you should definetl try Joinfaces which does exaclty this (and some other helpfull stuff)
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
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.
Can anyone spot why the file (Http.Part) Variable is null after submitting the form?
Controller Code
#RequestMapping(value="/account/update", method=RequestMethod.POST)
public String addImage(Account account, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest, RedirectAttributes redirectAttributes,
Locale locale,HttpServletRequest request, #RequestParam(value="file", required=false) Part file){
if(file==null){
uiModel.addAttribute("file_error", "File upload failure");
}
View
<spring:url value="/account/update" var="update" />
<form:form modelAttribute="account" action="${update}" method="POST" enctype="multipart/form-data" >
<c:if test="${file_error != null}">
Errors: ${file_error }
</c:if><br />
<label for="file">
<spring:message code="account.upload.file"/>
</label>
<input name="file" type="file"/>
<input type="submit" value="Save" />
</form:form>
Have you add a multipartResolver?
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000"/>
</bean>