package jacorb.security.level2;

/*
 *        JacORB - a free Java ORB
 *
 *   Copyright (C) 1997-99  Gerald Brose.
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

import org.omg.Security.*;
import org.omg.SecurityLevel2.*;

import java.util.*;
import java.io.*;

import jacorb.util.*;

/**
 *
 * @author Nicolas Noffke, Gerald Brose, André Benvenuti
 * @version $Id: CurrentImpl.java,v 1.5 2000/09/15 18:10:44 brose Exp $
 *
 */

public class CurrentImpl
    extends jacorb.orb.LocalityConstrainedObject
    implements org.omg.SecurityLevel2.Current
{
    private CredentialsImpl[] own_credentials;

    private PrincipalAuthenticatorImpl principalAuthenticator;
    private AccessDecision access_decision = null;
    private Hashtable policies = null;

    private SecAttributeManager attrib_mgr = null;
    
    //thread specific credentials
    private Hashtable ts_credentials = null;
    private Hashtable ts_received_credentials = null;
    
    private org.omg.CORBA.ORB orb = null;  
    
    public CurrentImpl(org.omg.CORBA.ORB orb)
    {
        this.orb = orb;
        
        attrib_mgr = SecAttributeManager.getInstance();

        ts_credentials = new Hashtable();
        ts_received_credentials = new Hashtable();
        policies = new Hashtable();
        
        principalAuthenticator = new PrincipalAuthenticatorImpl(orb);
        
        byte value = (byte)Environment.supportedBySSL();

        if( Environment.supportSSL() && ( value & 0x60 ) != 0 ) 
            // i.e.: if either client or target trust establishement is supported
        {
            Debug.output( 3, "Authenticate");
            authenticate();            
        }

        //build access decision
        try
        {
            Class ad_class = Class.forName
                (Environment.getProperty("jacorb.security.access_decision"));

            access_decision = (AccessDecision) ad_class.newInstance();
        }
        catch (Exception e)
        {
            Debug.output(Debug.SECURITY | Debug.IMPORTANT,
                         "Class " + Environment.getProperty
                         ("jacorb.security.access_decision") +
                         " not found!");

            Debug.output(Debug.SECURITY | Debug.DEBUG1, e);
            
            access_decision = new AccessDecisionImpl();
        }
    }

    /** 
        Request Credentials and set them.
    
        @return false If an exception was raised during the authentication
        process or if the authentication failed, true otherwise.  
    */
    private void authenticate()
    {
        String security_name = jacorb.util.Environment.defaultUser();
        String password = jacorb.util.Environment.defaultPassword();
        
        CredentialsHolder coh = new CredentialsHolder();
        SecAttribute attribute = new SecAttribute();
        attribute.attribute_type = new AttributeType(new ExtensibleFamily((short) 0,
                                                                          (short) 1),
                                                     AccessId.value);
        
        if (principalAuthenticator.authenticate(0, null, 
                                                security_name, 
                                                password == null ? null : password.getBytes(), 
                                                new SecAttribute[]{attribute}, 
                                                coh, 
                                                null, null)
            == AuthenticationStatus.SecAuthSuccess) 
        {
            own_credentials = new CredentialsImpl[]{ (CredentialsImpl) coh.value };
            Debug.output( 2, "AuthenticationStatus.SecAuthSuccess");
        }
        else
        {
            Debug.output( 2, "AuthenticationStatus.SecAuthFailure");
        }
    }

    /* thread specific, from SecurityLevel1*/
    public SecAttribute[] get_attributes(AttributeType[] types)
    {
        
        CredentialsImpl[] tsc = getTSCredentials();
        
        if( tsc != null && tsc.length > 0)
        {
            return tsc[0].get_attributes( types );
        }
        else if ( own_credentials != null &&
                  own_credentials.length > 0 )
        {
            return own_credentials[0].get_attributes( types );
        }
        else
        {
            return new SecAttribute[0];
        }
    }

    /* thread specific*/

    public ReceivedCredentials received_credentials()
    {
        return (ReceivedCredentials)ts_received_credentials.get( Thread.currentThread() );
    }
    
    /* thread specific*/
    public void set_credentials( CredentialType cred_type, 
                                 Credentials[] creds, 
                                 org.omg.SecurityLevel2.DelegationMode del )
    {
        //ignoring DelegationMode
        ts_credentials.put( Thread.currentThread(),
                            creds );
    }

    /* thread specific*/

    public void set_received_credentials( ReceivedCredentials creds ) 
    {
        //ignoring DelegationMode
        ts_received_credentials.put( Thread.currentThread(),
                            creds );
    }

    /* thread specific*/
    public Credentials[] get_credentials(CredentialType cred_type)
    {
        CredentialsImpl[] tsc = getTSCredentials();

        if ( tsc == null )
        {
            tsc = own_credentials;
        }

        Vector found_creds = new Vector();

        for( int i = 0; i < tsc.length; i++ )
        {             
            if ( cred_type.value() == tsc[i].credentials_type().value() )
            {
                found_creds.addElement( tsc[i] );
            }
        }

        Credentials[] creds = new Credentials[found_creds.size()];

        for( int i = 0; i < creds.length; i++ )
        {             
            creds[i] = (Credentials) 
                found_creds.elementAt( i );
        }

        return creds;
    }
  
    /* application specific */
    public Credentials[] own_credentials()
    {
        return own_credentials;       
    }
  
    /* application specific */
    /**
     * This will remove the passed Credentials from the list 
     * of own_credentials.
     * The passed object has to be the same instance as the one 
     * to be removed.
     */
    public void remove_own_credentials(Credentials credentials)
    {
        boolean found_credentials = false;
        Vector kept_credentials = new Vector();
        
        for (int i = 0; i < own_credentials.length; i++)
        {
            if ( credentials == own_credentials[i] )
            {
                found_credentials = true;
            }
            else
            {
                kept_credentials.addElement( own_credentials[i] );
            }
        }
        
        if ( found_credentials )
        {
            own_credentials = new CredentialsImpl[kept_credentials.size()];

            for (int i = 0; i < kept_credentials.size(); i++)
            {
                own_credentials[i] = (CredentialsImpl) 
                    kept_credentials.elementAt( i );
            }
        }
        else
        {
            throw new org.omg.CORBA.BAD_PARAM();
        }
    }

    /* application specific */
    public SecurityFeature[] received_security_features()
    {
        return null;
    }
  
    /* application specific */
    public org.omg.CORBA.Policy get_policy(int policy_type)
    {
        return (org.omg.CORBA.Policy) policies.get(new Integer(policy_type));
    }
  
    /* application specific */
    public org.omg.Security.MechandOptions[] supported_mechanisms()
    {
        return null;
    }

    /* application specific */
    public SecurityMechanismData[] get_security_mechanisms(org.omg.CORBA.Object obj_ref)
    {
        return null;
    }

    /* application specific */
    public RequiredRights required_rights_object()
    {
        return null;
    }
  
    /* application specific */
    public  PrincipalAuthenticator principal_authenticator()
    {
        return principalAuthenticator;
    }
  
    /* application specific */
    public AccessDecision access_decision()
    {
        return access_decision;
    }
  
    /* application specific */
    public AuditDecision audit_decision()
    {
        return null;
    }
  
    /* application specific */
    public QOPPolicy create_qop_policy(QOP qop)
    {
        return new QOPPolicyImpl(qop);
    }
  
    /* application specific */
    public MechanismPolicy create_mechanism_policy(String[] mechanisms)
    {
        return new MechanismPolicyImpl(mechanisms);
    }
  
    /* application specific */
    public InvocationCredentialsPolicy create_invoc_creds_policy(Credentials[] creds)
    {
        return new InvocationCredentialsPolicyImpl(creds);
    }

    private CredentialsImpl[] getTSCredentials()
    {
        return (CredentialsImpl[])
            ts_credentials.get( Thread.currentThread() );
    }

    public KeyAndCert[] getSSLCredentials()
    {
        if( own_credentials == null ||
            own_credentials.length == 0 )
        {
            return new KeyAndCert[0];
        }

        AttributeType type = new AttributeType
            ( new ExtensibleFamily( (short) 0,
                                    (short) 1 ),
              AccessId.value );

        SecAttribute[] attribs = 
            own_credentials[0].get_attributes( new AttributeType[]{type} );
            
        KeyAndCert[] certs = new KeyAndCert[attribs.length];
            
        for( int i = 0; i < certs.length; i++ )
        {
            certs[i] = attrib_mgr.getAttribValue( attribs[i] );
        }

        return certs;
    }          


    public void close()
    {
        Debug.output( 3, "Closing Current");
        
        if( principalAuthenticator != null )
            principalAuthenticator.close();
        policies.clear();
        ts_credentials.clear();
        ts_received_credentials.clear();
    }

    public void finalize()
    {
        close();
    }
}




