org.springframework.security.oauth.provider.CoreOAuthProviderSupport.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.security.oauth.provider.CoreOAuthProviderSupport.java

Source

/*
 * Copyright 2008 Web Cohesion
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.security.oauth.provider;

import org.apache.commons.codec.DecoderException;
import static org.springframework.security.oauth.common.OAuthCodec.oauthDecode;
import static org.springframework.security.oauth.common.OAuthCodec.oauthEncode;
import org.springframework.security.oauth.common.OAuthConsumerParameter;
import org.springframework.security.util.StringSplitUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.net.URL;
import java.net.MalformedURLException;

/**
 * Utility for common logic for supporting an OAuth provider.
 *
 * @author Ryan Heaton
 */
public class CoreOAuthProviderSupport implements OAuthProviderSupport {

    private final Set<String> supportedOAuthParameters;
    private String baseUrl = null;

    public CoreOAuthProviderSupport() {
        Set<String> supportedOAuthParameters = new TreeSet<String>();
        for (OAuthConsumerParameter supportedParameter : OAuthConsumerParameter.values()) {
            supportedOAuthParameters.add(supportedParameter.toString());
        }
        this.supportedOAuthParameters = supportedOAuthParameters;
    }

    // Inherited.
    public Map<String, String> parseParameters(HttpServletRequest request) {
        Map<String, String> parameters = parseHeaderParameters(request);

        if (parameters == null) {
            //if there is no header authorization parameters, then the oauth parameters are the supported OAuth request parameters.
            parameters = new HashMap<String, String>();
            for (String supportedOAuthParameter : getSupportedOAuthParameters()) {
                String param = request.getParameter(supportedOAuthParameter);
                if (param != null) {
                    parameters.put(supportedOAuthParameter, param);
                }
            }
        }

        return parameters;
    }

    /**
     * Parse the OAuth header parameters. The parameters will be oauth-decoded.
     *
     * @param request The request.
     * @return The parsed parameters, or null if no OAuth authorization header was supplied.
     */
    protected Map<String, String> parseHeaderParameters(HttpServletRequest request) {
        String header = null;
        Enumeration<String> headers = request.getHeaders("Authorization");
        while (headers.hasMoreElements()) {
            String value = headers.nextElement();
            if ((value.toLowerCase().startsWith("oauth "))) {
                header = value;
                break;
            }
        }

        Map<String, String> parameters = null;
        if (header != null) {
            parameters = new HashMap<String, String>();
            String authHeaderValue = header.substring(6);

            //create a map of the authorization header values per OAuth Core 1.0, section 5.4.1
            String[] headerEntries = StringSplitUtils.splitIgnoringQuotes(authHeaderValue, ',');
            for (Object o : StringSplitUtils.splitEachArrayElementAndCreateMap(headerEntries, "=", "\"")
                    .entrySet()) {
                Map.Entry entry = (Map.Entry) o;
                try {
                    String key = oauthDecode((String) entry.getKey());
                    String value = oauthDecode((String) entry.getValue());
                    parameters.put(key, value);
                } catch (DecoderException e) {
                    throw new IllegalStateException(e);
                }
            }
        }

        return parameters;
    }

    /**
     * Get the supported OAuth parameters. The default implementation supports only the OAuth core parameters.
     *
     * @return The OAuth core parameters.
     */
    protected Set<String> getSupportedOAuthParameters() {
        return this.supportedOAuthParameters;
    }

    // Inherited.
    public String getSignatureBaseString(HttpServletRequest request) {
        SortedMap<String, SortedSet<String>> significantParameters = loadSignificantParametersForSignatureBaseString(
                request);

        //now concatenate them into a single query string according to the spec.
        StringBuilder queryString = new StringBuilder();
        Iterator<Map.Entry<String, SortedSet<String>>> paramIt = significantParameters.entrySet().iterator();
        while (paramIt.hasNext()) {
            Map.Entry<String, SortedSet<String>> sortedParameter = paramIt.next();
            Iterator<String> valueIt = sortedParameter.getValue().iterator();
            while (valueIt.hasNext()) {
                String parameterValue = valueIt.next();
                queryString.append(sortedParameter.getKey()).append('=').append(parameterValue);
                if (paramIt.hasNext() || valueIt.hasNext()) {
                    queryString.append('&');
                }
            }
        }

        String url = getBaseUrl(request);
        if (url == null) {
            //if no URL is configured, then we'll attempt to reconstruct the URL.  This may be inaccurate.
            url = request.getRequestURL().toString();
        }
        url = normalizeUrl(url);
        url = oauthEncode(url);

        String method = request.getMethod().toUpperCase();
        return new StringBuilder(method).append('&').append(url).append('&')
                .append(oauthEncode(queryString.toString())).toString();
    }

    /**
     * Normalize the URL for use in the signature. The OAuth spec says the URL protocol and host are to be lower-case,
     * and the query and fragments are to be stripped.
     *
     * @param url The URL.
     * @return The URL normalized for use in the signature.
     */
    protected String normalizeUrl(String url) {
        try {
            URL requestURL = new URL(url);
            StringBuilder normalized = new StringBuilder(requestURL.getProtocol().toLowerCase()).append("://")
                    .append(requestURL.getHost().toLowerCase());
            if ((requestURL.getPort() >= 0) && (requestURL.getPort() != requestURL.getDefaultPort())) {
                normalized.append(":").append(requestURL.getPort());
            }
            normalized.append(requestURL.getPath());
            return normalized.toString();
        } catch (MalformedURLException e) {
            throw new IllegalStateException("Illegal URL for calculating the OAuth signature.", e);
        }
    }

    /**
     * Loads the significant parameters (name-to-value map) that are to be used to calculate the signature base string.
     * The parameters will be encoded, per the spec section 9.1.
     *
     * @param request The request.
     * @return The significan parameters.
     */
    protected SortedMap<String, SortedSet<String>> loadSignificantParametersForSignatureBaseString(
            HttpServletRequest request) {
        //first collect the relevant parameters...
        SortedMap<String, SortedSet<String>> significantParameters = new TreeMap<String, SortedSet<String>>();
        //first pull from the request...
        Enumeration parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String parameterName = (String) parameterNames.nextElement();
            String[] values = request.getParameterValues(parameterName);
            if (values == null) {
                values = new String[] { "" };
            }

            for (String parameterValue : values) {
                if (parameterValue == null) {
                    parameterValue = "";
                }

                parameterName = oauthEncode(parameterName);
                parameterValue = oauthEncode(parameterValue);
                SortedSet<String> significantValues = significantParameters.get(parameterName);
                if (significantValues == null) {
                    significantValues = new TreeSet<String>();
                    significantParameters.put(parameterName, significantValues);
                }
                significantValues.add(parameterValue);
            }
        }

        //then take into account the header parameter values...
        Map<String, String> oauthParams = parseParameters(request);
        oauthParams.remove("realm"); //remove the realm
        Set<String> parsedParams = oauthParams.keySet();
        for (String parameterName : parsedParams) {
            String parameterValue = oauthParams.get(parameterName);
            if (parameterValue == null) {
                parameterValue = "";
            }

            parameterName = oauthEncode(parameterName);
            parameterValue = oauthEncode(parameterValue);
            SortedSet<String> significantValues = significantParameters.get(parameterName);
            if (significantValues == null) {
                significantValues = new TreeSet<String>();
                significantParameters.put(parameterName, significantValues);
            }
            significantValues.add(parameterValue);
        }

        //remove the oauth signature parameter value.
        significantParameters.remove(OAuthConsumerParameter.oauth_signature.toString());
        return significantParameters;
    }

    /**
     * The configured base URL for this OAuth provider for the given HttpServletRequest. Default implementation return getBaseUrl() + request URI.
     *
     * @param request The HttpServletRequest currently processed
     * @return The configured base URL for this OAuth provider with respect to the supplied HttpServletRequest.
     */
    protected String getBaseUrl(HttpServletRequest request) {
        String baseUrl = getBaseUrl();
        if (baseUrl != null) {
            StringBuilder builder = new StringBuilder(baseUrl);
            String path = request.getRequestURI();
            if (path != null && !"".equals(path)) {
                if (!baseUrl.endsWith("/") && !path.startsWith("/")) {
                    builder.append('/');
                }
                builder.append(path);
            }
            baseUrl = builder.toString();
        }
        return baseUrl;
    }

    /**
     * The configured base URL for this OAuth provider.
     *
     * @return The configured base URL for this OAuth provider.
     */
    public String getBaseUrl() {
        return baseUrl;
    }

    /**
     * The configured base URL for the OAuth provider.
     *
     * @param baseUrl The configured base URL for the OAuth provider.
     */
    public void setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
    }
}