This document covers the SAML in a network environment where Citrix ADC is a virtual standalone instance running as SAML Identity Provider (IdP) and Cisco Call Manager as SAML Service Provider (SP). There are some important facts about Cisco UCM that should be taken into consideration before proceeding with SAML configuration.
Cisco UCM Cluster:
Cisco UCM cluster handles call processing in Cisco's implementation of IP Telephony. The cluster has two types of nodes.
a) Publisher:
The publisher is the authoritative database for configuration. When changes are made in configuration, they are made on the publisher and replicated to the subscribers. NODE-C1 is a publisher node in this configuration document.
b) Subscriber:
If the publisher is unavailable, the phones can re-home themselves to a subscriber in order to continue to be functional. Subscribers are not entitled to make any SAML configuration related changes. NODE-C2 and NODE-C3 are subscriber nodes in this document.
Cisco UCM SSO allowed operations according to node type is in the table below.
Operation | Allowed on Publisher | Allowed on Subcriber |
Upload IdP Metadata | Yes | No |
Download SP Metadata | Yes | No |
Regenerate SAML Certificate | Yes | No |
Regenerate Signing Key | Yes | No |
Unified Communications Manager no longer uses the Assertion Consumer Service URL in SAML authentication requests, instead uses the Assertion Consumer Service Index URL.
ACS URL is the SP endpoint to which SAML assertion is redirected at SP. In Cisco UCM, each node in the cluster is a unique SP endpoint. Therefore, Publisher node generates SP metadata configuration with a list of indexes in which each index represents a unique URL and assertion method for each node in the cluster.
Below is an example of ACS Indexing, obtained from SP metadata file.
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://NODE-C3.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C3.ucm.test.com" index="0"/> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://NODE-C3.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C3.ucm.test.com" index="1"/> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://NODE-C1.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C1.ucm.test.com" index="2"/> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://NODE-C1.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C1.ucm.test.com" index="3"/> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://NODE-C2.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C2.ucm.test.com" index="4"/> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://NODE-C2.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C2.ucm.test.com" index="5"/> |
In the above example,
Index “0” points to subscriber node “NODE-C3” with assertion method “POST”.
Index “2” points to publisher node “NODE-C1” with assertion method “POST”.
Index “4” points to subscriber node “NODE-C2” with assertion method “POST”.
Starting from R13.0, Citrix ADC as SAML Identity Provider (IdP) support ACS indexing. The SAML IdP imports ACS indexing configuration from SP metadata only. ACS indexing cannot be configured via GUI or CLI. R13.0 also provides additional SAML debugging messages, which can be useful in troubleshooting. If you running an older version, you must upgrade to R13.0 to use this feature. Please refer to the release notes for more information.
https://docs.citrix.com/en-us/citrix-adc/downloads/release-notes-13-0-41-28.html
This section describes the call flow between Citrix ADC and Cisco UCM. This example is a SP initiated SSO where an unauthenticated client connects to SP, which then redirects the client to IdP for authentication. The successfully authenticated client is redirected back to SP and is allowed to access the resource.
This document covers Citrix ADC configuration only. For SP related configuration, please refer to Cisco documentation.
1. Create an authentication virtual server on Citrix ADC which represents the IdP.
add authentication vserver aaavserver_AAA_EN_IDP SSL x.x.x.x. 443 |
2. Create SAML IdP Policy which is bound to the authentication vserver.
add authentication samlIdPPolicy IDP_AUTH_Pol_AAA_EN -rule "http.REQ.URL.CONTAINS(\"saml\")||http.REQ.URL.CONTAINS(\"idp\")" -action IDP_AUTH_Prof_AAA_EN |
3. Create SAML IdP Profile.
add authentication samlIdPProfile IDP_AUTH_Prof_AAA_EN -samlIdPCertName idp.test.com -rejectUnsignedRequests OFF -metadataUrl "https://x.x.x.x/vpn/spmetadata.xml" -metadataRefreshInterval 5 -assertionConsumerServiceURL “https://NODE-C1.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C1.ucm.test.com” -audience NODE-C1.ucm.test.com -Attribute1 uid -Attribute1Expr aaa.user.LOGIN_NAME -Attribute1Format Basic |
where:
samlIdPCert:
Name of the SSL certificate-key pair of SAML IdP, referred here as idp.test.com. This certificate is used to sign the SAMLResponse that is sent to Service Provider after successful authentication
metadataRefreshInterval:
It is an interval in minutes after which Citrix ADC tries to refresh metadata configuration file from its hosted location.
assertionConsumerServiceURL:
It is a URL where authenticated users will be redirected at SP. This parameter will not be used in SAML assertion if Citrix ADC has the ACS indexing information. If Citrix ADC fails to download metadata file from its hosted location, then ACS URL will be used.
Reject Unsigned Requests:
It is an option you can specify to ensure only Assertions signed with the SP Certificate are accepted. In this example, we have set this to OFF.
Audience:
It is a unique identifier, typically a URL, to identify the SP. However, Cisco UCM doesn’t accept the audience value auto-generated by Citrix ADC in SAML response. This parameter should be manually configured and correct value of audience is the SP EntityID in its metadata, which is “NODE-C1.ucm.test.com”.
Attribute1:
Cisco UCM expects User Login name to be returned as an attribute in SAML Assertion. Attribute must be defined as “uid”.
metadataUrl:
As mentioned above in the document, Citrix ADC supports ACS Indexing configuration by importing SP metadata configuration only. Manual configuration is not supported as of now. SP metadata provides information about SP parameters such as SP Entity ID, assertion format and ACS indexing. ADC will download the metadatafile using HTTP/HTTPS. It is highly recommended that metadata file should be hosted external to ADC.
Below is the sample metadata file from Cisco UCM that is imported by Citrix ADC.
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="NODE-C1.ucm.test.com" entityID="NODE-C1.ucm.test.com"> <md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <md:KeyDescriptor use="signing"> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:X509Data> <ds:X509Certificate> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </md:KeyDescriptor> <md:KeyDescriptor use="encryption"> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:X509Data> <ds:X509Certificate> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </md:KeyDescriptor> <md:NameIDFormat> urn:oasis:names:tc:SAML:2.0:nameid-format:transient </md:NameIDFormat> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://NODE-C3.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C3.ucm.test.com" index="0"/> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://NODE-C3.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C3.ucm.test.com" index="1"/> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://NODE-C1.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C1.ucm.test.com" index="2"/> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://NODE-C1.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C1.ucm.test.com" index="3"/> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://NODE-C2.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C2.ucm.test.com" index="4"/> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://NODE-C2.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C2.ucm.test.com" index="5"/> </md:SPSSODescriptor> </md:EntityDescriptor> |
Some important parameters in the SP metadata are:
EntityID:
Uniquely identifies SP. Usually, it is the publisher node in Cisco UCM cluster.
WantAssertionSigned:
It defines that SAML assertion sent by Citrix ADC must be signed using IdP Certificate or unsigned.
ACS Indexing:
Already explained above.
Name ID Format:
It is the format that the Username is transmitted and expected between the IdP and SP.
4. Bind SAML IdP Profile to authentication vserver.
bind authentication vserver aaavserver_AAA_EN_IDP -policy IDP_AUTH_Pol_AAA_EN -priority 100 -gotoPriorityExpression END |
5. Create LDAP profile and bind to authentication vserver.
add authentication ldapPolicy LDAP_AUTH_POL_AAA_EN_NZ ns_true LDAP_AUTH_Prof_AAA_EN bind authentication vserver aaavserver_AAA_EN_IDP -policy LDAP_AUTH_Pol_AAA_EN -priority 100 -gotoPriorityExpression NEXT |
Cisco UCM requires metadata from Citrix ADC to import IdP SAML configuration. Once IdP profile configuration is complete on Citrix ADC, metadata is generated by browsing to authentication virtual server in the following format.
https://idp.test.com/metadata/samlidp/IDP_AUTH_Prof_AAA_EN
where:
idp.test.com is the FQDN of authentication virtual server.
DP_AUTH_Prof_AAA_EN is the name of SAML IdP Policy bound to authentication VS.
Below is the sample IdP metadata generated by ADC.
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_38a92bcc3a89fbe0b6d9d363b5381708" entityID="idp.test.com"> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference URI="#_38a92bcc3a89fbe0b6d9d363b5381708"> <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#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue> yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy </ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <md:KeyDescriptor use="signing"> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:X509Data> <ds:X509Certificate> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </md:KeyDescriptor> <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp.test.com/cgi/tmlogout"/> <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.test.com/cgi/tmlogout"/> <md:NameIDFormat> urn:oasis:names:tc:SAML:2.0:nameid-format:transient </md:NameIDFormat> <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp.test.com/saml/login"/> <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.test.com/saml/login"/> </md:IDPSSODescriptor> </md:EntityDescriptor> |
Please note that every time IdP metadata link is refreshed, a new signature is generated in metadata XML file. Therefore, SP should import most recent metadata file with the updated signature.
In the following SAML request, Index 0 is requested which corresponds to NODE-C3. You will see that NODE-C3 as destination URL in SAML response.
SAML Request:
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="s27a8bc05f84c3e1a4d4b5aef2066c47e0867e4c22" Version="2.0" IssueInstant="2019-09-30T01:40:39Z" Destination="https://idp.test.com/saml/login" ForceAuthn="false" IsPassive="false" AssertionConsumerServiceIndex="0" > <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">NODE-C1.ucm.test.com</saml:Issuer> <samlp:NameIDPolicy xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" SPNameQualifier="NODE-C1.ucm.test.com" AllowCreate="true" /> </samlp:AuthnRequest> |
SAML Response:
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://NODE-C3.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C3.ucm.test.com" ID="_2b6e5603253d1716f88f263f7dc9f9c8" InResponseTo="s27a8bc05f84c3e1a4d4b5aef2066c47e0867e4c22" IssueInstant="2019-09-30T01:40:49Z" Version="2.0 > <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" >idp.test.com</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /> </samlp:Status> <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_60d1358b2bd0e5979cfa06c7b77e145" IssueInstant="2019-09-30T01:40:49Z" Version="2.0"> <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">idp.test.com</saml:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /> <ds:Reference URI="#_60d1358b2bd0e5979cfa06c7b77e145"> <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#" /> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> <ds:DigestValue>kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">Jabber1@</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="s27a8bc05f84c3e1a4d4b5aef2066c47e0867e4c22" NotOnOrAfter="2019-09-30T01:45:49Z" Recipient="https://NODE-C3.ucm.test.com:8443/ssosp/saml/SSO/alias/NODE-C3.ucm.test.com" /> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2019-09-30T01:35:49Z" NotOnOrAfter="2019-09-30T01:45:49Z" > <saml:AudienceRestriction> <saml:Audience>NODE-C1.ucm.test.com</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2019-09-30T01:40:49Z" SessionIndex="NSC_TMAAbd719d8b25357394a2c0c9016c90e3ed" > <saml:AuthnContext> saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> <saml:AttributeStatement> <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue>46995</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> </saml:Assertion> </samlp:Response> |
Exception Reported by Cisco UCM:
In case of SAML exceptions faced at Cisco UCM, always verify that correct ACS index is returned in SAML response. One common reason for not returning correct index is when Citrix ADC is unable to fetch metadata file, thus responding with incorrect ACS index.
SAML Assertion Failed:
ERROR [http-bio-443-exec-383] fappend.SamlLogger - SAML2Utils.verifyResponse:Assertion is not signed or signature is not valid. |
Always verify that signed assertion is sent by ADC using correct signing algorithms. Cisco UCM does not accept unsigned assertions.
Missing Attribute:
servlet.ErrorServlet - Attributes are missing in the saml response. Please check the attribute configuration on the IDP.Error Message |
Cisco UCM expects username as an attribute in SAML assertions. Without this attribute, Cisco UCM will not successfully parse SAML assertion.
Incorrect Audience:
DEBUG [http-bio-443-exec-432] fappend.SamlLogger - SAML2Utils.checkAudience:This SP is not the intended audience. |
Cisco UCM does not accept URI as audience. This has to be manually configured as SP ID in SAML IdP policy, otherwise default ADC settings will update audience as URI.