001/*
002 * The contents of this file are subject to the license and copyright
003 * detailed in the LICENSE and NOTICE files at the root of the source
004 * tree.
005 */
006package org.fcrepo.http.commons.test.util;
007
008import static java.lang.reflect.Proxy.newProxyInstance;
009import static java.util.Collections.emptySet;
010import static java.util.Collections.singleton;
011import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION;
012import static org.slf4j.LoggerFactory.getLogger;
013
014import java.io.IOException;
015import java.lang.reflect.InvocationHandler;
016import java.lang.reflect.Method;
017import java.security.Principal;
018import java.util.Base64;
019import java.util.Set;
020
021import javax.servlet.Filter;
022import javax.servlet.FilterChain;
023import javax.servlet.FilterConfig;
024import javax.servlet.ServletException;
025import javax.servlet.ServletRequest;
026import javax.servlet.ServletResponse;
027import javax.servlet.http.HttpServletRequest;
028import javax.ws.rs.WebApplicationException;
029
030import org.glassfish.grizzly.http.server.GrizzlyPrincipal;
031import org.slf4j.Logger;
032
033/**
034 * @author Gregory Jansen
035 */
036public class TestAuthenticationRequestFilter implements Filter {
037
038    private static final Logger log = getLogger(TestAuthenticationRequestFilter.class);
039
040    private static final String FEDORA_ADMIN_USER = "fedoraAdmin";
041
042    /*
043     * (non-Javadoc)
044     * @see
045     * com.sun.jersey.spi.container.ContainerRequestFilter#filter(com.sun.jersey
046     * .spi.container.ContainerRequest)
047     */
048    @Override
049    public void doFilter(final ServletRequest request,
050            final ServletResponse response, final FilterChain chain)
051            throws IOException, ServletException {
052        final HttpServletRequest req = (HttpServletRequest) request;
053        final String username = getUsername(req);
054        // Validate the extracted credentials
055        Set<String> containerRoles = emptySet();
056        if (username == null) {
057            log.debug("ANONYMOUS");
058        } else if (FEDORA_ADMIN_USER.equals(username)) {
059            containerRoles = singleton("fedoraAdmin");
060            log.debug("ADMIN AUTHENTICATED");
061        } else if ("noroles".equals(username)) {
062            log.debug("USER (without roles); AUTHENTICATED");
063        } else {
064            containerRoles = singleton("fedoraUser");
065            log.debug("USER AUTHENTICATED");
066        }
067        final ServletRequest proxy = proxy(req, username, containerRoles);
068        chain.doFilter(proxy, response);
069    }
070
071    private static ServletRequest proxy(final HttpServletRequest request,
072            final String username, final Set<String> containerRoles) {
073        final Principal user = username != null ? new GrizzlyPrincipal(username) : null;
074        final HttpServletRequest result =
075                (HttpServletRequest) newProxyInstance(request.getClass()
076                        .getClassLoader(),
077                        new Class[] {HttpServletRequest.class},
078                        new InvocationHandler() {
079
080                            @Override
081                            public Object invoke(final Object proxy,
082                                    final Method method, final Object[] args)
083                                    throws Throwable {
084                                if (method.getName().equals("isUserInRole")) {
085                                    final String role = (String) args[0];
086                                    return containerRoles.contains(role);
087                                } else if (method.getName().equals(
088                                        "getUserPrincipal")) {
089                                    return user;
090                                } else if (method.getName().equals(
091                                        "getRemoteUser")) {
092                                    return username;
093                                }
094                                return method.invoke(request, args);
095                            }
096                        });
097        return result;
098    }
099
100    private static String getUsername(final HttpServletRequest request) {
101        // Extract authentication credentials
102        String authentication = request.getHeader(AUTHORIZATION);
103        if (authentication == null) {
104            return null;
105        }
106        if (!authentication.startsWith("Basic ")) {
107            return null;
108        }
109        authentication = authentication.substring("Basic ".length());
110        final String[] values = new String(Base64.getDecoder().decode(authentication)).split(":");
111        if (values.length < 2) {
112            throw new WebApplicationException(400);
113            // "Invalid syntax for username and password"
114        }
115        final String username = values[0];
116        final String password = values[1];
117        if ((username == null) || (password == null)) {
118            return null;
119        }
120        return username;
121    }
122
123    /*
124     * (non-Javadoc)
125     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
126     */
127    @Override
128    public void init(final FilterConfig filterConfig) {
129    }
130
131    /*
132     * (non-Javadoc)
133     * @see javax.servlet.Filter#destroy()
134     */
135    @Override
136    public void destroy() {
137    }
138}