SOAP WS-Security header UsernameToken is element tenant valid? - soap

I've got a UsernameToken:
<wsse:UsernameToken>
<tenant>myTenant</tenant>
<wsse:Username>
USER
</wsse:Username>
<wsse:Password Type="blabla"
>PASSWORD
</wsse:Password>
</wsse:UsernameToken>
Now I've googled a lot but couldn't find out, if the element <tenant> is a valid element for the wsse:UsernameToken. I've found informations about the UsernameToken but there was no information about the tenant element.
My question is: Is this element valid and if yes, where can I find a specific declaration, how such a UsernameToken has to look like?

The schema http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd allows arbitrary elements under UsernameToken, so that looks like a custom extension. (Technically, wsse:Username should be first, so it probably won't validate, but semantically it's OK)

Related

Problem with validation of SOAP request with Zeep (python)

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.

How to compose SPML v2 'modify' request to delete object attribute

I need to maintain an Active Directory service via SPMLv2 SOAP requests to an Active Roles Server.
I'm trying to do something ostensibly simple: delete the telephoneNumber attribute from an object. I'd never heard of SPML before so I spent some time trying to understand the specification available on the list of OASIS open standards.
I've figured out how to do it if the value is known. For example, the payload below will delete the telephoneNumber attribute if it matches the value '12345', but not any other value.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:urn="urn:oasis:names:tc:SPML:2:0">
<soapenv:Header/>
<soapenv:Body>
<urn:modifyRequest xmlns:spml="urn:oasis:names:tc:SPML:2:0">
<urn:psoID ID="CN=Some User,OU=User,OU=Accounts,DC=someorganisation,DC=org"/>
<urn:modification>
<modification name="telephoneNumber" operation="delete" xmlns="urn:oasis:names:tc:DSML:2:0:core">
<value>12345</value>
</modification>
</urn:modification>
</urn:modifyRequest>
</soapenv:Body>
</soapenv:Envelope>
What I can't figure out is how to do this for an unspecified value, i.e. I don't care what the value is before I delete it, I just want to delete it. I suspect this has something to do with the SelectionType and I just need to use a 'match anything' selector, but I'm having trouble understanding the specification.
Any ideas?
Edit: To add to the confusion, I see we're using the DSMLv2 namespace for the modification. I just pulled this from a sample on the Active Roles SPML service documentation so I don't know how/why it works. The SPML specification does mention DSML but doesn't give any context around its usage as far as I can tell. It could actually be a vendor specific implementation.
Figured out a solution/work-around to this problem.
To delete the attribute without knowing its current value, you can simply include a 'replace' operation to first set some arbitrary value and include it in the same modify request as the 'delete' operation.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:urn="urn:oasis:names:tc:SPML:2:0">
<soapenv:Header/>
<soapenv:Body>
<urn:modifyRequest xmlns:spml="urn:oasis:names:tc:SPML:2:0">
<urn:psoID ID="CN=Some User,OU=User,OU=Accounts,DC=someorganisation,DC=org"/>
<urn:modification>
<modification name="telephoneNumber" operation="replace" xmlns="urn:oasis:names:tc:DSML:2:0:core">
<value>deleteMe</value>
</modification>
<modification name="telephoneNumber" operation="delete" xmlns="urn:oasis:names:tc:DSML:2:0:core">
<value>deleteMe</value>
</modification>
</urn:modification>
</urn:modifyRequest>
</soapenv:Body>
</soapenv:Envelope>

How to set the KeyIdentifier in the SecurityTokenReference to the Assertion ID with WSS4j

I'm a bit of a Noob with WSS4J so I'm hoping I'm missing something simple. I'm trying to create a Security header for an outbound SOAP message using WSS4j and CXF. As per the requirements the Assertion and the Timestamp have to be signed. The Assertion is done in a SAMLCallback and the Timestamp with the properties for the WSS4JOutInterceptor. All of that is straight forward. The hitch is instead of embedding the KeyInfo information for the Timestamp signature in the Signature, I need to reference the Assertion, which has the KeyInfo for it's Signature within it. So the Signature for the Timestamp's KeyInfo should look like this:
<ds:KeyInfo>
<wsse:SecurityTokenReference TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">3a4edd62-458e-4c3f-adc0-a9b505cb6284</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
Note how the KeyIdentifier points to and ID which is the ID of the Assertion. I've tried all the different WSHandlerConstants.SIG_KEY_ID options for the WSS4JOutInterceptor but all of them populate the KeyInfo element with the information from the certificate. I'm hoping there is some straightforward solution within the WSS4J framework for this. Otherwise I'm looking at writing an interceptor to hack up the SOAP header.
Thanks In Advance.
Yes it's possible, here's a test I pushed to CXF to show how it can be done:
https://github.com/apache/cxf/commit/5504cad08be5f2eb8396410618da68cb732b80e0

Adding SOAP implicit headers to WSDL

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.

Are attributes allowed in a SAML authentication request?

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.