Glassfish, EJB3, SOAP web service and basic authentication - web-services

I'm setting up a glassfish server with a single EJB3 as a mocked up backend for a POC. Everything was working fine until I went to add some basic authentication. Just plan text userid and password, nothing sophisticated for this job. I added the following annotations to the EJB:
#WebService(name = "Banking", serviceName = "Banking", targetNamespace = BANKING_NAMESPACE)
#DeclareRoles("user")
#Stateless
public class Banking {
...
#RolesAllowed("user")
#SOAPBinding(parameterStyle = ParameterStyle.BARE)
#WebMethod(action = BANKING_NAMESPACE + "/logon", operationName = "logon")
#WebResult(targetNamespace = XmlStrings.BANKING_MODEL_NAMESPACE)
public LogonResponse logon(#WebParam(targetNamespace = XmlStrings.BANKING_MODEL_NAMESPACE) Logon request) throws WebServiceException {
...
}
}
According to what I've read of EJB3 spec, this is pretty common for doing a SOAP web service.
However when I send this xml:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mod="http://www.dhcbank.com/banking/model">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-79" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>fred</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">fred</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<mod:logon/>
</soapenv:Body>
</soapenv:Envelope>
I get the following error back as a SOAP fault:
java.lang.Exception: Client not authorized for invocation of public com.dhcbank.www.banking.schema.LogonResponse com.dhcbank.www.banking.Banking.logon(com.dhcbank.www.banking.schema.Logon) throws javax.xml.ws.WebServiceException
And in the glassfish log:
[#|2010-10-10T12:49:27.497+1100|INFO|glassfish3.0.1|javax.enterprise.system.core.security|_ThreadID=41;_ThreadName=http-thread-pool-8080-(2);|JACC Policy Provider: Failed Permission Check, context(BankingEAR/Banking_war_internal)- permission((javax.security.jacc.EJBMethodPermission Banking logon,ServiceEndpoint,com.dhcbank.www.banking.schema.Logon))|#]
In the glassfish admin screens I added a user called fred with a fred password and assigned it to a groups called user. But that didn't work.
I did some more reading which suggested that I create a sun-ejb-jar.xml file and add it to the ear file. So I created it with this content:
<sun-ejb-jar>
<enterprise-beans>
<ejb>
<ejb-name>Banking</ejb-name>
<webservice-endpoint>
<port-component-name>Banking</port-component-name>
<login-config>
<auth-method>BASIC</auth-method>
<realm>file</realm>
</login-config>
</webservice-endpoint>
</ejb>
</enterprise-beans>
</sun-ejb-jar>
This is as near as I can tell, correct. However I could not find anything that told me what the values of the port-component-name element should be. So I don't know if I've got it right.
Security does still not appear to be working and I cannot figure out why. Does anyone have any experience with this and can point me at what I've got wrong or not done?

I'm assuming your declared role "user" is the same role name in your file realm? if not provide this mapping in your descriptor:
<sun-ejb-jar>
<security-role-mapping>
<role-name>user</role-name>
<group-name>filerealm-group-name</group-name>
</security-role-mapping>
...

I don't think that you're currently creating the appropriate HTTP header for Basic Authentication. I'm not sure how you create the SOAP request but if you're using a JAX-WS client, the JAX-WS FAQ documents the following:
Q. How do I do basic authentication in JAX-WS?
You can do the following:
HelloService service = new HelloService();
Hello proxy = (service.getHelloPort());
((BindingProvider)proxy).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "userfoo");
((BindingProvider)proxy).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "passbar");
USERNAME_PROPERTY, PASSWORD_PROPERTY
are used primarily for service
requests. I think when you instantiate
Service, it fetches WSDL and the
server is returning 401. You could try
any one of the following solutions.
Use java.net.Authenticator class in your client application.
Provide a local access to the WSDL using catalog. There is a catalog
sample in the jax-ws distribution.
Configure web.xml to allow GET requests without authentication
And unless I'm wrong, the usernametoken would fit if the webservice expects the authentication in the SOAP header, which is not the case according to your description.
In other words, for me, you're currently not sending the credentials for the BASIC auth.
See also
Example: Basic Authentication with JAX-WS
SSL and HTTP BASIC authentication with Glassfish and JAX-WS (more complex scenario)

Related

Sending SOAP multiparam message to a Webservice vía Camel routing, with user&pass authentication

I've been trying to connect to an external endpoint vía camel routing, with SOAP.
So far I succeded in routing files in my localhost but I cant find how to do this part.
I need to route a message to a webservice in Camel. It needs to authenticate with username and password.
The message requires two parameters as seen here:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<cli:sendOrder>
<Param1>?</Param1>
<Param2>?</Param2>
</cli:sendOrder>
</soapenv:Body>
</soapenv:Envelope>
Perhaps you can enlighten me in configuring the endpoint with the two parameters and sending it with a username and password.
If you use the camel-cxf endpoint, you can configure the username and password for the basic authentication on the httpconduit just like this.
<conduit name="{http://example.com/}HelloWorldServicePort.http-conduit"
xmlns:sec="http://cxf.apache.org/configuration/security"
xmlns="http://cxf.apache.org/transports/http/configuration">
<authorization>
<sec:UserName>myuser</sec:UserName>
<sec:Password>mypasswd</sec:Password>
<sec:AuthorizationType>Basic</sec:AuthorizationType>
</authorization>
</conduit>

SOAP WS authentication in Websphere

I'm new to both SOAP WS and Websphere Application Server(8.5).
I have a web service which is currently accessed over http and my objectives are :
Changing the access protocol from http to https
Implementing the authentication for the users which are located in an Active Directory group
I went through several stackoverflow threads like this and I also tried attaching 'policy set' to the web service and somehow now its accessible only over https despite of detaching policy sets. Then, I also created custom policy sets and bindings as per IBM developer blog but every time I invoke the WS (using SOAP UI) as follows :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://xmlns.scania.com/logistics/schema/transport/v1">
<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" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-7AEC79B67DC85BBB5A14210677185104">
<wsse:Username>12345</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">12345</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<v1:TransportInformationRequest>
<!--1 or more repetitions:-->
<v1:ChassisNumber>2105909</v1:ChassisNumber>
</v1:TransportInformationRequest>
</soapenv:Body>
</soapenv:Envelope>
I get an error on the server side :
Oracle Database Vault and Real Application Testing options ,Oracle JDBC driver 11.2.0.2.0).
[2015-01-12 14:17:09:525 CET] 000000b1 AxisEngine E org.apache.axis2.engine.AxisEngine receive Must Understand check failed for headers: {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security
org.apache.axis2.AxisFault: Must Understand check failed for headers: {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security
at org.apache.axis2.jaxws.handler.HandlerUtils.checkMustUnderstand(HandlerUtils.java:160)
at org.apache.axis2.jaxws.server.EndpointController.inboundHeaderAndHandlerProcessing(EndpointController.java:338)
at org.apache.axis2.jaxws.server.EndpointController.handleRequest(EndpointController.java:260)
at org.apache.axis2.jaxws.server.EndpointController.invoke(EndpointController.java:103)
at org.apache.axis2.jaxws.server.JAXWSMessageReceiver.receive(JAXWSMessageReceiver.java:161)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:208)
at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:172)
at com.ibm.ws.websvcs.transport.http.WASAxis2Servlet.doPost(WASAxis2Servlet.java:1583)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:595)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1227)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:776)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:458)
at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1032)
at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:87)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:909)
at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1662)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:200)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:459)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:526)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:312)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:283)
at com.ibm.ws.ssl.channel.impl.SSLConnectionLink.determineNextChannel(SSLConnectionLink.java:1048)
at com.ibm.ws.ssl.channel.impl.SSLConnectionLink.readyInboundPostHandshake(SSLConnectionLink.java:716)
at com.ibm.ws.ssl.channel.impl.SSLConnectionLink$MyHandshakeCompletedCallback.complete(SSLConnectionLink.java:412)
at com.ibm.ws.ssl.channel.impl.SSLUtils.handleHandshake(SSLUtils.java:1066)
at com.ibm.ws.ssl.channel.impl.SSLHandshakeIOCallback.complete(SSLHandshakeIOCallback.java:87)
at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175)
at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1862)
When I remove the header and simply pass the body, the response is correct.
I understand that the web service isn't configured properly to handle the header but I'm really not able establish the way I should proceed.
Any relevant inputs are welcome.
If your application is JAX-WS and your active directory is your websphere registry, you can follow this article to add WS-Security constraints for a UsernameToken:
http://www-01.ibm.com/support/knowledgecenter/SSEQTP_8.5.5/com.ibm.websphere.base.doc/ae/twbs_stand_alone_security_token.html
If active directory is not your WebSphere registry, then you must also do this and write code to do the authentication to AD in custom code:
http://www-01.ibm.com/support/knowledgecenter/SSEQTP_8.5.5/com.ibm.websphere.base.doc/ae/twbs_replace_authmethod_usernametoken.html
If you had to do that 2nd step there and you also want WebSphere credentials for the user, you must do this:
http://www-01.ibm.com/support/knowledgecenter/SSEQTP_8.5.5/com.ibm.websphere.base.doc/ae/twbs_config_wssec_caller_no_reg.html
In order to get HTTPS, at the point in the 1st article when you were adding the WS-Security policy type to the policy set, you would also add the SSLTransport policy type.

Custom Soap Header in asmx web serrvice

In an existing web service application(asmx services) I need to add new service which will be called through SOAP(java client), and it looks some thing like this
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pus="http://www.example.org/pusheventservice/">
<soapenv:Header>
<pus:WSSecurity>
<Credentials>
<Username>someuser</Username>
<Password>somepwd</Password>
<Credentials>
</pus:WSSecurity>
<PUS:ServiceHeader>
<PUS:TransactionID>101</PUS:TransactionID>
<PUS:TransactionDate>2014/12/21</PUS:TransactionDate>
<PUS:TransactionTime>14:54</PUS:TransactionTime>
I Inherited class class ServiceHeader: SoapHeader having username,password, TransactionId... and mention [SoapHeader("userCredentials", Direction = SoapHeaderDirection.InOut)] with WebMethod.
but my resultant soap message is not be same as above.
What are the steps need to be done..

Enable WS Security Authentication in SOAP UI mockService

I am trying to create a mockWebservice which should Authenticate UserName,password sent in the SOAP Request xml header.
My request xml will look like this
<s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/">
<s11:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>User_Name</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>
<wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">DeliverAccountInvestigationCaseStatus</wsa:Action>
<wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://rp.baml.com</wsa:To>
<wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">Test from APP_NAME</wsa:MessageID>
</s11:Header>
<s11:Body>
<tns:DeliverAccountInvestigationCaseStatusRequest xsi:schemaLocation="http://rp.baml.com/data/DeliverAccountInvestigationCaseStatusV001 DeliverAccountInvestigationCaseStatusV001.xsd" xmlns:tns="http://rp.baml.com/data/DeliverAccountInvestigationCaseStatusV001" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<tns:ReferenceNumber type="GSS">1-</tns:ReferenceNumber>
<tns:TimeStamp>2014-01-31</tns:TimeStamp>
<tns:Status></tns:Status>
<tns:Resolution></tns:Resolution>
<tns:Comment>Test</tns:Comment>
</tns:DeliverAccountInvestigationCaseStatusRequest>
</s11:Body>
</s11:Envelope>
My Webservice should throw error if, username or password is not correct in the header.
When you mock a response you are simulating a response to a service's request. You normally mock when you cannot reach one of the supporting web services or it has not yet been built.
What this means is that you can mock any kind of response. If you need to validate the username and password, you will have to write that validation code yourself.
Check out soapUI.org's service mocking guide for some background on mocking.

Calling weblogic deployed OASIS WSSE web service

We have webservice deployed on weblogic that implements oasis wsse. Then I created the client using wsconsume from jboss (later tried metro) and called the web service. It always throws an error, I tried to create a test client in soapUI that is sent successfully and found out that the request produced by jboss doesn't match.
There are 2 difference that I've found:
1.) DateToken:
Working:
<wsu:Created>2011-09-06T08:22:14.515Z</wsu:Created>
Not working:
<wsse:Created>2011-09-07T06:12:37.322Z</wsse:Created>
2.) Password Type:
Working:
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">OB7izBPcPE0sfJaAEdD1uIrlFT4=</wsse:Password>
Not working:
<wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd#PasswordDigest'>trvFhf0ZCHQy4cBtNu984fs/nIg=</wsse:Password>
This is how I call the web service from client:
URL clientSideSecurityfile = new File("jboss-wsse-client.xml").toURI().toURL();
BindingProvider bp = (BindingProvider) port;
((StubExt) port).setSecurityConfig(clientSideSecurityfile.toExternalForm());
((StubExt) port).setConfigName("Standard WSSecurity Client");
bp.getRequestContext().put(StubExt.PROPERTY_AUTH_TYPE, StubExt.PROPERTY_AUTH_TYPE_BASIC);
bp.getRequestContext().put(StubExt.PROPERTY_CLIENT_TIMEOUT, 30000);
bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "usernmae");
bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "password");
responseACK = port.callWebService();
I'm using jboss4.2.3, jbossws-client 3.0.1-native-2.0.4.GA.
Any idea how to resolve this? It seems jbossws is producing wrong wsse tag which should be wsu for datetoken and type for password :-?.
According to the UsernameToken profile specification it should be,
<wsu:Created>
Where
wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-
1.0.xsd"
Also, as per the specification type should be,
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"
Both;
<wsse:Created>2011-09-07T06:12:37.322Z</wsse:Created>
And
<wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd#PasswordDigest'>trvFhf0ZCHQy4cBtNu984fs/nIg=</wsse:Password>
are, not compliant with the specification...