001/**
002 * Copyright 2015 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fcrepo.http.commons.test.util;
017
018import static java.lang.reflect.Proxy.newProxyInstance;
019import static java.util.Collections.emptySet;
020import static java.util.Collections.singleton;
021import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION;
022import static org.slf4j.LoggerFactory.getLogger;
023
024import java.io.IOException;
025import java.lang.reflect.InvocationHandler;
026import java.lang.reflect.Method;
027import java.security.Principal;
028import java.util.Set;
029
030import javax.servlet.Filter;
031import javax.servlet.FilterChain;
032import javax.servlet.FilterConfig;
033import javax.servlet.ServletException;
034import javax.servlet.ServletRequest;
035import javax.servlet.ServletResponse;
036import javax.servlet.http.HttpServletRequest;
037import javax.ws.rs.WebApplicationException;
038
039import org.glassfish.grizzly.http.server.GrizzlyPrincipal;
040import org.glassfish.jersey.internal.util.Base64;
041import org.slf4j.Logger;
042
043/**
044 * @author Gregory Jansen
045 */
046public class TestAuthenticationRequestFilter implements Filter {
047
048    private static final Logger log = getLogger(TestAuthenticationRequestFilter.class);
049
050    private static final String FEDORA_ADMIN_USER = "fedoraAdmin";
051
052    /*
053     * (non-Javadoc)
054     * @see
055     * com.sun.jersey.spi.container.ContainerRequestFilter#filter(com.sun.jersey
056     * .spi.container.ContainerRequest)
057     */
058    @Override
059    public void doFilter(final ServletRequest request,
060            final ServletResponse response, final FilterChain chain)
061            throws IOException, ServletException {
062        final HttpServletRequest req = (HttpServletRequest) request;
063        final String username = getUsername(req);
064        // Validate the extracted credentials
065        Set<String> containerRoles = emptySet();
066        if (FEDORA_ADMIN_USER.equals(username)) {
067            containerRoles = singleton("fedoraAdmin");
068            log.debug("ADMIN AUTHENTICATED");
069        } else {
070            containerRoles = singleton("fedoraUser");
071            log.debug("USER AUTHENTICATED");
072        }
073        final ServletRequest proxy = proxy(req, username, containerRoles);
074        chain.doFilter(proxy, response);
075    }
076
077    /**
078     * @param request
079     * @param username
080     * @param containerRoles
081     * @return
082     */
083    private static ServletRequest proxy(final HttpServletRequest request,
084            final String username, final Set<String> containerRoles) {
085        final Principal user = new GrizzlyPrincipal(username);
086        final HttpServletRequest result =
087                (HttpServletRequest) newProxyInstance(request.getClass()
088                        .getClassLoader(),
089                        new Class[] {HttpServletRequest.class},
090                        new InvocationHandler() {
091
092                            @Override
093                            public Object invoke(final Object proxy,
094                                    final Method method, final Object[] args)
095                                    throws Throwable {
096                                if (method.getName().equals("isUserInRole")) {
097                                    final String role = (String) args[0];
098                                    return containerRoles.contains(role);
099                                } else if (method.getName().equals(
100                                        "getUserPrincipal")) {
101                                    return user;
102                                } else if (method.getName().equals(
103                                        "getRemoteUser")) {
104                                    return username;
105                                }
106                                return method.invoke(request, args);
107                            }
108                        });
109        return result;
110    }
111
112    private static String getUsername(final HttpServletRequest request) {
113        // Extract authentication credentials
114        String authentication = request.getHeader(AUTHORIZATION);
115        if (authentication == null) {
116            return null;
117        }
118        if (!authentication.startsWith("Basic ")) {
119            return null;
120        }
121        authentication = authentication.substring("Basic ".length());
122        final String[] values = Base64.decodeAsString(authentication).split(":");
123        if (values.length < 2) {
124            throw new WebApplicationException(400);
125            // "Invalid syntax for username and password"
126        }
127        final String username = values[0];
128        final String password = values[1];
129        if ((username == null) || (password == null)) {
130            return null;
131        }
132        return username;
133    }
134
135    /*
136     * (non-Javadoc)
137     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
138     */
139    @Override
140    public void init(final FilterConfig filterConfig) {
141    }
142
143    /*
144     * (non-Javadoc)
145     * @see javax.servlet.Filter#destroy()
146     */
147    @Override
148    public void destroy() {
149    }
150}