groovyx.net.http.AuthConfig.java Source code

Java tutorial

Introduction

Here is the source code for groovyx.net.http.AuthConfig.java

Source

/*
 * Copyright 2008-2011 Thomas Nichols.  http://blog.thomnichols.org
 *
 * 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.
 *
 * You are receiving this code free of charge, which represents many hours of
 * effort from other individuals and corporations.  As a responsible member
 * of the community, you are encouraged (but not required) to donate any
 * enhancements or improvements back to the community under a similar open
 * source license.  Thank you. -TMN
 */
package groovyx.net.http;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;

import oauth.signpost.OAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import oauth.signpost.exception.OAuthException;

import org.apache.http.Header;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;

/**
 * Encapsulates all configuration related to HTTP authentication methods.
 * @see HTTPBuilder#getAuth()
 *
 * @author <a href='mailto:tomstrummer+httpbuilder@gmail.com'>Tom Nichols</a>
 */
public class AuthConfig {
    protected HTTPBuilder builder;

    public AuthConfig(HTTPBuilder builder) {
        this.builder = builder;
    }

    /**
     * Set authentication credentials to be used for the current
     * {@link HTTPBuilder#getUri() default host}.  This method name is a bit of
     * a misnomer, since these credentials will actually work for "digest"
     * authentication as well.
     * @param user
     * @param pass
     */
    public void basic(String user, String pass) {
        URI uri = ((URIBuilder) builder.getUri()).toURI();
        if (uri == null)
            throw new IllegalStateException("a default URI must be set");
        this.basic(uri.getHost(), uri.getPort(), user, pass);
    }

    /**
     * Set authentication credentials to be used for the given host and port.
     * @param host
     * @param port
     * @param user
     * @param pass
     */
    public void basic(String host, int port, String user, String pass) {
        builder.getClient().getCredentialsProvider().setCredentials(new AuthScope(host, port),
                new UsernamePasswordCredentials(user, pass));
    }

    /**
     * Sets a certificate to be used for SSL authentication.  See
     * {@link Class#getResource(String)} for how to get a URL from a resource
     * on the classpath.
     * @param certURL URL to a JKS keystore where the certificate is stored.
     * @param password password to decrypt the keystore
     */
    public void certificate(String certURL, String password) throws GeneralSecurityException, IOException {

        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        InputStream jksStream = new URL(certURL).openStream();
        try {
            keyStore.load(jksStream, password.toCharArray());
        } finally {
            jksStream.close();
        }

        SSLSocketFactory ssl = new SSLSocketFactory(keyStore, password);
        ssl.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);

        builder.getClient().getConnectionManager().getSchemeRegistry().register(new Scheme("https", ssl, 443));
    }

    /**
     * </p>OAuth sign all requests.  Note that this currently does <strong>not</strong>
     * wait for a <code>WWW-Authenticate</code> challenge before sending the
     * the OAuth header.  All requests to all domains will be signed for this
     * instance.</p>
     *
     * <p>This assumes you've already generated an <code>accessToken</code> and
     * <code>secretToken</code> for the site you're targeting.  For More information
     * on how to achieve this, see the
     * <a href='http://code.google.com/p/oauth-signpost/wiki/GettingStarted#Using_Signpost'>Signpost documentation</a>.</p>
     * @since 0.5.1
     * @param consumerKey <code>null</code> if you want to <strong>unset</strong>
     *  OAuth handling and stop signing requests.
     * @param consumerSecret
     * @param accessToken
     * @param secretToken
     */
    public void oauth(String consumerKey, String consumerSecret, String accessToken, String secretToken) {
        this.builder.client.removeRequestInterceptorByClass(OAuthSigner.class);
        if (consumerKey != null)
            this.builder.client
                    .addRequestInterceptor(new OAuthSigner(consumerKey, consumerSecret, accessToken, secretToken));
    }

    /**
     * This class is used to sign all requests via an {@link HttpRequestInterceptor}
     * until the context-aware AuthScheme is released in HttpClient 4.1.
     * @since 0.5.1
     */
    static class OAuthSigner implements HttpRequestInterceptor {
        protected OAuthConsumer oauth;

        public OAuthSigner(String consumerKey, String consumerSecret, String accessToken, String secretToken) {
            this.oauth = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
            oauth.setTokenWithSecret(accessToken, secretToken);
        }

        public void process(HttpRequest request, HttpContext ctx) throws HttpException, IOException {
            /* The full request URI must be reconstructed between the context and the request URI.
             * Best we can do until AuthScheme supports HttpContext.  See:
             * https://issues.apache.org/jira/browse/HTTPCLIENT-901 */
            try {
                HttpHost host = (HttpHost) ctx.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
                final URI requestURI = new URI(host.toURI()).resolve(request.getRequestLine().getUri());

                oauth.signpost.http.HttpRequest oAuthRequest = new OAuthRequestAdapter(request, requestURI);
                this.oauth.sign(oAuthRequest);
            } catch (URISyntaxException ex) {
                throw new HttpException("Error rebuilding request URI", ex);
            } catch (OAuthException e) {
                throw new HttpException("OAuth signing error", e);
            }
        }

        static class OAuthRequestAdapter implements oauth.signpost.http.HttpRequest {

            final HttpRequest request;
            final URI requestURI;

            OAuthRequestAdapter(HttpRequest request, URI requestURI) {
                this.request = request;
                this.requestURI = requestURI;
            }

            public String getRequestUrl() {
                return requestURI.toString();
            }

            public void setRequestUrl(String url) {
                /*ignore*/}

            public Map<String, String> getAllHeaders() {
                Map<String, String> headers = new HashMap<String, String>();
                // FIXME this doesn't account for repeated headers,
                // which are allowed by the HTTP spec!!
                for (Header h : request.getAllHeaders())
                    headers.put(h.getName(), h.getValue());
                return headers;
            }

            public String getContentType() {
                try {
                    return request.getFirstHeader("content-type").getValue();
                } catch (Exception ex) { // NPE or ArrayOOBEx
                    return null;
                }
            }

            public String getHeader(String name) {
                Header h = request.getFirstHeader(name);
                return h != null ? h.getValue() : null;
            }

            public InputStream getMessagePayload() throws IOException {
                if (request instanceof HttpEntityEnclosingRequest)
                    return ((HttpEntityEnclosingRequest) request).getEntity().getContent();
                return null;
            }

            public String getMethod() {
                return request.getRequestLine().getMethod();
            }

            public void setHeader(String key, String val) {
                request.setHeader(key, val);
            }

            public Object unwrap() {
                return request;
            }
        };
    }
}