/************************************************************************
*
* 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.SOAPMessage;
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.GEMSSSecurityContext;
import eu.gemss.components.security.token.SecurityToken;
import eu.gemss.components.security.token.types.contexttoken.SecurityContextToken;
import eu.gemss.components.security.token.types.key.symmetric.SecretKeyToken;
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.NSLPolicy;
import de.nece.ccrl.securitycontext.policies.X509ExchPolicy;
import de.nece.ccrl.securitycontext.token.types.contexttoken.*;
import java.net.URL;
import java.util.*;
import eu.gemss.GridException;


public class  NSLProcessor implements MessageProcessor {    

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

 
	System.out.println("");
	System.out.println("NSL started ...");

	// check if the right policy was passed

	if (!(p instanceof NSLPolicy)) throw new MessagingException("NSLProcessor requires NSLPolicy");

	
	GEMSSSecurityContext 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();
	String tokenservice;
	

	service = host + path; // I don't want the service endpoint to be dependend from PORT this
	                       // allows intermediaries !!! service is used as a RESPONDER info and
	                       // not for invocation. 

	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/NSL";
	}
	else { 
	    tokenservice = prot + "://"+host+":"+port+part+"/axis/NSL";
	}

	SecurityContextTokenDescriptor cxtdesc = new SecurityContextTokenDescriptor("NSL",service,tokenservice);

	
	// try to see if context token already exists if not or expired generate it
	
	SecurityContextToken token = null;

	try{
	    token = (SecurityContextToken) seccxt.getSecurityToken(cxtdesc);
	} catch (GridException e) {throw new MessagingException("Unexpected security context GET error -- " + e.getUserMessage());}

	if ((token==null) || token.isExpired()) {
	    try{

		if ((token!=null) && (token.isExpired())) System.out.println("Token EXPIRED.");
		System.out.println("Security Context will be (re)established.");

		// call x509context exchange. 

		Policy policy = new X509ExchPolicy();
		X509ExchProcessor proc = new X509ExchProcessor();
	
		proc.enforceMessage(desc,policy,null);

		token = (SecurityContextToken) seccxt.generateSecurityToken(cxtdesc);

		System.out.println("End-to-end Mutual authentication established with: " + service);

	    } catch (GridException e) {throw new MessagingException("Unexpected security context GENERATE error -- " + e.getUserMessage());}
	    token.setExpirationDate(10000000);
	    // store the new token
	    try{
		seccxt.addSecurityTokenToContext(token);
	    } catch (GridException e) {throw new MessagingException("Unexpected security context ADD error -- " + e.getUserMessage());}
	    

	    // extract secret key and store it with owner information. This is where the owner is assigned.

	    
	    
	    SecurityToken skey = token.getIncludedToken();
	
	    if (skey instanceof SecretKeyToken) {
		ArrayList owners = new ArrayList();
		owners.add(service);
		
		((SecretKeyToken)skey).setOwners(owners); 
		// store secret key token
		try{
		    seccxt.addSecurityTokenToContext(skey);

		} catch (Exception e) {throw new MessagingException("Unexpected security context error");}

		System.out.println("A new Symmetric Key has been exchanged");
		System.out.println("Security Context Token expiration date: " + token.getExpirationDate());

	    } else throw new MessagingException("NSL processor expects a secret key token");



	}
	System.out.println("NSL completed");

	javax.xml.soap.SOAPMessage message = ((SOAPMessage) msg).getSOAPWireMessage();
	msg = (Message) new SOAPMessage(message,msg.getMessageContext());
       
	return msg;
    }

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