Get original url from J2EE Security Forward - jsf

I am using Container security (J2EE Security) in a PrimeFaces application and I cannot get the originally requested URL. After the user is authenticated, I want to direct them back to their original request. I cannot find that original request anywhere.
J2EE security provider is configured in Weblogic and form authentication is in the web XML like this:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>myrealm</realm-name>
<form-login-config>
<form-login-page>/faces/login.xhtml</form-login-page>
<form-error-page>/faces/unauthorized.xhtml</form-error-page>
</form-login-config>
</login-config>
In the login form, I do the authentication inside the bean. Imagine a simple form as such:
<h:form>
<p:inputText id="userName" value="#{userManager.userName}" />
<p:password id="password" value="#{userManager.password}"/>
<p:commandButton action="#{userManager.login()}" value="Login"/>
</h:form>
Login Bean would look like this:
#Named
#SessionScoped
public class UserManager implements Serializable {
private String userName;
private String password;
private String requestedURL;
#Inject
private HttpServletRequest request;
#PostConstruct
public void init() {
requestedURL = request.getHeader("Referer"); //this is null
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
String forwardRequestURI = (String)externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
}
public void login() {
request.login(getUserName(), getPassword());
//if successful, redirect back to place they came from
}
}
Both request.getHeader("Referer") and the RequestDispatcher.FORWARD_REQUEST_URI are null. What is the magic I need here?

For Weblogic, use:
String targetUrl = (String) session.getAttribute("weblogic.formauth.targeturl");

Related

JSF 2.2 Target Unreachable, identifier 'login' resolved to null

I have faced a problem which may be common in this forum but found no good solution.
Why this problem occurs and how to solve.
My program details are as follows
#Named("login")
#SessionScoped
public class Login implements Serializable {
private String userId;
private String password;
#Inject
private UserBeanLocal userBean;
public Login() {
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String isValid(){
if(userBean.getUser(userId).getPassword().equals(getPassword())) {
return "home?faces-redirect=true";
}
return "index?faces-redirect=true";
}
and the index.xhtml
<h:form>
<h:outputText class="title" value="Login"/><br/>
<h:inputText id="userId"
value="#{login.userId}"
requiredMessage="User Id is required!" /><br />
<h:inputText id="password"
value="#{login.password}"
requiredMessage="Password is required!"/>
<h:commandButton id="submit"
value="Submit"
action="#{login.isValid()}"/>
</h:form>
and the web.xml and beans.xml file is already there..
Did the CDI container boot properly? Please review your logs or try to inject an interface with no implementation and make sure that an exception is thrown.
Further if you have nothing defined in beans.xml then please remove everything in the file so that it's completely empty.
Remove the ("login") part of your #Named definition, it is superfluous to override with exact same value it would default to.
Make sure #SessionScoped is imported using the correct package. What you want is javax.enterprise.
Further answer the following questions:
1) What is your container?
2) Has CDI worked previously or is this your first try?
3) Describe the exact location of your beans.xml file.
Pasting your boot log from your servlet container would be helpful too (Tomcat, jboss whatever)

Session Scoped Managed Bean constructor being called on each page refresh

I am using a session scoped managed bean for handling login in a Java EE application. After I authenticate the user, the user object is saved in this session bean. However, after I refresh the page, the session bean values are gone.
I was debugging the code and it results that the constructor of the session scoped managed bean is called again on page refresh, therefore initializing the user object with a new user. I guess this is not a normal behavior since it should be preserved on the session shouldn't it?
I am posting some parts of the login managed bean including the parameters and the login method. Basically the enteredEmail and enteredPassword stand for the entered data on the login form. If the authentication succeeds, the loggedIn boolean is turned to true and the logged in user object is stored in the checkedUser variable.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class LoginController implements Serializable {
#EJB
private LoginSessionBean loginSessionBean;
#EJB
private LecturerFacade lecturerFacade;
private Lecturer checkedUser;
private String enteredEmail;
private String enteredPassword;
private boolean loggedIn;
/** Creates a new instance of loginController */
public LoginController() {
loggedIn = false;
checkedUser = new Lecturer();
}
public String login(){
RequestContext context = RequestContext.getCurrentInstance();
FacesMessage msg = null;
this.setCheckedUser(lecturerFacade.findLecturerByEmail(enteredEmail));
if(loginSessionBean.checkPassword(checkedUser, enteredPassword))
{
loggedIn = true;
msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Welcome", checkedUser.getFirstName()+ " " + checkedUser.getLastName());
FacesContext.getCurrentInstance().addMessage(null, msg);
context.addCallbackParam("loggedIn", loggedIn);
}
return "Index";
I am also posting the two EJBs that the above managed bean uses. The lecturerFacade retrieves the user object with the entered email, while the loginSessionBean checks the password.
#Stateless
public class LecturerFacade extends AbstractFacade<Lecturer> {
#PersistenceContext(unitName = "EffectinetWebPU")
private EntityManager em;
Logger logger = Logger.getLogger("MyLog");
FileHandler fh;
protected EntityManager getEntityManager() {
return em;
}
public LecturerFacade() {
super(Lecturer.class);
}
public Lecturer findLecturerByEmail(String email) {
try {
return (Lecturer) this.getEntityManager().createQuery("SELECT l FROM Lecturer l WHERE l.email = :email").setParameter("email", email).getSingleResult();
} catch (NoResultException e) {
System.err.println("Caught NOResultException: "+ e.getMessage());
return null;
} catch (NonUniqueResultException e) {
System.err.println("Caught NonUniqueResultException: "+ e.getMessage());
return null;
} catch (IllegalStateException e) {
System.err.println("Caught IllegalStateException: "+ e.getMessage());
return null;
}
}
_
#Stateless
public class LoginSessionBean {
// Add business logic below. (Right-click in editor and choose
// "Insert Code > Add Business Method")
#PersistenceContext(unitName = "EffectinetWebPU")
private EntityManager em;
protected EntityManager getEntityManager() {
return em;
}
public void setEntityManager(EntityManager em) {
this.em = em;
}
public boolean checkPassword(Lecturer user, final String enteredPassword) {
if (user.getPassword().equals(enteredPassword)) {
return true;
} else {
return false;
}
}
}
Please if someone has any suggestion of what is going wrong, please tell me
Im using glassfish 3.1 as application server and Primefaces as JSF library. Also, I have checked and the imported the sessionScoped annotation from the right package and not from javax.enterprise...
Your problem is thus here:
<p:menuitem value="Logout" ... onclick="#{loginController.logout()}"/>
The onclick attribute should represent a JavaScript handler function which is to be executed in the webbrowser when the enduser clicks the element. Something like
onclick="alert('You have clicked this element!')"
The onclick attribute also accepts a ValueExpression, so you can even let JSF/EL autogenerate its value accordingly:
onclick="#{bean.onclickFunction}"
with
public String getOnclickFunction() {
return "alert('You have clicked this element!')";
}
All the EL is thus evaluated when the page is rendered. In your particular case, the logout() method is called everytime the EL is evaluated and thus you're invalidating the session everytime the page is rendered!
You need to bind it to an attribute which takes a MethodExpression like <h:commandLink action>, <h:commandButton action> and in this particular case <p:menuitem action>.
<p:menuitem value="Logout" ... action="#{loginController.logout()}"/>
This can be understood by understanding basic HTML and JavaScript concepts and keeping in mind that JSF ultimately produces HTML/CSS/JS. Open the JSF page in webbrowser, rightclick and View Source to realize it.
Well I managed to solve it today. This was the problem, although I cannot explain why:
I was using Primefaces 3.2 as JSF library so this was the main menu of the index page.
<h:form>
<p:menubar >
<p:menuitem id="registerLink" value="Register" rendered="#{!loginController.loggedIn}" onclick="registerDialog.show()" />
<p:menuitem id="loginLink" value="Login" rendered="#{!loginController.loggedIn}" onclick="loginDialog.show()" />
<p:submenu label="Units" rendered="true">
<p:menuitem id="addNew" value="Add New" onclick="createUnitDialog.show()" />
<p:menuitem id="myUnits" value="My Units" onclick="" />
</p:submenu>
<p:menuitem id="results" value="Results/Statistics" rendered="#{loginController.loggedIn}" onclick=""/>
<p:menuitem id="profile" value="My Profile" rendered="#{loginController.loggedIn}" onclick=""/>
<p:menuitem id="logout" value="Logout" rendered="#{loginController.loggedIn}" onclick="#{loginController.logout()}"/>
</p:menubar>
</h:form>
After setting breakpoints to the whole code I discovered that the logout() method, which is supposed to destroy the managed bean, was called on every page refresh. I don't know why this happened as it should be called when the logout menuitem was clicked.
However, after changing the onclick="#{loginController.logout()} with action="#{loginController.logout()} the problem was solved.
I checked the documentation of Primefaces but nowhere this behavior was explained

JSF #ManagedProperty doesn't work

On various places they said that you should use #ManagedProperty to get a request parameters. The problem is that I try to get the token from the request string but it somehow stays null all the time.
The link where the page is with called looks like this:
http://example.com/faces/Check.xhtml?token=EC-8AT450931P272300C&ID=VKEFF29XNGNJG
The bean:
#Named(value = "bean")
#RequestScoped
public class Bean implements Serializable {
#Inject
private AccountBean account;
#Inject
private Service web;
#ManagedProperty(value = "#{param.token}")
private String token;
#ManagedProperty(value = "#{param.ID}")
private String id;
#PostConstruct
public void init() {
System.out.println("token: " + token);
}
The page
<ui:define name="content">
<h:form>
<pou:commandButton action="#{bean.test()}" value="complete"/>
</h:form>
</ui:define>
And other things I tried:
Map<String, String> e = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
This doesn't contain the request parameters also. Same goes for all the facesContext things where you can get requests with.
Help will be appreciated.
P.S. I can't change anything behind the ? cause its called from a program not in my reach
Okay made it work.
#Inject to pass params to a CDI #Named bean via URL
This was the solution just needed to add a few more things to my site
<ui:define name="content">
<h:form>
<h:inputHidden value="#{bean.token}"/>
<h:inputHidden value="#{bean.id}"/>
<pou:commandButton action="#{bean.test()}" value="complete"/>
</h:form>
</ui:define>
And remove the #{param.xxx} part from the naming
#Inject #HttpParam
private String token;
#Inject #HttpParam(value = "ID")
private String id;

JSF lifecycle - Execute managed bean method after request complete

Using JSF 2.0 and Spring, I use an #RequestScope managed bean. This bean stores information about the logged-in user. It loads the user from the DB in a #PostConstruct method:
#PostConstruct
public void init() {
String username = login.getUsername();
user = userDao.load(username);
}
The logged-in user can then trigger on action on the page that updates the user in database (using another managed bean).
However, the #RequestScope bean is constructed at the beginning of the request, which is before the call to the updating action. As a result, when the page is redisplayed, the User variable still has its old values.
My question is: do I have a way to run my loading method not at the beginning of the request, but after the request has been sent? Or am I dealing with this in the wrong way?
Thanks for your insight,
Sébastien
The logged-in user can then trigger on action on the page that updates the user in database (using another managed bean).
The same managed bean should have been updated at that point. If you can't reuse the same managed bean for some reason, then you should manually do it by accessing it in the action method and calling the setters yourself.
Update: based on the comments, here's how the beans should be declared and injected and used in your particular requirement:
#ManagedBean(name="#{login}")
#SessionScoped
public class LoginManager {
private String username;
// ...
}
#ManagedBean(name="#{user}")
#RequestScoped
public class UserManager {
#ManagedProperty(value="#{login}")
private LoginManager login;
private User current;
#PostConstruct
public void init() {
current = userDAO.find(login.getUsername());
}
// ...
}
#ManagedBean(name="#{profile}")
#RequestScoped
public class ProfileManager {
#ManagedProperty(value="#{user}")
private UserManager user;
public void save() {
userDAO.save(user.getCurrent());
}
// ...
}
<h:form>
<h:inputText value="#{user.current.firstname}" />
<h:inputText value="#{user.current.lastname}" />
<h:inputText value="#{user.current.birthdate}" />
...
<h:commandButton value="Save" action="#{profile.save}" />
</h:form>

Performing user authentication in Java EE / JSF using j_security_check

I'm wondering what the current approach is regarding user authentication for a web application making use of JSF 2.0 (and if any components do exist) and Java EE 6 core mechanisms (login/check permissions/logouts) with user information hold in a JPA entity. The Oracle Java EE tutorial is a bit sparse on this (only handles servlets).
This is without making use of a whole other framework, like Spring-Security (acegi), or Seam, but trying to stick hopefully with the new Java EE 6 platform (web profile) if possible.
I suppose you want form based authentication using deployment descriptors and j_security_check.
You can also do this in JSF by just using the same predefinied field names j_username and j_password as demonstrated in the tutorial.
E.g.
<form action="j_security_check" method="post">
<h:outputLabel for="j_username" value="Username" />
<h:inputText id="j_username" />
<br />
<h:outputLabel for="j_password" value="Password" />
<h:inputSecret id="j_password" />
<br />
<h:commandButton value="Login" />
</form>
You could do lazy loading in the User getter to check if the User is already logged in and if not, then check if the Principal is present in the request and if so, then get the User associated with j_username.
package com.stackoverflow.q2206911;
import java.io.IOException;
import java.security.Principal;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
#ManagedBean
#SessionScoped
public class Auth {
private User user; // The JPA entity.
#EJB
private UserService userService;
public User getUser() {
if (user == null) {
Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
if (principal != null) {
user = userService.find(principal.getName()); // Find User by j_username.
}
}
return user;
}
}
The User is obviously accessible in JSF EL by #{auth.user}.
To logout do a HttpServletRequest#logout() (and set User to null!). You can get a handle of the HttpServletRequest in JSF by ExternalContext#getRequest(). You can also just invalidate the session altogether.
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "login?faces-redirect=true";
}
For the remnant (defining users, roles and constraints in deployment descriptor and realm), just follow the Java EE 6 tutorial and the servletcontainer documentation the usual way.
Update: you can also use the new Servlet 3.0 HttpServletRequest#login() to do a programmatic login instead of using j_security_check which may not per-se be reachable by a dispatcher in some servletcontainers. In this case you can use a fullworthy JSF form and a bean with username and password properties and a login method which look like this:
<h:form>
<h:outputLabel for="username" value="Username" />
<h:inputText id="username" value="#{auth.username}" required="true" />
<h:message for="username" />
<br />
<h:outputLabel for="password" value="Password" />
<h:inputSecret id="password" value="#{auth.password}" required="true" />
<h:message for="password" />
<br />
<h:commandButton value="Login" action="#{auth.login}" />
<h:messages globalOnly="true" />
</h:form>
And this view scoped managed bean which also remembers the initially requested page:
#ManagedBean
#ViewScoped
public class Auth {
private String username;
private String password;
private String originalURL;
#PostConstruct
public void init() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
if (originalURL == null) {
originalURL = externalContext.getRequestContextPath() + "/home.xhtml";
} else {
String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING);
if (originalQuery != null) {
originalURL += "?" + originalQuery;
}
}
}
#EJB
private UserService userService;
public void login() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
try {
request.login(username, password);
User user = userService.find(username, password);
externalContext.getSessionMap().put("user", user);
externalContext.redirect(originalURL);
} catch (ServletException e) {
// Handle unknown username/password in request.login().
context.addMessage(null, new FacesMessage("Unknown login"));
}
}
public void logout() throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.invalidateSession();
externalContext.redirect(externalContext.getRequestContextPath() + "/login.xhtml");
}
// Getters/setters for username and password.
}
This way the User is accessible in JSF EL by #{user}.
After searching the Web and trying many different ways, here's what I'd suggest for Java EE 6 authentication:
Set up the security realm:
In my case, I had the users in the database. So I followed this blog post to create a JDBC Realm that could authenticate users based on username and MD5-hashed passwords in my database table:
http://blog.gamatam.com/2009/11/jdbc-realm-setup-with-glassfish-v3.html
Note: the post talks about a user and a group table in the database. I had a User class with a UserType enum attribute mapped via javax.persistence annotations to the database. I configured the realm with the same table for users and groups, using the userType column as the group column and it worked fine.
Use form authentication:
Still following the above blog post, configure your web.xml and sun-web.xml, but instead of using BASIC authentication, use FORM (actually, it doesn't matter which one you use, but I ended up using FORM). Use the standard HTML , not the JSF .
Then use BalusC's tip above on lazy initializing the user information from the database. He suggested doing it in a managed bean getting the principal from the faces context. I used, instead, a stateful session bean to store session information for each user, so I injected the session context:
#Resource
private SessionContext sessionContext;
With the principal, I can check the username and, using the EJB Entity Manager, get the User information from the database and store in my SessionInformation EJB.
Logout:
I also looked around for the best way to logout. The best one that I've found is using a Servlet:
#WebServlet(name = "LogoutServlet", urlPatterns = {"/logout"})
public class LogoutServlet extends HttpServlet {
#Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession(false);
// Destroys the session for this user.
if (session != null)
session.invalidate();
// Redirects back to the initial page.
response.sendRedirect(request.getContextPath());
}
}
Although my answer is really late considering the date of the question, I hope this helps other people that end up here from Google, just like I did.
Ciao,
Vítor Souza
It should be mentioned that it is an option to completely leave authentication issues to the front controller, e.g. an Apache Webserver and evaluate the HttpServletRequest.getRemoteUser() instead, which is the JAVA representation for the REMOTE_USER environment variable. This allows also sophisticated log in designs such as Shibboleth authentication. Filtering Requests to a servlet container through a web server is a good design for production environments, often mod_jk is used to do so.
The issue HttpServletRequest.login does not set authentication state in session has been fixed in 3.0.1. Update glassfish to the latest version and you're done.
Updating is quite straightforward:
glassfishv3/bin/pkg set-authority -P dev.glassfish.org
glassfishv3/bin/pkg image-update

Resources