I am trying to compose a SAML2 AuthnRequest for OpenAM. I have a URL that I can perform a get against that works, but am having problems composing this into the XHTML post form.
The working URL with query string is
http://internal.authhost.com:8080/opensso/idpssoinit?NameIDFormat=urn:oasis:names:tc:SAML:2.0:nameid-format:transient&metaAlias=%2FMYRealm%2Fidp&spEntityID=https%3A%2F%2Fsaml.salesforce.com&binding=urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Abindings%3AHTTP-POST&RelayState=webj_captureCustomerDetails
My html form looks like:
<form action="http://internal.authhost.com:8080/opensso/idpssoinit" method="post" target="new">
<input type="text" name="SAMLRequest" value="PHNhbWxwOkF1dGhuUmV..."></input>
<input type="text" name="RelayState" value="webj_captureCustomerDetails"></input>
<input type="submit"/>
</form>
with the value of SAMLRequest being the Base 64 encoded representation of
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_d7607d551380ac97853a6ff4907c4ef01219be97dd" Version="2.0"
IssueInstant="2008-05-27T07:46:06Z" ForceAuthn="true" IsPassive="false"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
AssertionConsumerServiceURL="https://cs4.salesforce.com/?saml=lkjhkljhkljhkjhlkjh"
ProviderName="https://saml.salesforce.com">
<saml:Issuer>https://saml.salesforce.com</saml:Issuer>
<samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
AllowCreate="true"/>
</samlp:AuthnRequest>
Issuing this form results in an error message from OpenAM stating "Service Provider ID is null"
I can immediately see that the XML does not contain the metaAlias=/MYRealm/idp argument, but the message suggests that it cannot find the spEntityID=https://saml.salesforce.com argument either.
Please advise on where these two properties (metaAlias and spEntityID) need to be specified in the XML.
A link to somewhere specifying how OpenAM COT / IdP configuration maps against SAML AuthnRequest message would also be appreciated.
Problem was that I was accessing the wrong URL, should have been hitting the spssoinit as it was Service Provider intitated SSO
Related
I am trying to test a Web API using Postman on a project which I have inherited from previous developers. All I know so far is that Authentication has been configured using ASP.Net Identity and Identity Server 4.0 which implements OAuth and issues short lived JSON Web Tokens (JWT) and Refresh Tokens.
If I navigate to the development website, log in (successfully), and use Chrome Developer Tools to inspect the initial log in request I can see that the body of the request contains a Form with 3 fields; userName, password and returnUrl. If I right-click on the request I can copy the request as cURL (bash) and in Postman I can import the data to create a new request. If I send the request I get a status 200 OK back and the response includes 6 cookies. However the body of the response contains an htlm page which Postman can't render and a message You need to enable JavaScript to run this app.
I'm lost now as to how I can use the response to authenticate a request for some data. Is the Token I need contained within one of the cookies? How do I extract the Token and use it within a request for some data? Any advice or suggestions would be very welcome.
Normally, with JavaScript enabled in the browser, <form> would be automatically posted to its' destination defined in action, using method. JavaScript would do somethign like the following:
window.addEventListener('load', function(){document.forms[0].submit();});
So without JavaScript, you would need to somehow parse the form that you received and recreate equivalent request.
The form, received upon successful login, contains data that should be sent back to your origin website, to authenticate the end-user.
For example, form's body contains hidden input fields, defined by OpenID protocol:
...
<input type='hidden' name='token_type' value='Bearer' />
<input type='hidden' name='expires_in' value='600' />
...
Form action attribute points back to sign-in endpoint on your website. For example:
<form method='post' action='https://{hostname:post}/signin-oidc'>
I wish to confirm that RelayState is required for a valid signed SAML logout request.
We have federated Microsoft's ADFS 2012 R2 with Oracle's Identity Federation where ADFS is the SP and OIF is the IdP. As a basis, we followed Integrating ADFS 2.0/3.0 SP with OIF IdP.
Everything works, except logout. We have another SP doing a logout and working with OIF. One difference we've found is that ADFS is not sending a RelayState parameter with its signed logout request, but the other SP is. I've been using SAMLTool's Validate Logout Req, where I input the following:
SAML Logout Request
EntityId of the source
Target URL, Destination of the Logout Request
SigAlg
Signature of the SAML Logout Request
X.509 cert of the source (to check Signature)
Ignore timing issues: checked
That then gives me the error:
In order to check Signature you must provide the RelayState parameter and the X.509 cert
If I input RelayState along with my other values in SAMLTool's Validate Logout Req then it reports back that my signed logout request is valid.
In the case of ADFS, because it does not have a RelayState parameter, I cannnot get SAMLTool's Validate Logout Req to say that a logout from ADFS is valid.
All that said, I cannot find anywhere in the SAML spec that says RelayState is required for a signed logout request. Can anyone confirm that it is required and back it up with documentation?
The LogoutRequest message would not have a reference to the RelayState parameter (as the other post suggests) but it is part of the so-called binding that is used to convey messages between SAML parties. Assuming that the Logout uses the HTTP-Redirect, HTTP-POST or Artifact binding, the spec allows for the sender to include a RelayState parameter and the receiver must then return that same RelayState parameter as a part of the response (as a way for the sender to keep state).
See section 3.4.3 RelayState of the SAML bindings document: https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf for the HTTP-Redirect binding:
3.4.3 RelayState
RelayState data MAY be included with a SAML protocol message transmitted with
this binding. The value MUST NOT exceed 80
bytes in length and SHOULD be integrity protected by the entity
creating the message independent of any other protections that may or
may not exist during message transmission. Signing is not realistic
given the space limitation, but because the value is exposed to
third-party tampering, the entity SHOULD ensure that the value has not
been tampered with by using a checksum, a pseudo-random value, or
similar means. If a SAML request message is accompanied by RelayState
data, then the SAML responder MUST return its SAML protocol response
using a binding that also supports a RelayState mechanism, and it MUST
place the exact data it received with the request into the
corresponding RelayState parameter in the response. If no such value
is included with a SAML request message, or if the SAML response
message is being generated without a corresponding request, then the
SAML responder MAY include RelayState data to be interpreted by the
recipient based on the use of a profile or prior agreement between the
parties
For the other bindings a similar section exists. So as #nzpcmad says: it's not mandatory to include it in a request.
Reading SAMLv2 core spec "Single Logout Protocol" XML schema for the SAML LogoutRequestType
<element name="LogoutRequest" type="samlp:LogoutRequestType" />
<complexType name="LogoutRequestType">
<complexContent>
<extension base="samlp:RequestAbstractType">
<sequence>
<choice>
<element ref="saml:BaseID" />
<element ref="saml:NameID" />
<element ref="saml:EncryptedID" />
</choice>
<element ref="samlp:SessionIndex" minOccurs="0" maxOccurs="unbounded" />
</sequence>
<attribute name="Reason" type="string" use="optional" />
<attribute name="NotOnOrAfter" type="dateTime" use="optional" />
</extension>
</complexContent>
</complexType>
<element name="SessionIndex" type="string" />
does not mention the RelayState Element. The "Single Logout Profile" in the SAMLv2 profile spec does also not mention RelayState.
I would say this suggests that RelayState (which is a request parameter, so can only be used in a front-channel binding) is not mandatory.
I'm currently developing an integration with PayPal's Payflow Pro Gateway. I'm sending a request to PayPal to get their "Secure Token" so that I can use that to do the real transaction. A sample I found on SO works via cURL, but the original HTML Form POST and RunScope tests I ran did not work.
Here is the cURL command:
curl https://pilot-payflowpro.paypal.com -kd "PARTNER=PayPal&VENDOR=*****&USER=*****&PWD=*****&TRXTYPE=A&AMT=40&CREATESECURETOKEN=Y&SECURETOKENID=*******&SILENTTRAN=TRUE"
Per the cURL documentation:
The -k option is:
"(SSL) This option explicitly allows curl to perform "insecure" SSL
connections and transfers. All SSL connections are attempted to be
made secure by using the CA certificate bundle installed by default.
This makes all connections considered "insecure" fail unless -k,
--insecure is used."
The -d option is:
"(HTTP) Sends the specified data in a POST request to the HTTP server,
in the same way that a browser does when a user has filled in an HTML
form and presses the submit button. This will cause curl to pass the
data to the server using the content-type
application/x-www-form-urlencoded. Compare to -F, --form."
-d, --data is the same as --data-ascii. To post data purely binary, you should instead use the --data-binary option. To URL-encode the
value of a form field you may use --data-urlencode.
If any of these options is used more than once on the same command
line, the data pieces specified will be merged together with a
separating &-symbol. Thus, using '-d name=daniel -d skill=lousy' would
generate a post chunk that looks like 'name=daniel&skill=lousy'.
If you start the data with the letter #, the rest should be a file
name to read the data from, or - if you want curl to read the data
from stdin. The contents of the file must already be URL-encoded.
Multiple files can also be specified. Posting data from a file named
'foobar' would thus be done with --data #foobar. When --data is told
to read from a file like that, carriage returns and newlines will be
stripped out.
That works great and returns this response:
RESULT=0&SECURETOKEN=*****&SECURETOKENID=*****&RESPMSG=Approved
HTML Form POST
However, what I perceive to be the same request fails in the following HTML form POST:
<input type="hidden" name="TRXTYPE" value="A" />
<input type="hidden" name="SILENTTRAN" value="TRUE" />
<input type="hidden" name="AMT" value="40" />
<input type="hidden" name="CREATESECURETOKEN" value="Y" />
<input type="hidden" name="SECURETOKENID" value="*****" />
<input type="submit" value="Get Secure Token" />
That gives me "The connection was reset" in FireFox.
I also tried using jQuery to POST the data using $.ajax(), but I received a 200 response with no data in it.
Runscope
When I enter the above parameters into RunScope, I get:
RESULT=1&SECURETOKENID=*****&RESPMSG=User authentication failed
Which doesn't make any sense!
I was thinking that PayPal is either doing something with examining the user agent, or request headers, but I don't have any real idea. Can anyone shed some light on this behavior?
WARNING:root:403 POST /upload (127.0.0.1): '_xsrf' argument missing from POST
WARNING:root:403 POST /upload (127.0.0.1) 2.95ms
What did I deal with?
The server to which you are attempting to upload a file does not allow uploads without the appropriate XSRF value. This value is supplied by per-user cookie.
Apart from having the appropriate cookie, you must ensure that your upload form contains a field for this value. Tornado provides a xsrf_form_html() function which you'd call from your form, e.g.:
<form action="/upload" method="post">
{{ xsrf_form_html() }}
<input type="text" name="foo"/>
<input type="submit" value="Upload"/>
</form>
References:
http://en.wikipedia.org/wiki/Cross-site_request_forgery
http://www.tornadoweb.org/documentation/overview.html?highlight=forgery#cross-site-request-forgery-protection
<form method="POST" action="/index?key=1">
<input type="text" name="another_key" value="2" />
</form>
When I submit such a form and trying to fetch the GET parameter with CGI->new->param('key'),
it doesn't work..
Can CGI work when both GET and POST parameters exist?
For a POST request, CGI's param method will only get post parameters, but there is an alternate url_param method that will provide the "GET" parameters from the url.
This can be very helpful for file uploads; if the post request is too large, it will be entirely discarded, but the url parameters can tell you what kind of upload it was so you can show the user an error message in the correct context.