plork said:
(e-mail address removed) (plork) wrote in message
What's the best way of writing the handlers - i have a
SOAPHandler.jaav and a LoginHandler.java file
I think l i'm missing something - well i must be think cos i'm not
understanding this
Most of the code i'm writing at the moment is server-side, so i
haven't done any of the wsdl/xml etc.. files yet
This is where i am struggling - how to i set the token in the header
to begin with and then how do i pass the token value back to the
handlers to check it's valid , if it isn't i nedd to produce another
token value and send this back to the client header and update it
I'm using eclipse, tomcat , apache axis
Try passing your token as an xml string - much easier. You could also
place a hashmap in the handler as I do in the example I'm giving. IMHO
avoid wsdl like the plague - I speak from experience. The code examples
I give are long but there is a lot to know and its hard stuff at first.
To put a client handler in you path, try:
public String getData (HashMap invokeProps, String in) throws
WebServiceClientException
{
String ret = null;
try
{
//Invoke properties - configurable by user
String LDAPUserName = Utils.getKeyAsString(invokeProps,
"LDAPUserName");
String LDAPUserPassword = Utils.getKeyAsString(invokeProps,
"LDAPUserPassword");
String nameSpaceUri = Utils.getKeyAsString(invokeProps,
"nameSpaceUri");
String endpoint = Utils.getKeyAsString(invokeProps, "endpoint");
String pq = Utils.getKeyAsString(invokeProps, "portQN");
String service = Utils.getKeyAsString(invokeProps, "service");
String timeout = Utils.getKeyAsString(invokeProps, "timeout");
//Get element to encrypt
String elementToEncrypt = Utils.getKeyAsString(handlerConfig,
"elementToEncrypt");
//Add host to HashMap sent to Handler
handlerConfig.put("host", Utils.getKeyAsString(invokeProps,
"host"));
this.handlerConfig.put("elementToEncrypt", elementToEncrypt);
//Initialize all params needed for call
QName svcQName = new QName(endpoint, nameSpaceUri);
QName portQN = new QName(endpoint, pq);
ServiceFactory sf = ServiceFactory.newInstance();
Service svc = sf.createService(svcQName);
/***
Having problems getting the WSDL, but seems to
work without it
Nota - could try changing the web service web.xml
from .jws to *
URL loc = svc.getWSDLDocumentLocation();
*/
//add ClientHandler to chain of events
java.util.List list =
svc.getHandlerRegistry().getHandlerChain(portQN);
list.add(new
javax.xml.rpc.handler.HandlerInfo(ClientHandler.class,this.handlerConfig,null));
Call call = (Call) svc.createCall(portQN);
if (this.debug)
{
Fwlog.debug(this, Fwlog.WI, "Client handler registry size: " +
list.size());
Fwlog.debug(this, Fwlog.WI, "call created");
}
//set timeout - default is 60s
call.setTimeout(new Integer(timeout));
//explicitly name the XML Element to encrypt in parameter mode
call.addParameter(elementToEncrypt, XMLType.XSD_STRING,
String.class, ParameterMode.IN);
call.setReturnType(XMLType.XSD_STRING);
call.setTargetEndpointAddress(endpoint);
call.setOperationName(new QName(nameSpaceUri, service));
call.setUsername(LDAPUserName);
call.setPassword(LDAPUserPassword);
ret = (String) call.invoke( new Object[] { in } );
}
catch (Exception e)
{
Fwlog.error(this, Fwlog.WI, e);
throw new WebServiceClientException("Web Service failed", e);
}
return ret;
}
To get your soap message to xml, you could try invoke in your handlers:
public class SOAPUtility {
/****************************************************************************
* class MyByteArrayOutputStream ajuda em evitando uma copia do
buffer.
****************************************************************************/
private static class MyByteArrayOutputStream extends
ByteArrayOutputStream {
public MyByteArrayOutputStream(){
super();
}
public ByteArrayInputStream getByteArrayInputStream(){
return new ByteArrayInputStream(buf, 0, count);
}
}
/** Uses serialization due to problems in axis
**/
public static Document toDocument(SOAPMessage soapMsg) throws
ParserConfigurationException, SAXException, SOAPException,
IOException {
MyByteArrayOutputStream baos = new MyByteArrayOutputStream();
soapMsg.writeTo(baos);
ByteArrayInputStream bais = baos.getByteArrayInputStream();
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(bais);
return doc;
}
/** Uses serialization due to problems in axis
**/
public static SOAPMessage toSOAPMessage(Document doc) throws
TransformerConfigurationException, TransformerException,
SOAPException, IOException, XMLHelperException {
Fwlog.debug(SOAPUtility.class, Fwlog.WI, "Before
SOAPPart set/get Content: " + XMLHelper.getXml(doc));
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
MyByteArrayOutputStream baos = new MyByteArrayOutputStream();
transformer.transform(new DOMSource(doc), new StreamResult(baos));
ByteArrayInputStream bais = baos.getByteArrayInputStream();
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage soapMsg = mf.createMessage(new MimeHeaders(), bais);
return soapMsg;
}
}
Call that in you handlers. The client handler is like:
public class ClientHandler implements Handler
{
private static final String securityDomain = "wssDomain";
private String elementToEncrypt = null;
private String host = null;
private boolean debug;
private X509Certificate cert = null;
private SecretKey secretKey = null;
private PrivateKey privateKey = null;
private String jaas_prop = null;
/** Class contructor **/
public ClientHandler()
{
}
/**
Gerencia uma requisição SOAP no Axis.
<p>
@param context Tudo disponível de SOAP message - headers,
envelopes, body etc.
@return boolean retorno true para sucesso ou false para parar o
processamento
*/
public boolean handleRequest(MessageContext context)
{
try
{
Fwlog.debug(this, Fwlog.WI, "Entered Client handler
handleRequest()...");
//Login user via LDAP
if (!doLDAPLogin(context))
{
throw new LoginException("\n\nClientHandler::handleRequest
failed, could not **LOGIN** \n\n");
}
SOAPMessageContext soapCtx = (SOAPMessageContext)context;
//Get SOAP message to encrypt and sign
SOAPMessage soapMsg = soapCtx.getMessage();
org.w3c.dom.Document doc = SOAPUtility.toDocument(soapMsg);
Fwlog.debug(this, Fwlog.WI, "Client is signing this SOAP
Document: \n\n" + XMLHelper.getXml(doc));
if(!SecurityHelper.sign(doc, cert, privateKey, debug))
{
throw new
IllegalStateException("\n\nClientHandler::handleRequest failed, could
not **SIGN** soap message\n\n");
}
Fwlog.debug(this, Fwlog.WI, "Client is encrypting this SOAP
Document: \n\n" + XMLHelper.getXml(doc));
if (!SecurityHelper.encrypt(doc, elementToEncrypt, secretKey,
debug))
{
throw new
IllegalStateException("\n\nClientHandler::handleRequest failed, could
not **ENCRYPT** soap message\n\n");
}
soapMsg = SOAPUtility.toSOAPMessage(doc);
soapCtx.setMessage(soapMsg);
}
catch (Exception e)
{
Fwlog.error(this, Fwlog.WI, e);
throw new JAXRPCException(e.toString(), e);
}
Fwlog.debug(this, Fwlog.WI, "ClientHandler: ... handleRequest
executed");
return true;
}
/**
Gerencia uma resposta SOAP no Axis.
<p>
@param context Tudo disponível de SOAP message - headers,
envelopes, body etc.
@return boolean retorno true para sucesso ou false para parar o
processamento.
*/
public boolean handleResponse(MessageContext context)
{
try
{
Fwlog.debug(this, Fwlog.WI, "Entered Client handler
handleResponse()...");
//Login user via LDAP
if (!doLDAPLogin(context))
{
throw new LoginException("\n\nClientHandler::handleResponse
failed, could not **LOGIN** \n\n");
}
SOAPMessageContext soapCtx = (SOAPMessageContext)context;
SOAPMessage soapMsg = soapCtx.getMessage();
org.w3c.dom.Document doc = SOAPUtility.toDocument(soapMsg);
Fwlog.debug(this, Fwlog.WI, "Client is decrypting this SOAP
Document: \n " + XMLHelper.getXml(doc));
if (!SecurityHelper.decrypt(doc, secretKey, debug))
{
throw new
IllegalStateException("\n\nClientHandler::handleResponse failed, could
not **DECRYPT** soap message\n\n");
}
Fwlog.debug(this, Fwlog.WI, "Client is validating this SOAP
Document: \n" + XMLHelper.getXml(doc));
if (!SecurityHelper.verify(doc))
{
throw new
IllegalStateException("\n\nClientHandler::handleResponse failed, could
not **VERIFY** soap message\n\n");
}
soapMsg = SOAPUtility.toSOAPMessage(doc);
if (debug)
{
Fwlog.debug(this, Fwlog.WI, "\n\nClientHandler::handleResponse
returning Xml Signature validated, decrypted and deserialized XML doc
to SOAP service: \n\n" + XMLHelper.getXml(doc));
}
soapCtx.setMessage(soapMsg);
}
catch (Exception e)
{
Fwlog.error(this, Fwlog.WI, e);
throw new JAXRPCException(e.toString(), e);
}
Fwlog.debug(this, Fwlog.WI, "ClientHandler: ... handleResponse
executed");
return true;
}
/**
Gerencia um erro ocorrido com esta requisição SOAP no Axis.
<p>
@param context Tudo disponível de SOAP message - headers,
envelopes, body etc.
@return boolean retorno true para sucesso ou false para parar o
processamento
*/
public boolean handleFault(MessageContext context)
{
Fwlog.debug(this, Fwlog.WI, "ClientHandler: In handleFault");
return true;
}
/**
Carrega todos os parâmetros de configuração para o funcionamento
do WS-Security.
<p>
@param config Basicamente um HashMap definido
no arquivo deploy.wssd para o web service que permite
receber os variavies do usuário.
*/
public void init(HandlerInfo config)
{
Fwlog.debug(this, Fwlog.WI, "ClientHandler: init ...");
try
{
jaas_prop = System.getProperty("jaas.prop");
if (null == jaas_prop)
{
throw new IllegalStateException("jaas_prop not set, must point
to login config file 'wssDomain.cfg' needed for
java.security.auth.login.config");
}
Map configProps = config.getHandlerConfig();
if (configProps.containsKey("elementToEncrypt"))
{
elementToEncrypt = (String)configProps.get("elementToEncrypt");
}
else
{
throw new IllegalStateException("Handler chain config property
missing: elementToEncrypt");
}
if (configProps.containsKey("host"))
{
host = (String)configProps.get("host");
}
else
{
throw new IllegalStateException("Handler chain config property
missing: host");
}
if (configProps.containsKey("verbose"))
{
String verbose = (String)configProps.get("verbose");
if (verbose.equalsIgnoreCase("on"))
{
debug = true;
}
else if (verbose.equalsIgnoreCase("off"))
{
debug = false;
}
else
{
throw new IllegalStateException("verbose config property not
'on' or 'off': " + verbose);
}
}
else
{
throw new IllegalStateException("Handler chain config property
missing: verbose");
}
}
catch (Exception e)
{
Fwlog.error(this, Fwlog.WI, e);
throw new JAXRPCException(e.toString(), e);
}
}
/**
Esse metodo precisa ser implementado via interface Handler
*/
public void destroy()
{
}
/**
Esse metodo precisa ser implementado via interface Handler
@return QName volta null
*/
public javax.xml.namespace.QName[] getHeaders()
{
return null;
}
/**
Logar o usário
<p>
@param context Tudo disponível de SOAP message - headers,
envelopes, body etc.
@return true ou false
*/
public boolean doLDAPLogin(javax.xml.rpc.handler.MessageContext
javaxcontext)
{
try
{
org.apache.axis.MessageContext mc =
(org.apache.axis.MessageContext) javaxcontext;
//set jass config parameter on every call to prevent environment
hell
System.getProperties().setProperty("java.security.auth.login.config",
this.jaas_prop);
// login user via JAAS
CallbackHandler callbackHandler = new WSSCallbackHandler(mc,
this.host);
LoginContext lc = new LoginContext(securityDomain,
callbackHandler);
lc.login();
Fwlog.debug(this, Fwlog.WI, "User logged in successfully: " +
mc.getUsername());
// Get instance from singleton
WSSecurityManager wsm = WSSecurityManager.getInstance();
// Get get X509 certificate needed to sign message
this.cert = wsm.getCert(mc.getUsername());
// Get PrivateKey needed to sign X509 Certificate
this.privateKey = wsm.getPrivateKey(mc.getUsername());
// Get SecretKey needed to encrypt/decrypt message
this.secretKey = wsm.getSecretKey(mc.getUsername());
Fwlog.debug(this, Fwlog.WI, "Got cert, pk and sk for user: " +
mc.getUsername());
return true;
}
catch (Exception e)
{
Fwlog.error(this, Fwlog.WI, "ServiceHandler::doLDAPLogin --
Exception: ");
Fwlog.error(this, Fwlog.WI, e);
return false;
}
}
}
Server side hanlder is just the opposite:
/**
Implementa um Axis Handler. Atua como um XML firewall para todos os
pedidos e repostas
para o web service servidor.
@author Robert Lazarski
*/
public class ServiceHandler implements Handler
{
private String host = null;
private boolean debug;
private static final String securityDomain = "wssDomain";
private X509Certificate cert = null;
private PrivateKey privateKey = null;
private SecretKey secretKey = null;
private String jaas_prop = null;
/** Class contructor **/
public ServiceHandler()
{
}
/**
Gerencia uma requisição SOAP no Axis.
<p>
@param context Tudo disponível de SOAP message - headers,
envelopes, body etc.
@return boolean retorno true para sucesso ou false para parar o
processamento
*/
public boolean handleRequest(MessageContext context)
{
try
{
Fwlog.debug(this, Fwlog.WI, "Entered Service handler
handleRequest()...");
//Login user via LDAP
if (!doLDAPLogin(context))
{
throw new LoginException("\n\nServiceHandler::handleRequest
failed, could not **LOGIN** \n\n");
}
SOAPMessageContext soapCtx = (SOAPMessageContext)context;
SOAPMessage soapMsg = soapCtx.getMessage();
Document doc = SOAPUtility.toDocument(soapMsg);
if (!SecurityHelper.decrypt(doc, secretKey, debug))
{
throw new
IllegalStateException("\n\nServiceHandler::handleRequest failed, could
not **DECRYPT** soap message\n\n");
}
if (!SecurityHelper.verify(doc))
{
throw new
IllegalStateException("\n\nServiceHandler::handleRequest failed, could
not **VERIFY** soap message\n\n");
}
soapMsg = SOAPUtility.toSOAPMessage(doc);
if (debug)
{
Fwlog.debug(this, Fwlog.WI, "\n\nServiceHandler:: handleRequest
**RECIEVED** Xml Signature validated, decrypted and deserialized XML
doc to SOAP service: \n\n" + XMLHelper.getXml(doc));
}
soapCtx.setMessage(soapMsg);
}
catch (Exception e)
{
Fwlog.error(this, Fwlog.WI, e);
throw new JAXRPCException(e.toString(), e);
}
Fwlog.debug(this, Fwlog.WI, "Service handler handleRequest()
completed, returning true");
return true;
}
/**
Gerencia uma resposta SOAP no Axis.
<p>
@param context Tudo disponível de SOAP message - headers,
envelopes, body etc.
@return boolean retorno true para sucesso ou false para parar o
processamento.
*/
public boolean handleResponse(MessageContext context)
{
try
{
Fwlog.debug(this, Fwlog.WI, "Entered Service handler
handleResponse()...");
SOAPMessageContext soapCtx = (SOAPMessageContext)context;
SOAPMessage soapMsg = soapCtx.getMessage();
Document doc = SOAPUtility.toDocument(soapMsg);
if (!SecurityHelper.sign(doc, cert, privateKey, debug))
{
throw new
IllegalStateException("\n\nServiceHandler::handleResponse failed, could
not **SIGN** soap message\n\n");
}
if (!SecurityHelper.encrypt(doc, getElementToEncrypt(context),
secretKey, debug))
{
throw new
IllegalStateException("\n\nServiceHandler::handleResponse failed, could
not **ENCRYPT** soap message\n\n");
}
soapMsg = SOAPUtility.toSOAPMessage(doc);
if (debug)
{
Fwlog.debug(this, Fwlog.WI, "\n\nServiceHandler::handleResponse
**RETURNING** Xml Signature signed, encrypted and deserialized XML doc
to SOAP service: \n\n" + XMLHelper.getXml(doc));
}
soapCtx.setMessage(soapMsg);
}
catch (Exception e)
{
Fwlog.error(this, Fwlog.WI, e);
throw new JAXRPCException(e.toString(), e);
}
Fwlog.debug(this, Fwlog.WI, "Service handler handleResponse()
completed, returning true");
return true;
}
/**
Gerencia um erro ocorrido com esta requisição SOAP no Axis.
<p>
@param context Tudo disponível de SOAP message - headers,
envelopes, body etc.
@return boolean retorno true para sucesso ou false para parar o
processamento
*/
public boolean handleFault(MessageContext context)
{
Fwlog.error(this, Fwlog.WI, "ServiceHandler::handleFault
recieved");
return true;
}
/**
Carrega todos os parâmetros de configuração para o funcionamento
do WS-Security.
<p>
@param config Basicamente um HashMap definido
no arquivo deploy.wssd para o web service que permite
receber os variavies do usuário.
*/
public void init(HandlerInfo config)
{
Fwlog.debug(this, Fwlog.WI, "ServiceHandler: init ...");
try
{
jaas_prop = System.getProperty("jaas.prop");
if (null == jaas_prop)
{
throw new IllegalStateException("jaas_prop not set, must point
to login config file 'wssDomain.cfg' needed for
java.security.auth.login.config");
}
Map configProps = config.getHandlerConfig();
if (configProps.containsKey("host"))
{
host = (String)configProps.get("host");
}
else
{
throw new IllegalStateException("Handler chain config property
missing: host");
}
if (configProps.containsKey("verbose"))
{
String verbose = (String)configProps.get("verbose");
if (verbose.equalsIgnoreCase("on"))
{
debug = true;
}
else if (verbose.equalsIgnoreCase("off"))
{
debug = false;
}
else
{
throw new IllegalStateException("verbose config property not
'on' or 'off': " + verbose);
}
}
else
{
throw new IllegalStateException("Handler chain config property
missing: verbose");
}
}
catch (Exception e)
{
Fwlog.error(this, Fwlog.WI, e);
throw new JAXRPCException(e.toString(), e);
}
Fwlog.debug(this, Fwlog.WI, "Service handler init() completed");
}
/**
Esse metodo precisa ser implementado via interface Handler
*/
public void destroy()
{
}
/**
Esse metodo precisa ser implementado via interface Handler
@return QName volta null
*/
public javax.xml.namespace.QName[] getHeaders()
{
return null;
}
/**
Logar o usário
@return true ou false
*/
public boolean doLDAPLogin(javax.xml.rpc.handler.MessageContext
javaxcontext)
{
try
{
org.apache.axis.MessageContext mc =
(org.apache.axis.MessageContext) javaxcontext;
//set jass config parameter on every call to prevent environment
hell
System.getProperties().setProperty("java.security.auth.login.config",
this.jaas_prop);
// login user via JAAS
CallbackHandler callbackHandler = new WSSCallbackHandler(mc,
this.host);
LoginContext lc = new LoginContext(securityDomain,
callbackHandler);
lc.login();
Fwlog.debug(this, Fwlog.WI, "User logged in successfully: " +
mc.getUsername());
// Get instance from singleton
WSSecurityManager wsm = WSSecurityManager.getInstance();
// Get get X509 certificate needed to sign message
this.cert = wsm.getCert(mc.getUsername());
Fwlog.debug(this, Fwlog.WI, "Got cert for user: " +
mc.getUsername());
// Get PrivateKey needed to sign X509 Certificate
this.privateKey = wsm.getPrivateKey(mc.getUsername());
// Get SecretKey needed to encrypt/decrypt message
this.secretKey = wsm.getSecretKey(mc.getUsername());
Fwlog.debug(this, Fwlog.WI, "Got pk and sk for user: " +
mc.getUsername());
return true;
}
catch (Exception e)
{
Fwlog.error(this, Fwlog.WI, "ServiceHandler::doLDAPLogin --
Exception: ");
Fwlog.error(this, Fwlog.WI, e);
return false;
}
}
/**
Pega o nome do Element para encryptar
@param javaxcontext Tudo disponível de SOAP message - headers,
envelopes, body etc.
@return nome do Element
*/
private String
getElementToEncrypt(javax.xml.rpc.handler.MessageContext javaxcontext)
throws java.io.IOException
{
org.apache.axis.MessageContext mc =
(org.apache.axis.MessageContext) javaxcontext;
String service = mc.getOperation().getName();
if(null == service || service.length() < 1)
{
throw new IOException("Web Service name must not be null or
blank");
}
StringBuffer sb;
//nome do servico + 'Return'
//<parameter name="elementToEncrypt" value="ns1:hub_indiceReturn"/>
sb = new StringBuffer();
sb.append("ns1:");
sb.append(service);
sb.append("Return");
return sb.toString();
}
}
HTH,
iksrazal
http://www.braziloutsource.com/