001    /*
002     * Copyright 2012 UnboundID Corp.
003     *
004     * This program is free software; you can redistribute it and/or modify
005     * it under the terms of the GNU General Public License (GPLv2 only)
006     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
007     * as published by the Free Software Foundation.
008     *
009     * This program is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012     * GNU General Public License for more details.
013     *
014     * You should have received a copy of the GNU General Public License
015     * along with this program; if not, see <http://www.gnu.org/licenses>.
016     */
017    
018    package com.unboundid.scim.sdk;
019    
020    import java.io.IOException;
021    
022    import org.apache.http.HttpException;
023    import org.apache.http.HttpRequest;
024    import org.apache.http.HttpRequestInterceptor;
025    import org.apache.http.auth.AuthScheme;
026    import org.apache.http.auth.AuthState;
027    import org.apache.http.auth.Credentials;
028    import org.apache.http.client.protocol.ClientContext;
029    import org.apache.http.protocol.HttpContext;
030    
031    
032    /**
033     * This class can be used to configure the Apache Http Client for preemptive
034     * authentication. In this mode, the client will send the basic authentication
035     * response even before the server gives an unauthorized response in certain
036     * situations. This reduces the overhead of making requests over authenticated
037     * connections.
038     *
039     * This behavior conforms to RFC2617: A client MAY preemptively send the
040     * corresponding Authorization header with requests for resources in that space
041     * without receipt of another challenge from the server. Similarly, when a
042     * client sends a request to a proxy, it may reuse a userid and password in the
043     * Proxy-Authorization header field without receiving another challenge from the
044     * proxy server.
045     *
046     * The Apache Http Client does not support preemptive authentication out of the
047     * box, because if misused or used incorrectly the preemptive authentication can
048     * lead to significant security issues, such as sending user credentials in
049     * clear text to an unauthorized third party.
050     */
051    public class PreemptiveAuthInterceptor implements HttpRequestInterceptor
052    {
053      private final AuthScheme authScheme;
054      private final Credentials credentials;
055    
056      /**
057       * Constructs a new PreemptiveAuthInterceptor. It is important that this is
058       * added as the <b>first</b> request interceptor in the chain. You can do this
059       * by making sure the second parameter is zero when adding the interceptor:
060       * <p>
061       * <code>
062       * httpClient.addRequestInterceptor(
063       *   new PreemptiveAuthInterceptor(new BasicScheme(), credentials), 0);
064       * </code>
065       *
066       * @param authScheme The AuthScheme to use. This may not be null.
067       * @param credentials The Credentials to use. This may not be null.
068       */
069      public PreemptiveAuthInterceptor(final AuthScheme authScheme,
070                                       final Credentials credentials)
071      {
072        if(authScheme == null)
073        {
074          throw new NullPointerException(
075                  "The 'authScheme' parameter cannot be null");
076        }
077    
078        if(credentials == null)
079        {
080          throw new NullPointerException(
081                  "The 'credentials' parameter cannot be null");
082        }
083    
084        this.authScheme = authScheme;
085        this.credentials = credentials;
086      }
087    
088      /**
089       * {@inheritDoc}
090       */
091      @Override
092      public void process(final HttpRequest request, final HttpContext context)
093          throws HttpException, IOException
094      {
095        AuthState authState = (AuthState) context.getAttribute(
096                                            ClientContext.TARGET_AUTH_STATE);
097        if(authState != null)
098        {
099          authState.setAuthScheme(authScheme);
100          authState.setCredentials(credentials);
101        }
102      }
103    }