Looking for feedback on a first SAML implementation - saml

I've been tasked with designing a very simple SSO (single sign-on) process. My employer has specified that it should be implemented in SAML. I'd like to create messages that are absolutely as simple as possible while confirming to the SAML spec.
I'd be really grateful if some of you would look at my request and response messages and tell me if they make sense for my purpose, if they include anything that doesn't need to be there, and if they are missing anything that does need to be there.
Additionally, I'd like to know where in the response I should put additional information about the subject; in particular, the subject's email address.
The interaction needs to work as follows:
User requests service from service provider at this point, the service provider knows nothing about the user.
Service provider requests authentication for user from identity provider
User is authenticated/registered by identity provider
Identity provider responds to Service provider with authentication success message, PLUS user's email address.
Here's what I think the request should be:
<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="abc"
IssueInstant="1970-01-01T00:00:00.000Z"
Version="2.0"
AssertionConsumerServiceURL="http://www.IdentityProvider.com/loginPage">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
http://www.serviceprovider.com
</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">3f7b3dcf-1674-4ecd-92c8-1544f346baf8</saml:NameID>
</saml:Subject>
Here's what I think the response should be:
<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://www.serviceprovider.com/desitnationURL" ID="123" IssueInstant="2008-11-21T17:13:42.872Z" Version="2.0">
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0">
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">3f7b3dcf-1674-4ecd-92c8-1544f346baf8</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser">
<saml:SubjectConfirmationData InResponseTo="abc"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:AuthnStatement AuthnInstant="2008-11-21T17:13:42.899Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
So, again, my questions are:
Is this a valid SAML interaction?
Can either the request or response XML be simplified?
Where in the response should I put the subject's email address?
I really appreciate your help. Thanks so much!
-Morgan

You don't need a Subject in the request - looking at the specs, I think it can be this simple:
<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="abc" Version="2.0" IssueInstant="1970-01-01T00:00:00.000Z"
</samlp:AuthnRequest>
Omitting all the optional elements and attributes (Issuer, NameIDPolicy, AssertionConsumerServiceURL etc) means that your identity provider and service provider have agreed these up front, so they don't need to be specified in the AuthnRequest. If you're in control of both ends and you absolutely know that you'll never add another provider to the mix then this is a perfectly legal SAML request. It means "Authenticate the user who presents this via the mechanism we agreed".
Looking at the response, I think this is the minimal case:
<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="123" InResponseTo="abc" IssueInstant="2008-11-21T17:13:42.872Z"
Version="2.0">
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0">
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
user#example.com
</saml:NameID>
</saml:Subject>
<saml:AuthnStatement AuthnInstant="2008-11-21T17:13:42.899Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
You can send the user's email address as the NameID, and the AuthnStatement just carries the fact that the identity provider authenticated the user at the given time by the given mechanism. Again, this is stripped to the bone - we omit attributes and elements such as Destination and SubjectConfirmationMethod as they are superfluous to the use case.
So, this response says "This is user#example.com; he logged in with a password over a protected transport (SSL/TLS) at 17:13:42 on 11/21/2008".
You should take a look at the SAML 2.0 profiles spec for the exact mechanism for passing these back and forth. The AuthnRequest is usually compressed, encoded and passed as a URL parameter in a GET, while the simplest way to return the Response is via the POST binding - return an HTML page with a form whose target is the service provider, and which is submitted at page load time via some JavaScript.

Yes, it seems to be a SAML interaction
Your authentication response is rather simple now. Usually you would want to add more attributes in your assertions. And for the security sake, at least the response should be signed.
It uses to be set after the .In your case you do not have it, so after the status should be ok...
I would recommend you to create an account in http://www.ssocircle.com, and with one HTTP headers profiler (i.e. the classic and great LiveHttpHeaders) and a SAML2 debugger (Feide Rn SAML2 debugger thanks guys!) take a look at the request/response flow...
Hope it helps,
Luis
ps: if you want to take a look at a complete implementation SP/IdP: http://sourceforge.net/projects/spring-saml/files%2F0.1/

Related

Retrieve SOAP Request Valid from XSD

I have this kind of "guidelines" to call a SOAP service:
URL: http://80.211.113.172:8080/soap
No WSDL at all!
The XSD for request:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="/soap_serv" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAPENC="http://schemas.xmlsoap.org/soap/encoding/" SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:TRACKING>
<ldv xsi:type="xsd:string">2020.00.0070423</ldv>
<codcli xsi:nil="true"/>
<rifcli xsi:nil="true"/>
<anno_bl xsi:nil="true"/>
</ns1:TRACKING>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Does anyone know how to create a request object to send with SoapUI?
The XML you are showing isn't an XML Schema (or XSD file). As pointed out in the comment by #kimbert, that is actually an SOAP XML message. The payload inside it is what an XML instance of an XSD schema would be.
You have two options:
ask for a WSDL for the web service so that you can generate some client code to help you with the calls.
if a WSDL is not available, ask for better documentation for how to call the service. Not sure where you got that example but is the operation name TRACKING? Is the ns1 prefix pointing to the correct namespace? Should the elements inside the TRACKING element also be in this namespace? Note also that you are using codcli and rifcli in your call, when that guideline shows cod_cli and rif_cli. You most likely also need to send values for your elements, not have them null like that.
Not having a WSDL or valid up to date documentation for how the exchanged messages should look like will make things very difficult for you in interacting with the web service.

Why do i get "Wrong API base URL used" when pinging Adobe EchoSign Cloud by a SOAP request?

I am trying to access signed documents within the Adobe EchoSign Cloud. I have got an API key for authentication and used it in a testPing SOAP request like
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:api="http://api.echosign">
<soapenv:Header/>
<soapenv:Body>
<api:testPing>
<api:apiKey>myKeyhere</api:apiKey>
</api:testPing>
</soapenv:Body>
</soapenv:Envelope>
I sent this request to
https://secure.echosign.com/services/EchoSignDocumentService22
But as a result I only get
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>Wrong API base URL used</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
What does that message mean?
I suspect Cross-Domain but you should test it with fiddler. It reports you more clean data with your problem.
I found an important note in the Adobe documentation:
However, starting from version 22 of the Document API, all API calls must be made on a specific base URL obtained either using the OAuth workflow (the api_access_point parameter that is included with an authorization code) or by making a call to the getBaseUris method. The corresponding gateway can then be constructed by concatenating the base URL with "services/EchoSignDocumentService22". Calls made on the wrong base URL will result in an exception indicating that the wrong API base URL was used. Note that getBaseUris itself can be called on any appropriate gateway, including the one mentioned above.
Calling getBaseUris indeed returns another URI which then can be used for subsequent requests.

Correct envelope to use for a SOAP request?

I'm trying to integrate with the SOAP API specified here:
https://api.okpay.com/OkPayAPI?singleWsdl
https://api.okpay.com/OkPayAPI?wsdl
At the moment the code autogenerated from the wsdl files appears to be acting up, so I'm wondering what should be the correct envelope to send and where should I be sending it?
I used this service for testing: http://www.soapclient.com/soapmsg.html . For server address I put in:
https://api.okpay.com/
And for SOAP Message I put in what my code is currently generating:
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Body xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Get_Date_Time xmlns="https://api.okpay.com"></Get_Date_Time></Body></Envelope>
And the response appears to be a HTML code of a page, rather than an envelope response.
What would be the correct SOAP Action / Message to what Server Address to send in order to invoke the Get_Date_Time method as specified in the WSDL?
A couple of things:
The "Server Address" needs to point at the actual service, so in this case
https://api.okpay.com/OkPayAPI
The action can be seen in the WSDL, in this case
https://api.okpay.com/I_OkPayAPI/Get_Date_Time
Have a look at the WSDL and search for the action I gave above, that should give you an idea for how to find it for other actions.
With those two updates you should get back the response you expect:
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<Get_Date_TimeResponse xmlns="https://api.okpay.com">
<Get_Date_TimeResult>2015-01-31 17:52:37</Get_Date_TimeResult>
</Get_Date_TimeResponse>
</s:Body>
</s:Envelope>

Workday SOAP API : How to authenticate

I'm a newbie to workday soap api and I'm trying to figure out how to send a soap request to authenticate using SOAPUI.
Any suggestions, would be greatly appreciated.
Workday APIs use WS-Security for authentication.
Remember that the workday host is multi-tenant. So, you'll use the WSDL endpoint to connect to the correct server, and the user name field will contain both your user name and the tenant on that server.
User name format for SOAP Auth to Workday:
[user-name]#[tenant-name]
Example: youUserName#tenant6
Your workday account will need to be in the Integration Developer's group, as well.
You may need to adjust security and permissions beyond that to permit access to certain functional groups and domains which relate to the web service.
If you're using SoapUI, do the following:
Import the WSDL into a project.
In "Integration binding", go to settings.
On the "Service endpoints" tab, set the username as I've described above.
Set the password to your password in the tenant.
The WSS-Type should be set to PasswordText.
Now, you can make a request.
Not sure what exactly you are referring to. You authenticate implicitly - there is no separate request. The Workday API documentation is published here. You should read it. When you import the WSDL, for example in a .Net solution, it will give you access to various API classes.
For example, to connect to the Compensation API from an SSIS script task I use the following:
// Instantiate and configure compensation client
CompensationPortClient compClient = // I use custom binding - gives me more control
new CompensationPortClient(CompensationObjectFactory.getWorkdayBinding(),
new EndpointAddress(endpointURL));
compClient.ClientCredentials.UserName.UserName = userName;
compClient.ClientCredentials.UserName.Password = password;
(I created the CompensationObjectFactory to instantiate all the client-side API objects because the process is somewhat formulaic.)
Then you can make API calls with the client object, for example, query a one-time award:
Request_OneTime_Payment_RequestType request =
CompensationObjectFactory.getOneTimePaymentRequest(
CompensationObjectFactory.getBusinessProcessParameters(),
CompensationObjectFactory.getOneTimePaymentData(
planId, currency, amount, effDt, emplID, positionID));
Request_OneTime_Payment_ResponseType response =
compClient.Request_OneTime_Payment(request);
I finally figured this out after debugging a working SOAP UI example by installing wireshark and forcing my request over HTTP!
The previously posted header example did not work for me because it was missing some info. I noticed further that my captured header worked several hours later and I developed a theory that Workday was ignoring everything but username and password. So I tested the following and it worked:
<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="bogus">
<wsse:Username>user#tenant</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">[PASSWORD HERE]</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">bogus</wsse:Nonce>
<wsu:Created>2000-10-02T21:12:28.365Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
Best of luck if you are reading this. SOAP is a complete nightmare!
To add to the responses already here, you may need to also add in your credentials in the SOAP header, like so:
<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="bogus">
<wsse:Username>[user]#[tenant]</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">[PASSWORD HERE]</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">bogus</wsse:Nonce>
<wsu:Created>2000-10-02T21:12:28.365Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
Modifying "Request Properties" worked for me. The username is [user-name]#[tenant-name] as mentioned in #dbh's answer
Screenshot:

linkedin connect API gives error 401 - iphone

hi i am sending connect invitation by email using linkedin iphone api
Request xml:
<?xml version='1.0' encoding='UTF-8'?>
<mailbox-item>
<recipients>
<recipient>
<person path="/people/email=%#">
<first-name>%#</first-name>
<last-name>%#</last-name>
</person>
</recipient>
</recipients>
<subject>Invitation to Connect</subject>
<body>Please join my professional network on LinkedIn.</body>
<item-content>
<invitation-request>
<connect-type>friend</connect-type>
</invitation-request>
</item-content>
</mailbox-item>
where %# indicates dynamic value.
Content Type: text/xml
Request Method: POST
Response xml :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<error>
<status>401</status>
<timestamp>1342092385484</timestamp>
<request-id>FX9SK3ZVG9</request-id>
<error-code>0</error-code>
<message>[unauthorized]. OAU:076lb67kcfe2|dc01dc46-4d78-44d2-9f9b-49053b8094db|*01|*01:1342092534:iZ/mDlOL7eo4fGv2O/rQZKe8oCA=</message>
</error>
Also verified that authorization header is proper.
I have also debugged with oAuth debug console, i have enter same values in debug console, but signature key are different.
So is it a problem with signature key ??
I have also gone through forums.
But still i am not able to find an exact problem.
Any help will be appreciated.
Thanks
There's a sample LinkedIn iPhone client on github here:
https://github.com/synedra/LinkedIn-OAuth-Sample-Client
You should be able to use that to see what the proper headers look like. As you're on a macintosh (or wouldn't be developing for the iPhone), I strongly encourage you to use HTTPScoop to watch the traffic when using the simulator and see what the differences are between what your application is doing and what the sample client does.