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 }