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

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;
}

Related

How to access DropDown values in Struts 2 Action

My requirement is, at beginning I want to show users data on page and when user make changes in form, I want to access changed data.
Below is my code in Action class,
public class DisplayData extends ActionSupport implements ModelDriven<List<User>>, Preparable {
private List<User> userList;
#Override
public void prepare() throws Exception {
userList = new ArrayList<User>();
userList.add(new User("Demo","N"));
userList.add(new User("Demo1","Y"));
userList.add(new User("Demo2","Y"));
userList.add(new User("Demo3","N"));
}
#Override
public List<User> getModel() {
return userList;
}
public String execute(){
for (User value: userList) {
System.out.println(value.getName() +":"+value.getFlag());
}
return "success";
}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
}
User class,
public class User implements Serializable
{
private String name;
private String flag;
public User() {}
public User(String name,String flag) {
super();
this.name = name;
this.flag = flag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
}
Code in Jsp page,
<s:form name="getData" action="getData" method="post">
<table>
<s:iterator value="model" status="rowStatus">
<tr>
<td>
<s:textfield name="model[%{#rowStatus.index}].name" value="%{model[#rowStatus.index].name}"/>
<s:select name="%{model[#rowStatus.index].flag}" value="%{model[#rowStatus.index].flag}"
list="#{'Y':'Yes','N':'No'}" />
</td>
</tr>
</s:iterator>
</table>
<s:submit name="ok" value="ok" />
</s:form>
When page get rendered, it shows appropriate value of textfield and dropdown.
If I changed the values in Textfield and droprdown and submit the form then I am getting modified value of textfield but for the dropdwon it shows old value. How can I access selected value of dropdown?
Got the answer... :)
It was syntax mistake. Instead of
<s:select name="%{model[#rowStatus.index].flag}" value="%{model[#rowStatus.index].flag}"
list="#{'Y':'Yes','N':'No'}" />
Use
<s:select name="model[#rowStatus.index].flag" value="%{model[#rowStatus.index].flag}"
list="#{'Y':'Yes','N':'No'}" />
I have used %{ } in name attribute..

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

JSF Login with HttpServletRequest

i found a solution in stackoverflow how to code a login in JSF using HttpServletRequest.
First things first, the login.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Login</title>
</h:head>
<h:body>
<h3>Login here</h3>
<h:form id="loginForm">
<h:outputLabel for="username" value="Username:" />
<h:inputText value="#{loginService.userName}" id="username" requried="true" />
<br/>
<h:outputLabel for="password" value="Password:" />
<h:inputSecret value="#{loginService.password}" id="password" requried="true" />
<br/>
<h:commandButton id="button" value="Login" action="#{loginService.doLogin}" />
<br/>
<h:commandLink action="#{navigationService.redirectToIndex}" value="Home" />
<br/>
<h:messages />
<br/>
</h:form>
</h:body>
The loginService:
#Named
#SessionScoped
public class LoginService implements Serializable {
private String userName = "";
private String password = "";
#Inject
private NavigationService navigationService = null;
#Inject
private String originalURL = "";
/**
*
*/
#PostConstruct
public void init() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
this.originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
if(this.originalURL == null) {
this.originalURL = externalContext.getRequestContextPath() + navigationService.toIndex();
} else {
String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING);
if(originalQuery != null) {
this.originalURL += "?" + originalQuery;
}
}
}
/**
*
* #return
* #throws IOException
*/
public void doLogin() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest)externalContext.getRequest();
try {
request.login(this.userName, this.password);
User user = dao.findUserByUserName(userName);
externalContext.getSessionMap().put("user", user);
externalContext.redirect(this.originalURL);
} catch(ServletException e) {
context.addMessage(null, new FacesMessage("Unknown login"));
} catch (NoSuchUserException e) {
context.addMessage(null, new FacesMessage(e.getMessage()));
}
}
/**
*
* #return
* #throws IOException
*/
public void doLogout() throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.invalidateSession();
externalContext.redirect(externalContext.getRequestContextPath() + navigationService.toLogin());
}
// Getters and Setters
}
The only thing i still need to know is now:
Where can i define for which pages login is needed?
A suggested solution is: putting all the pages requiring logging under one place (folder, ex: "private_section"), and the pages that don't need it (public access) are to be put wherever in the project context except under the folder "private_section". Then you can use a simple filter to control accessing to the private region (to our folder), and through this pattern (first annotation) you can specify the region to be controlled :
// imports
#WebFilter("/private_section/*")
public class LoggingFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
UserBean user = (UserBean) req.getSession().getAttribute("user");
if (user != null && user.isLoggedIn()){
chain.doFilter(request,response);
}
else res.sendRedirect(req.getContextPath()+"/index.xhtml");
}
// other overriden methods

Auto login and redirect after registration

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");

POJO's collection not populated when submitting form

I have a POJO named "FlashCard" which has a field named "links" which is collection (set) of Link objects. When I submit a FORM to my Action all the POJO fields are populated with values from the form except the collection of "links". I have no idea why this isn't getting populated.
Any advice on how to resolve this problem or how to better troubleshoot it would be much appreciated.
Also, my POJO's collection is a Set. Does it matter (or complicate things) that I'm using a Set and not a List?
I'm including a simplified version of my code below.
Here's my POJO:
public class FlashCard implements java.io.Serializable {
private int flashCardId;
private String question;
private String answer;
private Set<Link> links = new HashSet<Link>(0);
public FlashCard() {
}
public FlashCard(String question, String answer) {
this.question = question;
this.answer = answer;
}
public FlashCard(String question, String answer, Set<Link> links) {
this.question = question;
this.answer = answer;
this.links = links;
}
public int getFlashCardId() {
return this.flashCardId;
}
public void setFlashCardId(int flashCardId) {
this.flashCardId = flashCardId;
}
public String getQuestion() {
return this.question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getAnswer() {
return this.answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
public Set<Link> getLinks() {
return this.links;
}
public void setLinks(Set<Link> links) {
this.links = links;
}
}
Here's the POJO for the Link object:
public class Link implements java.io.Serializable {
private int linkId;
private String url;
private Set<FlashCard> flashcards = new HashSet<FlashCard>(0);
public Link() {
}
public Link(String url) {
this.url = url;
}
public Link(String url, Set<FlashCard> flashcards) {
this.url = url;
this.flashcards = flashcards;
}
public int getLinkId() {
return this.linkId;
}
public void setLinkId(int linkId) {
this.linkId = linkId;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public Set<FlashCard> getFlashcards() {
return this.flashcards;
}
public void setFlashcards(Set<FlashCard> flashcards) {
this.flashcards = flashcards;
}
}
Here's the relevant part of the Action
public class FlashCardAction extends FlashCardsAppBaseAction implements ModelDriven<FlashCard>, Preparable, SessionAware {
static Logger logger = Logger.getLogger(FlashCardAction.class);
FlashCard flashCard = new FlashCard();
Map <String,Object> httpSession;
Session session;
FlashCardPersister fcPersister;
public Map<String, Object> getHttpSession() {
return httpSession;
}
public FlashCard getFlashCard() {
return this.flashCard;
}
public void setFlashCard(FlashCard flashCard) {
this.flashCard = flashCard;
}
public void validate() {
logger.debug("Entering validate()");
if ( flashCard.getQuestion().length() == 0 ){
addFieldError("flashCard.question", getText("error.flashcard.question"));
}
if ( flashCard.getAnswer().length() == 0 ) {
addFieldError("flashCard.answer", getText("error.flashcard.answer"));
}
}
public String saveOrUpdate() {
logger.debug("Entering saveOrUpdate()");
// assume we'll fail
boolean result = false;
// are we creating a New Flash Card or Updating and existing one
// for now, let's assume we are creating a New Flash Card
boolean newFlashCard = true;
// if this is an Update of an existing Flash CArd then we'll have a Flash Card Id other than 0
if (this.flashCard.getFlashCardId() != 0) {
newFlashCard = false;
}
try {
result = fcPersister.saveOrUpdateFlashCard(this.flashCard, session);
// did we save a new FlashCard successfully?
if (result == true && newFlashCard) {
logger.debug("Flash Card created successfully");
this.addActionMessage(getText("actionmessage.flashcard.created"));
}
// did we update an existing Flash Card successfully?
else if (result == true && newFlashCard == false) {
logger.debug("Flash Card updated successfully");
this.addActionMessage(getText("actionmessage.flashcard.updated"));
}
// such a failure
else {
logger.error("unable to create or update FlashCard");
return "error";
}
return "success";
} catch (Exception e) {
logger.error("Exception in createFlashCard():", e);
return "error";
}
}
#Override
public FlashCard getModel() {
return this.flashCard;
}
#Override
public void setSession(Map<String, Object> httpSession) {
this.httpSession = httpSession;
}
#Override
public void prepare() throws Exception {
logger.debug("Entering prepare()");
// get a handle to a Hibernate session
session = getHibernateSession();
// get a handle to the FlashCard persistance utility class
fcPersister = new FlashCardPersister();
}
}
And lastly here's the JSP
<%#page import="com.opensymphony.xwork2.ActionContext"%>
<%#page import="com.opensymphony.xwork2.ActionSupport"%>
<%# page contentType="text/html; charset=UTF-8"%>
<%# taglib prefix="s" uri="/struts-tags"%>
<%# taglib prefix="sjr" uri="/struts-jquery-richtext-tags"%>
<h3><s:text name="label.flashcard.title"/></h3>
<s:actionerror theme="jquery" />
<s:actionmessage theme="jquery"/>
<s:fielderror theme="jquery"/>
<s:form action="saveOrUpdate" method="post">
<s:hidden name="flashCard.flashCardId" />
<s:textfield name="flashCard.question" key="label.flashcard.question" size="66" />
<sjr:tinymce
id="flashCard.answer"
name="flashCard.answer"
key="label.flashcard.answer"
rows="20"
cols="50"
editorTheme="simple"
/>
<s:textfield name="flashCard.links.url" key="label.flashcard.link" size="66" />
<tr>
<td>
<s:submit label="label.flashcard.submit" align="center" theme="simple" />
</td>
<td>
<s:submit key="label.flashcard.cancel" name="redirectAction:list" theme="simple" />
</td>
</tr>
</s:form>
<%((ActionSupport)ActionContext.getContext().getActionInvocation().getAction()).clearErrorsAndMessages();%>
First of all I don't think you can use Set here, because Sets are unordered and you can't get an item from a set by an index or key like List and Map. The only way is to iterate through the set and get the items.
Second assuming you're using a collection other than set, in:
<s:textfield name="flashCard.links.url" key="label.flashcard.link" size="66"/>
You try to set the value of the text field to url field of links which is a collection and doesn't have such a field. So you need to get the specific item from the collection you're editing and pass the value. Like:
<s:textfield name="flashCard.links[0].url" key="label.flashcard.link" size="66"/>
But since you can't get the specific item you are editing I suggest you create a link field in your Action and set the updated link to it. Then you can perform a logic to relace the updated link with obsolete one in you flashcards. Hope this helps.
Since you are using modeldriven and the model is FlashCard, i think the following
<sjr:tinymce
id="flashCard.answer"
name="flashCard.answer"
key="label.flashcard.answer"
rows="20"
cols="50"
editorTheme="simple"/>
should be changed to
<sjr:tinymce
id="flashCard.answer"
name="answer"
key="label.flashcard.answer"
rows="20"
cols="50"
value="answer"
editorTheme="simple"/>
the name field should be given without the prefix flashcard.also you should provide the 'value' attribute in order for it to be pre-populated.

Resources