开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜