Bug in authorization filter(JEE6)
I am writing an authorization filter for my JEE6 application, to be able to restrict access to certain users to some pages. For some reason the browser doesn't display any page at all(I just see white). There has to be a bug somewhere but i don't know where, i am new to JEE6 security and i am trying to implement my authentication mechanism in the easiest possible way.
Here is my source code
The filter:
public class RestrictPageFilter implements Filter {
private FilterConfig fc;
private InputStream in;
private Access access;
public void init(FilterConfig filterConfig) throws ServletException {
// The easiest way to initialize the filter
fc = filterConfig;
// Prepare the parsing
try {
in = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("allowedpages.xml");
Access access = (Access) JAXBContext.newInstance(Access.class)
.createUnmarshaller().unmarshal(in);
} catch (JAXBException e) {
e.printStackTrace();
}
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
HttpSession session = req.getSession(true);
String pageRequested = req.getRequestURL().toString();
// Get the value of the current logged user
Role currentUser = (Role) session.getAttribute("userRole");
if (currentUser != null) {
if (currentUser.getType().equals("BUYER")) {
List<String> buyerPages = access.getBuyer().getPages();
for (String s : buyerPages) {
if (pageRequested.contains(s)) {
chain.doFilter(request, response);
} else {
resp.sendRedirect("main.xml");
}
}
} else if (currentUser.getType().equals("SELLER")) {
List<String> buyerPages = access.getSeller().getPages();
for (String s : buyerPages) {
if (pageRequested.contains(s)) {
chain.doFilter(request, response);
} else {
resp.sendRedirect("main.xml");
}
}
} else if (currentUser.getType().equals("ADMINISTRATOR")) {
List<String> buyerPages = access.getAdministrator().getPages();
for (String s : buyerPages) {
if (pageRequested.contains(s)) {
chain.doFilter(request, response);
} else {
resp.sendRedirect("main.xml");
}
}
}
}
}
public void destroy() {
// Not needed
}
}
To support this filter i use a .xml file(located in WEB-INF/classes) that contains the allowed pages and also a bean to store the details of the .xml as an object:
<access>
<buyer>
<page>buyoffer.xhtml</page>
<page>faq.xhtml</page>
<page>index.jsp</page>
<page>login.xhtml</page>
<page>main.xhtml</page>
<page>registrationSucceded.xhtml</page>
</buyer>
<seller>
<page>sellerpanel.xhtml</page>
<page>faq.xhtml</page>
<page>index.jsp</page>
<page>login.xhtml</page>
<page>main.xhtml</page>
<page>registrationSucceded.xhtml</page>
</seller>
<administrator>
<page>sellerpanel.xhtml</page>
<page>faq.xhtml</page>
<page>index.jsp</page>
<page>login.xhtml</page>
<page>main.xhtml</page>
<page>registrationSucceded.xhtml</page>
</administrator>
</access>
--
package simplebeans;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Access {
@XmlElement
private User buyer;
@XmlElement
private User seller;
@XmlElement
private User administrator;
public User getBuyer() {
return buyer;
}
public User getSeller() {
return seller;
}
public User getAdministrator() {
return administrator;
}
@XmlRootElement
public static class User {
@XmlElement(name="page")
private List<String> pages;
public List<String> getPages() {
return pages;
}
}
}
This is how i add the filter to the web.xml file:
<!--Page restriction filter -->
<filter>
<filter-name>restrict</filter-name>
<filter-class>filters.RestrictPageFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>restrict</filter-name>
<url-pattern>*.xhtml</ur开发者_JS百科l-pattern>
</filter-mapping>
What do you think is the reason i only see white in my browser? I try to navigate using the URL to some of the pages, but i see only white.
Update I made a few changes to be able to allow users that at not logged in to see some of the pages but i get a NPE:
Changes at the doFilter method:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
HttpSession session = req.getSession(true);
String pageRequested = req.getRequestURL().toString();
// Get the value of the current logged user
Role currentUser = (Role) session.getAttribute("userRole");
boolean authorized = false;
if (!pageRequested.contains("main.xhtml") && currentUser != null) {
switch (currentUser.getType()) {
case BUYER:
for (String s : access.getBuyer().getPages()) {
if (pageRequested.contains(s)) {
authorized = true;
}
}
break;
case SELLER:
for (String s : access.getSeller().getPages()) {
if (pageRequested.contains(s)) {
authorized = true;
}
}
break;
case ADMINISTRATOR:
for (String s : access.getAdministrator().getPages()) {
if (pageRequested.contains(s)) {
authorized = true;
}
}
break;
}
}
else {
for (String s : access.getVisitor().getPages()) {
if (pageRequested.contains(s)) {
authorized = true;
}
}
}
if (authorized || pageRequested.contains("main.xhtml")) {
chain.doFilter(request, response);
} else {
resp.sendRedirect("main.xhtml");
}
}
Changes at the xml file:
<visitor>
<page>faq.xhtml</page>
<page>login.xhtml</page>
<page>main.xhtml</page>
<page>registration.xhtml</page>
<page>registrationbuyer.xhtml</page>
<page>registrationseller.xhtml</page>
</visitor>
Changes made to the Access bean:
@XmlElement
private User visitor;
public User getVisitor() {
return visitor;
}
If you don't see anything, then the Filter has blocked the request. I.e. it has neither continued the chain, nor forwarded or redirected the request. Your code flow is illogical. You should also do the redirect as well when the current user is null
or when the current user does not have any of those roles. You should also call chain.doFilter()
or response.sendRedirect()
effectively only once throughout entire filter's code. Right now you're calling them multiple times for each page inside a loop. Those method calls do not magically abort the for
loop.
I'd suggest to rewrite the main if
block as follows
boolean authorized = false;
if (currentUser != null) {
if (currentUser.getType().equals("BUYER")) {
for (String s : access.getBuyer().getPages()) {
if (pageRequested.contains(s)) {
authorized = true;
break;
}
}
} else if (currentUser.getType().equals("SELLER")) {
for (String s : access.getSeller().getPages()) {
if (pageRequested.contains(s)) {
authorized = true;
break;
}
}
} else if (currentUser.getType().equals("ADMINISTRATOR")) {
for (String s : access.getAdministrator().getPages()) {
if (pageRequested.contains(s)) {
authorized = true;
break;
}
}
}
}
if (authorized) {
chain.doFilter(request, response);
} else {
resp.sendRedirect("main.xhtml");
}
I'd personally also make the CurrentUser#getType()
an enum
so that you can use a switch
instead of if else if else if else ...
and refactor the three duplicated blocks into a single helper method.
Update: as per your redirect loop issue, if your filter is mapped on a generic URL pattern like /*
(which also covers main.xhtml
) instead of e.g. /secured/*
, then you need to not redirect the request when the currently requested page is main.xhtml
, but you need to continue the chain instead. You can do this by skipping the main if
check whenever the currently requested page is main.xhtml
. You don't care about the authorization for main.xhtml
anyway.
精彩评论