Automatic NTLM Authentication for WSO2 ESB - wso2

I have a WCF Web Service sitting on a client's IIS server secured with NTLM authentication - I have no control over the authentication configuration on that server.
I need to integrate my WSO2 ESB server with this service, but I can't find a way to get the ESB to authenticate automatically. I have successfully pushed requests through the ESB to the service with web applications, but I was prompted to provide my Windows credentials during that process - I would like for this to not happen.
I have attempted to set up an NTLM proxy on my server, but couldn't figure this out either.
Any guidance would be much appreciated.
Strainy

Ok, i found your answer. As you know, WSO2 ESB uses Axis2 for web services. You must add NTLM configuration in Axis2 config file (ESB_HOME/repository/conf/axis2/axis2.xml).
This links, describes the configuration.
http://wso2.com/library/161/
http://axis.apache.org/axis2/java/core/docs/http-transport.html

There were a few components to getting this working correctly. It's hard to find it all written down in one place, so I'll attempt to provide an end-to-end overview here.
I first had to use a class mediator within my WSO2 ESB in-sequence to handle the sending and the NTLM authentication. The class mediator references a custom class which takes the message context from the mediation flow (called the Synapse message context) and extracts the SOAP envelope. I then loaded the Synapse SOAP envelope into an Axis2 message context object. I then used an Axis2 client along with the message context to submit my authenticated request to the server. The authentication for NTLM through Axis2 comes from the JCIFS_NTLMScheme class, which you can reference here.
Note: you'll have to play with the logging configuration in that class to make it work with WSO2. I just removed the " org.sac.crosspather.common.util* " libraries and altered any logging I saw to use the Apache Commons logging capability
Create a Custom Mediator Project in WSO2 Developer Studio
Create a new project in Developer studio. Right click the project node in the project explorer and select "New > Mediator Project".
This will generate a bit of boilerplate code for you - that is, a class which extends AbstractMediator and which implements an "mediate()" method which Synapse will call when it comes to executing the logic defined within your sequence.
public class NTLMAuthorisation extends AbstractMediator {
public boolean mediate(MessageContext context){
//Mediation Logic
return true;
}
}
Expose Some Variables/Properties to the User
The class mediator looks for variables which are publicly accessible and exposes them in the WSO2 configuration. This is helpful before you can create a re-usable mediator which adapts itself to properties or values defined in the WSO2 Carbon Web UI. Here we need to expose seven variables: soapAction, SoapEndpoint, domain, host, port, username, and password. Expose the variables by defining your instance variables, along with their accessors and mutators.
This is all really quite useful for using the WSO2 Secure Vault to store your NTLM password and fetching other configuration from a system registry with properties.
public class NTLMAuthorisation extends AbstractMediator {
private String soapAction;
private String soapEndpoint;
private String domain;
private String host;
private int port;
private String username;
private String password;
public boolean mediate(MessageContext context) {
//Mediation Logic
return true;
}
public void setSoapAction(String _soapAction){
soapAction = _soapAction;
}
public String getSoapAction(){
return soapAction;
}
public void setSoapEndpoint(String _soapEndpoint){
soapEndpoint = _soapEndpoint;
}
public String getSoapEndpoint(){
return soapEndpoint;
}
public void setDomain(String _domain){
domain = _domain;
}
public String getDomain(){
return domain;
}
public void setHost(String _host){
host = _host;
}
public String getHost(){
return host;
}
public void setPort(int _port){
port = _port;
}
public int getPort(){
return port;
}
public void setUsername(String _username){
username = _username;
}
public String getUsername(){
return username;
}
public void setPassword(String _password){
password = _password;
}
public String getPassword(){
return password;
}
}
The Custom Mediation Logic
Make sure you created an JCIFS_NTLMScheme class from here and have added the org.samba.jcifs dependency to your Maven dependencies like so:
<dependency>
<groupId>org.samba.jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.17</version>
</dependency>
Now you can use the following mediate method in your custom mediator class:
public boolean mediate(MessageContext context) {
//Build NTLM Authentication Scheme
AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, JCIFS_NTLMScheme.class);
HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
auth.setUsername(username);
auth.setPassword(password);
auth.setDomain(domain);
auth.setHost(host);
auth.setPort(port);
ArrayList<String> authPrefs = new ArrayList<String>();
authPrefs.add(AuthPolicy.NTLM);
auth.setAuthSchemes(authPrefs);
//Force Authentication - failures will get caught in the catch block
try {
//Build ServiceClient and set Authorization Options
ServiceClient serviceClient = new ServiceClient();
Options options = new Options();
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, auth);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
options.setTo(new EndpointReference(soapEndpoint));
options.setAction(soapAction);
serviceClient.setOptions(options);
//Generate an OperationClient from the ServiceClient to execute the request
OperationClient opClient = serviceClient.createClient(ServiceClient.ANON_OUT_IN_OP);
//Have to translate MsgCtx from Synapse to Axis2
org.apache.axis2.context.MessageContext axisMsgCtx = new org.apache.axis2.context.MessageContext();
axisMsgCtx.setEnvelope(context.getEnvelope());
opClient.addMessageContext(axisMsgCtx);
//Send the request to the server
opClient.execute(true);
//Retrieve Result and replace mediation (synapse) context
SOAPEnvelope result = opClient.getMessageContext(WSDLConstants.MESSAGE_LABEL_IN_VALUE).getEnvelope();
context.setEnvelope(result);
} catch (AxisFault e) {
context.setProperty("ResponseCode", e.getFaultCodeElement().getText());
return false; //This stops the mediation flow, so I think it executes the fault sequence?
}
return true;
}
Package as an OSGi Bundle and Deploy to the Server
At this stage you should be able to your custom mediator project within the project explorer in WSO2 Developer Studio and from the context menu select Export Project as Deployable Archive. Follow the prompts to save the JAR file somewhere on your system. After generating the JAR file, locate it and transfer it to the [ESB_HOME]/repository/components/dropins directory. You may need to restart the server for it to detect the new external library.
Using the Custom Mediator
In your sequence, you should now be able to add a class mediator and reference your custom class using the package name and class name together, for example: org.strainy.ntlmauthorisation.

Related

Optional authentication for Java EE Resource

I would like to protect a SOAP JAX-WS webservice with a java security authentication but, because a lot of users are already using it, i don't want to ask them to implement the authentication on their side.
The idea is to permit the access to everybody to the WS (no login required, as is right now) but if anyone pass newly authentication HTTP Basic login i will detect it (request.getUserPrincipal()) and i will enable some new functionalities.
I'm trying to use java security but i didn't find how to specify that the basic authentication is OPTIONAL for a specific security-constraint and not required. This is a problem because if i use it i cannot grant anonymous access anymore.
I'm using Java EE 5 on Glassish v2.1.1
Example:
#WebService
public class MyWs {
#Resource
protected WebServiceContext wsContext;
#WebMethod()
public void myWebMethod(){
HttpServletRequest request = (HttpServletRequest) wsContext.getMessageContext().get(MessageContext.SERVLET_REQUEST);
if (request.getPrincipal() != null && request.getPrincipal().getName().equals("myAuthenticatedUser")){
//do something new
}
//do the same as before
}
}

SoapUI web service authentication programmatically

I am writing SOAP web service tests using SoapUi API. I am using SoapUITestCaseRunner for that.
My code looks like
public class MyRunner extends SoapUITestCaseRunner{
public void runTest(){
setProjectFile("pro_file_path");
setEndpoint("endpoint");
setUsername("username");
setPassword("password");
setTestSuite("testSuiteName");
setTestCase("TestCaseName");
run();
}
}
public class MyTestClass(){
#Test
public void test(){
new MyRunner().runTest();
}
}
But username and password are getting passed as properties (I could see them in junit failure logs).
And service is saying me 401-unauthorized ? Am I missing anything? Is there anything need to be done to pass username and password?
I got the answer. The problem is with the version of SoapUI I am using to create project.xml file. If we create project using version below 5.0.0 and use 5.0.0 while writing junit it won't work.
Actually, the it seems that SoapUI ahs made changes to authentication part in 5.0.0 which has few more options like NTML. So we have to configure authentication type in project.xml and send the username and password either pre-configured in project.xml or manually through junit.

Using Connection: Close in webserver SOAP requests

The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
We're getting this exception frequently when using .Net 4.0 web service client to communicate with an ONVIF network device.
Looking at the packet captures, this seems to be a device that is non compliant with the HTTP spec and closing a connection after sending the response, against the HTTP/1.1 default of keeping it alive.
This results in the client (WCF) trying to reuse the connection while the server has just closed it,
Until the manufacturer can fix this, is there any way I can tell the web service/SOAP client NOT to use persistent connections?
Note that modifying the header to use Connection: Close won't help unless as it's being closed anyway, but the SOAP client is expecting it to stay open.
but is there any way I can tell the web service/SOAP client NOT to use persistent connections?
Yes, you can set InstanceContextMode to PerCall, it will create new InstanceContext object is created prior to and recycled subsequent to each call.
In other words, When we configure a WCF service as per call, new service instances are created for every method call you make via a WCF proxy client.
You can use it like :
setting in ServiceBehavior over Contract Interface implementation like:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class CalculatorService : ICalculator
{
...
}
UPDATE --
As per your comment, it seems the solution is to explicitly set the KeepAlive property to FALSE.
It can be done in multiple ways:
Code
IIS Settings
Web.config
Code
I actually don't know how much control you have over code.But at the client end where you are consuming service, we can change this behavior like:
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)base.GetWebRequest(uri);
webRequest.KeepAlive = false;
return webRequest;
}
Or
namespace YourNamespace
{
using System.Diagnostics;
using System.Web.Services;
using System.ComponentModel;
using System.Web.Services.Protocols;
using System;
using System.Xml.Serialization;
/// <summary>
/// This partial class makes it so all requests specify
/// "Connection: Close" instead of "Connection: KeepAlive" in the HTTP headers.
/// </summary>
public partial class YourServiceNameWse : Microsoft.Web.Services3.WebServicesClientProtocol
{
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)base.GetWebRequest(uri);
webRequest.KeepAlive = false;
return webRequest;
}
}
}
IIS Settings
Open Internet Information Services (IIS) Manager:
If you are using Windows Server 2008 or Windows Server 2008 R2:
On the taskbar, click Start, point to Administrative Tools, and then click Internet Information Services (IIS) Manager.
If you are using Windows Vista or Windows 7:
On the taskbar, click Start, and then click Control Panel.
Double-click Administrative Tools, and then double-click Internet Information Services (IIS) Manager.
In the Connections pane, go to the site, application, or directory for which you want to enable HTTP keep-alives.
In the Home pane, double-click HTTP Response Headers.
In the HTTP Response Headers pane, click Set Common Headers... in the Actions pane.
In the Set Common HTTP Response Headers dialog box, uncheck the box to disable HTTP keep-alives, and then click OK.
Additionally you can set for particular website on IIS using CommandLine like:
appcmd.exe set config "<Your Web Site Here>" -section:system.webServer/httpProtocol /allowKeepAlive:"False"
Web.Config
<configuration>
<system.webServer>
<httpProtocol allowKeepAlive="false" />
</system.webServer>
</configuration>
I hope it can help you in some way.
The underlying HttpWebRequests are created in the HttpChannelFactory used by the generated client classes.
This is created from the HttpTransportBindingElement which exposes a KeepAliveEnabled property.
The binding element is created internally in the WSHttpBinding class, and can be changed by overriding GetTransport().
private class WSHttpBindingNoKeepAlive : WSHttpBinding {
public WSHttpBindingNoKeepAlive(SecurityMode securityMode)
: base(securityMode) {
}
protected override TransportBindingElement GetTransport() {
TransportBindingElement transport = base.GetTransport();
if (transport is HttpTransportBindingElement) {
((HttpTransportBindingElement)transport).KeepAliveEnabled = false;
}
return transport;
}
}
This overriden ...Binding class can then be used like:
WSHttpBindingNoKeepAlive clientBinding = new WSHttpBindingNoKeepAlive(SecurityMode.None);
EndpointAddress address = new EndpointAddress(this.deviceUrl);
WSNameSpace.WSClient client = new WSNameSpace.WSClient(clientBinding, address);

Accessing WSO2 ESB proxy in java program

I have configured one wsdl proxy for external wsdl in WSO2 esb. Its successfully created proxy. While creating proxy, I have not selected Publish Same Service Contract check box. If we are consuming external web services, is it mandatory to check? When I click on try it, it is not showing operations which are available in wsdl.
If at all the above issues gets solved, we need to access the proxy from our java project. How can we access WSO2 ESB proxy in our java program?
Thanks in advance.
Thanks,
Raghu
Yes you need to check Publish Same Service Contract if you want to publish the same WSDL.
in java code you can write a simple axis2 client like shown below. To the enxpoint of your proxy.
public OMElement sendReceive(OMElement payload, String endPointReference, String operation)
throws AxisFault {
ServiceClient sender;
Options options;
OMElement response = null;
try {
sender = new ServiceClient();
options = new Options();
options.setTo(new EndpointReference(endPointReference));
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED, Boolean.FALSE);
options.setTimeOutInMilliSeconds(45000);
options.setAction("urn:" + operation);
sender.setOptions(options);
response = sender.sendReceive(payload);
} catch (AxisFault axisFault) {
throw new AxisFault("AxisFault while getting response :" + axisFault.getMessage(), axisFault);
}
Assert.assertNotNull(response);
return response;
}
You can get the sample payload by tying a tool like soap UI.
Thank You,
Dharshana.
Try like this:
CentralUuidService service = new CentralUuidService(new URL("http://wls02.tigeritbd.com:8280/services/CentralUuidService?wsdl"),new QName("http://bean.service.uuid.gov.bd/", "CentralUuidService"));
GetBirthPlaceServiceResponse response = service.getCentralUuidServiceHttpSoap11Endpoint().getBirthPlace(request);
if(response != null) {
System.out.println("Operation status is:"+response.isOperationStatus());
}
}

Rich client (swing) application which connects to Remote database over http

i have a local client j2se application and backend is derby(javadb) database and dao is jpa eclipselink .
how do i send these database pojo to a remote database which linked with spring ( jsp) application on tomcat server
simply this is a rich client with swing which connects to tomcat deployed web application. The client should receive data and send data through HTTP requests to the server-side of the service,
what would be the best solution ??
01) direct database connection/transaction through socket using Eclipselink
02) web service ??
03) just send post request to spring web application and convert it to POJO and persist to database
how do i achieve this??
DISCLAIMER I am not suggesting you port your app from Spring to EJB. Despite how people like to compare them as exclusively one or the other, you can use them both. Its your app, you can be as pragmatic as you want to be :)
You don't necessarily have to use Web Services if you wanted. You could drop the OpenEJB war file into Tomcat as well and create an Remote EJB to send data back and forth.
Once you drop in OpenEJB you can put a remote #Stateless bean in your app like so:
#Stateless
#Remote
public class MyBean implements MyBeanRemote {
//...
}
public interface MyBeanRemote {
// any methods you want remotely invoked
}
Then look it up and execute it over HTTP from your Swing app like so:
Properties p = new Properties();
p.put("java.naming.factory.initial", "org.apache.openejb.client.RemoteInitialContextFactory");
p.put("java.naming.provider.url", "http://tomcatserver:8080/openejb/ejb");
// user and pass optional
p.put("java.naming.security.principal", "myuser");
p.put("java.naming.security.credentials", "mypass");
InitialContext ctx = new InitialContext(p);
MyBean myBean = (MyBean) ctx.lookup("MyBeanRemote");
Client-side all you need are the openejb-client.jar and javaee-api.jar from the OpenEJB war file and your own classes.
Since it's already a Spring app don't bother trying to use #PersistenceContext to get a reference to the EntityManager so the EJB can use it. Just figure out how to expose the EntityManagerFactory that Spring creates (or you create) to the EJB via any means possible. The direct and ugly, but effective, approach would be a static on the MyBean class and a bit of startup logic that sets it. You'd just be using the EJB for remoting so no need for fancier integration.
If you did really need web services for non-java communication or something, you can add #WebService to the top of your bean and then it will have WSDL and all that generated for it:
#Stateless
#Remote
#WebService(portName = "MyBeanPort",
serviceName = "MyBeanService",
targetNamespace = "http://superbiz.org/wsdl"
endpointInterface = "org.superbiz.MyBeanRemote")
public class MyBean implements MyBeanRemote {
//...
}
public interface MyBeanRemote {
// any methods you want remotely invoked
}
Then you can also use the same bean as a web service like:
Service service = Service.create(
new URL("http://tomcatserver:8080/MyBeanImpl?wsdl"),
new QName("http://superbiz.org/wsdl", "MyBeanService"));
assertNotNull(service);
MyBeanRemote myBean = service.getPort(MyBeanRemote.class);
Both approaches are over http, but the web service approach will be a bit slower as it isn't a binary protocol.