django-saml2-auth
django-saml2-auth copied to clipboard
Certificate and Key file
Hello! Is it there a way to specify certificate and key file or information? Something like it is done within pysaml2: https://pysaml2.readthedocs.io/en/latest/howto/config.html#cert-file
At the moment when the code execute saml_client = Saml2Client(config=sp_config): https://github.com/grafana/django-saml2-auth/blob/46181c19e53cc9949767ce851ba8fa7696b71266/django_saml2_auth/saml.py#L197
then runs here: https://github.com/IdentityPython/pysaml2/blob/155910dabffa0f60a2075be862f2cf8c31fad685/src/saml2/sigver.py#L1044
doesn't find the file and return sec_backend = None
Then, here gives error because of the above: https://github.com/IdentityPython/pysaml2/blob/master/src/saml2/pack.py#L194
Any advice? Thank you very much.
Hey @sgabb,
Can you explain what you're trying to do with the certificate and the key file? AFAIK, the certificate is already available in the metadata file and the library automatically picks it up and signs assertions with it.
Hi @mostafa,
unfortunately I am not a SAML expert and yes, in the metadata file that I received there are the signature and the x509 certificate strings; this is a blueprint of the metadata:
XML METADATA
<?xml version="1.0" encoding="utf-8"?>
<EntityDescriptor ID="entity-descriptor-id" entityID="https://sts.windows.net/entity-id/" xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="#entity-descriptor-id">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>b6libAlGkhZQK7d97/2sxahiOxxAsae58Uho5RHr8aI=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>signature-value-uid</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>x509-certificate-string</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
<RoleDescriptor xsi:type="fed:SecurityTokenServiceType" protocolSupportEnumeration="http://docs.oasis-open.org/wsfed/federation/200706" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:fed="http://docs.oasis-open.org/wsfed/federation/200706">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>x509-certificate-string</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<fed:ClaimTypesOffered>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Name</auth:DisplayName>
<auth:Description>The mutable display name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Subject</auth:DisplayName>
<auth:Description>An immutable, globally unique, non-reusable identifier of the user that is unique to the application for which a token is issued.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Given Name</auth:DisplayName>
<auth:Description>First name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Surname</auth:DisplayName>
<auth:Description>Last name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/displayname" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Display Name</auth:DisplayName>
<auth:Description>Display name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/nickname" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Nick Name</auth:DisplayName>
<auth:Description>Nick name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Authentication Instant</auth:DisplayName>
<auth:Description>The time (UTC) when the user is authenticated to Windows Azure Active Directory.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Authentication Method</auth:DisplayName>
<auth:Description>The method that Windows Azure Active Directory uses to authenticate users.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/objectidentifier" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>ObjectIdentifier</auth:DisplayName>
<auth:Description>Primary identifier for the user in the directory. Immutable, globally unique, non-reusable.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/tenantid" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>TenantId</auth:DisplayName>
<auth:Description>Identifier for the user's tenant.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/identityprovider" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>IdentityProvider</auth:DisplayName>
<auth:Description>Identity provider for the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Email</auth:DisplayName>
<auth:Description>Email address of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/groups" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Groups</auth:DisplayName>
<auth:Description>Groups of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/accesstoken" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>External Access Token</auth:DisplayName>
<auth:Description>Access token issued by external identity provider.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/expiration" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>External Access Token Expiration</auth:DisplayName>
<auth:Description>UTC expiration time of access token issued by external identity provider.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/openid2_id" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>External OpenID 2.0 Identifier</auth:DisplayName>
<auth:Description>OpenID 2.0 identifier issued by external identity provider.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/claims/groups.link" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>GroupsOverageClaim</auth:DisplayName>
<auth:Description>Issued when number of user's group claims exceeds return limit.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Role Claim</auth:DisplayName>
<auth:Description>Roles that the user or Service Principal is attached to</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/wids" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>RoleTemplate Id Claim</auth:DisplayName>
<auth:Description>Role template id of the Built-in Directory Roles that the user is a member of</auth:Description>
</auth:ClaimType>
</fed:ClaimTypesOffered>
<fed:SecurityTokenServiceEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/entity-id/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:SecurityTokenServiceEndpoint>
<fed:PassiveRequestorEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/entity-id/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:PassiveRequestorEndpoint>
</RoleDescriptor>
<RoleDescriptor xsi:type="fed:ApplicationServiceType" protocolSupportEnumeration="http://docs.oasis-open.org/wsfed/federation/200706" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:fed="http://docs.oasis-open.org/wsfed/federation/200706">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>x509-certificate-string</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<fed:TargetScopes>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://sts.windows.net/entity-id/</wsa:Address>
</wsa:EndpointReference>
</fed:TargetScopes>
<fed:ApplicationServiceEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/entity-id/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:ApplicationServiceEndpoint>
<fed:PassiveRequestorEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/entity-id/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:PassiveRequestorEndpoint>
</RoleDescriptor>
<IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>x509-certificate-string</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://login.microsoftonline.com/entity-id/saml2" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://login.microsoftonline.com/entity-id/saml2" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://login.microsoftonline.com/entity-id/saml2" />
</IDPSSODescriptor>
</EntityDescriptor>
However, when the Saml2Client class is initialised, it extends Base and Entity classes, this last one execute the following: https://github.com/IdentityPython/pysaml2/blob/master/src/saml2/entity.py#L187
self.sec = security_context(self.config)
then here it does not find the 'key_file' and set the sec_backend = None: https://github.com/IdentityPython/pysaml2/blob/master/src/saml2/sigver.py#L1044
then saml_client.prepare_for_authenticate(relay_state=next_url): https://github.com/grafana/django-saml2-auth/blob/master/django_saml2_auth/views.py#L176 then self.apply_binding https://github.com/IdentityPython/pysaml2/blob/master/src/saml2/client.py#L174 then http_redirect_message where tries to use self.sec.sec_backend (which is None) https://github.com/IdentityPython/pysaml2/blob/master/src/saml2/entity.py#L295
info = http_redirect_message(
message=msg_str,
location=destination,
relay_state=relay_state,
typ=typ,
sign=sign,
sigalg=sign_alg,
backend=self.sec.sec_backend,
)
and finally tries to execute signer = backend.get_signer(sigalg) where it fails since backend is None: https://github.com/IdentityPython/pysaml2/blob/master/src/saml2/pack.py#L194
So, is it that there is an issue to retrieve the signature/certificate data from the metadata? Or does pysaml2 only search for them in the external files and not in the xml?
It seems like there's a configuration issue of sorts with your code because the certificate should be extracted from the metadata file. Are you setting the METADATA_LOCAL_FILE_PATH
option and the path is accessible from your Django app? You also need to set WANT_ASSERTIONS_SIGNED
and WANT_RESPONSE_SIGNED
to True
.
This are my settings:
SAML2_AUTH = {
# Metadata is required, choose either remote url or local file path
'METADATA_LOCAL_FILE_PATH': os.path.join(BASE_DIR, "web", "settings", "metadata.xml"),
'DEBUG': True,
# Optional settings below
'DEFAULT_NEXT_URL': '/',
'ATTRIBUTES_MAP': {
'first_name': 'Given Name',
'last_name': 'Surname',
'email': 'Email',
'username': 'Email',
},
'WANT_ASSERTIONS_SIGNED': True,
'AUTHN_REQUESTS_SIGNED': True,
'WANT_RESPONSE_SIGNED': True,
# Set 'USE_JWT' to True if you are running a Single Page Application (SPA) with Django Rest Framework (DRF),
# and are using JWT authentication to authorize client users
'USE_JWT': True,
# Redirect URL for the client if you are using JWT auth with DRF. See explanation below
'FRONTEND_URL': 'http://frontend.domain/sso/login',
}
And this is the resulting saml_settings prepared in get_saml_client:
{'metadata': {'local': ['/app/web/settings/metadata.xml']}, 'allow_unknown_attributes': True, 'debug': True, 'service': {'sp': {'endpoints': {'assertion_consumer_service': [('http://localhost:8000/saml/acs/', 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'), ('http://localhost:8000/saml/acs/', 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST')]}, 'allow_unsolicited': True, 'authn_requests_signed': True, 'logout_requests_signed': True, 'want_assertions_signed': True, 'want_response_signed': True}}}
Trying to set in settings WANT_ASSERTIONS_SIGNED, AUTHN_REQUESTS_SIGNED and WANT_RESPONSE_SIGNED to False, it creates the AuthNReq and does the redirect. This is the AuthNReq printed:
<ns0:AuthnRequest xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion" ID="id-requestuid" Version="2.0" IssueInstant="2022-03-10T19:10:50Z" Destination="https://login.microsoftonline.com/uuid/saml2" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="http://localhost:8000/saml/login/"><ns1:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" /></ns0:AuthnRequest>
However the microsoft login page gives an error: Request Id: uuid1 Correlation Id: uuid2 Timestamp: 2022-03-10T19:10:51Z Message: AADSTS7500525: There was an XML error in the SAML message at line 1, position 488. Verify that the XML content of the SAML messages conforms to the SAML protocol specifications.
where line 488 is right before "ns0:AuthnRequest>".
Based on these tests, it should work fine unless there's a misconfiguration somewhere. I suggest you follow this guide, specifically step 13, as it might help pinpoint configuration issues on your SAML app (on Azure). You can also make use of SAML-tracer addon for Firefox or Chrome to debug SAML messages.
Update on the issue: if I add the "ENTITY_ID" value in the settings, then the auth request if correctly accepted by the identity provider:
<ns0:AuthnRequest xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion"
ID="id-uid" Version="2.0" IssueInstant="2022-03-16T13:30:14Z"
Destination="https://login.microsoftonline.com/uuid/saml2" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
AssertionConsumerServiceURL="https://domain.com/saml/acs/">
<ns1:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://domain.com</ns1:Issuer>
</ns0:AuthnRequest>
Effectively, in the metadata xml file that was provided there wasn't the information on the Identity URL.
However, if AUTHN_REQUESTS_SIGNED is set to True, it still appears the signing error.
Based on the metadata blueprint provided before, could it be a problem of that specific file (even though there is the data o key and 509 certificates)?
@sgabb Nice find!
Also, if the authentication requests are not signed, it means you haven't installed xmlsec1
on your system. If so, then there's some other configuration issue somewhere.
https://www.aleksey.com/xmlsec/
@sgabb Were you able to solve this issue?
Unfortunately not yet :disappointed: Could it be linked to this issue of the original fangli repository?
This is an example of the metadata where there should be the Key and Certificate:
XML METADATA
<?xml version="1.0" encoding="utf-8"?>
<EntityDescriptor ID="entity-descriptor-id" entityID="https://sts.windows.net/entity-id/" xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="#entity-descriptor-id">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>b6libAlGkhZQK7d97/2sxahiOxxAsae58Uho5RHr8aI=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>signature-value-uid</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>x509-certificate-string</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
<RoleDescriptor xsi:type="fed:SecurityTokenServiceType" protocolSupportEnumeration="http://docs.oasis-open.org/wsfed/federation/200706" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:fed="http://docs.oasis-open.org/wsfed/federation/200706">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>x509-certificate-string</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<fed:ClaimTypesOffered>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Name</auth:DisplayName>
<auth:Description>The mutable display name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Subject</auth:DisplayName>
<auth:Description>An immutable, globally unique, non-reusable identifier of the user that is unique to the application for which a token is issued.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Given Name</auth:DisplayName>
<auth:Description>First name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Surname</auth:DisplayName>
<auth:Description>Last name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/displayname" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Display Name</auth:DisplayName>
<auth:Description>Display name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/nickname" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Nick Name</auth:DisplayName>
<auth:Description>Nick name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Authentication Instant</auth:DisplayName>
<auth:Description>The time (UTC) when the user is authenticated to Windows Azure Active Directory.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Authentication Method</auth:DisplayName>
<auth:Description>The method that Windows Azure Active Directory uses to authenticate users.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/objectidentifier" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>ObjectIdentifier</auth:DisplayName>
<auth:Description>Primary identifier for the user in the directory. Immutable, globally unique, non-reusable.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/tenantid" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>TenantId</auth:DisplayName>
<auth:Description>Identifier for the user's tenant.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/identityprovider" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>IdentityProvider</auth:DisplayName>
<auth:Description>Identity provider for the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Email</auth:DisplayName>
<auth:Description>Email address of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/groups" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Groups</auth:DisplayName>
<auth:Description>Groups of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/accesstoken" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>External Access Token</auth:DisplayName>
<auth:Description>Access token issued by external identity provider.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/expiration" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>External Access Token Expiration</auth:DisplayName>
<auth:Description>UTC expiration time of access token issued by external identity provider.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/openid2_id" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>External OpenID 2.0 Identifier</auth:DisplayName>
<auth:Description>OpenID 2.0 identifier issued by external identity provider.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/claims/groups.link" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>GroupsOverageClaim</auth:DisplayName>
<auth:Description>Issued when number of user's group claims exceeds return limit.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Role Claim</auth:DisplayName>
<auth:Description>Roles that the user or Service Principal is attached to</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/wids" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>RoleTemplate Id Claim</auth:DisplayName>
<auth:Description>Role template id of the Built-in Directory Roles that the user is a member of</auth:Description>
</auth:ClaimType>
</fed:ClaimTypesOffered>
<fed:SecurityTokenServiceEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/entity-id/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:SecurityTokenServiceEndpoint>
<fed:PassiveRequestorEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/entity-id/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:PassiveRequestorEndpoint>
</RoleDescriptor>
<RoleDescriptor xsi:type="fed:ApplicationServiceType" protocolSupportEnumeration="http://docs.oasis-open.org/wsfed/federation/200706" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:fed="http://docs.oasis-open.org/wsfed/federation/200706">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>x509-certificate-string</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<fed:TargetScopes>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://sts.windows.net/entity-id/</wsa:Address>
</wsa:EndpointReference>
</fed:TargetScopes>
<fed:ApplicationServiceEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/entity-id/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:ApplicationServiceEndpoint>
<fed:PassiveRequestorEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/entity-id/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:PassiveRequestorEndpoint>
</RoleDescriptor>
<IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>x509-certificate-string</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://login.microsoftonline.com/entity-id/saml2" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://login.microsoftonline.com/entity-id/saml2" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://login.microsoftonline.com/entity-id/saml2" />
</IDPSSODescriptor>
</EntityDescriptor>
Does it look correct? Should the library read the private key and the certificate value from it without issue? I am still not sure if the issue regards the configuration of the metadata or if the library effectively does not search within the metadata but need to receive the key_file and cert_file as requested in pysam2...
@sgabb It all seems like a configuration issue to me. Have you read https://github.com/IdentityPython/pysaml2/issues/598?
I'm running into this issue as well.
I'm very early days into doing my development, so I'm using https://samltest.id/saml/idp as the IdP to authenticate against. I'm assuming that this should be the value of METADATA_AUTO_CONF_URL.
If I set AUTHN_REQUESTS_SIGNED to False, I'm able to trigger a SP initiated request and get the redirect to the IdP.
However, if AUTHN_REQUESTS_SIGNED is True, then I end up with an exception from the bowels of the saml2 lib.
Here is a stack trace of where the error is coming from.
Traceback (most recent call last):
File "/usr/local/lib/python3.7/dist-packages/django_saml2_auth/utils.py", line 165, in wrapper
result = function(request)
File "/usr/local/lib/python3.7/dist-packages/django_saml2_auth/views.py", line 267, in signin
_, info = saml_client.prepare_for_authenticate(relay_state=next_url) # type: ignore
File "/usr/local/lib/python3.7/dist-packages/saml2/client.py", line 84, in prepare_for_authenticate
**kwargs,
File "/usr/local/lib/python3.7/dist-packages/saml2/client.py", line 168, in prepare_for_negotiated_authenticate
**kwargs,
File "/usr/local/lib/python3.7/dist-packages/saml2/client_base.py", line 494, in create_authn_request
**args,
File "/usr/local/lib/python3.7/dist-packages/saml2/entity.py", line 610, in _message
digest_alg=digest_alg,
File "/usr/local/lib/python3.7/dist-packages/saml2/entity.py", line 542, in sign
return signed_instance_factory(msg, self.sec, to_sign)
File "/usr/local/lib/python3.7/dist-packages/saml2/sigver.py", line 345, in signed_instance_factory
signed_xml, node_name=node_name, node_id=nodeid
File "/usr/local/lib/python3.7/dist-packages/saml2/sigver.py", line 1790, in sign_statement
node_id,
File "/usr/local/lib/python3.7/dist-packages/saml2/sigver.py", line 860, in sign_statement
(stdout, stderr, output) = self._run_xmlsec(com_list, [tmp.name])
File "/usr/local/lib/python3.7/dist-packages/saml2/sigver.py", line 921, in _run_xmlsec
logger.debug('xmlsec command: %s', ' '.join(com_list))
TypeError: sequence item 3: expected str instance, NoneType found
From what I can make out, item 3 is a key_file, either put to disk by saml2 or passed as an actual file location.
However, I can't find the location in the code that would extract a signing key file from either my own metadata (wouldn't that be dangerous?) or the IdP metadata. From all that I've seen, it would appear they a key_file attribute is expected in the saml_settings provided in django_saml2_auth/saml.py.
Some addendum:
To generate my metadata file in the first place (I needed to supply it to samltest.id so they would recognise me), I generated a sp_conf.py as per the instructions in the saml2 project, supplying a key_file and cert_file location.
I wasn't sure if I had the file right, so I ended up supplying a metadata key that was {"local": ["idp_metadata.xml"]}
and in the service.sp part, an idp
key that is the IdP URL. The generated metadata.xml file only has a signing KeyDescriptor element that is the public certificate mentioned in the sp_conf.py CONFIG['cert_file'].
I could not see anything resembling the private key in that metadata file, which leads me to suspect that something is missing between django_saml2_auth and saml2 when it comes to signing the Authn Request.
Do we know if this issue is being looked into? I am also running into this issue after 8hrs of troubleshooting with no luck between django_saml2_auth and saml2.client.py I was able to see that the issue is somewhere with samlclient and I am getting the exception: TypeError: sequence item 3: expected str instance, NoneType found as well
Edit: Also, when switching to the fangli library, I am able to see the URL redirects between the idp and sp and I am seeing the authn information being passed. I might just switch to the fangli library until this is resolved, however, I am looking to tie Django groups with Active Directory roles.
Any updates on the issue? We have the same issue. We tried locally to test Google IdP with this library on both Windows/Linux (CentOS) machines.
As per other comments we are getting TypeError: sequence item 3: expected str instance, NoneType found error where it seems that the library passes None as the private cert file location to xmlsec and hence it fails.
If we disable following settings as per code below:
'WANT_ASSERTIONS_SIGNED': False, 'AUTHN_REQUESTS_SIGNED': False, 'WANT_RESPONSE_SIGNED': False,
We get the redirect to Google, however upon selecting the user, we get another exception: failed to verify signature.
Would appreciate any help. Happy to do further testing and provide any required information.
Any updates on the issue? We have the same issue. We tried locally to test Google IdP with this library on both Windows/Linux (CentOS) machines. As per other comments we are getting TypeError: sequence item 3: expected str instance, NoneType found error where it seems that the library passes None as the private cert file location to xmlsec and hence it fails. If we disable following settings as per code below:
'WANT_ASSERTIONS_SIGNED': False, 'AUTHN_REQUESTS_SIGNED': False, 'WANT_RESPONSE_SIGNED': False,
We get the redirect to Google, however upon selecting the user, we get another exception: failed to verify signature. Would appreciate any help. Happy to do further testing and provide any required information.
Exact same situation here. Django 4.1, Python 3.8 and Okta dev tennant.
@michaelsteigman @defigor @tdiaque @rhelms AFAIK, if the key is not present in the metadata file, currently there's no way to explicitly pass it as part of the configuration settings. Can you confirm that the key is present in the metadata file? This is what @sgabb also figured out from an issue on fangli repo. I'll try to see if I can fix it. 👀 It might take some time, though.
@mostafa There is a request signing cert in the Okta metadata.
<md:EntityDescriptor entityID="http://www.okta.com/..">
<md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
...
Seems like this is what we're looking for?
@mostafa The same here, this is how it looks in the Google metadata: `
<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:X509CertificateCERTIFICATE_HERE</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </md:KeyDescriptor> md:NameIDFormaturn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat> <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://accounts.google.com/o/saml2/idp?idpid=ID_GOES_HERE"/> <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://accounts.google.com/o/saml2/idp?idpid=ID_GOES_HERE"/> </md:IDPSSODescriptor> </md:EntityDescriptor> `
We wanted to use this library, but couldn't wait that long for this :( We've already switched to djangosaml2 ( https://github.com/IdentityPython/djangosaml2 ) instead and it works with no issues.
@defigor Are you passing your own certificate or is it auto-generated?
@mostafa what do you mean passing? I was passing the metadata file via METADATA_LOCAL_FILE_PATH, that contained the certificate. This certificate is generated by Google when you setup a custom SAML app (but it seems that this certificate is being reused across all SAML apps in google).
See these links for more details: https://support.google.com/a/answer/6087519?product_name=UnuFlow&hl=en&visit_id=638040987359057980-994443535&rd=1&src=supportwidget0&hl=en https://support.google.com/a/answer/7394709?product_name=UnuFlow&hl=en&visit_id=638040987359057980-994443535&rd=1&src=supportwidget0&hl=en
Same error. TypeError: sequence item 3: expected str instance, NoneType found error. I trace the library and passes None as the private cert file location to xmlsec and hence it fails.
I get the same error "TypeError: sequence item 3: expected str instance, NoneType found error" as well. Has there been any progress with this?
we switched to djangosaml2
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.
We also switched to djangosaml2 because could not get this one to work :(
Unfortunately not yet disappointed Could it be linked to this issue of the original fangli repository?
This is an example of the metadata where there should be the Key and Certificate:
XML METADATA Does it look correct? Should the library read the private key and the certificate value from it without issue? I am still not sure if the issue regards the configuration of the metadata or if the library effectively does not search within the metadata but need to receive the key_file and cert_file as requested in pysam2...
@sgabb I am also facing the same issue ..my request is not getting signed from the SP....can you help me .I am using Djangosaml2 and authentik
Below is my saml configuration AML_CONFIG = { 'xmlsec_binary': '/usr/bin/xmlsec1', 'name': 'authentik', 'entityid': 'http://localhost:8003/saml2/metadata/', 'service': { 'sp': { 'want_assertions_signed': True, 'want_response_signed': True, 'allow_unsolicited': True, 'endpoints': { 'assertion_consumer_service': [ ('http://localhost:8003/saml/acs/', saml2.BINDING_HTTP_POST), ], 'single_logout_service': [ ('http://localhost:8003/saml/ls/', saml2.BINDING_HTTP_REDIRECT), ], }, 'required_attributes': ['email'], 'assertionConsumerService': { 'url': 'localhost:8003/admins/message/', # URL to receive SAML responses # Use the Redirect binding 'binding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', }, }, }, 'debug': 1, 'key_file': os.path.join(BASE_DIR, 'authentik_private_key.pem'), 'cert_file': os.path.join(BASE_DIR, 'authentik_certificate.pem'), 'allow_unknown_attributes': True, 'metadata': { 'local': [os.path.join(BASE_DIR, 'SAML-admin_authentik_meta.xml')], }, 'valid_for': 24, # how long is our metadata valid 'accepted_time_diff': 120, # seconds }
I've done a quick check on the code and it seemed quite easy to add a configuration to add the key and cert file and pass them down to pysaml2 library. I've made a PR that @mostafa may check https://github.com/grafana/django-saml2-auth/pull/176
If anybody that has "working" configuration that were broken because of the missing files, maybe can try checking the fork and test it to see if it works. I haven't had the time to add specific tests, but there weren't already as it seems for checking signed requests and responses...if someone can try it out then it's already a good starting point :grin:
@sgabb
Thanks for your contribution! I just merged it.
@mostafa my pleasure! Sorry about adding additional tests but I was a bit busy. However I tested it on a real working environment and it kinda worked! The AuthRequest was created with the certificate correctly (SP initiated request), than there was an error on the IdP but it was probably a misconfiguration on their part.
I am not sure what type of test we could prepare, maybe just trying the creation of a request by setting AUTHN_REQUESTS_SIGNED=True
, but at least now it doesn't break :muscle:
@sgabb Are you confident in the code and tests and should I go forward with the release or it needs more testings? I can think of a few options for testing:
- A developer account on Okta: easier to set up and test and we can store credentials and keys on GitHub.
- A local IdP for testing in CI: needs more investigation and possibly harder to configure, but is not prone to any attack vectors (I know of).
WDYT?
I am confident because the addition is very small and only add the possibility to pass down to pysaml the key and cert files. I would go forward with the release, and then we can think of adding some testing for signed requests and responses.
For sure it is better than before because it was immediately breaking whenever the settings asked for signing.