simple jsf commandbutton work on every single page except home page - jsf

A Java EE 8/SE 8 web application in deployement runnnig on Glassfish 5 build 25 both production and development, uses jsf 2.3. users create accounts and login. there is a 'logout' button for loging out.
Problem: 'logout' button works as expected everywhere on the website. EXCEPT home page (example.com) & (example.com/home.xhtml). the problem does not exists on my local computer. only in production (example.com).
So I have a template called : index.xhtml . all pages use it, including home.xhtml:
<ui:composition template="index.xhtml">
<ui:define name="top-bar">
<c:if test="#{request.remoteUser ne null}">
<h:form ><h:commandButton value="Log out" action="#{registerAdvanced.logout}"/></h:form>
</c:if>
</ui:define>
and
#Named
#RequestScoped
public class RegisterAdvanced extends BaseBacking implements Serializable {
public String logout() {
try {
getRequest().logout();
getContext().getExternalContext().getSessionMap().remove("user");
return REDIRECT_PAGE;
} catch (ServletException ex) {
return REDIRECT_PAGE;
}
}
}
Users login & logout fairly easily until I noticied that clicking on logout on the home page (home.xhtml) prints a null pointer exception AND redirect to 404 error page.
[[/home.xhtml #450,77 value="#{passesTestBean.displayPassSummaryList}": java.lang.NullPointerException
javax.el.ELException: /home.xhtml #450,77 value="#{passesTestBean.displayPassSummaryList}": java.lang.NullPointerException
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:119)
at com.sun.faces.facelets.component.UIRepeat.getValue(UIRepeat.java:314)
at com.sun.faces.facelets.component.UIRepeat.getDataModel(UIRepeat.java:256)
at com.sun.faces.facelets.component.UIRepeat.setIndex(UIRepeat.java:507)
at com.sun.faces.facelets.component.UIRepeat.process(UIRepeat.java:557)
at com.sun.faces.facelets.component.UIRepeat.processDecodes(UIRepeat.java:861)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1258)....
part of jsf where there is a call to value="#{passesTestBean.displayPassSummaryList}" is 100% seperate to logout and PassesTestBean CDI is request scope.
so the problem is SOMEHOW when I click on logout button. PassesTestBean is called for no reason and not since jsf must Initialize (since Request Scoped). it ends up returning null.
Now remember this only happens in: production at example.com AND only home page of all pages.
I'm thinking of writing a page only for loging out: has a log out button only.

Check for null pointer exception
getRequest().logout(); //here
getContext().getExternalContext().getSessionMap().remove("user");//here

Related

JSF setKeepMessages(true) stopped working for Chrome on redirect

I am trying to display a success message in the case of a succesful user creation after it redirects from the create_user page to the users list.
This specific part of code used to work fine for Chrome, Firefox and Edge browsers.
The button which creates the user on the respected xhtml page:
<p:commandButton actionListener="#{myHandler.createUpdateUser}" value="#{msg.save}" />
which calls this specific code :
#ManagedBean
#ViewScoped
public Class myClass implements Serializable {
public void createUpdateUser(){
myBean.createUpdateUser();
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, StringUtils.EMPTY));
externalContext.getFlash().setKeepMessages(true);
externalContext.redirect(new StringBuilder(externalContext.getRequestContextPath())
.append("/users/list_users.jsf");
}
}
Both pages can display messages as follows :
<p:messages id="messages" autoUpdate="true" />
Now it works only for Firefox and Edge.
When creating a user in chrome the success message appears spontaneously on the create_user page and redirects succesfully to the list page without displaying the message. The message is also not in FacesContext.getMessageList();
I tried switching from actionListener to action in the commandButton which
successfully worked for Chrome, but unfortunately did not work correct for the other two.
I am using Primefaces v6.0, java 1.8, jboss eap 7.
Chrome Version 64.0.3282.186 (Official Build) (64-bit)
Any ideas what has gone wrong?

Verifying additional parameter with j-security-check

I have implemented web application login using j-security-check which accepts parameters j_username and j_password for authentication with background registry. Now, I need to add date of birth as one more parameter and need to authenticate the user with this parameter too.
Is there a way to extend j-security-check to accept additional parameters?
I would like to avoid performing the check in a servlet filter, if possible.
Using WebSphere V8, MyFaces JSF 2.0, Servlet 3.0, Custom database based authentication
The easiest way would be to append the date of birth to the actual j_username (ie. with JavaScript and then manually split it in the login module.
Replace j_security_check by programmatic login via HttpServletRequest#login().
E.g.
<h:form>
<h:inputText value="#{bean.username}" />
<h:inputSecret value="#{bean.password}" />
<h:inputText value="#{bean.birthdate}" />
<h:commandButton value="Login" action="#{bean.login}" />
</h:form>
with
public void login() {
// Do your thing with birthdate here.
// ...
// Then perform programmatic login.
try {
request.login(username, password);
// Login success. Redirect to landing page.
} catch (ServletException e) {
// Login fail. Return to login page.
}
}
This is in detail outlined in 2nd part of this answer: Performing user authentication in Java EE / JSF using j_security_check

JSF / Java EE form vs programmatic authentication

I have been experimenting with the substance of this question (JSF / Java EE login without requiring a protected resource).
If I set up a sample application using BASIC authentication, with one public page (/public.xhtml), and one protected page (/protected/private.xhtml), and I have a link from the first page to the second (as shown below), everything works perfectly.
<h:commandButton value="Go Private" action="/protected/private?faces-redirect=true" />
However, if I remove the login-config and replace the above button with:
<h:commandButton value="Go Private" action="#{mybean.login}" />
...and #{mybean.login} looks something like this...
public String login() {
HttpServletRequest request = ...
try {
request.login("known username", "known password");
} catch (Exception e) {
// handle unknown credentials
}
return "/protected/private?faces-redirect=true";
}
In this case, the login succeeds (no exception from request.login()), but the browser shows a "forbidden resource" page.
Can anyone shed any light on the difference between the two scenarios?
The HttpServletRequest#login() programmatic login works only with FORM based authentication configuration. Removing the <login-config> would make it to default to BASIC and thus the login() will never work. The login() basically sets the user in the session, however the BASIC authentication basically checks the Authenticate HTTP request header, not the session.
Put that <login-config> back and set it to FORM if you want to utilize login().
Where it is:
<h:commandButton value="Go Private" action="#{mybean.login}" />
it should be:
<h:commandButton value="Go Private" action="#{mybean.login()}" />
if you want to use the login methode.
But maybe your mybean also has
String private login;
public String getLogin(){ return this.login ;}
and you've loaded the var with the desired response.

jsf navigation question

I have a JSF2 project with a "view user" page that reads the currently selected user from a session bean; userHandler.selectedUser.
The page is intended to be visited by navigating with links in the app.
However, if the user attempts to hit the "view user" page directly by this URL ...
http://localhost:8080/webapp/userView.jsf
... they see the page with no data on it (because there's no selected user in the userHandler).
I think what I'd like to do is redirect the user to the main page of the app if they try to hit it directly like that. What is a simple and elegant way of handling this problem?
Thanks,
Rob
You'd like to hook on the preRenderView event and then send a redirect when this is the case.
<f:metadata>
<f:event type="preRenderView" listener="#{bean.preRenderView}" />
</f:metadata>
with
public void preRenderView() throws IOException {
if (userHandler.getSelectedUser() == null) {
FacesContext.getCurrentInstance().getExternalContext().redirect("home.jsf");
}
}
A way to avoid this problem from the start is to have pages that you don't want to be accessed directly via URL into the WEB-INF folder of your project.
This way, your pages aren't accessible directly via URL.

Xhtml pages and HttpSession test , no jstl?

I have a dynamic web application in Java EE with JSF, Facelets, Richfaces.
My pages are all xhtml pages.
So JSTL isn't working in it.
For my account pages and all other private pages to be reachable, I want to test if the user got connected, so if the attribute session in HttpSession is not null. If it's null, the user gets redirected in the welcome page.
I tried in my xhtml page :
<jstl:if test="${sessionScope['session']==null}">
<jstl redirect...>
</jstl:if>-->
but as it's not jsp page it won't work. So where am I supposed to test if the session is not null to allow the user to see his private pages ?
in a central managed bean ?
The normal place for this is a Filter.
Create a class which implementsjavax.servlet.Filter and write the following logic in the doFilter() method:
if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
// Not logged in, so redirect request to login page.
((HttpServletResponse) response).sendRedirect("/login.jsf");
} else {
// Logged in, so just continue request.
chain.doFilter(request, response);
}
Map this filter in web.xml on an url-pattern of something like /private/*, /secured/*, /restricted/*, etc.
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>com.example.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/private/*</url-pattern>
</filter-mapping>
If you have the private pages in the /private folder then this filter will be invoked and handle the presence of the logged-in user in the session accordingly.
Note that I renamed attribute name session to user since that makes much more sense. The HttpSession itself is namely already the session. It would otherise been too ambiguous and confusing for other developers checking/maintaining your code.

Resources