All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.client.security.SecurityListener Maven / Gradle / Ivy

There is a newer version: 11.0.0.beta1
Show newest version
// ========================================================================
// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at 
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses. 
// ========================================================================

package org.eclipse.jetty.client.security;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpEventListenerWrapper;
import org.eclipse.jetty.client.HttpExchange;
import org.eclipse.jetty.http.HttpHeaders;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;


/**
 * SecurityListener
 * 
 * Allow for insertion of security dialog when performing an
 * HttpExchange.
 */
public class SecurityListener extends HttpEventListenerWrapper
{
    private static final Logger LOG = Log.getLogger(SecurityListener.class);
	
    private HttpDestination _destination;
    private HttpExchange _exchange;
    private boolean _requestComplete;
    private boolean _responseComplete;  
    private boolean _needIntercept;
    
    private int _attempts = 0; // TODO remember to settle on winning solution

    public SecurityListener(HttpDestination destination, HttpExchange ex)
    {
        // Start of sending events through to the wrapped listener
        // Next decision point is the onResponseStatus
        super(ex.getEventListener(),true);
        _destination=destination;
        _exchange=ex;
    }
    
    
    /**
     * scrapes an authentication type from the authString
     * 
     * @param authString
     * @return the authentication type
     */
    protected String scrapeAuthenticationType( String authString )
    {
        String authType;

        if ( authString.indexOf( " " ) == -1 )
        {
            authType = authString.toString().trim();
        }
        else
        {
            String authResponse = authString.toString();
            authType = authResponse.substring( 0, authResponse.indexOf( " " ) ).trim();
        }
        return authType;
    }
    
    /**
     * scrapes a set of authentication details from the authString
     * 
     * @param authString
     * @return the authentication details
     */
    protected Map scrapeAuthenticationDetails( String authString )
    {
        Map authenticationDetails = new HashMap();
        authString = authString.substring( authString.indexOf( " " ) + 1, authString.length() );
        StringTokenizer strtok = new StringTokenizer( authString, ",");
        
        while ( strtok.hasMoreTokens() )
        {
            String token = strtok.nextToken();
            String[] pair = token.split( "=" );
            
            // authentication details ought to come in two parts, if not then just skip
            if ( pair.length == 2 )
            {
                String itemName = pair[0].trim();
                String itemValue = pair[1].trim();
                
                itemValue = StringUtil.unquote( itemValue );
                
                authenticationDetails.put( itemName, itemValue );
            }    
            else
            {
                LOG.debug("SecurityListener: missed scraping authentication details - " + token );
            }
        }
        return authenticationDetails;
    }

  
    @Override
    public void onResponseStatus( Buffer version, int status, Buffer reason )
        throws IOException
    {
        if (LOG.isDebugEnabled())
            LOG.debug("SecurityListener:Response Status: " + status );

        if ( status == HttpStatus.UNAUTHORIZED_401 && _attempts<_destination.getHttpClient().maxRetries()) 
        {
            // Let's absorb events until we have done some retries
            setDelegatingResponses(false);
            _needIntercept = true;
        }
        else 
        {
            setDelegatingResponses(true);
            setDelegatingRequests(true);
            _needIntercept = false;
        }
        super.onResponseStatus(version,status,reason);
    }


    @Override
    public void onResponseHeader( Buffer name, Buffer value )
        throws IOException
    {
        if (LOG.isDebugEnabled())
            LOG.debug( "SecurityListener:Header: " + name.toString() + " / " + value.toString() );
        
        
        if (!isDelegatingResponses())
        {
            int header = HttpHeaders.CACHE.getOrdinal(name);
            switch (header)
            {
                case HttpHeaders.WWW_AUTHENTICATE_ORDINAL:

                    // TODO don't hard code this bit.
                    String authString = value.toString();
                    String type = scrapeAuthenticationType( authString );                  

                    // TODO maybe avoid this map creation
                    Map details = scrapeAuthenticationDetails( authString );
                    String pathSpec="/"; // TODO work out the real path spec
                    RealmResolver realmResolver = _destination.getHttpClient().getRealmResolver();
                    
                    if ( realmResolver == null )
                    {
                        break;
                    }
                    
                    Realm realm = realmResolver.getRealm( details.get("realm"), _destination, pathSpec ); // TODO work our realm correctly 
                    
                    if ( realm == null )
                    {
                        LOG.warn( "Unknown Security Realm: " + details.get("realm") );
                    }
                    else if ("digest".equalsIgnoreCase(type))
                    {
                        _destination.addAuthorization("/",new DigestAuthentication(realm,details));
                        
                    }
                    else if ("basic".equalsIgnoreCase(type))
                    {
                        _destination.addAuthorization(pathSpec,new BasicAuthentication(realm));
                    }
                    
                    break;
            }
        }
        super.onResponseHeader(name,value);
    }
    

    @Override
    public void onRequestComplete() throws IOException
    {
        _requestComplete = true;

        if (_needIntercept)
        {
            if (_requestComplete && _responseComplete)
            {
               if (LOG.isDebugEnabled())
                   LOG.debug("onRequestComplete, Both complete: Resending from onResponseComplete "+_exchange); 
                _responseComplete = false;
                _requestComplete = false;
                setDelegatingRequests(true);
                setDelegatingResponses(true);
                _destination.resend(_exchange);  
            } 
            else
            {
                if (LOG.isDebugEnabled())
                    LOG.debug("onRequestComplete, Response not yet complete onRequestComplete, calling super for "+_exchange);
                super.onRequestComplete(); 
            }
        }
        else
        {
            if (LOG.isDebugEnabled())
                LOG.debug("onRequestComplete, delegating to super with Request complete="+_requestComplete+", response complete="+_responseComplete+" "+_exchange);
            super.onRequestComplete();
        }
    }


    @Override
    public void onResponseComplete() throws IOException
    {   
        _responseComplete = true;
        if (_needIntercept)
        {  
            if (_requestComplete && _responseComplete)
            {              
                if (LOG.isDebugEnabled())
                    LOG.debug("onResponseComplete, Both complete: Resending from onResponseComplete"+_exchange);
                _responseComplete = false;
                _requestComplete = false;
                setDelegatingResponses(true);
                setDelegatingRequests(true);
                _destination.resend(_exchange); 

            }
            else
            {
               if (LOG.isDebugEnabled())
                   LOG.debug("onResponseComplete, Request not yet complete from onResponseComplete,  calling super "+_exchange);
                super.onResponseComplete(); 
            }
        }
        else
        {
            if (LOG.isDebugEnabled())
                LOG.debug("OnResponseComplete, delegating to super with Request complete="+_requestComplete+", response complete="+_responseComplete+" "+_exchange);
            super.onResponseComplete();  
        }
    }

    @Override
    public void onRetry()
    {
        _attempts++;
        setDelegatingRequests(true);
        setDelegatingResponses(true);
        _requestComplete=false;
        _responseComplete=false;
        _needIntercept=false;
        super.onRetry();
    }  
    
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy