package jacorb.security.level2;

import org.omg.Security.*;
import java.util.Vector;
import java.security.cert.*;
import jacorb.security.util.*;

/**
 *  JacORB implementation of security Credentials
 *
 *  $Id: Credentials.java,v 1.1 2000/03/27 09:50:02 brose Exp $
 *
 */

public class Credentials
    extends jacorb.orb.LocalityConstrainedObject
    implements org.omg.SecurityLevel2.Credentials
{
    private jacorb.orb.Principal principal;
    private PrincipalAuthenticator authenticator;
    private java.security.cert.X509Certificate [] certs;
    private SecAttribute[] my_attributes;
  
    private short accepting_options_supported;
    private short accepting_options_required;
    private short invocation_options_required;

    private org.omg.Security.AuthenticationStatus authStatus;
    
    /** SecurityFeature is an enum, its integer value is the index */
    private boolean [] securityFeaturesForRequests;
    private boolean [] securityFeaturesForReplies;

    public Credentials(PrincipalAuthenticator authenticator,
		       java.security.cert.X509Certificate [] certs, 
		       org.omg.Security.AuthenticationStatus status)    
    {
	this.authenticator = authenticator;
	this.authStatus = status;
	initPublicAttributes();
	initAttributesFromCerts(certs);       
    }

    /**
     * creates a Credentials object with one public, unauthenticated
     * attribute, viz. the user name as defined by the underlying OS
     * (unauthenticated in this context means that the attribute is 
     * not provided in the form of a signed certificate and requires
     * no further client authentication)
     */

    public Credentials()
    {
	initPublicAttributes();
    }

    private void initPublicAttributes()
    {
	java.util.Properties props = System.getProperties();
	String public_name = props.getProperty("user.name");
	byte [] name = (public_name != null ? public_name.getBytes() : new byte[0]);
	String definer = props.getProperty("os.name") + props.getProperty("os.version");
	byte [] defining_auth = ( definer != null ? definer.getBytes() : new byte[0]);

	my_attributes = new SecAttribute[1];
	my_attributes[0] = new SecAttribute(
				 new AttributeType(
				      new ExtensibleFamily((short)0,(short)1),
				      Public.value), 
				 defining_auth, name
				 );	
    }

    private void initAttributesFromCerts(java.security.cert.X509Certificate [] certs)
    {
	this.certs = certs;
	for(int i=0; i < certs.length; i++)
	{
	    X509Certificate cert = null;
	    try
	    {
		cert = (X509Certificate)certs[i];
		if( CertUtils.isRoleCert(cert))
		{
		    String roleName = CertUtils.getRoleName(cert);
		    AttributeType attrType = new AttributeType(
				      new ExtensibleFamily((short)0,(short)1),
				      Role.value);
		    byte [] definingAuthority = (byte[])cert.getIssuerDN().getName().getBytes();
		    SecAttribute attr = new SecAttribute(attrType,
							      definingAuthority,
							      roleName.getBytes());	
		}
		else 
		{
		    // other ;
		}
	    }
	    catch( ClassCastException cce )
	    {
		jacorb.util.Debug.output(3,"ignoring unknown cert " + cert.toString());
		continue;
	    }
	}
    }

    public org.omg.SecurityLevel2.Credentials copy()
    { 
	// not implemented
	return null; 
    }
  
    public org.omg.Security.InvocationCredentialsType credentials_type()
    {
	return org.omg.Security.InvocationCredentialsType.SecOwnCredentials;
    }
    
    public org.omg.Security.AuthenticationStatus authentication_state()
    {
	return authStatus;
    }
    
    public java.lang.String mechanism()
    {
	return null;
    }

    public short accepting_options_supported()
    {
	return accepting_options_supported;
    }

    public void accepting_options_supported(short arg)
    {
	accepting_options_supported = arg;
    }

    public short accepting_options_required()
    {
	return accepting_options_required;
    }

    public void accepting_options_required(short arg)
    {
	 accepting_options_required = arg;
    }

    public short invocation_options_required()
    {
	return invocation_options_required;
    }

    public void invocation_options_required(short arg)
    {
	invocation_options_required = arg;
    }

    /**
     * can be used in access control decisions or auditing
     *
     * @param attributes - the set of attributes whose values are desired. 
     *                     If this list is empty, all attributes are returned
     * 
     * @return The requested set of attributes reflecting the state of Credentials
     */

    public  SecAttribute[] get_attributes(AttributeType[] attributes)
    {
	if( attributes == null || attributes.length == 0 )
	    return my_attributes;
      
	/* sort out the requested attributes */

	Vector v = new Vector();
	for( int i = 0; i < attributes.length; i++ )
	{
	    for( int j = 0; j < my_attributes.length; j++ )
	    {
		if( my_attributes[j].attribute_type.attribute_family.family == attributes[i].attribute_family.family &&
		    my_attributes[j].attribute_type.attribute_type == attributes[i].attribute_type
		    )
		    v.addElement(my_attributes[j]);
	    } 
	}
	SecAttribute[] result = new SecAttribute[v.size()];
	for( int i = 0; i < result.length; i++ )
	    result[i] = (SecAttribute)v.elementAt(i);
      
	return result; 
    }
  
    public  void destroy()
    {
    }
  
    public void set_security_feature(CommunicationDirection direction, 
				       SecurityFeature[] security_features)
    {
	switch( direction.value() )
	{
	case  CommunicationDirection._SecDirectionRequest:
	    setFeatures( securityFeaturesForRequests, security_features);

	case CommunicationDirection._SecDirectionReply:
	    setFeatures( securityFeaturesForReplies, security_features);

	case CommunicationDirection._SecDirectionBoth:
	    setFeatures( securityFeaturesForRequests, security_features);
	    setFeatures( securityFeaturesForReplies, security_features);
	}
    }

    private void setFeatures( boolean[] target, SecurityFeature[] features )
    {
	if( features.length > target.length )
	    throw new java.lang.IllegalArgumentException("Too many features");

	for( int i = 0; i < features.length; i++ )
	{
	    int value =  features[i].value();
	    if( value > target.length || value < 0)
	    {
		throw new java.lang.IllegalArgumentException("SecurityFeatureValue out of range");
	    }
	    target[ value ] = true;
	}
    }

  
    public boolean get_security_feature(CommunicationDirection direction,
					org.omg.Security.SecurityFeature feature)
    {
	switch( direction.value() )
	{
	case  CommunicationDirection._SecDirectionRequest:
	    return securityFeaturesForRequests[feature.value()];

	case CommunicationDirection._SecDirectionReply:
	    return securityFeaturesForReplies[feature.value()];

	default: //  CommunicationDirection._SecDirectionBoth:
	    return securityFeaturesForRequests[feature.value()] && 
		securityFeaturesForReplies[feature.value()];

	}
    }
  
    public  boolean set_privileges(boolean force_commit, 
				   SecAttribute[] requested_privileges, 
				   AttributeListHolder/*out*/ actual_privileges)
    { 
	return false; 
    }
  
  
    public boolean is_valid(org.omg.Security.UtcTHolder/*out*/ expiry_time)
    { 
	return false; 
    }
  
    public  boolean refresh(byte[] refresh_data)
    { 
	return false; 
    }
}





