blob: 24ac62d6a38268b336443d5b71eda177a4c303eb [file] [log] [blame]
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.ws.sandbox.axis.security.conversation;
import org.apache.axis.AxisFault;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.SOAPPart;
import org.apache.axis.handlers.BasicHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.SOAPConstants;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSEncryptionPart;
import org.apache.ws.security.WSSConfig;
import org.apache.ws.sandbox.security.conversation.*;
import org.apache.ws.sandbox.security.conversation.message.info.DerivedKeyInfo;
import org.apache.ws.sandbox.security.conversation.message.token.SecurityContextToken;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.message.token.Reference;
import org.apache.ws.security.message.token.SecurityTokenReference;
import org.apache.ws.security.transform.STRTransform;
import org.apache.ws.security.util.StringUtil;
import org.apache.ws.security.util.WSSecurityUtil;
import org.apache.xml.security.transforms.Transform;
import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Stack;
import java.util.Vector;
/**
* Serverside handler that implements WS-Secure Conversation for Axis.
*
*
* @author Dimuthu Leealarthne. (muthulee@yahoo.com)
*
*/
public class ConversationServerHandler extends BasicHandler {
private static Log log =
LogFactory.getLog(ConversationServerHandler.class.getName());
private boolean doDebug = false;
private static DerivedKeyCallbackHandler dkcbHandler =
new DerivedKeyCallbackHandler();
private static boolean isConfigured = false;
private SOAPConstants soapConstants = null;
private HashMap configurator = new HashMap();
private int[] actionsInt = null;
private boolean isSessionInfoConfigured = false;
private boolean isInitTrustVerified = false;
private Vector sigParts=null;
private Vector encParts=null;
private int keyLen =-1;
public ConversationServerHandler() {
log.debug("ConversationServerHandler :: created");
}
/**
* Method inherited from the BasicHandler.
* If in the request flow calls the doRequestMetod()
* else calls the doResponse() method.
*
*/
public void invoke(MessageContext msg) throws AxisFault {
log.debug("ConversationServerHandler :: invoked");
if (msg.getPastPivot())
doResponse(msg);
else
doRequest(msg);
}
/**
* Called in the request flow of the request.
* Method looks for a SecurityToken in the SOAP envelope.
* Process the header.
*
* @param msg
* @throws AxisFault
*/
private void doRequest(MessageContext msg) throws AxisFault {
if(!isSessionInfoConfigured){
initSessionInfo();
isSessionInfoConfigured = true;
}
Document doc = null;
Message message = msg.getCurrentMessage();
// Get the soap message as a Docuemnt
SOAPPart sPart = (org.apache.axis.SOAPPart) message.getSOAPPart();
try {
doc =
((org.apache.axis.message.SOAPEnvelope) sPart.getEnvelope())
.getAsDocument();
} catch (Exception e) {
e.printStackTrace();
}
// if((this.configurator = (HashMap)msg.getProperty("PolicyObject"))==null){
// log.debug("ConversationServerHandler :: I am configuring");
// initSessionInfo(); // load values to this.configurator from wsdd
// }
soapConstants = WSSecurityUtil.getSOAPConstants(doc.getDocumentElement());
ConversationEngine eng = new ConversationEngine(this.configurator);
// try {
// boolean trustEngineResult = false;
// if(!isInitTrustVerified){
// String tmpStr = null;
// if ((tmpStr = (String) getOption(ConvHandlerConstants.TOKEN_TRUST_VERIFY))
// != null) {
// if(Boolean.getBoolean(tmpStr)){
// String trustPropFile = (String) getOption(ConvHandlerConstants.TRUST_ENGINE_PROP);
// TrustEngine trstEngine = new TrustEngine(trustPropFile);
// System.out.println("call the engine here ...");
// trustEngineResult=true;
// }
// isInitTrustVerified = true;
// }
// }
// if(trustEngineResult){
// //getUUID and proof of possession
// //add it to the derived key token
// }
// } catch (WSTrustException e2) {
// // TODO Auto-generated catch block
// e2.printStackTrace();
// }
try {
Vector results = eng.processSecConvHeader(doc, "", dkcbHandler, (String)this.configurator.get(WSHandlerConstants.PW_CALLBACK_CLASS));
ConvEngineResult convResult = null;
String uuid = "";
/*put the actions into a stack to obtain LIFO behavior
* Rational for using the stack;
*
* Consider "Signature Encrypt"
* Then the ConvEngine Results will be in the order "Encrypt Signature"
* i.e. ConvEngine reusult containing ConvEngineResult.ENCRYPT_DERIVED_KEY
* will be before ConvEngineResult.SIGN_DERIVED_KEY
*
* Hense I need to read actions in the order of Last in First out - the stack
*
* This is same for "Encrypt Signature" visa versa.
*/
Stack stk = new Stack();
for(int i=0; i<actionsInt.length ; i++){
stk.push(new Integer(actionsInt[i]));
}
int act = -1;
boolean rstr = false;
for(int i=0; i<results.size(); i++){
convResult=(ConvEngineResult)results.get(i);
switch(convResult.getAction()){
case ConvEngineResult.SECURITY_TOKEN_RESPONSE :
log.debug("ConversationServerHandler :: Found RSTR result");
uuid = convResult.getUuid();
rstr = true;
break;
case ConvEngineResult.ENCRYPT_DERIVED_KEY :
log.debug("ConversationServerHandler :: Found dk_encrypt result");
// if(stk.isEmpty()){
// throw new AxisFault("Action mismatch");
// }
//
// act =((Integer)stk.pop()).intValue();
// if(act == ConversationConstants.DK_ENCRYPT){
// //fine do nothing
// }else{
// throw new AxisFault("Mismatch action order");
// }
break;
case ConvEngineResult.SIGN_DERIVED_KEY :
log.debug("ConversationServerHandler :: Found dk_sign result");
// if(stk.isEmpty()){
// throw new AxisFault("Action mismatch");
// }
// act =((Integer)stk.pop()).intValue();
// if(act == ConversationConstants.DK_SIGN){
// //fine do nothing
// }else{
// throw new AxisFault("Mismatch action order");
// }
break;
case ConvEngineResult.SCT :
log.debug("ConversationServerHandler :: Found SCT result");
uuid = convResult.getUuid();
break;
}
}
if(uuid.equals("")||(uuid==null)){
//throw new AxisFault("ConversationServerHandler :: Cannot find Session.");
}else{
msg.setProperty(ConversationConstants.IDENTIFIER,uuid);
}
//
// if(!rstr){
// if(!stk.isEmpty()){
// throw new AxisFault("Action mismatch. Required action missing");
// }
// }
} catch (ConversationException e1) {
e1.printStackTrace();
throw new AxisFault("CovnersationServerHandler :: "+e1.getMessage());
}
// Replace sPart with the new sPart.
ByteArrayOutputStream os = new ByteArrayOutputStream();
XMLUtils.outputDOM(doc, os, true);
String osStr = os.toString();
sPart.setCurrentMessage(osStr, SOAPPart.FORM_STRING);
//Following sets the headers as processed.
SOAPHeader sHeader = null;
try {
sHeader = message.getSOAPEnvelope().getHeader();
} catch (Exception ex) {
throw new AxisFault(
"ConversatonServerHandler: cannot get SOAP header after security processing",
ex);
}
String actor = null;
Iterator headers = sHeader.examineHeaderElements(actor);
SOAPHeaderElement headerElement = null;
while (headers.hasNext()) {
SOAPHeaderElement hE = (SOAPHeaderElement) headers.next();
if (hE.getLocalName().equals(WSConstants.WSSE_LN)
&& hE.getNamespaceURI().equals(WSConstants.WSSE_NS)) {
headerElement = hE;
break;
}
}
(
(
org
.apache
.axis
.message
.SOAPHeaderElement) headerElement)
.setProcessed(
true);
msg.setProperty(ConvHandlerConstants.DK_CB_HANDLER,dkcbHandler);
} //do request
/**
* This method is called in the response.
* This method should
* 1) Add derived keys to the message as required.
* 2) Sign/encrypt as required.
*
* @param msg
* @throws AxisFault
*/
private void doResponse(MessageContext msg) throws AxisFault {
if(!isSessionInfoConfigured){
initSessionInfo();
isSessionInfoConfigured = true;
}
//System.out.println("Doing response .... ");
Document doc = null;
Message message = msg.getCurrentMessage();
String uuid, identifier;
// Code to get the soap message as a Docuemnt
SOAPPart sPart = (org.apache.axis.SOAPPart) message.getSOAPPart();
try {
if ((doc = (Document) msg.getProperty(WSHandlerConstants.SND_SECURITY))
== null) {
doc =
((org.apache.axis.message.SOAPEnvelope) sPart.getEnvelope())
.getAsDocument();
}
} catch (Exception e) {
e.printStackTrace();
throw new AxisFault("CovnersationServerHandler :: "+e.getMessage());
}
//get the uuid
uuid = (String) msg.getProperty(ConversationConstants.IDENTIFIER);
if (uuid == null) {
//TODO :: throw exception
System.out.println("UUID NULl line :: 346");
}
try {
ConversationSession session = dkcbHandler.getSession(uuid);
if(session.isAddBase2Message()){
//add the relavent SCT
Element securityHeader =
WSSecurityUtil.findWsseSecurityHeaderBlock(
doc,
doc.getDocumentElement(),
true);
WSSecurityUtil.appendChildElement(
doc,
securityHeader,
(new SecurityContextToken(doc, uuid)).getElement());
}
ConversationManager manager = new ConversationManager();
for (int i = 0; i < this.actionsInt.length; i++) {
// Derrive the token
SecurityTokenReference stRef2Base = null;
if(session.getRef2Base()==null){
//do nothing
}else{
stRef2Base = new SecurityTokenReference(doc);
Reference ref = new Reference(doc);
Reference oldRef = session.getRef2Base();
ref.setURI(oldRef.getURI());
ref.setValueType(oldRef.getValueType());
stRef2Base.setReference(ref);
}
DerivedKeyInfo dkInfo =
manager.createDerivedKeyToken(doc, uuid, dkcbHandler,stRef2Base, keyLen);
String genID = dkInfo.getId();
SecurityTokenReference stRef =
dkInfo.getSecTokRef2DkToken();
if (actionsInt[i] == ConversationConstants.DK_ENCRYPT) {
manager.performDK_ENCR(
ConversationUtil.generateIdentifier(uuid, genID),
"",
true,
doc,
stRef,
dkcbHandler, this.encParts, (String)this.configurator.get(ConvHandlerConstants.DK_ENC_ALGO));
} else if(actionsInt[i]==ConversationConstants.DK_SIGN){
//TODO
manager.performDK_Sign(doc, dkcbHandler, uuid, dkInfo,this.sigParts);
}
manager.addDkToken(doc,dkInfo);
}
} catch (ConversationException e1) {
e1.printStackTrace();
throw new AxisFault(
"ConversationClientHandler ::" + e1.getMessage());
}
//set it as current message
ByteArrayOutputStream os = new ByteArrayOutputStream();
XMLUtils.outputDOM(doc, os, true);
String osStr = os.toString();
sPart.setCurrentMessage(osStr, SOAPPart.FORM_STRING);
} //doResponse
/**
* Conversation parameters are read from the wsdd file.
* When WS-Policy is implemented, these parameters should be
* configurable using policy components.
*
* @throws AxisFault
*/
/**
* Reads configeration parameters from the wsdd file.
* @throws AxisFault
*/
private void initSessionInfo() throws AxisFault {
/**
* Default values for a session. These will be overriden by WSDD file parameters.
*/
this.configurator = new HashMap();
String tmpStr;
if ((tmpStr = (String) getOption(ConvHandlerConstants.KEY_FREQ))
!= null) {
log.debug("Key Frequency is set ::" + tmpStr);
this.configurator.put(
ConvHandlerConstants.KEY_FREQ,
new Integer(tmpStr));
}
if ((tmpStr = (String) getOption(ConvHandlerConstants.DK_ACTION))
!= null) {
log.debug("Derived Key Action is read ::" + tmpStr);
String[] action = StringUtil.split(tmpStr, ' ');
actionsInt = new int[action.length];
for (int i = 0; i < action.length; i++) {
if ((action[i]).equalsIgnoreCase("Signature")) {
actionsInt[i] = ConversationConstants.DK_SIGN;
} else if ((action[i]).equalsIgnoreCase("Encrypt")) {
actionsInt[i] = ConversationConstants.DK_ENCRYPT;
}
}
}
if ((tmpStr =
(String) getOption(ConvHandlerConstants.SEVER_PROP_FILE))
!= null) {
this.configurator.put(ConvHandlerConstants.SEVER_PROP_FILE, tmpStr);
}
if ((tmpStr =
(String) getOption(ConvHandlerConstants.KEY_LEGNTH))
!= null) {
log.debug("Key Frequency is set ::" + tmpStr);
this.keyLen=Integer.parseInt(tmpStr);
this.configurator.put(ConvHandlerConstants.KEY_LEGNTH, new Long(tmpStr));
}
if ((tmpStr =
(String) getOption(WSHandlerConstants.PW_CALLBACK_CLASS))
!= null) {
this.configurator.put(WSHandlerConstants.PW_CALLBACK_CLASS, tmpStr);
}else{
log.debug("Set the pass word call back class.");
}
if ((tmpStr =
(String) getOption(WSHandlerConstants.SIGNATURE_PARTS))
!= null) {
this.sigParts = new Vector();
this.splitEncParts(tmpStr,sigParts);
}
if ((tmpStr =(String) getOption(WSHandlerConstants.ENCRYPTION_PARTS))
!= null) {
this.encParts = new Vector();
this.splitEncParts(tmpStr,encParts);
}
if((tmpStr =(String) getOption(WSHandlerConstants.DEC_PROP_FILE))!= null) {
this.configurator.put(WSHandlerConstants.DEC_PROP_FILE, tmpStr);
System.out.println("Decryption properties read");
}
if((tmpStr =(String) getOption(ConvHandlerConstants.DK_ENC_ALGO))!= null) {
this.configurator.put(ConvHandlerConstants.DK_ENC_ALGO, tmpStr);
}
}
/**
* Extracted from the class <code>org.apache.ws.axis.security.WSDoAllSender.java</code>.
*
* @param tmpS
* @param encryptParts
* @throws AxisFault
*/
private void splitEncParts(String tmpS, Vector encryptParts)
throws AxisFault {
WSEncryptionPart encPart = null;
String[] rawParts = StringUtil.split(tmpS, ';');
for (int i = 0; i < rawParts.length; i++) {
String[] partDef = StringUtil.split(rawParts[i], '}');
if (partDef.length == 1) {
if (doDebug) {
log.debug("single partDef: '" + partDef[0] + "'");
}
encPart =
new WSEncryptionPart(
partDef[0].trim(),
soapConstants.getEnvelopeURI(),
"Content");
} else if (partDef.length == 3) {
String mode = partDef[0].trim();
if (mode.length() <= 1) {
mode = "Content";
} else {
mode = mode.substring(1);
}
String nmSpace = partDef[1].trim();
if (nmSpace.length() <= 1) {
nmSpace = soapConstants.getEnvelopeURI();
} else {
nmSpace = nmSpace.substring(1);
}
String element = partDef[2].trim();
if (doDebug) {
log.debug(
"partDefs: '"
+ mode
+ "' ,'"
+ nmSpace
+ "' ,'"
+ element
+ "'");
}
encPart = new WSEncryptionPart(element, nmSpace, mode);
} else {
throw new AxisFault(
"WSDoAllSender: wrong part definition: " + tmpS);
}
encryptParts.add(encPart);
}
}
}