/************************************************************************
*
* 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.transport.processor;


import uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.processing.MessageProcessor;
import uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.Message;
import uk.ac.soton.itinnovation.gemss.transportmessaging.messaging.MessagingException;
import eu.gemss.components.transport.servicedescription.ServiceDescription;
import eu.gemss.components.transport.servicedescription.policytypes.Policy;
import eu.gemss.components.security.token.SecurityToken;
import eu.gemss.components.security.token.types.contexttoken.SecurityContextToken;
import eu.gemss.components.security.token.types.pki.X509CertificateToken;
import eu.gemss.components.transport.servicedescription.ServiceEndpoint;
import eu.gemss.components.transport.servicedescription.endpointtypes.WSDLEndpoint;
import de.nece.ccrl.securitycontext.NECSecurityContext;
import de.nece.ccrl.securitycontext.policies.X509ExchPolicy;
import de.nece.ccrl.securitycontext.token.types.contexttoken.*;
import de.nece.ccrl.securitycontext.token.types.pki.*;
import java.net.URL;
import eu.gemss.GridException;

public class  X509ExchProcessor implements MessageProcessor {    




    public Message enforceMessage(ServiceDescription desc, Policy p, Message msg) throws MessagingException {

	System.out.println("Certificate exchange started ...");

	// check if the right policy was passed

	if (!(p instanceof X509ExchPolicy)) throw new MessagingException("X509ExchProcessor requires X509ExchPolicy");

	
	NECSecurityContext seccxt = null;

	String pt = System.getProperty("gemss.home");
	if (pt==null) throw new MessagingException("No System Property gemss.home set");

	try{
	    seccxt = new NECSecurityContext(pt, pt+"/config/gemss.security.context.properties");
	} catch (Exception e) {throw new MessagingException("Security Context configuration error");}


	// construct security context token descriptor from information passed in the service description

	ServiceEndpoint serviceendpoint = desc.getServiceEndpoint();
	URL serviceURL = null;
	if (serviceendpoint instanceof WSDLEndpoint) {
	    serviceURL = ((WSDLEndpoint) serviceendpoint).getEndpointURL();
	} else throw new MessagingException("only WSDL endpoints supported");
	String service;
	String host = serviceURL.getHost();
	int port = serviceURL.getPort();
	String prot = serviceURL.getProtocol();
	String path = serviceURL.getPath();
	service = host + path; // service not depending from port !! see NSLProcessor for explanation.

	String tokenservice;

	String[] parts = path.split("/");
	String part = null;
	if (parts.length>1)
	    part ="/"+parts[1]+"/"+parts[2];
	else part="/"+parts[1];

	if (port == -1) {
	    tokenservice = prot + "://"+host+part+"/axis/X509Exchange";
	}
	else {
	    tokenservice = prot + "://"+host+":"+port+part+"/axis/X509Exchange";
	}
	SecurityContextTokenDescriptor cxtdesc = new SecurityContextTokenDescriptor("X509Exch",service,tokenservice);

	// set certificate as the support token in the descriptor
	String initiator = null;
	try {
	    initiator = seccxt.getInitiator();
	} catch (eu.gemss.GridException e) {throw new MessagingException("Can't retrieve initiator");}
	
	

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

	// retrive certificate from keystore
	
	SecurityToken[] stoken = new SecurityToken[1];
	try{
	    stoken[0] = seccxt.getSecurityToken(tokendesc);
	} catch (Exception e) {throw new MessagingException("Can't retrieve token");}
	
	if ((stoken[0] ==null) || (!(stoken[0] instanceof X509CertificateToken))) 
	    throw new MessagingException("certificate not in store");

	cxtdesc.setSupportTokens(stoken);

	// generate i.e. retrieve the context token with the responder certificate
	
	SecurityContextToken token = null;
	try{
	    token = (SecurityContextToken) seccxt.generateSecurityToken(cxtdesc);
	} catch (GridException e) {
	    e.printStackTrace();
	    throw new MessagingException("Unexpected security context error -- " + e.getUserMessage());
	}
  
	// extract certificate and store it 

	SecurityToken cert = token.getIncludedToken();
       
	if (cert instanceof X509CertificateToken) {
	
	    try{
		if (seccxt.isTrusted(cert))
		    seccxt.addSecurityTokenToContext(cert);
		else {
		    // use a signal! so that a session can be saved. TODO
		    // a similar thing needs to be done in the manager
		    System.out.println("WARNING: An Untrusted or Expired CERTIFICATE was recieved.");
		    System.out.println("Please contact your service provider.");
		    System.exit(0);
		}
	    } catch (Exception e) {throw new MessagingException("Unexpected security context error -- " + e.getMessage());}
	} else throw new MessagingException("X509Exch processor expects an X509 certificate");


	System.out.println("Certificate Exchange was successful");

	return msg;
    }

   
    public String getDescription() {
	return "X509ExchProcessor";
    }
 
}
