My diary of software development

Posts tagged ‘WSE’

Calling a SAS WebService from an .Net application

I finally got SAS BI Web Services for .Net installed after I received my 6th installation plan file from SAS and that odyssey is blogged here: 

Creating The SAS Web Service

I am now ready to create a simple web service on SAS and to call that web service from a .Net application. SAS web services are wrappers which are created around a SAS stored process (SP). I found some basic SAS code on the Internet and created a simple SP which took in zero parameters, did some calculations, and returned 2 strings. I then used the SAS Management console to deploy that SP as a web service named CPI1.asmx. 

SAS web services are located in an IIS virtual directory named SASBIWS. This directory contains the WebServiceMaker.asmx web service which SAS used to create my CPI1 web service and the directory contained my CPI1.asmx file. On my SAS server, this filesystem directory is located here: 

 E:\SAS\Config\Lev1\Web\Applications\SASBIWebServicesDotNet9.2\webroot 

  

Setting Up SAS Web Service Logging

I was now ready to create the .Net app to call the web service, but before I did I wanted to ensure I had as much logging turned on at the SAS server as I could get. This desire for massive quantities of log information was a direct result of the injuries I had experienced while trying to get SAS installed in the first place. Nothing in SAS is simple so I wanted to turn on logging. Thankfully I had figured out that SAS uses log4net as their logging module during my SAS installation odyssey by sifting through their .Net assemblies with reflector. If you ever need to know where this log4net config file is located, it is located here on my SAS server:  

c:\Documents and Settings\All Users\Application Data\SAS\WindowsClientLogging\log4netConfig.xml 

  

Creating A .Net App To Call The WebService

I created a console app compliled as .Net 2.0 because I have to use WSE. I don’t know if I could have used .Net 3.5 and WCF to call it but why make this more complex right now? I simply want to call the WS and get my results back. 

I called the web service and immediately got back this exception: 

System.Web.Services.Protocols.SoapHeaderException: Microsoft.Web.Services3.Secuity.SecurityFault: Security requirements are not satisfied because the security header is not present in the incoming message. 

That made sense because I wasn’t passing any credentials and surely SAS would expect them. I looked at the wse3policyCache.config located in the SASBIWS directory and found that it is expecting the security header in the SOAP package and by poking around on the web, I found I could pass that header with this code (my generated web service client proxy is named CPI1WS.CPI1):

CPI1WS.CPI1 ws = new CPI1WS.CPI1();
UsernameToken token = new UsernameToken(“
sasadm@saspw“, “Password123”, PasswordOption.SendPlainText);
ws.SetClientCredential(token);
ws.SetPolicy(“usernameTokenSecurity”);

But there was a problem because the CPI1 class derived from SoapHttpClientProtocol which did not contain a SetClientCredential() or a SetPolicy() method. I fixed this by ignoring line 6 of the auto-generated CPI1 file which states Changes to this file may cause incorrect behavior… and modifying it to derive the CPI1 class from WebServicesClientProcotol.

I executed again and this time, the call was successful and I got my results back.

WAHOO!!!! I did it!!!! I called a SAS web service from a .Net application!!!! WAHOO!!!

I’m so happy. It took me forever to get to this point. There are many more details to fill in such as using Windows integrated security to make the call rather than passing plain text credentials, but this is a major milestone and I am happy.

Advertisements

Figuring out why SAS BI Web Services for .Net doesn’t work – Part 3

It’s been well over a week since I wrote about battling the SAS BI Web Services for .Net beast and a lot has changed. A week or so ago I was pretty sure that I had gotten it installed and was dealing with problems created by configuration issues. I have since found out that I did not have it installed correctly and through the course of the last 10 days SAS sent me 3 additional plan files, the last of which still didn’t work correctly.

I’ll recap what I’m doing. I’m trying to get SAS BI Web Services for .Net installed and working so that I can work on the bigger picture of my project which is to document how to call these web services from a .Net web application. Installing SAS is like building the bay bridge from a bucket (a really big one) of nuts and bolts and cables and other stuff. The full installation for all of the SAS components encompasses dozens and dozens of CDs. So you install SAS in almost any permutation of components but the specific permutation which I need is the one which enables me to use SAS BI Web Services for .Net. The ‘plan’ file which I spoke of above is basically the blueprint to the bridge. It is an XML file which is fed into the SAS installer to tell it which components to install in what order and how to configure them.

Dissecting a SAS installation plan file

I’m still trying to get a working plan file from SAS. I have a ticket open with them to get a plan file with which I can install SAS BI Web Services for .Net plus all the other needed components. But to date, I haven’t received a working plan file. I am now in receipt of the 5th plan file but it doesn’t work and so I’m currently awaiting the 6th one. SAS does not support user modifications of a plan file, they only support plan files from SAS Support or a dedicated account rep. Well, I don’t have a dedicated account rep and I’m still waiting on a good plan file from SAS so last week I set about creating my own. And I succeeded. But I’m not telling SAS because with all of the complexity of SAS, I may have missed something so I’m going to wait on a blessed and ordained plan file from SAS rather than my own creation.

I took a look at the XML plan file to see what it looked like and I found that the plan file’s contents really don’t look that complicated; there are 3 basic types of information in it:

  1. Component section. These are sections which identify a component (e.g. SAS Web Infrastructure Client) and give it a unique ID within the plan file.
  2. The properties section of a component section. Properties are sequentially numbered within the whole plan file so if a new component section is inserted; all properties in the entire file need to be renumbered. These properties for the most part have identical names and values between sections. There are a couple of components which have different props but overall, they’re the same for each component section.
  3. References to other components. This seems to be the way dependencies between components are defined. Here is an example of the first 3 types of information:
    1. Plan1
  4. Some components are hierarchically children of other components. I *think* that is because the parent component is dependent on the child but then again, number 3 above seemed to indicate.  Here is an example:
    1. Plan2

I now have a working installation of SAS BI Web Services for .Net but, like I said, I’m keeping my ticket open with SAS until I get an official one from SAS because I probably missed something.

Figuring out why SAS BI Web Services for .Net doesn’t work Part 2

Well, in my last post, I basically couldn’t get the WebServiceMaker.asmx service to work. I now have it working and the problem was because it was not installed properly. You see, SAS is like a bucket of Lego bricks. It contains dozens and dozens of modules and services which can be installed in what seems like endless permutations of arrangements. These arrangements are defined by an XML ‘plan file’ used by the SAS deployment wizard and  SAS support had sent me a couple of plan files which ‘appeared’ to work but did not. There are also some pre-defined plan files provided by the installation download which didn’t build the exact Lego castle I needed but got close. So, I created my own plan file from the plan files provided by SAS and these pre-defined ones. I got everything installed fine and I am able to call the services within WebServiceMaker.asmx without trouble but, given that there is precedence in the world of SAS for gettting an installation with no errors but not necessarily working, I worry.
 
I still can’t call ListWebServices in the WebServiceMaker.asmx file from my .Net console app but the Enterprise Manager on the SAS server can call it without trouble. I verified this using netmon on the server. Right now I’m at the point where I can deploy a SAS Stored Process as a web service using the Enterprise Manager and then attempt to call it from my .Net console app. When I called my test SAS web service, I got this error:
System.Web.Services.Protocols.SoapException: System.Web.Services.Protocols.SoapException: There was an error due to configuration of the middle tier.
 
Oh great. Now what? I thought for sure there was some issue with security (which seems to be plaguing me with the ListWebServices call). I poked around online a bit but didn’t really find anything so I decided to fire up Fiddler (such a wonderful tool) and see what my SOAP request and response looked like. Now I have some more information because in the SOAP response I see this information in the SOAP fault:
 
<Fault code=”4000″ xmlns=”http://support.sas.com/xml/namespace/biwebservices/webservicemaker-9.2“>
 <Exception message=”Folder path ‘/Users/sasadm/My Folder’ was not found or you may lack permission to view some part of the path.” />
</Fault>

 

 Well, that *kind of* makes sense. I created my stored process in the above SAS folder and the name of the folder leads me to believe there is one for every user of SAS. I was signed on as SASADM when I created the stored process and I sent the user sasadm in the Username token but maybe the identity attempting to run the service is other than sasadm.
 
What to do, what to do….
 
I tried calling the service without providing a WSE UsernameToken and got this response:
Could not establish a connection to the SAS server on the requested machine. Verify that the SAS server has been started with the -objectserver option or that the SAS spawner has been started. Verify that the port Combridge is attempting to connect to is the same as the port SAS (or the spawner) is listening on.
 

Figuring out why SAS BI Web Services for .Net doesn’t work – Part 1

For my current project, I have to document and define how to call web services on a Windows based SAS analytics server and so I’ve been working on installing a SAS virtual machine server which I can use in my development lab. I battled this installation for several days until I finally figured it out. Well, that’s not really true. I didn’ figure it out on my own, it took a ticket to SAS support to figure out how to install that monolithic beast of 13GB of installation files and laybrinths of documentation from http://support.sas.com.

So now I was at the point where I needed to create a web service on my SAS server. Creating a web service on SAS means that you take a SAS stored proc, not to be confused with an RDBMS stored proc, and use the SAS Enterprise Console to deploy it as a web service. When the Enterprise Console deploys a web service, it will call some services within a web service file named WebServiceMaker.asmx which got installed with SAS. I was excited that I had got to this point because after all, the SAS vendor themselves helped me to install everything I needed. I figured all I needed to do was deploy the SP as a web servce but when I went to deploy, I got this error: Microsoft.Web.Services3.Security.SecurityFault: The security token could not be authenticated or authorized —> System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)).

Well, so much for my faith in things automatically working if I get them installed with the support of the vendor.

I took a look at the WebServiceMaker.asmx and found it contained these 3 services:

  1. ListWebServices
  2. MakeWebService
  3. RemoveWebService

The SAS Enterprise Console indicated it was calling ListWebServices as the first step in deployment so I set about creating a quick .Net console application which called the same service to see what would happen. I knew that WebServiceMaker.asmx was secured with WSE 3.0 and that I wouldn’t be able to call it without passing sometype of credentials but I called it without creds anyway to see what would happen. Of course I got an exception but after researching the error and refreshing my knowledge of WSE, I realized that I needed to pass a UsernameToken in the WS-Security header. I then setup my console app to provide the UsernameToken with some credentials which I assumed would work. These credentials were the sasadm account and password., but I got the same error. Just to make sure I was covering all of the angles, I placed a completely random id and password in the token and called the service again and got the same error.

I then fired up the Fiddler HTTP debugger on my SAS server to get a look at the SOAP request coming out of the Enterprise Console. But I couldn’t get Fiddler to show me the HTTP packets going to and from localhost, even with the tips I found for solving this type of problem during a Google search. So I then installed Microsoft’s netmon tool and was able to get a packet trace of these communications. I had to save the netmon packet trace and open it up with Notepad in order to locate and extract the SOAP request, which Fiddler would have made a piece of cake, but I was able to get it and create an XML file with the SOAP request.

Next I fired up Fiddler on my development workstation and pulled the SOAP request which my console app was sending to the ListWebServices web service. I compared the two requests and found that the two were not syntactically the same but I *think* they were more or less functionaly the same. Here is a list of the diffferences in the two requests:

  1. .Net used a prefix of soap and the SAS EC (Enterprise Console) used a prefix of soapenv. I was sure this was the problem but according to this article: http://www.experts-exchange.com/Programming/Languages/Java/Q_22096454.html it is probably not.
  2. The SAS EC placed a funky looking id in the element. I had connected to the SAS EC as the sasadm user so I expected to see the text ‘sasaadm’ here but instead it placed this text: element: sasadm@!*(generatedpassworddomain)*! into the element. My .Net console app was placing the text sasadm into this element.
  3. The password being passed from the .Net application was cleartext. So the Type attribute of the element was ‘PasswordText’ . The SAS EC used the same Type attribute but the password was definitely not cleartext, it appeared to be some hexadecimal value. This document: http://www.oasis-open.org/committees/wss/documents/WSS-Username-02-0223-merged.pdf indicates a Type attribute of ‘PasswordText’ may not be an actual password but rather a password equivilant. The .Net application was sending a and a element within the element.

My next blog post will discuss my research of these differences. At this point, I don’t know that this will actually solve anything since, like I said, I believe the two requests are functionally the same and they both produce the same error from calling the web service.

Calling a WSE web service from a SQL Server CLR UDF

My current project is to document and lay the foundation for communicating with web services from several different clients. Well, that’s pretty much a common activity for most developers today but the twist here is that the web services are implemented with SAS Analytics Server v9.2 and one of the clients will be SQL Server 2005. 
 
I set about putting up a lab to work in consisting of a SQL 05 virtual machine, a SAS 9.2 virtual machine, and my development workstation. Writing a web service client in SQL Server is fairly straightforward: just write a CLR user defined function and install it. Here are some good articles on that:
http://www.databasejournal.com/features/mssql/article.php/3821271/article.htm
http://www.simple-talk.com/sql/t-sql-programming/practical-sql-server-2005-clr-assemblies/.
 
 
Implementing web services in SAS is a challenge and I’ve not gotten completely through it yet but I do know that SAS web services are secured using WSE 3.0.  So, while waiting on SAS support to help me get the SAS server up and going, I figured I would write a WSE secured service in .Net and work through the issues of calling in from a SQL UDF. Wahoo! I thought, as I’ve pretty much forgotten how to work with WSE since I picked up WCF. But 1/2 day later I found that web services are like remembering how to ride bikes and learning to ride that multi-wheeled, multi-geared contraption of spokes, levers, arms, and seats out of a Dr. Suess book called WCF didn’t make me forget how to ride my WSE road bike I keep in the garage.
 
I quickly wrote and deployed an ASMX web service secured with WCF and wrote a simple .Net console client which communicated with it. Great, I thought, now all I have to do is lift my code from the console app and drop it into a SQL UDF and I’ll be done. Alas, I found that a SQL UDF cannot have an associated WSE policy configuration file. You see, normally a WSE client has the luxury of a policy configuration file (by default named wse3PolicyCache.config) to maintain the necessary policies and their assertions for calling the service. However a SQL UDF comes packaged as an assembly .dll so there can be no configuration files associated with it.
 
When I first began to work through this problem of no configuration file, I thought there would be 2 paths I could take: creating the policies found in the configuration file in code or using the ConfigurationManager class to build a placebo of my console app’s physical configuration file in memory. I tried the second path first and quickly realized that it just wasn’t possible. So next I began to research the first route and stumbled across an MSDN article that did exactly what I wanted – http://msdn.microsoft.com/en-us/library/aa528807.aspx. After the heavanly light dimmed back down to normal and the choirs of angels stopped singing, I began to implement it and now I have a CLR UDF in my SQL Server which can call a WSE secured web service.