Friday, April 30, 2010

OSB: how to introspect many things from the inbound request

$inbound/ctx:transport/ctx:uri/text()  will give you the proxy URI, that is /OSB_Project_1/Proxy_Service_1

$inbound contains this info:


<con:endpoint name="ProxyService$OSB Project 1$Proxy Service 1" xmlns:con="http://www.bea.com/wli/sb/context">
  <con:service/>
  <con:transport>
    <con:uri>/OSB_Project_1/Proxy_Service_1</con:uri>
    <con:mode>request-response</con:mode>
    <con:qualityOfService>best-effort</con:qualityOfService>
    <con:request xsi:type="http:HttpRequestMetaData" xmlns:http="http://www.bea.com/wli/sb/transports/http" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <tran:headers xsi:type="http:HttpRequestHeaders" xmlns:tran="http://www.bea.com/wli/sb/transports">
        <http:Content-Type>text/xml; charset=utf-8</http:Content-Type>
      </tran:headers>
      <tran:encoding xmlns:tran="http://www.bea.com/wli/sb/transports">utf-8</tran:encoding>
    </con:request>
    <con:response xsi:type="http:HttpResponseMetaData" xmlns:http="http://www.bea.com/wli/sb/transports/http" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <tran:headers xsi:type="http:HttpResponseHeaders" xmlns:tran="http://www.bea.com/wli/sb/transports">
        <http:Content-Type>text/xml</http:Content-Type>
      </tran:headers>
      <tran:response-code xmlns:tran="http://www.bea.com/wli/sb/transports">0</tran:response-code>
    </con:response>
  </con:transport>
  <con:security>
    <con:transportClient>
      <con:username><anonymous></con:username>
    </con:transportClient>
  </con:security>
</con:endpoint>

Thursday, April 29, 2010

OSB sample code

thank you Oracle

http://www.oracle.com/technology/sample_code/products/osb/index.html

if the above fails, try this:

http://www.oracle.com/technetwork/middleware/service-bus/osbsamples-085201.html


particularly impressive is the one on Tuxedo

http://www.oracle.com/technology/obe/fusion_middleware/tuxedo/OSBTuxedoTransport/UsingOSBTuxedoTransport.htm

Quick WLST script to setup JMS Server, Connection Factory and Queue

see also http://download.oracle.com/docs/cd/E13222_01/wls/docs91/config_scripting/using_WLST.html


setWLSEnv.cmd
java weblogic.WLST
execfile('myfile.py')

connect('weblogic', 'weblogic', 't3://localhost:7001')
startEdit()

cd('/')
cmo.createJMSSystemResource('ExceptionHandlingModule')

cd('/SystemResources/ExceptionHandlingModule')
set('Targets',jarray.array([ObjectName('com.bea:Name=AdminServer,Type=Server')], ObjectName))
cmo.createSubDeployment('acme.integration.ExceptionHandlingSubdeployment')

cd('/JMSSystemResources/ExceptionHandlingModule/JMSResource/ExceptionHandlingModule')
cmo.createConnectionFactory('acme.integration.QueueConnectionFactory')

cd('/JMSSystemResources/ExceptionHandlingModule/JMSResource/ExceptionHandlingModule/ConnectionFactories/acme.integration.QueueConnectionFactory')
cmo.setJNDIName('acme.integration.QueueConnectionFactory')

cd('/JMSSystemResources/ExceptionHandlingModule/JMSResource/ExceptionHandlingModule/ConnectionFactories/acme.integration.QueueConnectionFactory/SecurityParams/acme.integration.QueueConnectionFactory')
cmo.setAttachJMSXUserId(false)

cd('/SystemResources/ExceptionHandlingModule/SubDeployments/acme.integration.ExceptionHandlingSubdeployment')
set('Targets',jarray.array([], ObjectName))

cd('/JMSSystemResources/ExceptionHandlingModule/JMSResource/ExceptionHandlingModule/ConnectionFactories/acme.integration.QueueConnectionFactory')
cmo.setSubDeploymentName('acme.integration.ExceptionHandlingSubdeployment')

cd('/')
cmo.createFileStore('exceptionHandlingStore')

cd('/FileStores/exceptionHandlingStore')
set('Targets',jarray.array([ObjectName('com.bea:Name=AdminServer,Type=Server')], ObjectName))

cd('/')
cmo.createJMSServer('exceptionHandlingServer')

cd('/Deployments/exceptionHandlingServer')
cmo.setPersistentStore(getMBean('/FileStores/exceptionHandlingStore'))
set('Targets',jarray.array([ObjectName('com.bea:Name=AdminServer,Type=Server')], ObjectName))

cd('/SystemResources/ExceptionHandlingModule/SubDeployments/acme.integration.ExceptionHandlingSubdeployment')
set('Targets',jarray.array([ObjectName('com.bea:Name=exceptionHandlingServer,Type=JMSServer')], ObjectName))

cd('/JMSSystemResources/ExceptionHandlingModule/JMSResource/ExceptionHandlingModule')
cmo.createQueue('acme.integration.osbErrorQueue')

cd('/JMSSystemResources/ExceptionHandlingModule/JMSResource/ExceptionHandlingModule/Queues/acme.integration.osbErrorQueue')
cmo.setJNDIName('acme.integration.osbErrorQueue')
cmo.setSubDeploymentName('acme.integration.ExceptionHandlingSubdeployment')

cd('/SystemResources/ExceptionHandlingModule/SubDeployments/acme.integration.ExceptionHandlingSubdeployment')
set('Targets',jarray.array([ObjectName('com.bea:Name=exceptionHandlingServer,Type=JMSServer')], ObjectName))

activate()


Wednesday, April 28, 2010

XQuery tutorial: frequently used stuff

See here http://en.wikibooks.org/wiki/XQuery  for a wealth of excellent examples.

Also http://www.xqueryfunctions.com/xq/  is wonderful.

XQuery is a terrible pain in the knee, but if you get organized it's only a matter of copying/pasting/hacking....

___________________

Variable substitution in a text:

xquery version "1.0" encoding "Cp1252";
(:: pragma  type="xs:anyType" ::)

declare namespace xf = "http://tempuri.org/PVOSBProject1/XQExceptionHandling/";

declare function xf:XQExceptionHandling($thefault as xs:string)
as element(*) {
<ws:handleException xmlns:ws="http://com/pierre/ws">
    <ws:fault>{$thefault}</ws:fault>
</ws:handleException>   
};


declare variable $thefault as xs:string external;

xf:XQExceptionHandling($thefault)

___________________

if you want to pass any xml, use
declare variable $thefault as element(*) external;


______


if you callout a service expecting a String , you cannot pass an XML.... first you must fn-bea:serialize($thevariable)

the function fn:string($body) will somehow generate a toString() of your XML
_____________

Assume this is the $body:


<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <dbac:insertCompany xmlns:dbac="http://com/acme/dbaccess">
    <dbac:company xmlns:java="java:com.acme.dbaccess">
      <java:CreationDate>3</java:CreationDate>
      <java:Id>2</java:Id>
      <java:Name>Pluto</java:Name>
    </dbac:company>
  </dbac:insertCompany>
</soapenv:Body>


$body/.  means all the body... equivalent to $body

$body/dbac:company returns this:

<dbac:company      xmlns:java="java:com.acme.dbaccess" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:dbac="http://com/acme/dbaccess">
    <java:CreationDate>3</java:CreationDate>
    <java:Id>2</java:Id>
    <java:Name>Pluto</java:Name>
    </dbac:company>


$body/*/node()  also returns

<dbac:company      xmlns:java="java:com.acme.dbaccess" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:dbac="http://com/acme/dbaccess">
    <java:CreationDate>3</java:CreationDate>
    <java:Id>2</java:Id>
    <java:Name>Pluto</java:Name>
    </dbac:company>

(be careful: $body/node() is different from $body/*/node() )

 $operation will contain insertCompany

 $body/node() will return
  <dbac:insertCompany xmlns:dbac="http://com/acme/dbaccess">
    <dbac:company xmlns:java="java:com.acme.dbaccess">
      <java:CreationDate>3</java:CreationDate>
      <java:Id>2</java:Id>
      <java:Name>Pluto</java:Name>
    </dbac:company>
  </dbac:insertCompany>

use the condition fn:compare($a, $b) = 0 to test equality of 2 strings

fn:name($body) will return  dbac:insertCompany

fn:local-name($body) will return  insertCompany

fn:node-name($body): {http://com/acme/dbaccess}insertCompany

___________

XQuery: converting nodes in a CSV list

I have this:

<getLocationsByLocationIds>
    <string>string_1</string>
    <string>string_2</string>
</getLocationsByLocationIds>


and I want to convert it into this:
string_1,string_2


use this:

fn:string-join( $body/getLocationsByLocationIds/string, ',')

___________

The way a Weblogic Web Service returns a Stacktrace in a SOAP Fault

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
  <env:Header />
    <env:Body>
    <env:Fault>
      <faultcode>env:Server</faultcode>
      <faultstring>Failed to invoke end component com.pierre.ws.PierreWS (POJO), operation=generateFault1
-> Failed to invoke method
-> ciao1
</faultstring>
      <detail>
        <bea_fault:stacktrace xmlns:bea_fault="http://www.bea.com/servers/wls70/webservice/fault/1.0.0">java.lang.Exception: ciao1
    at com.pierre.ws.PierreWS.generateFault1(PierreWS.java:18)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at weblogic.wsee.component.pojo.JavaClassComponent.invoke(JavaClassComponent.java:112)
    at weblogic.wsee.ws.dispatch.server.ComponentHandler.handleRequest(ComponentHandler.java:84)
    at weblogic.wsee.handler.HandlerIterator.handleRequest(HandlerIterator.java:141)
    at weblogic.wsee.ws.dispatch.server.ServerDispatcher.dispatch(ServerDispatcher.java:114)
    at weblogic.wsee.ws.WsSkel.invoke(WsSkel.java:80)
    at weblogic.wsee.server.servlet.SoapProcessor.handlePost(SoapProcessor.java:66)
    at weblogic.wsee.server.servlet.SoapProcessor.process(SoapProcessor.java:44)
    at weblogic.wsee.server.servlet.BaseWSServlet$AuthorizedInvoke.run(BaseWSServlet.java:285)
    at weblogic.wsee.server.servlet.BaseWSServlet.service(BaseWSServlet.java:169)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3498)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(Unknown Source)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2180)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2086)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1406)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)
</bea_fault:stacktrace>
      </detail>
    </env:Fault>
  </env:Body>
  </env:Envelope>

OSB: difference between Route, Service Callout and Publish

service call out .. you call a service in a SYNCHRONOUS way (pipeline blocks and waits for service response)

publish ... same but ASYNCHRONOUS, so message flow continues in the pipeline

route ... it's the last node of the proxy, it's not in the pipeline, you pass all processing to another (business or proxy) service

Tuesday, April 27, 2010

OSB faults transformed into SOAP 1.2 and SOAP 1.1 format

If the client that invokes OSB adheres to the SOAP 1.2 standard, you can always transform the OSB SOAP Fault into the 1.2 standard with this XQuery transformation:


declare namespace xf =
"http://tempuri.org/Transformations/transformations/transformCustomFaultToSoapFault/";
declare namespace soap = "http://www.w3.org/2003/05/soap-envelope";
declare namespace flt = "http://www.bea.com/wli/sb/context";

declare function xf:transformCustomFaultToSoapFault($fault1 as
element(flt:fault))
   as element(soap:Fault) {
       <soap:Fault>
           <soap:Code>
               <soap:Value>soap:Receiver</soap:Value>
           </soap:Code>
           <soap:Reason>
               <soap:Text>{ concat(data($fault1/flt:errorCode) , "-"
, data($fault1/flt:reason)) }</soap:Text>
           </soap:Reason>
           {

               for $location in $fault1/flt:location
               let $node := data($location/flt:node)
               let $pipeline := data($location/flt:pipeline)
               let $stage := data($location/flt:stage)
               let $error-handler := data($location/flt:error-handler)
               let $path := data($location/flt:path)
               return
                   <soap:Node>{ concat($node ,"-" , $pipeline ,"-" ,
$stage ,"-" , $error-handler ,"-" , $path) }</soap:Node>
           }
           {
               for $details in $fault1/flt:details
               return
                   <soap:Detail>{ $details/@* , $details/node() }</soap:Detail>
           }
       </soap:Fault>
};

declare variable $fault1 as element(flt:fault) external;

xf:transformCustomFaultToSoapFault($fault1)

And this is the SOAP 1.1 version:

declare namespace xf =
"http://tempuri.org/Transformations/transformations/transformCustomFaultToSoap11Fault/";
declare namespace ns0 = "http://schemas.xmlsoap.org/soap/envelope/";
declare namespace ns1 = "http://www.bea.com/wli/sb/context";

declare function xf:transformCustomFaultToSoap11Fault($fault1 as
element(ns1:fault))
   as element(*) {
       <ns0:Fault>
       <faultcode>soap:Server</faultcode>
       <faultstring>{ concat($fault1/ns1:errorCode , "-"
,$fault1/ns1:reason) }</faultstring>
       {
       for $node in $fault1/ns1:location/ns1:node
       let  $error-handler := data($fault1/ns1:location/ns1:error-handler)
       let  $path := data($fault1/ns1:location/ns1:path)
       let  $stage := data($fault1/ns1:location/ns1:stage)
       let  $pipeline := data($fault1/ns1:location/ns1:pipeline)
       return
       <faultactor>{ concat($node , "-" , $error-handler , "-" ,
$path , "-" , $stage , "-" , $pipeline) }</faultactor>
       }
       {
       for $details in $fault1/ns1:details
       return
       <detail>{ $details/@* , $details/node() }</detail>
       }
       </ns0:Fault>
};

declare variable $fault1 as element(ns1:fault) external;

xf:transformCustomFaultToSoap11Fault($fault1)

OSB transport headers

<con:transport xmlns:con="http://www.bea.com/wli/sb/context">
  <con:uri>/PVOSBProject1/PVTestFault01</con:uri>
  <con:mode>request-response</con:mode>
  <con:qualityOfService>best-effort</con:qualityOfService>
  <con:request xsi:type="http:HttpRequestMetaData" xmlns:http="http://www.bea.com/wli/sb/transports/http" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <tran:headers xsi:type="http:HttpRequestHeaders" xmlns:tran="http://www.bea.com/wli/sb/transports">
      <http:Content-Type>text/xml; charset=utf-8</http:Content-Type>
      <http:SOAPAction>"generateFault2"</http:SOAPAction>
    </tran:headers>
    <tran:encoding xmlns:tran="http://www.bea.com/wli/sb/transports">utf-8</tran:encoding>
  </con:request>
  <con:response xsi:type="http:HttpResponseMetaData" xmlns:http="http://www.bea.com/wli/sb/transports/http" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <tran:headers xsi:type="http:HttpResponseHeaders" xmlns:tran="http://www.bea.com/wli/sb/transports">
      <http:Content-Type>text/xml</http:Content-Type>
    </tran:headers>
    <tran:response-code xmlns:tran="http://www.bea.com/wli/sb/transports">0</tran:response-code>
  </con:response>
</con:transport>


You can  customize the tran:headers section with a tran:user-header with a custom header

      <tran:headers xsi:type="http:HttpRequestHeaders" xmlns:tran="http://www.bea.com/wli/sb/transports">
        <tran:user-header name="messageHistory" value="ciaobellagioia"/>
        <http:Content-Type>text/xml; charset=utf-8</http:Content-Type>

this is how I added the header:



This way the Caller Proxy Service sets the header on the $outbound variable. The Called Proxy Service MUST be set with the option "GET ALL HEADERS" in the "Transport" tab, otherwise the transport header will be lost. Or, at least, add the "messageHistory" in the list of headers to be explicitly copied.
The Called Proxy Service  will get the header in the $inbound variable, transport section.

OF COURSE you whould not put messageHistory in a transport header, the right place is in the SOAP header. Don't confuse TRANSPORT HEADER with SOAP HEADER.

OSB: all bound variables and their structure

















Monday, April 26, 2010

SOAP Fault in OSB

see also http://www.javamonamour.org/2010/07/osb-error-handling-fault.html

this is what the WS method does:

    @WebMethod(action="generateFault1")
    public void generateFault1() throws Exception {
        throw new Exception("ciao1");
    }

and this is what the method generates when run in OSB

    <soapenv:Envelope      xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
    <soapenv:Fault>
    <faultcode>soapenv:Server</faultcode>
    <faultstring>BEA-380001: Internal Server Error</faultstring>
    <detail>
    <con:fault      xmlns:con="http://www.bea.com/wli/sb/context">
    <con:errorCode>BEA-380001</con:errorCode>
    <con:reason>Internal Server Error</con:reason>
    <con:location>
    <con:node>RouteTo_BSPVWS01</con:node>
    <con:path>response-pipeline</con:path>
    </con:location>
    </con:fault>
    </detail>
    </soapenv:Fault>
    </soapenv:Body>
    </soapenv:Envelope>


This is the structure of the fault element




This is how to declare the faults generated by an operation:

http://www.w3.org/TR/wsdl#_soap:fault

here in more details
http://docs.sun.com/app/docs/doc/821-0015/ggeip2?a=view

A really interesting article defining Business Faults versus System Faults, and Fault handling Policies
http://www.troubleshootingwiki.org/Handling_errors_in_SOA_based_systems

nothing new really, in the Java world there are the same concepts, much better defined.


The fascinating thing is that in the Error Handler you have all sort of information disseminated in 2 places: the $fault variable and the $body variable

$fault: <con:fault xmlns:con="http://www.bea.com/wli/sb/context">
  <con:errorCode>BEA-380001</con:errorCode>
  <con:reason>Internal Server Error</con:reason>
  <con:location>
    <con:node>RouteNode1</con:node>
    <con:path>response-pipeline</con:path>
  </con:location>
</con:fault>>

$body: <env:Body xmlns:
env="http://schemas.xmlsoap.org/soap/envelope/">
  <env:Fault>
    <faultcode>env:Server</faultcode>
    <faultstring>ciao2</faultstring>
    <detail>
      <java:PierreException xmlns:java="java:com.pierre.exceptions"/>
    </detail>
  </env:Fault>
</env:Body>>

(the exception being thrown is new com.pierre.exceptions.PierreException("ciao2")

The complete stacktrace is missing though...

Friday, April 23, 2010

SOAP or REST? Which is the BEST?

An interesting article examining REST features

https://www.ibm.com/developerworks/webservices/library/ws-restful/

and a good introduction to REST

http://www.ibm.com/developerworks/webservices/library/wa-jaxrs/index.html

more later....

Sunday, April 11, 2010

SOAP messages patterns

a useful collection of SOAP message patterns:

http://www.w3.org/TR/xmlp-scenarios/

a message for all seasons....


Especially interesting:

http://www.w3.org/TR/xmlp-scenarios/#S807


TrackingHeader with Via Intermediary with Timestamp 
(excellent for troubleshooting and performance monitoring!)
 
<t:TrackingHeader xmlns:t="http://example.org/2001/06/tracking">
      <t:Via>
        <t:Intermediary>soap://A.com/some/endpoint</t:Intermediary>
        <t:Timestamp>2001-03-09T08:00:00Z</t:Timestamp>
      </t:Via>
 
 
 
and the response correlated to the messageId
 <n:MsgHeader xmlns:n="http://example.org/requestresponse">
      <n:MessageId>uuid:09233523-567b-2891-b623-9dke28yod7m9</n:MessageId>
      <n:ResponseTo>uuid:09233523-345b-4351-b623-5dsf35sgs5d6</n:ResponseTo>

  </n:MsgHeader>

Wednesday, April 7, 2010

More on WLI and UsernameToken

if you provide this policy file to protect your WLI process:

@WSSecurityService(file="mypolicy.xml")


<wssecuritypolicy xsi:schemalocation="WSSecurity-policy.xsd">
xmlns="http://www.bea.com/2003/03/wsse/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<wssecurityin>
    <token tokentype="username">
</token></wssecurityin></wssecuritypolicy>


you get this error message:


java.rmi.RemoteException: EJB Exception: ; nested exception is:
com.bea.wli.knex.runtime.jws.wssecurity.exception.WLWWSSEException: Policy requires Message to contain UsernameToken, UsernameToken not found in the Message.
Caused by: com.bea.wli.knex.runtime.jws.wssecurity.exception.WLWWSSEException: Policy requires Message to contain UsernameToken, UsernameToken not found in the Message.


this is fantastic. I wonder why WLI manuals say that JPD don't support security... they are funny.


Now I try passing a Username in the Soap Header:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:open="http://www.openuri.org/">
<soapenv:Header>
<wsse:Security
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
soapenv:mustUnderstand="1">
<wsse:UsernameToken wsu:Id="SecurityToken-1">
<wsse:Username>username</wsse:Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
password
</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>

<soapenv:Body>
<open:clientRequestwithReturn>
<!--Optional:-->
<open:x0>pippo</open:x0>
</open:clientRequestwithReturn>
</soapenv:Body>
</soapenv:Envelope>


and I get a fantastic:

javax.security.auth.login.FailedLoginException: [Security:090304]Authentication Failed: User username at weblogic.security.providers.authentication.LDAPAtnLoginModuleImpl.login(LDAPAtnLoginModuleImpl.java:230)
    at com.bea.common.security.internal.service.LoginModuleWrapper$1.run(LoginModuleWrapper.java:110)
    at com.bea.common.security.internal.service.LoginModuleWrapper.login(LoginModuleWrapper.java:106)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
    at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
    at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
    at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
    at javax.security.auth.login.LoginContext.login(LoginContext.java:579)
    at com.bea.common.security.internal.service.JAASLoginServiceImpl.login(JAASLoginServiceImpl.java:113)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.bea.common.security.internal.utils.Delegator$ProxyInvocationHandler.invoke(Delegator.java:57)
    at $Proxy16.login(Unknown Source)
    at weblogic.security.service.internal.WLSJAASLoginServiceImpl$ServiceImpl.login(Unknown Source)
    at com.bea.common.security.internal.service.JAASAuthenticationServiceImpl.authenticate(JAASAuthenticationServiceImpl.java:82)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.bea.common.security.internal.utils.Delegator$ProxyInvocationHandler.invoke(Delegator.java:57)
    at $Proxy34.authenticate(Unknown Source)
    at weblogic.security.service.WLSJAASAuthenticationServiceWrapper.authenticate(Unknown Source)
    at weblogic.security.service.PrincipalAuthenticator.authenticate(Unknown Source)
    at weblogic.security.service.PrincipalAuthenticator.authenticate(Unknown Source)
    at weblogic.webservice.util.ServerSecurityHelper.assertIdentity(ServerSecurityHelper.java:45)
    at com.bea.wli.knex.runtime.jws.wssecurity.inbound.WLWInboundWSSEImpl.assertIdentity(WLWInboundWSSEImpl.java:458)



Exciting!
I can see in the stacktrace interesting stuff like: ServerSecurityHelper.assertIdentity(), PrincipalAuthenticator.authenticate(), JAASAuthenticationServiceImpl.authenticate(), LDAPAtnLoginModuleImpl.login()...

Now I create the username "username" in the default security realm, with password "anotherpassword"

I still get the

javax.security.auth.login.FailedLoginException: [Security:090302]Authentication Failed: User username denied

(so we understand that "User xxx denied" could also mean "bad password")

When I provide the right password, everything works.

I am using SOAPUI to submit the request.

If I remove the Security header from the SOAP message, and I select the WSS-Password Type= password text, and I provide username and password in the appropriate properties, things work again fine. (tip: look in the SOAPUI http log, you should see the password being trasmitted in the clear with the SOAP request).

If you choose WSS-Password Type=digest, you transmit this:

<soapenv:Envelope xmlns:open="http://www.openuri.org/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header><wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsse:UsernameToken wsu:Id="UsernameToken-5" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><wsse:Username>username</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">DNBu/78N8l0BgBzKPvJglF8zlqw=</wsse:Password><wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">Kb64xrWI9XLLjdmTcIZATQ==</wsse:Nonce><wsu:Created>2010-04-07T12:27:21.353Z</wsu:Created></wsse:UsernameToken></wsse:Security></soapenv:Header>[\n]"

As recommended by OASIS http://www.oasis-open.org/committees/wss/documents/WSS-Username-02-0223-merged.pdf , also Nonce and Timestamp ("Created") are supplied (they are supplied also in the "password text" case).

Now, just for fun I hack the header and set Created to 2009-04-07T12:33:17.551Z
The Web Service still process it.... how to tell Web Service to reject a request which is 1 year old?

I look into http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/ws-securitypolicy.xsd if there is any such option. I don't see anything inspiring.

Theoretically the "Created" info should be embedded into a  wsu:Timestamp element.... the WS-Security specs seem very loose and fuzzy, I have the impression that SOA is built on a under-specified standard which imposes every solution to reinvent the wheel adapting a generic standard to its own internal needs.
I guess some billion dollars have been lost so far because of this fuzziness.

Anyway... this is the standard:

           <wsse:Security xmlns:wsse="..." xmlns:wsu="..."
soapenv:mustUnderstand="1">
                <wsu:Timestamp wsu:Id="Timestamp-31497800">
                    <wsu:Created>2009-11-02T14:00:00Z</wsu:Created>
                    <wsu:Expires>2009-11-02T15:00:00Z</wsu:Expires>
                </wsu:Timestamp>


       <wsse:UsernameToken wsu:Id="UsernameToken-10697954">
                    <wsse:Username>...</wsse:Username>
                    <wsse:Password Type="...#PasswordText">...</wsse:Password>
                </wsse:UsernameToken>

so the "created" is associated to the Timestamp, not to the Username... in fact I have read that the "Created" clause can be attached to any Element.

WLDF in action

This is a REALLY interesting article on how to setup SNMP alerts in WebLogic, using the WLDF framework

http://www.oracle.com/technetwork/articles/cico-wldf-091073.html

It's POWERFUL. One wonders why people don't use WLDF and SNMP by default to manage WebLogic domains.
The answer is probably that these products are not properly packaged for the end user, they are still cumbersome to setup and exploit... so people still rely on 3rd party agents and monitoring tools like Nagios, Hyperic etc.

It's a pity that such a valuable tool receives so little attention.

Sunday, April 4, 2010

Good old Username Token authentication model for Web Services

Some practical documentation here:

http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/cwbs_usernametokenv6.html

and also an interesting podcast here

http://channel9.msdn.com/shows/ARCast+with+Ron+Jacobs/ARCast-Securing-Web-Services-with-the-Username-Token-in-WSE-30-Part-1/

on X509 PKI certificate and Username Token.

In a nutshell:

Kerberos and X509 are brokered authentication,  you present a token which vouches that you have gone somewhere else through an authentication process

Username Token is direct authentication

A X509 contains a certificate which has a public key that can be used by the recipient to encrypt messages that can be only decrypted by the X509 originator.

The official OASIS documentation (interesting reading)


http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf

An example of SOAP request with unencrypted Username token (thanks Tom Gullo, http://www.jroller.com/tgullo/, god bless your excellent recipes)

http://www.jroller.com/tgullo/resource/UsernamePasswordRequest.xml.txt

and encoded

http://www.jroller.com/tgullo/resource/EncryptedUsernamePasswordRequest.xml.txt

(it's really verbose, oh my god, I wonder about the performance impact)

Thursday, April 1, 2010

Penetration Tests and the Holy Grail of Security

I am reading this interesting document

http://www.owasp.org/images/5/56/OWASP_Testing_Guide_v3.pdf

provided by OWASP http://www.owasp.org , an "open source" security organization.

The dream was to find an intelligent PENETRATION (gasp!) test tool that find for you the security weaknesses of a Web Application (including Web Services).
See also http://en.wikipedia.org/wiki/Penetration_testing .

Anyway to quote the already quoted Gary McGraw,
“If you fail a penetration test you know you have a very bad problem indeed. If you pass a penetration test you do not know that you don’t have a very bad problem".

So, don't think that you are not PENETRABLE only because an AUTOMATED TOOL cannot PENETRATE you. Sorry but all this PENETRATION talks make me laugh. I am just Italian.

We shall cover later how to TEST your SECURITY. For a start never bend to pick up object that you dropped hahaha.