org.codice.ddf.security.handler.anonymous.AnonymousHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.ddf.security.handler.anonymous.AnonymousHandler.java

Source

/**
 * Copyright (c) Codice Foundation
 *
 * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details. A copy of the GNU Lesser General Public License
 * is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 *
 **/
package org.codice.ddf.security.handler.anonymous;

import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.sts.QNameConstants;
import org.apache.cxf.ws.security.sts.provider.model.secext.AttributedString;
import org.apache.cxf.ws.security.sts.provider.model.secext.PasswordString;
import org.apache.cxf.ws.security.sts.provider.model.secext.UsernameTokenType;
import org.apache.ws.security.WSConstants;
import org.codice.ddf.security.handler.api.AuthenticationHandler;
import org.codice.ddf.security.handler.api.HandlerResult;
import org.jasypt.contrib.org.apache.commons.codec_1_3.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.security.Principal;

/**
 * Handler that allows anonymous user access via a guest user account. The guest/guest account
 * must be present in the user store for this handler to work correctly.
 */
public class AnonymousHandler implements AuthenticationHandler {
    public static final Logger LOGGER = LoggerFactory.getLogger(AnonymousHandler.class.getName());

    /**
     * Anonymous type to use when configuring context policy.
     */
    public static final String AUTH_TYPE = "ANON";

    private static final JAXBContext utContext = initContext();

    private static JAXBContext initContext() {
        try {
            return JAXBContext.newInstance(UsernameTokenType.class);
        } catch (JAXBException e) {
            LOGGER.error("Unable to create UsernameToken JAXB context.", e);
        }
        return null;
    }

    @Override
    public String getAuthenticationType() {
        return AUTH_TYPE;
    }

    /**
     * Extracts a Principal from a UsernameToken
     *
     * @param result
     * @return Principal
     */
    private Principal getPrincipal(final UsernameTokenType result) {
        return new Principal() {
            private String username = result.getUsername().getValue();

            @Override
            public String getName() {
                return username;
            }
        };
    }

    /**
     * This method takes an anonymous request and attaches a UsernameTokenType
     * to the HTTP request to allow access. The method also allows the user to
     * sign-in and authenticate.
     *
     * @param request  http request to obtain attributes from and to pass into any local filter chains required
     * @param response http response to return http responses or redirects
     * @param chain    original filter chain (should not be called from your handler)
     * @param resolve  flag with true implying that credentials should be obtained, false implying return if no credentials are found.
     * @return HandlerResult
     */
    @Override
    public HandlerResult getNormalizedToken(ServletRequest request, ServletResponse response, FilterChain chain,
            boolean resolve) {

        HandlerResult handlerResult;

        UsernameTokenType result = setAuthenticationInfo((HttpServletRequest) request);
        String usernameToken = getUsernameTokenElement(result);
        Principal principal = getPrincipal(result);
        handlerResult = new HandlerResult(HandlerResult.Status.COMPLETED, principal, usernameToken);

        return handlerResult;
    }

    /**
     * This method handles errors related to failures related to credentials
     * verification. It returns a HTTP status code, 500 Internal Server Error,
     * which is then handled in Menu.view.js of the ddf-ui module.
     *
     * @param servletRequest  http request to obtain attributes from and to pass into any local filter chains required
     * @param servletResponse http response to return http responses or redirects
     * @param chain           original filter chain (should not be called from your handler)
     * @return HandlerResult
     * @throws ServletException
     */
    @Override
    public HandlerResult handleError(ServletRequest servletRequest, ServletResponse servletResponse,
            FilterChain chain) throws ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        httpResponse.setStatus(500);
        try {
            httpResponse.getWriter().write("Username/Password is invalid.");
            httpResponse.flushBuffer();
        } catch (IOException e) {
            LOGGER.debug("Failed to send auth response: {}", e);
        }

        HandlerResult result = new HandlerResult();
        LOGGER.debug("In error handler for anonymous - returning no action taken.");
        result.setStatus(HandlerResult.Status.NO_ACTION);
        return result;
    }

    /**
     * Returns the UsernameToken marshalled as a String so that it can be attached to the
     * {@link org.codice.ddf.security.handler.api.HandlerResult} object.
     *
     * @param usernameTokenType
     * @return String
     */
    private synchronized String getUsernameTokenElement(UsernameTokenType usernameTokenType) {
        Writer writer = new StringWriter();
        Marshaller marshaller = null;
        if (utContext != null) {
            try {
                marshaller = utContext.createMarshaller();
                marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
            } catch (JAXBException e) {
                LOGGER.error("Exception while creating UsernameToken marshaller.", e);
            }

            JAXBElement<UsernameTokenType> usernameTokenElement = new JAXBElement<UsernameTokenType>(
                    new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
                            "UsernameToken"),
                    UsernameTokenType.class, usernameTokenType);

            if (marshaller != null) {
                try {
                    marshaller.marshal(usernameTokenElement, writer);
                } catch (JAXBException e) {
                    LOGGER.error("Exception while writing username token.", e);
                }
            }
        }

        return writer.toString();
    }

    /**
     * This method uses the data passed in the HttpServletRequest to generate
     * and return UsernameTokenType.
     *
     * @param request http request to obtain attributes from and to pass into any local filter chains required
     * @return UsernameTokenType
     */
    private UsernameTokenType setAuthenticationInfo(HttpServletRequest request) {
        HttpServletRequest httpRequest = request;

        String username = "guest";
        String password = "guest";

        /**
         * Parse the header data and extract the username and password.
         *
         * Change the username and password if request contains values.
         */
        String header = httpRequest.getHeader("Authorization");
        if (!StringUtils.isEmpty(header)) {
            String headerData[] = header.split(" ");
            if (headerData.length == 2) {
                String decodedHeader = new String(Base64.decodeBase64(headerData[1].getBytes()));
                String decodedHeaderData[] = decodedHeader.split(":");
                if (decodedHeaderData.length == 2) {
                    username = decodedHeaderData[0];
                    password = decodedHeaderData[1];
                }
            }
        }

        /**
         * Use the collected information to set the username and password and
         * generate UsernameTokenType to return.
         */
        UsernameTokenType usernameTokenType = new UsernameTokenType();
        AttributedString user = new AttributedString();
        user.setValue(username);
        usernameTokenType.setUsername(user);
        PasswordString passwordString = new PasswordString();
        passwordString.setValue(password);
        passwordString.setType(WSConstants.PASSWORD_TEXT);
        JAXBElement<PasswordString> passwordType = new JAXBElement<PasswordString>(QNameConstants.PASSWORD,
                PasswordString.class, passwordString);
        usernameTokenType.getAny().add(passwordType);

        return usernameTokenType;
    }
}