/*
* Copyright 2011, Nabil Benothman, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.ubike.rest.security;
import com.ubike.faces.bean.BaseBean;
import com.ubike.model.Account;
import com.ubike.model.UbikeUser;
import com.ubike.services.AccountServiceLocal;
import java.io.IOException;
import javax.ejb.EJB;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationManager;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
import org.springframework.security.ui.WebAuthenticationDetails;
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
/**
* This class is used as managed bean for user authentication
* The authentication is done by a Spring Security authentication manager, so if
* the user has a valid username, password and authorities so he can be authenticated
* else the operation fails.
* @author Benothman Nabil
*/
@ManagedBean(name = "authenticationController")
@RequestScoped
public final class AuthenticationController {
@NotEmpty
@Length(min = 5, max = 12, message = "Username must contain between 7 and 25 characters")
@Pattern(regexp = ".*[^\\s]", message = "Username cannot contain spaces")
private String username;
@NotEmpty
@Length(min = 7, message = "Password must contain at least 7 characters")
@Pattern(regexp = "^(?=.*\\d)(?=.*[a-zA-Z]).{7,25}$", message = "The password is not valid")
private String password;
private boolean remember;
@EJB
private AccountServiceLocal accountService;
// injected properties
@ManagedProperty(value = "#{authenticationManager}")
private AuthenticationManager authenticationManager;
/**
* Try to authenticate the user using Spring Security authentication mecanism
* The authentication is considered as accepted if there's no exception
* handled
*
* @return <tt>success</tt> if the authentication succeeded else <tt>failure</tt>
*/
@SuppressWarnings("unchecked")
public String authenticate() {
try {
final UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(getUsername(), getPassword());
final HttpServletRequest request = getRequest();
authReq.setDetails(new WebAuthenticationDetails(request));
final HttpSession session = request.getSession();
session.setAttribute(AuthenticationProcessingFilter.SPRING_SECURITY_LAST_USERNAME_KEY, getUsername());
// perform authentication
final Authentication auth = getAuthenticationManager().authenticate(authReq);
// initialize the security context.
final SecurityContext secCtx = SecurityContextHolder.getContext();
secCtx.setAuthentication(auth);
session.setAttribute(HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY, secCtx);
Account account = accountService.getByUsername(username);
UbikeUser user = account.getOwner();
user.getAccount().setLoggedIn(true);
ExternalContext exctx = FacesContext.getCurrentInstance().getExternalContext();
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
attrs.setAttribute("user", user, RequestAttributes.SCOPE_SESSION);
HttpServletResponse response = (HttpServletResponse) exctx.getResponse();
response.sendRedirect(exctx.getRequestContextPath() + "/resources/users/" + user.getId());
return BaseBean.LOGIN_SUCCESS;
} catch (Exception e) {
FacesContext fc = FacesContext.getCurrentInstance();
fc.addMessage("login:login_error", new FacesMessage(FacesMessage.SEVERITY_ERROR,
"The username and/or password is not correct! Please try again",
"The username and/or password is not correct! Please try again"));
return BaseBean.FAILURE;
}
}
/**
* Try to logout the client
*
* @param e The action event of the logout action
*/
public String logout(ActionEvent e) throws IOException {
return logout();
}
/**
*
* @throws IOException
*/
public String logout() throws IOException {
final HttpServletRequest request = getRequest();
UbikeUser u = (UbikeUser) BaseBean.getSessionAttribute("user");
request.getSession().removeAttribute(HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY);
// simulate the SecurityContextLogoutHandler
SecurityContextHolder.clearContext();
request.getSession().invalidate();
if (u != null) {
Account account = u.getAccount();
account.setLoggedIn(false);
this.accountService.update(account);
}
BaseBean.removeSessionAttribute("user");
BaseBean.removeSessionAttribute("client");
return BaseBean.LOGIN_REQUIRED;
}
/**
* @return
*/
private HttpServletRequest getRequest() {
return (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
}
/**
* @return The authentication manager
*/
public AuthenticationManager getAuthenticationManager() {
return authenticationManager;
}
/**
* @param authenticationManager The authentication manager to set
*/
@Required
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
/**
* @return The password
*/
public String getPassword() {
return this.password;
}
/**
* Assert the given String value to the password field
* @param password The new password value
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return The username
*/
public String getUsername() {
return this.username;
}
/**
* Assert the given String value to the username field
* @param userName
*/
public void setUsername(String userName) {
this.username = userName;
}
/**
* @return the remember
*/
public boolean isRemember() {
return remember;
}
/**
* @param remember the remember to set
*/
public void setRemember(boolean remember) {
this.remember = remember;
}
}