001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027package org.apache.http.impl.client;
028
029import java.security.Principal;
030
031import javax.net.ssl.SSLSession;
032
033import org.apache.http.HttpConnection;
034import org.apache.http.annotation.Contract;
035import org.apache.http.annotation.ThreadingBehavior;
036import org.apache.http.auth.AuthScheme;
037import org.apache.http.auth.AuthState;
038import org.apache.http.auth.Credentials;
039import org.apache.http.client.UserTokenHandler;
040import org.apache.http.client.protocol.HttpClientContext;
041import org.apache.http.conn.ManagedHttpClientConnection;
042import org.apache.http.protocol.HttpContext;
043
044/**
045 * Default implementation of {@link UserTokenHandler}. This class will use
046 * an instance of {@link Principal} as a state object for HTTP connections,
047 * if it can be obtained from the given execution context. This helps ensure
048 * persistent connections created with a particular user identity within
049 * a particular security context can be reused by the same user only.
050 * <p>
051 * DefaultUserTokenHandler will use the user principal of connection
052 * based authentication schemes such as NTLM or that of the SSL session
053 * with the client authentication turned on. If both are unavailable,
054 * {@code null} token will be returned.
055 *
056 * @since 4.0
057 */
058@Contract(threading = ThreadingBehavior.IMMUTABLE)
059public class DefaultUserTokenHandler implements UserTokenHandler {
060
061    public static final DefaultUserTokenHandler INSTANCE = new DefaultUserTokenHandler();
062
063    @Override
064    public Object getUserToken(final HttpContext context) {
065
066        final HttpClientContext clientContext = HttpClientContext.adapt(context);
067
068        Principal userPrincipal = null;
069
070        final AuthState targetAuthState = clientContext.getTargetAuthState();
071        if (targetAuthState != null) {
072            userPrincipal = getAuthPrincipal(targetAuthState);
073            if (userPrincipal == null) {
074                final AuthState proxyAuthState = clientContext.getProxyAuthState();
075                userPrincipal = getAuthPrincipal(proxyAuthState);
076            }
077        }
078
079        if (userPrincipal == null) {
080            final HttpConnection conn = clientContext.getConnection();
081            if (conn.isOpen() && conn instanceof ManagedHttpClientConnection) {
082                final SSLSession sslsession = ((ManagedHttpClientConnection) conn).getSSLSession();
083                if (sslsession != null) {
084                    userPrincipal = sslsession.getLocalPrincipal();
085                }
086            }
087        }
088
089        return userPrincipal;
090    }
091
092    private static Principal getAuthPrincipal(final AuthState authState) {
093        final AuthScheme scheme = authState.getAuthScheme();
094        if (scheme != null && scheme.isComplete() && scheme.isConnectionBased()) {
095            final Credentials creds = authState.getCredentials();
096            if (creds != null) {
097                return creds.getUserPrincipal();
098            }
099        }
100        return null;
101    }
102
103}