cancel
Showing results for 
Search instead for 
Did you mean: 

Create SAML2.0 External Request in ABAP

02-20-2025 1:53 PM
javier_alonso63 Participant
523 views 1 comments Go to solution
0 Likes
SAP Managed Tags
Labels
SAMLXML
Subscribe

I am trying to develop an integration scenario which requires a call to an external Electronic Identification service using SAML 2.0 protocol. I need to create an XML message in eIDAS format, which should be signed using SAML protocol, in order to make an authetication request.

This is a request message example provided by the WebService (which is called Cl@ve 2.0) .

<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:eidas="http://eidas.europa.eu/saml-extensions" xmlns:eidas-natural="http://eidas.europa.eu/attributes/naturalperson" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AssertionConsumerServiceURL="https://pre-pasarela.clave.gob.es/SP2/ReturnPage" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" Destination="https://se-pasarela.clave.gob.es/Proxy2/ServiceProvider" ForceAuthn="false" ID="_r1LZ7loli5ZpGJtb6avNQiVvGFX1qgenzkP6v--cWHCNZBIcjn8EtHe4l2xB1E_" IsPassive="false" IssueInstant="2018-07-30T07:32:22.571Z" ProviderName="S2833002E_E04975701;Demo-SP" Version="2.0">
	<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
		<ds:SignedInfo>
			<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
			<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"/>
			<ds:Reference URI="#_r1LZ7loli5ZpGJtb6avNQiVvGFX1qgenzkP6v--cWHCNZBIcjn8EtHe4l2xB1E_">
				<ds:Transforms>
					<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
					<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
						<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="eidas-natural"/>
					</ds:Transform>
				</ds:Transforms>
				<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512"/>
				<ds:DigestValue>WowdQOy1xyCBZeNIe2CtqXXjr5rWyga2qzflk93EUpWmmCjeU83WpsIyPWy44CIXkdsOL+r3M3n4epCC5LMlOg==</ds:DigestValue>
			</ds:Reference>
		</ds:SignedInfo>
		<ds:SignatureValue>H4LznEe1vzhRjw9MMvp4LlkTONWh2rhK1kli4+ivQOnX6TSFApXaekPAq6AleZjaP209HNQyaG4QOHe9aqfzC08rBaSIdbS/GGL/Z17mYz/oWOI7QafQVqCWHc4m08KeLf4bnWZKXXWlWcQNYw+k/rHleiO0Ulesi5Ro5BWKmMqehrjK/XRkyvH2aX6gylOZZAG27g627VpuxKw8NarM4FVb5dZ2OGKoFQojvBtUbZNecwM5+MRrMUBQKjOi05VPNCevIFB7JG17YnH5GPexGAhe1VDKV2tXWHcKPKnytgNk97d0JLDcJzEWZ0jjtTdRxcfqhkNsoJcVlUr7/jBWVw==</ds:SignatureValue>
		<ds:KeyInfo>
			<ds:X509Data>
				<ds:X509Certificate>MIIF/TCCBOWgAwIBAgIQUj5ofy7TYXhWsKBZVz6lxDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG
EwJFUzERMA8GA1UECgwIRk5NVC1SQ00xJTAjBgNVBAsMHEFDIENvbXBvbmVudGVzIEluZm9ybcOh
dGljb3MwHhcNMTYwMjAyMTIyNjAxWhcNMTkwMjAyMTIyNTU5WjCB2DELMAkGA1UEBhMCRVMxDzAN
BgNVBAcMBk1BRFJJRDE8MDoGA1UECgwzTUlOSVNURVJJTyBERSBIQUNJRU5EQSBZIEFETUlOSVNU
UkFDSU9ORVMgUMOaQkxJQ0FTMUswSQYDVQQLDEJESVJFQ0NJw5NOIERFIFRFQ05PTE9Hw41BUyBE
RSBMQSBJTkZPUk1BQ0nDk04gWSBMQVMgQ09NVU5JQ0FDSU9ORVMxEjAQBgNVBAUTCVMyODMzMDAy
RTEZMBcGA1UEAwwQRFRJQyBBR0UgUFJVRUJBUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALBcouy5wk1P1Lwq38b+mVbZfoqskPBepawieHarQ1NrkJJV+hIYOngGX/4DdpoUKr/ezAqr
Niu0mH1WxPI+eRLse1loUbjwQTgxnJI9QP0v79L6g0UqLyFcwyy7/dIxVkJUIq7qPHXbjvlgu5fC
w6uB8h0EQ2JlrpKfqtdkh+ipDmUfinageM11sMXEebS+YxO0iiqK0WgHPG27dSzd0Tfo2SKQ/XHs
guTtrIoV4kktGhkb7IEpO8+G8QzHd347HiQAy/MruzeLAJjaBhcYzkCmMFw5xWc7k6PB0S82heFB
6RN+4RGYP149VINGSQrS0WqIXrXJCHLQb5c7HBeNpm0CAwEAAaOCAlEwggJNMAkGA1UdEwQCMAAw
gYEGCCsGAQUFBwEBBHUwczA7BggrBgEFBQcwAYYvaHR0cDovL29jc3Bjb21wLmNlcnQuZm5tdC5l
cy9vY3NwL09jc3BSZXNwb25kZXIwNAYIKwYBBQUHMAKGKGh0dHA6Ly93d3cuY2VydC5mbm10LmVz
L2NlcnRzL0FDQ09NUC5jcnQwRAYDVR0gBD0wOzA5BgorBgEEAaxmAwkCMCswKQYIKwYBBQUHAgEW
HWh0dHA6Ly93d3cuY2VydC5mbm10LmVzL2RwY3MvMC4GA1UdEQQnMCWkIzAhMR8wHQYJKwYBBAGs
ZgEIDBBEVElDIEFHRSBQUlVFQkFTMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA4GA1UdDwEB/wQEAwIE
sDAdBgNVHQ4EFgQUmUPaCKS1GXULRv7TYGFMG6BxmcQwHwYDVR0jBBgwFoAUGfhYLxTWpsybBJgI
DUzXqwCng2UwgeAGA1UdHwSB2DCB1TCB0qCBz6CBzIaBnmxkYXA6Ly9sZGFwY29tcC5jZXJ0LmZu
bXQuZXMvQ049Q1JMMSxPVT1BQyUyMENvbXBvbmVudGVzJTIwSW5mb3JtYXRpY29zLE89Rk5NVC1S
Q00sQz1FUz9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0O2JpbmFyeT9iYXNlP29iamVjdGNsYXNz
PWNSTERpc3RyaWJ1dGlvblBvaW50hilodHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9jcmxzY29tcC9D
UkwxLmNybDANBgkqhkiG9w0BAQsFAAOCAQEATlZ3DPFz1gQ32YOYIILzf99kuk2wFYULg+XaDqis
/y/S6bphKF3xbtyxsIX+lx0zI17dyDTKA+6sWNHiiuH4YjXkqbxbI8EYHfeRzbRK3S4Gj1yatGVt
hsCK6wDrlr8Rrj8QgntFAM+/kfysGJlHEiFsgTN2iXfOsjmXNNK1LwSbQ3GCwPaLYKZonNsEj8P/
S5r91ICejfGlVZp1AEXyP3jJzibr0SKxwEt32r/+ZjTmQgrLuAmGrgcVsjAAm2Cp7usJYaS/SyPF
j1QDUlZoVOuo4dfgFUZLCVBfMUBY73WNazVAojqZhG9d8tAgg2c64nusuMDY+25MLUKFzsbzFg==</ds:X509Certificate>
			</ds:X509Data>
		</ds:KeyInfo>
	</ds:Signature>
	<saml2p:Extensions>
		<eidas:RequestedAttributes>
			<eidas:RequestedAttribute FriendlyName="RelayState" Name="http://es.minhafp.clave/RelayState" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false">
				<eidas:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="eidas-natural:PersonIdentifierType">_v1m7pcn</eidas:AttributeValue>
			</eidas:RequestedAttribute>
		</eidas:RequestedAttributes>
	</saml2p:Extensions>
	<saml2p:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"/>
	<saml2p:RequestedAuthnContext Comparison="minimum">
		<saml2:AuthnContextClassRef>http://eidas.europa.eu/LoA/low</saml2:AuthnContextClassRef>
	</saml2p:RequestedAuthnContext>
</saml2p:AuthnRequest>

 I am unable to find ABAP libraries to make external request calls. I am also researching about SAP PI, but I cannot find any proper documentation about this kind of scenarios.

0 Likes

Accepted Solutions (1)

Accepted Solutions (1)

javier_alonso63
Participant
0 Likes

I was able to build the SAML2 XML.  First of all, I defined a custom structure for the eIDAS attributes.

DATA(saml2_extensions) = VALUE xsdany( ).
DATA(eidas_attributes) = VALUE zsaml2p_eidas_attribute_t( (
  friendlyname = `RelayState`
  name         = `http://es.minhafp.clave/RelayState`
  nameformat   = `urn:oasis:names:tc:SAML:2.0:attrname-format:uri`
  isrequired   = abap_false
  value        = VALUE #( ( get_secure_random( i_size = 8 ) ) ) ) ).

CALL TRANSFORMATION zsaml2_eidas_attribute SOURCE saml2_eidas_attributes = eidas_attributes RESULT XML saml2_extensions.

I needed to create a simple SAP transformation to convert the ABAP structure to XML.

<?sap.transform simple?>
<tt:transform xmlns:tt="http://www.sap.com/transformation-templates"
              xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
              xmlns:eidas="http://eidas.europa.eu/saml-extensions"
              xmlns:eidasnp="http://eidas.europa.eu/attributes/naturalperson"
              xmlns:ddic="http://www.sap.com/abapxml/types/dictionary"
              xmlns:def="http://www.sap.com/abapxml/types/defined">

  <tt:root name="SAML2_EIDAS_ATTRIBUTES" type="ddic:ZSAML2P_EIDAS_ATTRIBUTE_T"/>

  <tt:template>
    <samlp:Extensions>
      <eidas:RequestedAttributes>
        <tt:loop ref=".SAML2_EIDAS_ATTRIBUTES">
          <eidas:RequestedAttribute>
            <tt:attribute name="Name" value-ref="NAME"/>
            <tt:cond check="not-initial(NAMEFORMAT)">
              <tt:attribute name="NameFormat" value-ref="NAMEFORMAT"/>
            </tt:cond>
            <tt:cond check="not-initial(FRIENDLYNAME)">
              <tt:attribute name="FriendlyName" value-ref="FRIENDLYNAME"/>
            </tt:cond>
            <tt:cond check="not-initial(ISREQUIRED)">
              <tt:attribute name="isRequired" value-ref="ISREQUIRED"/>
            </tt:cond>
            <tt:group>
              <tt:cond frq="?">
                <tt:loop ref="VALUE">
                  <eidas:AttributeValue>
                    <tt:value ref="$ref"/>
                  </eidas:AttributeValue>
                </tt:loop>
              </tt:cond>
            </tt:group>
          </eidas:RequestedAttribute>
        </tt:loop>
      </eidas:RequestedAttributes>
    </samlp:Extensions>
  </tt:template>
</tt:transform>

In order to generate the SAML2 ticket, I used a standard ABAP structure.

DATA(issue_instant) = VALUE saml2_datetime( ).
GET TIME STAMP FIELD issue_instant.

DATA(saml_request) = VALUE saml2p_authn_request(
  request = VALUE #(
    id            = get_secure_random( i_size = 64 )
    version       = if_saml20_constants=>co_saml_version
    issueinstant  = issue_instant
    destination   = `https://se-pasarela.clave.gob.es/Proxy2/ServiceProvider`
      consent       = `urn:oasis:names:tc:SAML:2.0:consent:unspecified`
      extensions    = saml2_extensions )
    nameid       = VALUE #( allowcreate = abap_true idformat = wssec_co_saml_nid_form_unspec )
    authncontext = VALUE #( comparison = if_saml20_constants=>co_comparison_method_s_minimum authncontextclassref = VALUE #( ( `http://eidas.europa.eu/LoA/low` ) ) )
    forceauthn   = abap_true
    ispassive    = abap_false
    providername = `S2833002E_E04975701;Demo-SP`
    assertionconsumerserviceurl = `https://pre-pasarela.clave.gob.es/SP2/ReturnPage` ).

 The next step is the signature, using standard classes. The important part here is to set the SAML2 Request Schema in the signature transformation.

TRY.
    DATA(xml_signer) = cl_sec_sxml_dsignature=>create_writer_instance( ).

    " Digestion over ID attritube of samlp:AuthnRequest node
    xml_signer->set_attributes(
      if_str_transform       = abap_false   " Disable standard transformation
      if_attribute_name      = 'ID'
      if_attribute_namespace = if_saml20_constants=>co_saml_protocol_support ).

    " ENV-C14N-EXC signature with RSA-SHA512 algorithm
    xml_signer->m_pse_context              = cl_sec_sxml_dsignature=>co_ssfa.
    xml_signer->m_signature_type           = cl_sec_sxml_dsignature=>co_type_enveloped.
    xml_signer->m_signature_transformation = cl_sec_sxml_dsignature=>co_transform_envelope.
    xml_signer->m_canonicalization         = cl_sec_sxml_dsignature=>co_c14n_exclusive.
    xml_signer->m_signature_ns_prefix      = cl_sec_sxml_dsignature=>co_signature_nsprefix.
    xml_signer->m_signature_id             = space.
    xml_signer->m_dsig_hash_algorithm      = 'SHA512'.
    xml_signer->m_ssf_hash_algorithm       = 'SHA512'.
    xml_signer->m_dsig_method              = cl_sec_sxml_dsignature=>co_dsig_method_rsa.

    " Use SAML2 schema for the XSLT transformation
    xml_signer->set_transformation(
      EXPORTING
        if_name           = 'SAML2_AUTHN_REQUEST'
        if_data_tab       = VALUE #( ( name = 'SAML2_AUTHN_REQUEST' value = saml_request ) )
      CHANGING
        ch_signature_data = saml_request->request-signature_raw ).

    " Sign using PSE certificate stored in STRUST
    xml_signer->sign_xml(
      if_ssf_app      = if_saml20_constants=>co_ssfappl_sp_sign  " S2SVPS
      if_add_keyinfo  = abap_true
      if_re_transform = abap_true ).
  CATCH cx_sec_sxml_error.
    RAISE EXCEPTION TYPE cx_saml20_core EXPORTING textid = cx_saml20_core=>xml_create_error.
ENDTRY.

 I used an already existing STRUST app to store the certificate for the signature. However, you can use a custom one if you want.

Once the XML is signed, you can generate the final XML using a standard transformation.

CALL TRANSFORMATION saml2_authn_request SOURCE saml2_authn_request = saml_request RESULT XML DATA(signed_xml) OPTIONS xml_header = 'no'.

With this approach, I was able to generate the SAML2 ticket with the required format.

Answers (0)