Tuesday, June 30, 2015

How could I wire j_username and j_password in managed bean?

Two things required in a typical design of an authentication mechanism in J2EE 6; one is the security-constraint in Deployment Descriptor as shown below:
...

 <security-constraint>
  <web-resource-collection>
   <web-resource-name>Authentication</web-resource-name>
   <description>Please login</description>
   <url-pattern>/pages/*</url-pattern>
   <http-method>GET</http-method>
   <http-method>POST</http-method>
  </web-resource-collection>
  <auth-constraint>
   <role-name>Junior</role-name>
  </auth-constraint>
 </security-constraint>

 <login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
   <form-login-page>/login.xhtml</form-login-page>
   <form-error-page>/error.xhtml</form-error-page>
  </form-login-config>
 </login-config>
 
 <security-role>
  <role-name>Junior</role-name>
 </security-role>
Second would be the form in login page:
...

 <form method="post" action="j_security_check">
  <h:outputLabel value="Username: " />
  <p:inputText id="j_username" />
  <h:outputLabel value="Password: " />
     <p:password id="j_password" />
     <p:commandButton action="#{myController.link}" value="please login"/>
     
 </form>
As in the value shown in url-pattern, I have my protected page sit inside this directory. Whereas the login page doesn't need to be inside that directory, it would be best to put in the root of WebContent. The managed bean that wired the login page is as follow:
@ManagedBean
@RequestScoped
public class MyController {

 public void link() {
   FacesContext.getCurrentInstance().getExternalContext().redirect("landingpage.xhtml");
 }
}
But then I was wondering whether I'm doing the login page correctly as according to the J2EE 6 standard? Assuming I'm wrong, how could I move j_username, and j_password into a managed bean? After some research on this matter, there are two things need to be done in order to meet my objective. First, the form is no longer require to send post method to j_security_check:
...

 <h:form>
     <h:outputLabel value="Username: " />
     <p:inputText id="username" value="#{myController.username}" />
     <h:outputLabel value="Password: " />
     <p:password id="password" value="#{myController.password}" />
     <p:commandButton action="#{myController.link}" value="link"/>
 </h:form>
And the login process was handled in the managed bean as shown below:
@ManagedBean
@RequestScoped
public class MyController {
 private String username;
 private String password;

 public void link() {
  HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
  
  try {
   request.login(username, password);
   
   FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("user", username);
   FacesContext.getCurrentInstance().getExternalContext().redirect("landingpage.xhtml");
  }
  catch( ServletException e ) {
   ...
  }
 }
}
See it? The j_username, and j_password has been replace by the username and password wired inside the managed bean now. And the form is no longer contain any j_ fields.

No comments: