I'm using GlassFish server 4.0 in which I have assigned different authorities/roles to different users.
A user may have multiple authorities/roles. For example, an admin user may be associated with ROLE_ADMIN
(to perform administrative tasks) and ROLE_USER
(to perform tasks as a registered user).
In my web.xml
, this is configured as follows.
<security-constraint>
<display-name>AdminConstraint</display-name>
<web-resource-collection>
<web-resource-name>ROLE_ADMIN</web-resource-name>
<description/>
<url-pattern>/admin_side/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>ROLE_ADMIN</role-name>
</auth-constraint>
<user-data-constraint>
<description/>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-constraint>
<display-name>UserConstraint</display-name>
<web-resource-collection>
<web-resource-name>ROLE_USER</web-resource-name>
<description/>
<url-pattern>/user_side/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>ROLE_USER</role-name>
</auth-constraint>
<user-data-constraint>
<description/>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<!--<auth-method>DIGEST</auth-method>-->
<auth-method>FORM</auth-method>
<realm-name>projectRealm</realm-name>
<form-login-config>
<form-login-page>/utility/Login.jsf</form-login-page>
<form-error-page>/utility/ErrorPage.jsf</form-error-page>
</form-login-config>
</login-config>
<security-role>
<description/>
<role-name>ROLE_ADMIN</role-name>
</security-role>
<security-role>
<description/>
<role-name>ROLE_USER</role-name>
</security-role>
This works just fine.
There are two URL patterns /admin_side/*
and /user_side/*
. The administrator has two roles ROLE_ADMIN
and ROLE_USER
.
When the administrator logs in using the authority ROLE_USER
, the only resources located in /user_side/*
should be accessed. The resources located in /admin_side/*
should be forbidden from being accessed because the admin is logged in as a registered user and not as an admin.
Until now what happens in my case is that when admin logs in using any of the authorities, the resources in both the locations can be accessed which is perfectly illegal. It is because the system is able to locate both the authorities for that particular user.
How to have each user access resources at a specific location according to their authority/role?
The authentication filter:
@WebFilter(filterName = "SecurityCheck", urlPatterns = {"/jass/*"})
public final class SecurityCheck implements Filter
{
private FilterConfig filterConfig = null;
@Resource(mappedName="jms/destinationFactory")
private ConnectionFactory connectionFactory;
@Resource(mappedName="jms/destination")
private Queue queue;
@EJB
private final UserBeanLocal userService=null;
public SecurityCheck() {}
private void sendJMSMessageToDestination(String message) throws JMSException
{
Connection connection = null;
Session session = null;
try
{
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(queue);
TextMessage textMessage = session.createTextMessage();
textMessage.setText(message);
messageProducer.send(textMessage);
}
finally
{
if(session!=null){session.close();}
if(connection!=null){connection.close();}
}
}
private void doBeforeProcessing(ServletRequest request, ServletResponse response) throws IOException, ServletException
{
HttpServletRequest httpServletRequest=(HttpServletRequest)request;
httpServletRequest.login(httpServletRequest.getParameter("userName"), httpServletRequest.getParameter("password"));
}
private void doAfterProcessing(ServletRequest request, ServletResponse response) throws IOException, ServletException, JMSException
{
HttpServletRequest httpServletRequest=(HttpServletRequest)request;
HttpServletResponse httpServletResponse=(HttpServletResponse)response;
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
Map<String, Object> sessionMap = externalContext.getSessionMap();
if(httpServletRequest.isUserInRole("ROLE_USER"))
{
sendJMSMessageToDestination(httpServletRequest.getLocalName());
UserTable userTable = userService.setLastLogin(httpServletRequest.getParameter("userName"));
userTable.setPassword(null);
sessionMap.put("userName", userTable!=null?userTable.getFirstName():"Unknown");
sessionMap.put("user", userTable);
httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
httpServletResponse.setHeader("Pragma", "no-cache");
httpServletResponse.setDateHeader("Expires", 0);
httpServletResponse.sendRedirect("../user_side/Home.jsf");
}
else if(httpServletRequest.isUserInRole("ROLE_ADMIN"))
{
sendJMSMessageToDestination(httpServletRequest.getLocalName());
UserTable userTable = userService.setLastLogin(httpServletRequest.getParameter("userName"));
userTable.setPassword(null);
sessionMap.put("adminName", userTable!=null?userTable.getFirstName():"Unknown");
sessionMap.put("user", userTable);
httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
httpServletResponse.setHeader("Pragma", "no-cache");
httpServletResponse.setDateHeader("Expires", 0);
httpServletResponse.sendRedirect("../admin_side/Home.jsf");
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
try
{
doBeforeProcessing(request, response);
}
catch (Exception e)
{
HttpServletResponse httpServletResponse=(HttpServletResponse)response;
//FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "Incorrect user name and/or password. Access denied."));
httpServletResponse.sendRedirect("../utility/Login.jsf");
return;
}
chain.doFilter(request, response);
try
{
doAfterProcessing(request, response);
}
catch (JMSException ex)
{
Logger.getLogger(SecurityCheck.class.getName()).log(Level.SEVERE, null, ex);
}
}
//The rest of the filter.
}
If you need to see other things in my application then, please let me know.
/jass/*
(mistakenly typed, should have been/jaas/*
). It indicates a directory in which there is only one page -temp.jsp
where the request is dispatched, when the login button on JSF page is pressed (via its corresponding JSF managed bean). Is there no way to log in once as an admin and once as a user using the same id/password? I also felt so but thought the container might support some mechanisms to do this. I looked into some tutorials but found nothing about it. – Reber