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