/************************************************************************
*
* Copyright (c) 2003-2004, C&C Research Laboratories, NEC Europe Ltd.
*
* Copyright in this library belongs to C&C Research Laboratories,
* Rathausallee 10, 53757 Sankt Augustin, Germany.
*
* This software may not be used, sold, licensed, transferred, copied
* or reproduced in whole or in part in any manner or form or in or
* on any media by any person other than in accordance with the terms
* of the Licence Agreement supplied with the software, or otherwise
* without the prior written consent of the copyright owners.
*
* This software is distributed WITHOUT ANY WARRANTY, without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE, except where stated in the Licence Agreement supplied with
* the software.
*
*  Created By :           Federico Crazzolara
*  Created for Project :  GEMSS (IST-2001-37153)
*
************************************************************************/


package de.nece.ccrl.tokenservice.sessions;

import org.xmlsoap.schemas.ws._2002._12.secext.*;
import javax.xml.namespace.*;
import de.nece.ccrl.sessionmanager.*;
import de.nece.ccrl.schemas.sessid.SessionIdType;
import de.nece.ccrl.schemas.sessid.holders.SessionIdTypeHolder;
import de.nece.ccrl.tokenmanager.codec.GEMSSTokenManagerCoDec;
import de.nece.ccrl.tokenmanager.TokenManagerCoDec;
import de.nece.ccrl.tokenmanager.TokenManagerException;
import de.nece.ccrl.securitycontext.NECSecurityContext;
import de.nece.ccrl.securitycontext.token.types.pki.CertificateDescriptor;
import de.nece.ccrl.tokenservice.registry.*;
import eu.gemss.components.security.token.SecurityToken;
import eu.gemss.components.security.token.types.pki.X509CertificateToken;
import java.util.logging.*;


public class X509ExchangeSession extends Session{


    private static Logger logger = Logger.getLogger("logging.advancedSecurity");

    public void run() {

	SessionPort requests = null, responses = null;
	RequestSecurityTokenType req = null;
	RequestSecurityTokenResponseType resp;
	QName tokentype;
	TokenTypeEnum tokentypeenum;
	String initiator = null, responder = null;	
	
	SessionContext cxt = this.getContext();
	
	try{

	    try{

	    requests = cxt.getSessionPort("in");
	    responses = cxt.getSessionPort("out");

	    SessionIdTypeHolder sidh = (SessionIdTypeHolder) cxt.getSessionId(); 
	    SessionIdType sid = sidh.getSessionId();
            responder = sid.getResponder(); //the service on behalf of which I act	
	    initiator = sid.getInitiator();
	    logger.info("Acting on Behalf of: " + responder + " upon request of " + initiator);
	
	    req = (RequestSecurityTokenType) requests.getValue();
	
	    QName requesttype = (req.getRequestType()).getValue();
	    tokentype = (req.getTokenType()).getValue();

	
	
	    QName rtype = new QName("wsse:ReqExchange");
	    QName ttype = new QName("wsse:X509v3");

	
	    // instantiate codec

	    TokenManagerCoDec codec = new GEMSSTokenManagerCoDec();

	    // instantiate the security context of the service in question
		
	    NECSecurityContext seccxt = null;
	

	    RegistryImpl reg = new RegistryImpl();
	    KeystoreAccessor a = reg.getAccessor(responder);
	    
	    seccxt = new NECSecurityContext(".", a.getConfigfile());
	    
       

	    if (rtype.equals(requesttype) && ttype.equals(tokentype)) {
	    
		// extract token and save it in keystore 
		
		BinarySecurityTokenType bincert = (req.getRequestedSecurityToken(0)).getBinarySecurityToken();
	    
	    
		X509CertificateToken cert = null;
		try{
		    cert = (X509CertificateToken) codec.decode(bincert);		
		}catch(TokenManagerException e2){}
		if (seccxt.isTrusted(cert)) seccxt.addSecurityTokenToContext(cert);
		else {
		    System.out.println("CERTIFICATE of INITIATOR is expired or can not be trusted");
		    System.out.println("The Cert. will not be included in the keystore");
		}
	    

		// prepare response
	    
		resp = new RequestSecurityTokenResponseType();
		tokentype = new QName("wsse:X509v3");
		tokentypeenum = TokenTypeEnum.fromValue(tokentype);
		resp.setTokenType(tokentypeenum);
	    	    

		// construct token descriptor for the certificate -- only X509 supported for now

		CertificateDescriptor tokendesc = new CertificateDescriptor(CertificateDescriptor.X509,responder);


		// retrive certificate from keystore
	
		
		SecurityToken token = null;
		try{
		    token = seccxt.getSecurityToken(tokendesc);
		}catch(Exception e){}
		if ((token==null) || (!(token instanceof X509CertificateToken))) {
		    logger.info("Please check your keystore. The certificate can not be retrieved.");
		    resp = null; }
		else {
	
		    // check if certificate is trusted *** NO need its my certificate

		    // use tokenmanager codec to transform certificate in BinarySecurityTokenType
		
		    BinarySecurityTokenType t = null;
		    try{
		    t = (BinarySecurityTokenType) codec.encode(token);
		    }catch(TokenManagerException e2){}
		    RequestedSecurityTokenType[] art = new RequestedSecurityTokenType[1];
		    RequestedSecurityTokenType rt =  new RequestedSecurityTokenType();
		    rt.setBinarySecurityToken(t);
		    art[0] = rt;
		    resp.setRequestedSecurityToken(art);
		}
	   
	    } else resp = null;

	    // produces answer 
	    
	    responses.setValue(resp);

	    cxt.terminateContext(0);

	    }catch(SessionContextException e1) {}
       
	} catch (Exception e) {
	    try{
		logger.info("X509Exchange of " + initiator + " with " + responder + " failed");
		cxt.terminateContext(0);
	    } catch (SessionContextException e1) {
		logger.severe("Unexpected exception while trying to terminate a Session Context");
	    }
	}
    }
}
