com.seajas.search.profiler.authentication.strategy.codex.CodexAuthenticationStrategy.java Source code

Java tutorial

Introduction

Here is the source code for com.seajas.search.profiler.authentication.strategy.codex.CodexAuthenticationStrategy.java

Source

/**
 * Copyright (C) 2013 Seajas, the Netherlands.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3, as
 * published by the Free Software Foundation.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.seajas.search.profiler.authentication.strategy.codex;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;

import com.seajas.search.codex.wsdl.IIdentity;
import com.seajas.search.profiler.authentication.strategy.AuthenticationResult;
import com.seajas.search.profiler.authentication.strategy.AuthenticationStrategy;

/**
 * Search Codex authentication strategy.
 * 
 * @author Jasper van Veghel <jasper@seajas.com>
 */
public class CodexAuthenticationStrategy implements AuthenticationStrategy {
    /**
     * The logger.
     */
    private final static Logger logger = LoggerFactory.getLogger(CodexAuthenticationStrategy.class);

    /**
     * Constants.
     */
    private final static String REPLACEMENT_ACCESS_TOKEN = "{access_token}";
    private final static String REPLACEMENT_SECRET = "{secret}";

    /**
     * Identity service.
     */
    @Autowired
    private IIdentity identityService;

    /**
     * Result mapping username parameter.
     */
    @Value("${profiler.project.authentication.strategy.codex.result.mapping.username.parameter}")
    private String resultMappingUsernameParameter;

    /**
     * URL to provider mappings.
     */
    private final Map<String, String> urlToProviderMappings = new HashMap<String, String>();

    /**
     * Default constructor.
     * 
     * @param urlToProviderMappings
     */
    @Autowired
    public CodexAuthenticationStrategy(
            @Value("${profiler.project.authentication.strategy.codex.url.to.provider.mapping}") final String urlToProviderMappings) {
        for (String urlToProviderMapping : StringUtils.tokenizeToStringArray(urlToProviderMappings, ",", true,
                true)) {
            String[] keyValue = urlToProviderMapping.split(":");

            if (keyValue.length != 2 || !StringUtils.hasText(keyValue[0]) || !StringUtils.hasText(keyValue[1]))
                throw new IllegalArgumentException("Invalid URL-to-provider mapping '" + urlToProviderMapping
                        + "' - should be of type <provider>:<pattern>");

            this.urlToProviderMappings.put(keyValue[0].trim(), keyValue[1].trim());
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public AuthenticationResult authenticate(final String url, final Map<String, String> parameters) {
        String resultUrl = url, username = parameters.get(resultMappingUsernameParameter), providerId;

        // The resulting parameter-map can be optionally augmented with additional parameters - hence we create a new one

        Map<String, String> resultParameters = new HashMap<String, String>();

        resultParameters.putAll(parameters);

        // Determine which provider this URL belongs to (if any)

        try {
            providerId = urlToProviderId(new URL(resultUrl));
        } catch (MalformedURLException e) {
            logger.error("The given URL '" + url + "' was not valid - not performing authentication", e);

            return createEmptyResult(resultUrl, resultParameters);
        }

        // Now determine the token and secret from the codex' identity service

        String identityResult;

        if (providerId == null && username == null) {
            logger.error(
                    "Neither a provider could be detected from the URL, nor was a username given - unable to determine if we should apply for a poolable token (provider required) or a generic username (username required) - not performing authentication");

            return createEmptyResult(resultUrl, resultParameters);
        } else if (username != null) {
            identityResult = identityService.getLastToken(username, providerId);

            if (identityResult == null) {
                logger.error("Could not retrieve token for username '" + username + "'"
                        + (providerId != null ? " and provider '" + providerId + "'" : ""));

                return createEmptyResult(resultUrl, resultParameters);
            }
        } else {
            identityResult = identityService.getNextPoolableToken(providerId);

            if (identityResult == null) {
                logger.error("Could not retrieve poolable token for provider '" + providerId + "'");

                return createEmptyResult(resultUrl, resultParameters);
            }
        }

        // And split it up, should it also contain a secret (in the case of OAuth1)

        String[] accessTokenAndSecret = identityResult.split("/");

        String accessToken = accessTokenAndSecret[0].trim(),
                secret = accessTokenAndSecret.length > 1 ? accessTokenAndSecret[1].trim() : "";

        return new AuthenticationResult(
                resultUrl.replace(REPLACEMENT_ACCESS_TOKEN, accessToken).replace(REPLACEMENT_SECRET, secret),
                resultParameters);
    }

    /**
     * Determine the provider from the URL and mappings.
     * 
     * @param url
     * @return String
     */
    private String urlToProviderId(final URL url) {
        // Prefer matching against the hostname

        for (Entry<String, String> urlToProviderMapping : urlToProviderMappings.entrySet())
            if (url.getHost().matches(urlToProviderMapping.getValue().replace(".", "\\.").replace("*", ".*")))
                return urlToProviderMapping.getKey();

        // Then the whole URL

        for (Entry<String, String> urlToProviderMapping : urlToProviderMappings.entrySet())
            if (url.toString().matches(urlToProviderMapping.getValue().replace(".", "\\.").replace("*", ".*")))
                return urlToProviderMapping.getKey();

        return null;
    }

    /**
     * Create an empty result (access token and secret both replaced with emptiness.)
     * 
     * @param url
     * @return AuthenticationResult
     */
    private static AuthenticationResult createEmptyResult(final String url,
            final Map<String, String> resultParameters) {
        return new AuthenticationResult(url.replace(REPLACEMENT_ACCESS_TOKEN, "").replace(REPLACEMENT_SECRET, ""),
                resultParameters);
    }
}