6

I need to create a soap message that contains something like this:

<saml:Subject>     
    <saml:SubjectConfirmation>      
      <saml:ConfirmationMethod>
               urn:oasis:names:tc:SAML:1.0:cm:holder-of-key
      </saml:ConfirmationMethod>
      <saml:SubjectConfirmationData>
         <saml:Assertion AssertionID="123" 
                         IssueInstant="2018-12-27T17:59:36.284Z" 
                         Issuer="issuer" 
                         MajorVersion="1" 
                         MinorVersion="1">
            ...
         </saml:Assertion>
      </saml:SubjectConfirmationData>
   </saml:SubjectConfirmation>
</saml:Subject>

SubjectConfirmationData is of type AnyType.
I'm almost there with this code:

assertion_type = client.get_type("saml:AssertionType")
assertion = assertion_type(
    AssertionID = "123",
    MajorVersion = 1,
    MinorVersion = 1,
    Issuer = "issuer",
    IssueInstant = datetime.now())

subject_confirm = {
    'ConfirmationMethod': 'urn:oasis:names:tc:SAML:1.0:cm:holder-of-key',
    'SubjectConfirmationData': assertion
}

result = {
    'Subject': {
        'SubjectConfirmation': subject_confirm
    }
}

This is the result:

<saml:Subject>
  <saml:SubjectConfirmation>
    <saml:ConfirmationMethod>
          urn:oasis:names:tc:SAML:1.0:cm:holder-of-key
    </saml:ConfirmationMethod>
    <saml:SubjectConfirmationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        MajorVersion="1" 
        MinorVersion="1" 
        AssertionID="123" 
        Issuer="issuer" 
        IssueInstant="2018-12-31T13:10:00.471365"
        xsi:type="saml:AssertionType"/>
  </saml:SubjectConfirmation>
</saml:Subject>

The problem is that AssertionType needs to be wrapped in a seperate Assertion element and not inside SubjectConfirmationData. How can I add this extra element?

Update 1: I also tried something like this, but I get an error:

assertion_elem = client.get_element("saml:Assertion")
assertion = assertion_elem(
    AssertionID = "",
    MajorVersion = 1,
    MinorVersion = 1,
    Issuer = cert_subject,
    IssueInstant = datetime.now())

subj_conf_data_type = client.get_element("saml:SubjectConfirmationData")
subj_conf_data = xsd.AnyObject(assertion_elem, assertion)

subject_confirm = {
    'ConfirmationMethod': 'urn:oasis:names:tc:SAML:1.0:cm:holder-of-key',
    'SubjectConfirmationData': subj_conf_data,
    "KeyInfo": key_info
}

This is the error:

  File "...lib\site-packages\zeep\xsd\types\any.py", line 26, in render
    value.xsd_type.render(parent, value.value, None, render_path)
TypeError: render() takes from 3 to 4 positional arguments but 5 were given

Update 2:

I also tried this, but then I get a weird result:

assertion_elem = client.get_element("saml:Assertion")
assertion = assertion_elem(
    AssertionID = "",
    MajorVersion = 1,
    MinorVersion = 1,
    Issuer = cert_subject,
    IssueInstant = datetime.now())

subject_confirm = {
    'ConfirmationMethod': 'urn:oasis:names:tc:SAML:1.0:cm:holder-of-key',
    'SubjectConfirmationData': {
        'Assertion': assertion
    },
    "KeyInfo": key_info
}

This is the result:

<saml:Subject>
          <saml:SubjectConfirmation>
            <saml:ConfirmationMethod>
                urn:oasis:names:tc:SAML:1.0:cm:holder-of-key
            </saml:ConfirmationMethod>
            <saml:SubjectConfirmationData>{'Assertion': {
    'Conditions': None,
    'Advice': None,
    '_value_1': {
},
    'Signature': None,
    'MajorVersion': 1,
    'MinorVersion': 1,
    'AssertionID': '123',
    'Issuer': 'issuer',
    'IssueInstant': datetime.datetime(2018, 12, 31, 15, 2, 8, 518253)
}}</saml:SubjectConfirmationData>
          </saml:SubjectConfirmation>
        </saml:Subject>

Update 3:

I solved this by creating the complete header in a custom zeep plugin.
The headers are made with plain lxml and signed with xmlsec

roeland
  • 6,058
  • 7
  • 50
  • 67

0 Answers0