Is it possible to send attributes in a SAML authentication request?
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="aaf23196-1773-2113-474a-fe114412ab72"
Version="2.0"
IssueInstant="2004-12-05T09:21:59Z"
AssertionConsumerServiceIndex="0"
AttributeConsumingServiceIndex="0">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="true"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>
Technically, yes, it is possible, since AuthnRequest can contain an Extensions element, which can contain anything - see the SAML 'core' spec: AuthnRequest (section 3.4.1) is derived from RequestAbstractType (section 3.2.1) which has an optional Extensions. The sender and recipient would have to agree on the syntax and semantics of data sent this way.
I can't see a more 'conventional' way to do this, since Attributes are usually in Assertions, rather than AuthnRequests.
There is a case where attributes are to be part of auth request.
so that we can get that attribute name from request to construct response assertion with the same.
because service provider validates the response by comparing the attribute names.we can take the example of Salesforce as service provider, where the same happens.
Related
I have a client where the NotOnOrAfter condition in the SAML response is always 5 minutes after login. The IdP is Okta and the SP is Shibboleth SP 3. I am not seeing anything on the Shibboleth side that adds this condition. I'm being told Okta isn't sending this, but I'm skeptical.
I even tried adding Ignore PolicyRules for it, but we still have a 5 minute timeout.
<PolicyRule type="Ignore">saml2:NotOnOrAfter</PolicyRule>
Does the IdP or SP add that timeout? Where can it be changed?
Here is the excerpt from the SAML response:
<saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">userid</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="_bb4020da3209979ab2c018077ec29894"
NotOnOrAfter="2023-02-07T21:25:38.782Z"
Recipient=https://sitename.com/Shibboleth.sso/SAML2/POST/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
NotBefore="2023-02-07T21:15:38.782Z"
NotOnOrAfter="2023-02-07T21:25:38.782Z">
<saml2:AudienceRestriction>
<saml2:Audience>https://sitename.com/shibboleth</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>```
I might be wrong, but it should correspond to your authentication policy (sign-on) session lifetime applied during user authentication.
I have problems to get SOAP request through Zeep, I get a (client) validation error... I have also tested with SoapUI and that does NOT give me the same validation error...
The specification below is from the server... Based on that specification, the OrderStatus and SynchStatus are needed to perform the request.
<soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/ xmlns:web="WebServiceProvider">
<soapenv:Header/>
<soapenv:Body>
<web:Order_Get>
<!--Optional:-->
<web:orderOptions>
<web:FromDate>?</web:FromDate>
<web:ToDate>?</web:ToDate>
<web:OrderStatus>?</web:OrderStatus>
<web:SynchStatus>?</web:SynchStatus>
<!--Optional:-->
<web:OrderNumber>?</web:OrderNumber>
<web:FromOrderNumberToLastRecieved>?</web:FromOrderNumberToLastRecieved>
<web:PaymentStatus>?</web:PaymentStatus>
</web:orderOptions>
</web:Order_Get>
</soapenv:Body>
</soapenv:Envelope>
However, executing this from the SoapUI without OrderStatus and SynchStatus will give me a list of all the orders for the specified dates:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="WebServiceProvider">
<soapenv:Header/>
<soapenv:Body>
<web:Order_Get>
<web:orderOptions>
<web:FromDate>2021-03-30</web:FromDate>
<web:ToDate>2021-03-31</web:ToDate>
</web:orderOptions>
</web:Order_Get>
</soapenv:Body>
</soapenv:Envelope>
I want to do the same with Zeep (https://github.com/mvantellingen/python-zeep) but the client validation fails...
I initiate the request with the following code:
api_url = 'https://abc.se/Webservice20/v3.0/webservice.asmx?WSDL'
session.auth = HTTPDigestAuth(username, password)
api = Client(api_url, transport=Transport(session=session))
And then I try to execute the following request:
order_options = {
'FromDate': '2021-03-30',
'ToDate': '2021-03-31',
}
orders = api.service.Order_Get(orderOptions=order_options)
This will result in the following error:
zeep.exceptions.ValidationError: Missing element OrderStatus (Order_Get.orderOptions.OrderStatus)
If I add OrderStatus to the request, I will get a validation error saying that SynchStatus is missing. When that has been added as well, the request is sent to the server.
I.e. it seems like the zeep client is more strict with regards to validating the data in the request than what the server is... Is there a way to force the client to skip this validation?
Many thanks in advance!
Searched a bit more and found a workaround in this post: Getting zeep.exceptions.ValidationError: Missing element for method that worked with suds
So the solution in my case looks like this:
from zeep import xsd
...
order_options = {
'FromDate': '2021-03-30',
'ToDate': '2021-03-31',
'OrderStatus': xsd.SkipValue,
'SynchStatus': xsd.SkipValue,
}
response = api.service.Order_Get(orderOptions=order_options)
This will block zeep from doing client side validation of the parameters OrderStatus and SynchStatus.
it seems like the zeep client is more strict with regards to validating the data in the request than what the server is...
Looks like it.
Looking at the request SoapUI generates based on the WSDL, the two fields you mention are mandatory:
<web:orderOptions>
<web:FromDate>?</web:FromDate>
<web:ToDate>?</web:ToDate>
<web:OrderStatus>?</web:OrderStatus>
<web:SynchStatus>?</web:SynchStatus>
<!--Optional:-->
<web:OrderNumber>?</web:OrderNumber>
<web:FromOrderNumberToLastRecieved>?</web:FromOrderNumberToLastRecieved>
<web:PaymentStatus>?</web:PaymentStatus>
</web:orderOptions>
So the error that the zeep client displays is correct. Zeep inspects the WSDL and generates the corresponding code to use the types in the contract. Your WSDL contract says that OrderStatus and SynchStatus are mandatory. The fact that the server doesn't validate them shows a problem: the web service isn't respecting it's own documented contract
The WSDL and the behavior of the web service should be the same. I suggest you contact the web service owners and ask about this behavior. It might be a validation missing on the server and what you get is just some side effect of that, or the behavior is intentional but someone forgot to update the WSDL to say that you can also make the call without those parameters.
Meanwhile, the workaround is very simple. Download the WSDL, change it to make the two fields optional, then feed this changed WSDL to zeep for it to generate the code, instead of using the original WSDL. You should however clarify this with the web service provider. If it's indeed a neglect of someone, this might be spotted at some point and fixed, making your workaround call fail a server validation because of the missing fields.
> <samlp:LogoutRequest ID="_36167d94-d868-4c04-aee3-8bbd4ed91317"
> Version="2.0" IssueInstant="2017-01-05T16:21:55.704Z"
> Destination="https://werain.me/"
> xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><Issuer
> xmlns="urn:oasis:names:tc:SAML:2.0:assertion">urn:federation:MicrosoftOnline</Issuer><NameID
> Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
> xmlns="urn:oasis:names:tc:SAML:2.0:assertion">4948f6ce-4e3b-4538-b284-1461f9379b48</NameID><samlp:SessionIndex>_eafbb730-b590-0134-a918-00d202739c81</samlp:SessionIndex></samlp:LogoutRequest>
Given my, Logout Request looks like this. If I have to verify the Logout request do I have to construct the string that looks like this (i.e raw string value)
SAMLRequest=<samlp:LogoutRequest ID="_36167d94-d868-4c04-aee3-8bbd4ed91317" ... </samlp:LogoutRequest>&SigAlg=http://www.w3.org/2000/09/xmldsig#rsa-sha1
and then verify the signature for the above string or should I encode the SAMLRequest and SigAlg value
i.e
SAMLRequest=Base64 encode value or raw logout request&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1
Reason for this confusion is
SAML spec says extracted from here
A string consisting of the concatenation of the raw, unencoded XML
making up the SAML protocol message (NOT the base64-encoded version),
But OneSAML Create a signature with the Base64 encode version of the request (logout request). Have a look at here
Not sure what is the correct implementation I have to use to verify the signature.
NOTE: HTTP-Redirect BINDING.
Your link and quote is not related with the HTTP-Redirect binding.
Check the 3.4.4.1 section of
https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf
Onelogin's SAML toolkits implement signatures following the standard.
You can see for example that the implementation of simpleSAMLphp build the signature on the Redirect binding on the same way:
https://github.com/simplesamlphp/saml2/blob/master/src/SAML2/HTTPRedirect.php#L22
Or opensaml
https://github.com/apigee/java-opensaml2/blob/master/src/main/java/org/opensaml/saml2/binding/encoding/HTTPRedirectDeflateEncoder.java#L162
You can play signing and validating SAML Messages with:
https://www.samltool.com/online_tools.php
I am using spring-security saml extension to implement the IDP initiated SSO for my application. I am using https protocol and signature/encryption is ON. I dont need SLO/SP-Initiated SSO.
On the transport layer's encryption/decryption (because using HTTPS protocol), I am fine as My web container (SP one) is going to take care of the decryption part. And this certificate could be different then SP's certifiate.
At the SP end, I need the IDP's public key to verify the signature on SAMLAuthResponse Msg, which I have as part of the IDP's metadata file...so no issues here.
Couple of qns:
For decryption of the SAMLAuthResponse Msg, Do I need SP's
certificate's private key?
And If I need the private key, how to
create the bean definition for keyManager when I have the jks file,
jks-pwd, alias, but no pwd for privatekey? Can I pass the empty string (as "") in the password field in the alias-password value pair.
You can skip usage of private key in this case. You can find detail on how to use Spring SAML without keystore in the manual chapter 8.1:
In case your application doesn't need to create digital signatures
and/or decrypt incoming messages, it is possible to use an empty
implementation of the keystore which doesn't require any JKS file -
org.springframework.security.saml.key.EmptyKeyManager. This can be the
case for example when using only IDP-Initialized single sign-on.
Please note that when using the EmptyKeyManager some of Spring SAML
features will be unavailable. This includes at least SP-initialized
Single Sign-on, Single Logout, usage of additional keys in
ExtendedMetadata and verification of metadata signatures. Use the
following bean in order to initialize the EmptyKeyManager:
<bean id="keyManager" class="org.springframework.security.saml.key.EmptyKeyManager"/>
My question is similar to this. How To Pass Soap Header When WSDL Doesn't Define It? But is different.
For a web service I use, all methods need authentication which is sent in cleartext inside a SOAP header. However, my WSDL doesn't include any soap header information. I have a custom platform tool which I must use to generate code from the WSDL. Since the header info is not available, am unable to use the generated class directly - I do not want to manually modify the code to accommodate the header.
I tried specifying the SOAP header in the WSDL but I failed to get the correct namespaces. The WSDL is here https://stage.totalcheck.sensis.com.au/service/webservice?wsdl and the SOAP header is as follows:
<soapenv:Header>
<wsse:Security>
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
Can someone help me? Thanks!
From a conceptual point of view, WSDL is not supposed to define headers. WSDL is only for defining the functional aspects of a service, like operations, messages, binding and endpoints. Messages and bindings define how the payload of messages should be encoded and formatted.
The headers of SOAP messages however do not belong to the payload. They are typically used for configuring non-functional properties of a SOAP processor. Security is such a non-functional property. The functional aspect of the payload is not affected. It is only assured that the communication is secured and the WS tool stack, not the service implementation, should take care of that.
So the missing piece is now a standard that allows for attaching some non-functional requirements to WSDL services, so that code generators can automatically derive which headers need to be sent and/or understand in order to fulfill the non-functional property as desired -- without having to manually deal with header fields. This standard exists and is called WS-Policy. A policy contains typically a set of alternatives that expose a set of requirements that both, provider and consumer should be able to fulfill. When two services are supposed to interact with each other, both policies are taken and a so called "effective policy" is calculated. It defines the common non-functional requirements. Using this information, provider and consumer can configure themselves to add required headers, like the WS-Security headers. WS-SecurityPolicy also defines a set of policies that can be used. WS-PolicyAttachment defines how such policies can be attached to a WSDL.
There are code generators that can deal with WS-Policies, e.g. Metro or Axis2
You can add soap header information to method calls by decorating the methods in the proxy class generated from the wsdl with the SoapHeader attribute.
For example wsdl.exe will generate client proxy class Reference.cs for the web service reference when you "Add Web Reference". In the link mentioned above https://stage.totalcheck.sensis.com.au/service/webservice?wsdl there is a message suggestAddress which will translate to a method in the generated reference.cs client proxy code file when you add a web reference from visual studio. By default when this method is called there will be no Header in the soap envelope. To add a SoapHeader to the envelope for this request add a [SoapHeader("Security")] attribute to the top of the SuggestAddress method in the Reference.cs generated class, where "Security" is a class that inherits from SoapHeader base class.
Example for the above required Security SoapHeader you would create the following classes,
public partial class Security : SoapHeader
{
public UserNameToken UserNameToken { get; set; }
}
public partial class UserNameToken
{
public string UserName { get; set; }
public string Password { get; set; }
}
Then you would decorate the SuggestAddress method in the reference.cs like followed,
[SoapHeader("Security")]
public suggestAddressesResult suggestAddresses([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] addressSearch search) {
object[] results = this.Invoke("suggestAddresses", new object[] {search});
return ((suggestAddressesResult)(results[0]));
}
This will ensure that every envelope created when method suggestAddress is invoked contains a security header that looks like the one mentioned above,
<soapenv:Header>
<wsse:Security>
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
Key for me in using this question to help myself was recognizing (as some pointed out) that the headers in question are those of WS-Security standard.
If your proxy generating tool is "custom" it seems logical that you might have a switch to automatically add the headers for WS-Security. However, if you're using WSDL.exe ("Add Web Reference" in Visual Studio), consider svcutil.exe instead ("Add Service Reference").
If you use a WCF proxy, you can override the given config and allow WCF to add the headers for you:
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
From there you can specify the password:
RemoteSvcProxy.TheirClient client = new RemoteSvcProxy.TheirClient();
client.ClientCredentials.UserName.UserName = "uname";
client.ClientCredentials.UserName.Password = "pwd";
I don't know what your custom tool is, but perhaps the framework it's based on also has similar configuration options.