I am transitioning to GlassFish 3.1.2, and can't seem to resolve a problem with authentication.
The agenda is simple: I want a login bean to do programmatic authentication for a user. The authentication seems to work (the code goes past the login() method), but the server ends up shown 403 for the protected resources... Please help :)
Here are more details. There is a pure JSF login page with name/pass pair:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui" template="/templates/main.xhtml">
<ui:define name="body">
<h:form id="form">
<p:messages />
<p:panel>
<h:panelGrid>
<h:outputText value="User Name" />
<p:inputText value="#{loginBean.userName}" id="userName"
required="true" />
<p:message for="userName" />
<h:outputText value="Password" />
<p:password value="#{loginBean.password}" id="password"
required="true" />
<p:message for="password" />
</h:panelGrid>
<h:panelGrid columns="2">
<p:commandButton value="Clear"
actionListener="#{loginBean.clear()}" ajax="false" />
<p:commandButton value="Login" action="#{loginBean.login()}"
ajax="false" />
</h:panelGrid>
</p:panel>
</h:form>
</ui:define>
</ui:composition>
and a bean that carries out the login
@Named("loginBean")
@SessionScoped
public class LoginBean implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
@Named("dao")
private Dao dao;
private String userName;
private String password;
@Inject
private UserBean userBean;
...
public String login() {
HttpServletRequest request = (HttpServletRequest) FacesContext
.getCurrentInstance().getExternalContext().getRequest();
try {
request.login(getUserName(), getPassword());
Principal principal = request.getUserPrincipal();
logger.info("Logged in successfully: " + principal);
} catch (ServletException e) {
Messages.addError("Invalid user name or password.");
return null;
}
User user = dao.findSingle("SELECT u FROM User AS u WHERE u.name = ?1",
getUserName());
if (user == null) {
logger.severe("Unable to find user record after successful authentication");
Messages.addError("Unable to load user record");
try {
request.logout();
} catch (ServletException e) {
logger.log(Level.SEVERE, "Unable to logout after failed login attempt", e);
}
return null;
}
getUserBean().setUser(user);
return "/list/list.xhtml?faces-redirect=true";
}
...
accessors
...
}
Here is my web.xml
<?xml version='1.0' encoding='UTF-8'?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>GM</display-name>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<login-config>
<realm-name>gmRealm</realm-name>
</login-config>
<security-role>
<role-name>user</role-name>
</security-role>
<security-role>
<role-name>admin</role-name>
</security-role>
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/list/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Admin Area</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<welcome-file-list>
<welcome-file>login.xhtml</welcome-file>
</welcome-file-list>
</web-app>
Here is the folder structure for the project:
I was also able to set up the realm as discussed here: http://blog.gamatam.com/2009/11/jdbc-realm-setup-with-glassfish-v3.html
Nothing fancy, AFAICT.
However, whenever I get to the protected resource after a successful login, I get:
HTTP Status 403 - Access to the requested resource has been denied
Despite the fact that the server log contains the message:
INFO: Logged in successfully: nick
Also note that when I remove "?faces-redirect=true", from the login() method's return value, the initial protected resource is rendered just fine right after the login, but all the subsequent requests to it fail with 403.
Here is what it shows in the debugger:
I also think that I've done my homework:
Performing user authentication in Java EE / JSF using j_security_check
Programmatically control login with Servlet 3.0
Glassfish 3 security - Form based authentication using a JDBC Realm
Please help...
admin
have no access to thelist
directory. Is this what you want? If not you should add the roleadmin
to the Protected area constraint. – Matt Handy