Auto login and redirect after registration - jsf-2

I am creating a movie rental application using JSF 2.0 with Primefaces 3.4.1 as frontend. After a user is successfully registered, I need to automatically login with the newly created ID and redirect to the home page.
Currently, I am doing this way:
#ManagedBean
#ViewScoped
public class RegistrationBean extends BaseBean implements Serializable
{
...
public String register()
{
String nextPage = null;
User userDetails = new User();
try
{
BeanUtils.copyProperties(userDetails, this);
int registrationID = getServiceLocator().getUserService().registerUser(userDetails);
LOGGER.info("Registered user successfully. Registration ID - {}", registrationID);
// auto login
LoginBean loginBean = (LoginBean)FacesUtils.getManagedBean("loginBean");
loginBean.setUserId(userID);
loginBean.setPassword(password);
loginBean.login();
}
catch (Exception e) {
LOGGER.error("Error during registration - " + e.getMessage());
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, null,
FacesUtils.getValueFromResource(RESOURCE_BUNDLE, REGISTRATION_FAIL));
FacesContext.getCurrentInstance().addMessage(null, message);
}
return nextPage;
}
}
LoginBean :
#ManagedBean
#SessionScoped
public class LoginBean extends BaseBean implements Serializable
{
...
public String login()
{
FacesContext ctx = FacesContext.getCurrentInstance();
try
{
currentUser = getServiceLocator().getUserService().findUser(userID);
if (currentUser == null)
{
ctx.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, null,
FacesUtils.getValueFromResource(RESOURCE_BUNDLE, UNKNOWN_LOGIN)));
return (userID = password = null);
}
else
{
if (EncryptionUtils.compareHash(password, currentUser.getEncrPass())) {
return INDEX + "?faces-redirect=true";
}
else
{
ctx.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, null,
FacesUtils.getValueFromResource(RESOURCE_BUNDLE, AUTH_FAIL)));
return null;
}
}
}
catch (Exception e)
{
final String errorMessage = "Error occured during login - " + e.getMessage();
LOGGER.error(errorMessage);
ctx.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, null, errorMessage));
}
return null;
}
}
Above approach in register() method is, no doubt, wrong and insecure. Is there any way I can achieve the same in a cleaner way ??
Implementation using f:viewParam
RegistrationBean
int registrationID = getServiceLocator().getUserService().registerUser(userDetails);
LOGGER.info("Registered user successfully. Registration ID - {}", registrationID);
nextPage = LOGIN + "?faces-redirect=true&id=" + registrationID;
login.xhtml
<f:metadata>
<f:viewParam name="id" value="#{loginBean.regID}" />
<f:event listener="#{loginBean.autoLogin}" type="preRenderView"></f:event>
</f:metadata>
LoginBean
private int regID;
...
public void autoLogin()
{
if (regID > 0 && !FacesContext.getCurrentInstance().isPostback())
{
currentUser = getServiceLocator().getUserService().findUser(regID);
NavigationHandler navHandler = FacesUtils.getApplication().getNavigationHandler();
navHandler.handleNavigation(FacesContext.getCurrentInstance(), null, INDEX + "?faces-redirect=true");
}
}

So let us assume you are having three pages
Register/User Signup
Login
Home page
Here successful registration need auto login and needs to be redirected to home page but usually manual login is must after registration.
Anyhow, I would suggest you to separate login credential check in separate method in a facade class or you can have it in LoginBean too.
public User doLogin(String userName, String password) {
// query user
// match with password
// return null if not found or not matched
}
Add navigation-rule in faces-config.xml for registration bean and login bean
<navigation-case>
<from-outcome>loginSuccess</from-outcome>
<to-view-id>/home.xhtml</to-view-id>
<redirect/>
</navigation-case>
In both registration bean and login bean call doLogin method then if user found set navigation
NavigationHandler nh = facesContext.getApplication().getNavigationHandler();
nh.handleNavigation(facesContext, null, "loginSuccess");

Related

Get Managed Bean from servlet filter (is null) [duplicate]

This question already has an answer here:
JSF login filter, session is null
(1 answer)
Closed 7 years ago.
I've seen many posts like mine, but none could helped me.
this is my managed bean and it's sessionScoped, if the login is ok it redirects to index page else displays error
#ManagedBean
#SessionScoped
public class LoginBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final String[] users = {"anna:qazwsx","kate:123456"};
private String username;
private String password;
private boolean loggedIn
public String doLogin() {
for (String user: users) {
String dbUsername = user.split(":")[0];
String dbPassword = user.split(":")[1];
// Successful login
if (dbUsername.equals(username) && dbPassword.equals(password)) {
loggedIn = true;
return "/tmpl/home/index.xhtml?faces-redirect=true";
}
}
// Set login ERROR
FacesMessage msg = new FacesMessage("Login error!", "ERROR MSG");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
FacesContext.getCurrentInstance().addMessage(null, msg);
return "/login/login.xhtml";
}
public boolean isLoggedIn() {
return loggedIn;
}
}
The view, all is normal here , calls the doLogin method of managed bean
<h:form id="login-form">
<h:messages />
<h:outputText value="Nom d'utilisateur:"/>
<h:inputText value="#{loginBean.username}" id="username"/>
<br/>
<h:outputText value="Mot de passe:"/>
<h:inputSecret value="#{loginBean.password}" id="password"/>
<br/>
<h:commandButton id="button" value="Login" action="#{loginBean.doLogin}" />
<br/>
</h:form>
The filter: if the user is authenticated then the loginBean is not null and it's logged
public class LoginFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpSession session = ((HttpServletRequest) request).getSession(false);
LoginBean loginBean = (session != null) ? (LoginBean) session.getAttribute("loginBean") : null;
if (loginBean!=null)
System.out.println(loginBean.getUsername());
if (loginBean == null || !loginBean.isLoggedIn()) {
System.out.println("here agai");
String contextPath = ((HttpServletRequest)request).getContextPath();
((HttpServletResponse)response).sendRedirect(contextPath + "/login/login.xhtml");
}
chain.doFilter(request, response);
}
}
Why my managed bean (loginBean) is null?
Did you confirm that you're using the correct SessionScoped annotation?
See here:
JSF login filter, session is null

SpringSecurityService: Log other user out?

Is there any way, with springSecurityService, to log someone else out?
(For example, if a regular user leaves for the day and forgets to logout, and the manager wants to log their account out.)
I have done in my application where , A admin User can logged-out forcefully any user from the list of all users currently logged-in into the system.
I get all users those are currently logged-in into the system and send to the jsp where list of all logged-in users are shown to the Admin user.
#PreAuthorize("hasRole('Currently_Logged-In_Users')")
#RequestMapping(value = "/getLoggedInUsers", method = RequestMethod.POST)
#ResponseBody
public Map<String, List<?>> getLoggedInUsers(Map<String, Object> map ,Model model) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String userName = auth.getName();
List<Object> principals = sessionRegistry.getAllPrincipals();
List<UserInfo> usersInfoList = new ArrayList<UserInfo>();
for (Object principal: principals) {
if (principal instanceof UserInfo) {
if(!((UserInfo) principal).getUsername().equals(userName)){
for(SessionInformation sess :sessionRegistry.getAllSessions(principal, false)){
if(!sess.isExpired()){
usersInfoList.add((UserInfo) sess.getPrincipal());
}
}
}
}
}
Map<String, List<?>> loggedInUserMap = new HashMap<String, List<?>>();
loggedInUserMap.put("loggenInUsers",
usersInfoList);
return loggedInUserMap;
}
Now Admin user can select any user or multiple user by clicking on check box against the users. and call forced Logged-out action.
#PreAuthorize("hasRole('Currently_Logged-In_Users')")
#RequestMapping(value = "/logoutSelectedUsers", method = RequestMethod.POST)
#ResponseBody
public Map<String, String> forcedLoggedOut(#RequestParam("userList[]")ArrayList<String> userList ,Model model ,HttpServletRequest request ) {
Map<String,String> map= new HashMap<String,String>();
try{
String successMessage =null;
List<String> userCodeList = new ArrayList<String>();
for(String userCode :userList ){
userCodeList.add(userCode);
}
List<Object> principals = sessionRegistry.getAllPrincipals();
for (Object principal: principals) {
if (principal instanceof UserInfo) {
if(userCodeList.contains(((UserInfo) principal).getUsername())){
for(SessionInformation sess :sessionRegistry.getAllSessions(principal, false)){
sess.expireNow();
successMessage = "msg.loggedOutSuccessfully";
}
}
}
}
map.put("successmsg", successMessage);
}
catch(Exception e){
map.put("failmsg", "msg.notLoggedOut");
logger.error(e.toString(),e);
}
return map;
}
The springSecurityService itself does not have this capability.
However, nothing is stopping you from creating your own ServletFilter to track session ids and security principals and expose a controller and pages to invalidate the associated session with a login.
Here's how I do it.
Edit: The example below uses the webxml plugin. You can also edit web.xml directly. See this answer for setting the timeout.
// src/groovy/com/example/ExpiringSessionEventListener.groovy:
package com.example
import grails.util.Holders
import javax.servlet.http.HttpSessionListener
import javax.servlet.http.HttpSessionEvent
import org.springframework.security.core.context.SecurityContext
public class ExpiringSessionEventListener implements HttpSessionListener {
#Override
public void sessionCreated(HttpSessionEvent event) {
// Do some logging
}
#Override
public void sessionDestroyed(HttpSessionEvent event) {
SecurityContext securityContext = event.session.getAttribute("SPRING_SECURITY_CONTEXT")
if (securityContext) {
UserService userService = Holders.applicationContext.getBean("userService")
String userName = securityContext.authentication.principal.username
userService.userLoggedOut(userName, event.session.id, Boolean.TRUE)
}
}
}
// grails-app/services/com/example/UserService.groovy:
package com.example
import grails.plugin.springsecurity.annotation.Secured
class UserService {
#Secured(["ROLE_USER"])
def userLoggedOut(String userName, String sessionId, Boolean expired) {
User user = User.findByUsername(userName)
if (expired) {
// Do user cleanup stuff after expired session
} else {
// Do user cleanup stuff after clicking the logout button
}
}
}
Edit:
// grails-app/conf/WebXmlConfig.groovy:
webxml {
sessionConfig.sessionTimeout = 10 // minutes
listener.add = true
listener.classNames = [
"com.example.ExpiringSessionEventListener"
]
}

Webapp remembers last system login and displays to anyone accessing the site

Here is the scenario that I am noticing.
Jason logs in with username Jason
Tim logs in with username Tim
Jason logs out and gets redirected to login page
Jason sees username Tim in the username field
I am not understanding how/why Glassfish is doing this.
The project is deployed on Glassfish 3.1.2, running LDAP auth realm. The app is configured to use this realm to authenticate against.
The front end is using PrimeFaces for the login/logout functionality.
--EDIT--
Here is my login page
<h:form id="login-form" class="form-login">
<p:growl id="msg" showDetail="true" life="3000" />
<h4 class="form-login-heading">
Enter Login Information
</h4>
<br/>
<span class="error">
<h:messages errorStyle="color: red" infoStyle="color: green" globalOnly="true"/>
</span>
<div>
<h:panelGroup rendered="#{!authenticationController.authenticated}">
<div class="form-group">
<label for="username">Username</label>
<h:inputText id="username" styleClass="form-control" placeholder="Enter username" value="#{authenticationController.username}"/>
</div>
<div class="form-group">
<label for="password">Password</label>
<h:inputSecret id="password" styleClass="form-control" placeholder="Enter passowrd" value="#{authenticationController.password}" />
</div>
<h:commandButton id="login" styleClass="btn btn-primary pull-right lock-image" action="#{authenticationController.login}" value="Login">
</h:commandButton>
</h:panelGroup>
<br/>
</div>
Here is the login controller
#ManagedBean
#Named("authenticationController")
#SessionScoped
public class AuthenticationController implements Serializable {
#Inject
private AuthenticationOperation authOp;
private String username = null;
private User user = null;
private boolean authenticated = false;
private HttpSession session = null;
private String userAgent = null;
/**
* Creates a new instance of AuthenticationController
*/
public AuthenticationController() {
}
#PostConstruct
public void init(){
getUser();
}
public HttpSession getSession() {
// if(session == null){
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
session = request.getSession();
return session;
}
/**
* #return the username
*/
public String getUsername() {
this.username = getUser().getUsername();
return this.username;
}
/**
* #param username the username to set
*/
public void setUsername(String username) {
this.username = username;
getUser().setUsername(username);
}
/**
* #return the password
*/
public String getPassword() {
return authOp.getPassword();
}
/**
* #param password the password to set
*/
public void setPassword(String password) {
authOp.setPassword(password);
}
public User getUser() {
if (this.user == null) {
user = new User();
setUser(authOp.getUser());
}
return user;
}
public void setUser(User user) {
this.user = user;
}
/**
* This method is called from the view.
*
* On successful login the view will be forwarded to the main index page. Otherwise,
* The user will be prompted to login again.
* #return The view return either the index page or bad login.
*/
public String login() {
authOp.setUser(getUser());
if (authOp.authenticate()) {
this.authenticated = true;
setUser(authOp.getUser());
return "index?faces-redirect=true";
} else {
this.authenticated = false;
setUser(null);
return "BAD_LOGIN";
}
}
/**
* Logs a user out - essentially invalidating the user's http session and then
* forwarding the view on to the login page.
* #throws IOException
*/
public void logout() throws IOException{
user = null;
this.authenticated = false;
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.invalidateSession();
externalContext.redirect(externalContext.getRequestContextPath() + "/users/login.xhtml");
}
/**
* A simple check to see if the current user has been authenticated.
* #return the authenticated
*/
public boolean isAuthenticated() {
try {
// Allows subsequent requests to obtain authentication status from the session state
boolean auth = (Boolean) getSession().getAttribute("authenticated");
if (auth) {
this.authenticated = true;
} else {
authenticated = false;
}
} catch (Exception e) {
this.authenticated = false;
}
return authenticated;
}
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
}
I believe your authOp variable is likely application scoped. This would cause a user to see a previous users' name because of this section of code:
public User getUser() {
if (this.user == null) {
user = new User();
setUser(authOp.getUser());
}
return user;
}

Programmatically login from a link in spring security

i am trying to automatically authorization without login in spring security. The user would be authorized by clicking a link in a website.
I have a class UserLoginService that called from spring-security xml file like this;
<authentication-manager>
<authentication-provider user-service-ref="userLoginService" >
<password-encoder hash="md5"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="userLoginService"
class="tr.com.enlil.formdesigner.server.guvenlik.UserLoginService">
</beans:bean>
UserLoginService class;
public class UserLoginService implements UserDetailsService {
private static Logger logger = Logger.getLogger(InitServlet.class);
#Autowired
private IKullaniciBusinessManager iKullaniciBusinessManager;
/**
* {#inheritDoc}
*/
#Override
public UserDetails loadUserByUsername(String username) {
try {
Kullanici kullanici = new Kullanici();
kullanici.setKullaniciAdi(username);
Kullanici kullaniciBusinessManager = iKullaniciBusinessManager.getirKullaniciAdinaGore(kullanici);
User user = new User();
if (kullaniciBusinessManager != null && kullaniciBusinessManager.getAktifmi()) {
user.setUsername(kullaniciBusinessManager.getKullaniciAdi());
user.setPassword(kullaniciBusinessManager.getSifre());
user.setKullanici(kullaniciBusinessManager);
List<String> yetkiListesi = new ArrayList<String>();
List<GrantedAuthority> grandAuthorities = new ArrayList<GrantedAuthority>();
//TODO yetkilerle alakalı birşey yapmak gerekebilir.
for (String yetki : yetkiListesi) {
GrantedAuthorityImpl g = new GrantedAuthorityImpl(yetki);
grandAuthorities.add(g);
}
user.setAuthorities(grandAuthorities);
}
return user;
} catch (Exception e) {
logger.error("Kullanici alinirken hata olustu!!", e);
}
return null;
}
public static void autoLogin(User user, HttpServletRequest request, AuthenticationManager authenticationManager) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(),
user.getPassword(), user.getAuthorities());
// generate session if one doesn't exist
request.getSession();
token.setDetails(new WebAuthenticationDetails(request));
Authentication authenticatedUser = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
// setting role to the session
request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
SecurityContextHolder.getContext());
}
}
I found autoLogin method from Make Programmatic login without username/password?. But i dont know, from where can i call this method and will this code help me.
Thanks in advance.
You will have to create your own implementation of AbstractPreAuthenticatedProcessingFilter. The method getPreAuthenticatedPrincipal(HttpServletRequest request) will have the request where you can get your credentials from. You will need to return a subject if it is a valid user or null if it is not. Your implementation of UserDetailsService will transform the subject to a UserDetails object.

Guice 3.0 #ScopeSession User object not invalidate on session timeout

I have a class :
#SessionScoped
public class LoggedUser {
private User user;
...
}
that I use to keep track if a user is logged in my application.
In my Struts2 application I have a Interceptor to check if the user is logged, if not he's forwarded to the login page.
public class LoggedUserInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 2822434409188961460L;
#Inject
private LoggedUser loggedUser;
#Override
public String intercept(ActionInvocation invocation) throws Exception {
if(loggedUser==null || !loggedUser.isLogged()){
return "login";
}
return invocation.invoke();
}
}
The problem occur when the session timeout. The object LoggdeUser is never null or deleted. I have always the last instance.
I added A session listener.
public class SessionListener implements HttpSessionListener {
private static Logger logger = Logger.getLogger(SessionListener.class.getName());
#Override
public void sessionCreated(HttpSessionEvent event) {
logger.info("sessionCreated = " + event.getSession().getId());
}
#Override
public void sessionDestroyed(HttpSessionEvent event) {
logger.info("sessionDestroyed = " + event.getSession().getId());
}
}
I see that sessionDestroyed is called, but when I enter again in my Interceptor.. LoggedUser is never recreated for a new session.
why ?
my Struts2 Action for the login is this
public class LoginUserAction extends ActionSupport implements ModelDriven<LoggedUser>, ServletRequestAware {
...
#Inject
private LoggedUser loggedUser;
public String execute() throws Exception {
...
loggerUser.setLoggedTime(now);
...
return SUCCESS;
}
I add that too in web.xml
session-config
session-timeout 2 /session-timeout
/session-config
I don't know anything about Struts2, but my guess is that the interceptor's scope is wider than session scope. In other words, the interceptor instance is kept around longer than the session. Guice can't and won't set an injected field to null when the session ends, nor will it ever re-inject an object automatically.
What you need to do if you use an object with a shorter lifecycle inside an object with a longer lifecycle (such as a RequestScoped object inside a SessionScoped object or a SessionScoped object inside a singleton) is inject a Provider for the shorter lived object.
In your case, I think this is probably what you need:
public class LoggedUserInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 2822434409188961460L;
#Inject
private Provider<LoggedUser> loggedUserProvider;
#Override
public String intercept(ActionInvocation invocation) throws Exception {
LoggedUser loggedUser = loggedUserProvider.get();
if(loggedUser==null || !loggedUser.isLogged()){
return "login";
}
return invocation.invoke();
}
}
I don't know guice but the session is available to the interceptor and can be made readily available to the action via SessionAware :
ActionInvocation provides access to the session. The following is part of a "Authentication" interceptor. If there is not a "User" object then Action.LOGIN is returned.
public String intercept(ActionInvocation invocation) throws Exception {
Map session = invocation.getInvocationContext().getSession();
appLayer.User user = (appLayer.User) session.get("User");
if (user == null){
return Action.LOGIN;
}
return invocation.invoke();
}
I only place the user object on the session when the user logs in.
In the login action I place the user object on the session:
public class Login extends ActionSupport implements SessionAware {
private Map<String, Object> session;
private String userName;
private String password;
public String execute() {
//use DB authentication once this works
//if ("ken".equalsIgnoreCase(userName) && "ken".equalsIgnoreCase(password)){
try {
User user = new User(userName, password);
session.put("User", user);
return ActionSupport.SUCCESS;
} catch (Exception e) {
System.out.println("There was an exception" + e.getMessage());
return ActionSupport.LOGIN;
}
}
public void validate() {
String user = this.getUserName();
String pass = this.getPassword();
//This block is a bit redundant but I couldn't figure out how
//to get just the hibernate part to report an exception on Username/pass
if (!StringUtils.isBlank(this.getUserName()) && !StringUtils.isBlank(this.getPassword())) {
try {
Class.forName("com.ibm.as400.access.AS400JDBCDriver").newInstance();
String url = "jdbc:as400://192.168.1.14";
DriverManager.getConnection(url, user, pass).close();
} catch (Exception e) {
addFieldError("login.error.authenticate", "Bad Username / Password");
}
}
if (StringUtils.isBlank(getUserName())) {
addFieldError("login.error.name", "Missing User Name");
}
if (StringUtils.isBlank(getPassword())) {
addFieldError("login.error.password", "Missing Password");
}
//else both are blank don't report an error at this time
}
... getters/setters....
}//end class
If I remember correctly this comes from at least in part from "Struts2 in Action". Anyways I'm a big believer in DI but since the Session is pretty accessible from the interceptors and the action I don't bother.
the easiest way to do that is finally to put the token in the session at the login and check it with an Interceptor
#Override
public String intercept(ActionInvocation invocation) throws Exception {
loggedUser = (LoggedUser) invocation.getInvocationContext().getSession().get(LoggedUser.SESSIONTOKEN);
if(loggedUser==null || !loggedUser.isLogged()){
logger.info("loggedUser not present in session");
return "login";
}
return invocation.invoke();
}
in the Action
request.getSession().setAttribute(LoggedUser.SESSIONTOKEN, loggedUser);

Resources