Geeks With Blogs
Martin Abbott not just .net
I recently worked on a project where I had to develop a web service to perform single sign on (SSO) with the Salesforce.com platform.
 
The motivation behind this was that the customer wished to ensure that their security mechanism was enforced. In a fairly typical scenario the user would sign on to the customer system and click a link that took them to Salesforce.com which would recognise the username as an SSO user and redirect to a customer web service for authentication.
 
As the customer made heavy use of WCF already, naturally they wished to provide a WCF service out of the estate to perform this SSO function.
 
That was when the trouble started since the only implementations that I could find were all based on good old ASMX services.
 
The authentication web service had to adhere to the WSDL provided by Salesforce. Since the Salesforce platform does not support the latest SOAP and WS-* standards, the service needed to be made interoperable with SOAP 1.1 clients (i.e., the Salesforce platform) using the WCF basicHttpBinding.
 
In order to make it fully compliant with the platform, other actions needed to be taken such as making the use of Message Contracts, ensuring binding, service and service behaviour namespaces are consistent, ensuring that no XSD imports will be created by using a technique to place XSD schemas inline with the WSDL and by ensuring the SOAP actions in the WSDL match those required by the Salesforce.com platform.
 
Web Methods
 
The service defined by the WSDL required the creation of a single web method:
 
public AuthenticateResponse Authenticate(AuthenticateRequest request)
 
AuthenticateResponse and AuthenticateRequest were message contracts that conform to the requirements of the Salesforce.com WSDL file.
 
Message Contracts
 
The use of Message Contracts ensured that the request to and response from the service are strongly typed.
 
The parameters for the Message Contracts are.
 
Parameter
Parameter Type
Description
username
String
Username of user requiring authentication
password
String
Password or token for user
sourceIp
String
IP address of user machine
Any
System.Xml.XmlElement[]
Any additional information to help authenticate, but not needed in this case, so pass null 
 
Parameters for AuthenticateRequest Message Contract
 
Parameter
Parameter Type
Description
Authenticate
Bool
Success or failure
 
Parameters for AuthenticateResponse Message Contract
 
It was also necessary to use the WrapperName property of the MessageContract attribute
 
For AuthenticateRequest use  WrapperName = "Authenticate"
 
For AuthenticateResponse use  WrapperName = "AuthenticateResult"
 
Namespaces and Imports
 
To ensure there were be no namespace conflicts, which would result in the creation of <wsdl:import/> elements in the WSDL, it was important to have all namespaces for binding, endpoint and service consistent. This was be achieved through the use of the bindingNamespace attribute in configuration, and the ServiceContract and ServiceBehavior attributes on the service interface and service implementation respectively. Setting all these to use the same namespace eliminated the <wsdl:import/> elements.
 
When creating services using WCF, typically any XSD schemas representing request and response types are imported in to the WSDL using an <xsd:import/> element. However, this approach reduces interoperability and moreover did not work with the Salesforce.com platform.
 
Interoperability was achieved through the use of a custom endpoint behaviour using a well established technique involving the creation of one class that implements the IWsdlExportExtension and IEndpointBehavior interfaces, and another class that instantiates the custom behaviour class. For an example see this article.
 
Actions
 
It was necessary to ensure that the SOAP actions match those required by Salesforce.com.
 
This was be achieved by setting the SOAP actions on the OperationContractAttribute.
 
[OperationContractAttribute(Action = "", ReplyAction = "")]
 
This was necessary because if not set WCF creates an Action and ReplyAction based on the service namespace and the operation name. By explicitly defining the actions in code, you ensure a match with the required actions.
 
Testing and Finishing Off
 
Once the service is done I tested it just using a simple console application to ensure that the returned values of true or false were correct under the various scenarios I had to use.
 
To test with the SSO process the service needed to be publicly deployed as the SSO process requires a public URL. To close the loop from the Salesforce side of things, I needed to set the test user up to be an SSO user and set the SSO gateway to the public URL of my service.
 
The final piece of the puzzle is to create a web form that posts your login data to the appropriate Salesforce login page. There is a sample provided by Salesforce that shows you how to do this along with information about the actual process, and you can get this here.
 
So, once all this work had been done the Salesforce.com SSO process worked fine!
 
I have created a sanitized version of the service I used for you to download here so hopefully that will get you started on the service itself.
 
Posted on Friday, May 8, 2009 3:38 PM WCF | Back to top


Comments on this post: Single sign on with Salesforce.com and WCF

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Thanks Martin, That helps a bit. I've received the same request to implement the sso for salesforce.. problem is i've never worked with webservices and SOAP before I have learned it but that was simple stuff. Are you able to give some steps on where to start? Sample code provided by SalesForce is not production ready and hence i cant check what works and what doesnt.. and monitor the requests and response. I dont know where to go to start debugging the sample.. Its frustrating. Please help.

Thanks heaps,
Neha
Left by Neha on May 22, 2009 5:07 AM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Hi Neha,

The best thing to do is code up your Authenticate service as above (obviously doing anything you need regarding encryption and decryption of login details if necessary) and then write a simple test harness using a console app. To do this just write your service, publish it locally on your machine (or start it in debug) and then start a console app and add a Service Reference. Then just create the proxy client and call Authenticate passing in the relevant information (I always passed null for the final field as it wasn't required in my case).

That should give you an indication of whether the service is returning the true/false you expect given the input.

Regarding putting it together there are a few things:

1. The user needs to be a SSO user in SDFC
2. You need a web page to redirect the login request
3. Your SSO service needs to be on the Internet

The first one is simple enough, you just need to set the user credentials in SDFC for the incoming user to use SSO. This is done via the admin pages.

For the second point I simply used an ASP.NET application to write the username and password in to the hidden fields (just a really basic Response.Write) and used JavaScript (body onload) to automatically submit the form once the page had loaded.

The key fields are "un" for username, "pw" for password.

In my case I had a third party delivering an SDFC app, so the form action URL was not the standard SDFC login, but that may be different in your case.

Beyond this, providing a proper logout page is useful so SDFC knows where to redirect once the user logs out, the startURL is the SDFC page on which the user should "land" and the ssoStartPage I think I set to the redirect page.

Once this was done and the authentication service was publicly available (using SSL) then hopefully it should work.

My advice would be to develop the thing and put it on the Internet and then use your test harness pointed at the public URL to test it. If that works and the service is configured as in the article it should work with the SSO process, the only issue may then be the settings in your redirection page.

HTH.
Left by Martin Abbott on May 22, 2009 10:25 AM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Hi Martin,

Thank you sooooo much for replying. I'm trying to pass null for XML and empty string for IP.. but the webservice doesnt take null. Whats the workaround for that? I triend modifiying the Authenticate function but that doesnt seems to take affect in my consol app... Not sure what I'm doing wrong.
Please point me in the right direction if you have time.

Thanks heaps again,
Neha
Left by Neha on May 25, 2009 4:05 AM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Hi Neha,

I've updated the article, it now has a sample for the service that should get you started.

BTW, in a real scenario you will only set the username and password as the IP is passed from the browser request.

Also there is a link back to the SSO page on the force.com dev site that contains some information on how to set up your Salesforce user and a sample for the web form that you need to use to post information to the Salesforce login.

HTH.
Left by Martin Abbott on May 26, 2009 8:32 AM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Thanks heaps Martin.. I can get the web service running.. but I'm back to where i started, I can't use the webservice function to Authenticate as it requires the XML..

Dont know why Its not an optional parameter in webservice and Dont know How to make it an optional parameter, I've tried but failed.. and hence I'm stuck.

It wont let me pass Null for XML and Hence I cant Authenticate. It requires 1 dimensional array of System.XML.XMLElements.

I'm not sure what I'm doing wrong! We have the SSO properly configured on Salesforce side of things. Jsut cant communicate with it.

Any help will be very much appreciated

Thank you sooooo much again for all your help so far.
Left by Neha on Jun 03, 2009 2:42 AM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Hi Neha,

I have to confess I'm a bit confused as well.

Taking my sample I have just created a console application, added a service reference to my service (running in debug) and the service returns fine using null for the final parameter:

SSOService.SSOSoapClient client = new SDFCTest.SSOService.SSOSoapClient();
bool retVal = client.Authenticate("username", "password", "100.100.100.100", null);
Console.WriteLine(retVal.ToString());
Console.ReadLine();

So given that, I'm not really sure what to suggest. You could try adding a MessageInspector behaviour (Google for "WCF MessageInspector" for code on how to do this) to save the incoming message to check that it is indeed what you think it should be.

Beyond that do you know whether the service operation is actually executing? You could add some logging to a file or Event Log in your service for this.

For now I'd certainly recommend not doing any "actual" authentication, just get the connectivity sorted maybe just using the service in the sample and test for it returning both true and false to test the scenario.

I have to say the service will actually accept null in all the parameters and still return so it may be something that SDFC is sending as a result of your login request, and the information that is being included in the form post to the SDFC login page which simply gets played back to the Authenticate method. Again the MessageInspector behaviour should help you out there as you'll be able to save the incoming SOAP request and examine it.

Let me know how you get on.
Left by Martin Abbott on Jun 03, 2009 11:35 AM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Hi Martin,
My question is:
I already got ws working when I am passing in and pw, but how can I retrive them in real life?
I mean id and password ( no hardcode)
Left by Igor on Aug 18, 2009 12:34 PM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Hi Igor,

I am not sure what you mean regarding retrieving the id and password, could you elaborate?

Obviously they are available within the web service, so I'm not sure where you mean you need to get at it.
Left by Martin Abbott on Aug 21, 2009 9:31 AM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Martin,

Thanks for this info, but it looks like the link that you posted to your sample no longer works. I'd like to see a bit more of the detail that you used to get the proper xml for the service request/response with WCF.

Thanks,
Mark
Left by Mark on Feb 22, 2010 6:29 PM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Hi Mark,

Hmm, this used to work! Not sure what they done with the link on the site.

If you use the Contact form and give me your email address I'll try to dig out the file and send it on.

Cheers,

Martin
Left by Martin Abbott on Feb 23, 2010 1:04 PM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Martin,
Can you please give the link to the sample code. The link posted here is not working thanks
Left by chen on Apr 27, 2010 11:36 PM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Dear Martin,

It will be great help if you shared the shared the above example. I am unable to implement SSO using WCF.

Left by Nilesh Narkhede on Apr 29, 2011 8:01 AM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
can i develop sso for more than one user by useing Delegated Authentication. if yes how we will develop.

<?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope
11
About Single Sign-Onxmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<Authenticate xmlns="urn:authentication.soap.sforce.com">
<username>sampleuser@sample.org</username>
<password>myPassword99</password>
<sourceIp>1.2.3.4</sourceIp>
</Authenticate>
</soapenv:Body>
</soapenv:Envelope>

in this how we will give more than one user need sso

Any help will be very much appreciated
Left by babloo on Nov 14, 2012 7:52 AM

# re: Single sign on with Salesforce.com and WCF
Requesting Gravatar...
Hi Martin,
I am trying to get this to work. Since the examples that are provided by salesforce and the one here are old, do you have an update of this with the new version?

Also, if you dont mind me asking, what kind of logic can we have in the authentication method. salesforce example has some token creation with encrypt/decrypt. so was not sure what it is expecting.

Thanks a lot for your help.
Knut
Left by Knut on Jul 12, 2017 5:00 PM

Your comment:
 (will show your gravatar)


Copyright © martinabbott | Powered by: GeeksWithBlogs.net