我使用Simple SAML PHP作为我的IDP(身份提供程序)和Django SAML 2 Auth,以将SAML 2身份验证集成到我的Django应用程序(即SP(服务提供程序))。
这两个工具的配置如下:
简单的SAML PHP:
docker run --name=saml_idp -p 8080:8080 -p 8443:8443 -e SIMPLESAMLPHP_SP_ENTITY_ID=http://0.0.0.0:8000/saml2_auth/metadata.xml -e SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE=http://0.0.0.0:8000/saml2_auth/acs/ --network host -d kristophjunge/test-saml-idp
简单的SAML PHP元数据:
<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="http://127.0.0.1:8080/simplesaml/saml2/idp/metadata.php">
<md:IDPSSODescriptor 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>MIIDXTCCAkWgAwIBAgIJALmVVuDWu4NYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMxMTQzNDQ3WhcNNDgwNjI1MTQzNDQ3WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUCFozgNb1h1M0jzNRSCjhOBnR+uVbVpaWfXYIR+AhWDdEe5ryY+CgavOg8bfLybyzFdehlYdDRgkedEB/GjG8aJw06l0qF4jDOAw0kEygWCu2mcH7XOxRt+YAH3TVHa/Hu1W3WjzkobqqqLQ8gkKWWM27fOgAZ6GieaJBN6VBSMMcPey3HWLBmc+TYJmv1dbaO2jHhKh8pfKw0W12VM8P1PIO8gv4Phu/uuJYieBWKixBEyy0lHjyixYFCR12xdh4CA47q958ZRGnnDUGFVE1QhgRacJCOZ9bd5t9mr8KLaVBYTCJo5ERE8jymab5dPqe5qKfJsCZiqWglbjUo9twIDAQABo1AwTjAdBgNVHQ4EFgQUxpuwcs/CYQOyui+r1G+3KxBNhxkwHwYDVR0jBBgwFoAUxpuwcs/CYQOyui+r1G+3KxBNhxkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAAiWUKs/2x/viNCKi3Y6blEuCtAGhzOOZ9EjrvJ8+COH3Rag3tVBWrcBZ3/uhhPq5gy9lqw4OkvEws99/5jFsX1FJ6MKBgqfuy7yh5s1YfM0ANHYczMmYpZeAcQf2CGAaVfwTTfSlzNLsF2lW/ly7yapFzlYSJLGoVE+OHEu8g5SlNACUEfkXw+5Eghh+KzlIN7R6Q7r2ixWNFBC/jWf7NKUfJyX8qIG5md1YUeT6GBW9Bm2/1/RiO24JTaYlfLdKK9TYb8sG5B+OLab2DImG99CJ25RkAcSobWNF5zD0O6lgOo3cEdB/ksCq3hmtlC/DlLZ/D8CJ+7VuZnS1rR2naQ==</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>MIIDXTCCAkWgAwIBAgIJALmVVuDWu4NYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMxMTQzNDQ3WhcNNDgwNjI1MTQzNDQ3WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUCFozgNb1h1M0jzNRSCjhOBnR+uVbVpaWfXYIR+AhWDdEe5ryY+CgavOg8bfLybyzFdehlYdDRgkedEB/GjG8aJw06l0qF4jDOAw0kEygWCu2mcH7XOxRt+YAH3TVHa/Hu1W3WjzkobqqqLQ8gkKWWM27fOgAZ6GieaJBN6VBSMMcPey3HWLBmc+TYJmv1dbaO2jHhKh8pfKw0W12VM8P1PIO8gv4Phu/uuJYieBWKixBEyy0lHjyixYFCR12xdh4CA47q958ZRGnnDUGFVE1QhgRacJCOZ9bd5t9mr8KLaVBYTCJo5ERE8jymab5dPqe5qKfJsCZiqWglbjUo9twIDAQABo1AwTjAdBgNVHQ4EFgQUxpuwcs/CYQOyui+r1G+3KxBNhxkwHwYDVR0jBBgwFoAUxpuwcs/CYQOyui+r1G+3KxBNhxkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAAiWUKs/2x/viNCKi3Y6blEuCtAGhzOOZ9EjrvJ8+COH3Rag3tVBWrcBZ3/uhhPq5gy9lqw4OkvEws99/5jFsX1FJ6MKBgqfuy7yh5s1YfM0ANHYczMmYpZeAcQf2CGAaVfwTTfSlzNLsF2lW/ly7yapFzlYSJLGoVE+OHEu8g5SlNACUEfkXw+5Eghh+KzlIN7R6Q7r2ixWNFBC/jWf7NKUfJyX8qIG5md1YUeT6GBW9Bm2/1/RiO24JTaYlfLdKK9TYb8sG5B+OLab2DImG99CJ25RkAcSobWNF5zD0O6lgOo3cEdB/ksCq3hmtlC/DlLZ/D8CJ+7VuZnS1rR2naQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://127.0.0.1:8080/simplesaml/saml2/idp/SingleLogoutService.php"/>
<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="http://127.0.0.1:8080/simplesaml/saml2/idp/SSOService.php"/>
</md:IDPSSODescriptor>
</md:EntityDescriptor>
Django SAML 2身份验证:
XMLSEC_BINARY = '/usr/local/bin/xmlsec1'
# The configurations set here need to be the same as the IDP / SP configuration, that is
# described in the metadata files (https://www.samltool.com/online_tools.php)
SAML2_AUTH = {
# Metadata is required, choose either remote URL or local file path
'METADATA_AUTO_CONF_URL': 'http://127.0.0.1:8080/simplesaml/saml2/idp/metadata.php',
'METADATA_LOCAL_FILE_PATH': '/code/app/metadata_idp.xml',
# Optional settings below
'DEFAULT_NEXT_URL': '/',
'CREATE_USER': 'FALSE',
'NEW_USER_PROFILE': {
'USER_GROUPS': [],
'ACTIVE_STATUS': True,
'STAFF_STATUS': True,
'SUPERUSER_STATUS': False
},
# Change user name / password to corresponding SAML2 user profile attributes
'ATTRIBUTES_MAP': {
'username': 'username',
'password': 'password'
},
# 'TRIGGER': {
# 'CREATE_USER': 'path.to.your.new.user.hook.method',
# 'BEFORE_LOGIN': 'path.to.your.login.hook.method',
# },
# Custom URL to validate incoming SAML requests against
'ASSERTION_URL': 'http://0.0.0.0:8000/saml2_auth/acs/',
# Populates the Issuer element in authn request
'ENTITY_ID': 'http://0.0.0.0:8000/saml2_auth/metadata.xml'
}
[Django SAML 2 Auth元数据:
<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" validUntil="2019-12-09T14:01:55Z" cacheDuration="PT604800S" entityID="http://0.0.0.0:8000/saml2_auth/metadata.xml">
<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="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>MIIFazCCA1OgAwIBAgIUaIcEZyo+RfcwO/s/iug723Rs0BMwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTEyMDYxNzEzNDZaFw0yMDEyMDUxNzEzNDZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9COPzO/nV2t2c3nh0a5UvVD9S8wK1SDaiPWeJ2d8MjOV4NPQlTtKLG1JZcoOlNViZY+ywsIZFTYCyHIuoSX3gyd2p4PGGevip/SwWPxOQ00PStOuCMBJv9reoZEsIJd9V40FTbPCeNktWyO0u2NUWJmJnMOvhzaXvV4yNHZC3aUcYvuBmtodpBSuzLYgnsKJyCUV7XEwKrrYeHzZXsTTRmmnXxTFqs+zAFuhQRoRfMXaQjDFFwToX/fZ9YFlM3LdtkBv3gImSo5nuR1oP9k42H3B0ejK+i/CEzRk5y+4B5yIZLnnP+DVBqf9BXWeelYkaenU39gxH9Sb8dnBMR31FnXibUjrRXYB0t7a4Fl+ZLT3U7l1BHjqXJ2WO5/hybQ/dxUOJCoT93z9MLFegQfIx7AfJkQ/6xwKTgt7iCFFOswzPcvw/hzx//Cu2JxEaunYdHiJiQgDdZtIPn22BjJ2v2gxjKGUIascDmC78VH5ZA40XCXewHma6CLOWQ8FggKzYWr0WwCu+J/EmqDDPuZE/Qlz6ij2akfUh2LRpFZF5coKy9vpxiyeak9+3lKrTWkdflyd2uBhsqPoeXNvwrf4yC4TPNuIDGNYgstq80uCmaK4qBh+TGvnpeD8/3F+7q/t10hNJDftuKgz4zmIugcBs6x7CTMZjhJ+7bBAbzI4IJwIDAQABo1MwUTAdBgNVHQ4EFgQUVXGXpXGp2c8JC9+y/8a1t68Op54wHwYDVR0jBBgwFoAUVXGXpXGp2c8JC9+y/8a1t68Op54wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAudPK04qXdjVNSBS6kA2eitkePDfbn61uIe8zXUYMsXYXD97qrwuzKU4vPpvP9zjjRm24hYAuOQ6VARNBHfD2VDXcg/J2r8EuVS+/acElb3TIDJmFNYxVwahhC3ZQ27q8BOVWEUR22biloAkTAqbpZeugHVOCMRxS9DvBTOjw9RFV15qc7nzs9P9yM3Kss+TM6hAFetCi0LIhOTujv3j6GPzMQ9jITb4T+EdjvmazzjSEYPmm5QwVaL98hTlHfTSB8Gsx6Vh/K859ZDrNyzbqck4DKd1WcGjykmcEQQx6ixGGDx/nRKQyW5aYKD2a+AL5WcFqwIc974kH3fNKYyeIgucVmjeJsivzMx8u29AQ5RPLRW8iCGuX2+igNGG7NaHN2psaSnYW9Z8NCO7R9AQHuc9s5TJfV60gJ5JqxARL45veeE6ALiXGKEHMHSXBpHWKSF04eTNgGhq8IkJeQPR8Gv7aGu6lMn040C/YtwgYVuqsgtYRylhdPBUEHGhjdFBUlmcSnaDv8ro7J8IkafMACHgp8U27C7bHg6bwAbpiKYojKvCpZDBpGsAQui4JaCR1Z6CGdkTAXzArRIxgNG17m4vhJQOMyQCeIbryy510mjEWwircPQ2lFpO1KEIL7QXUVUxbpRCGfsEg4Oeqvhl57az2/UG/dSadIJLuVOxHDdc=</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>MIIFazCCA1OgAwIBAgIUaIcEZyo+RfcwO/s/iug723Rs0BMwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTEyMDYxNzEzNDZaFw0yMDEyMDUxNzEzNDZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9COPzO/nV2t2c3nh0a5UvVD9S8wK1SDaiPWeJ2d8MjOV4NPQlTtKLG1JZcoOlNViZY+ywsIZFTYCyHIuoSX3gyd2p4PGGevip/SwWPxOQ00PStOuCMBJv9reoZEsIJd9V40FTbPCeNktWyO0u2NUWJmJnMOvhzaXvV4yNHZC3aUcYvuBmtodpBSuzLYgnsKJyCUV7XEwKrrYeHzZXsTTRmmnXxTFqs+zAFuhQRoRfMXaQjDFFwToX/fZ9YFlM3LdtkBv3gImSo5nuR1oP9k42H3B0ejK+i/CEzRk5y+4B5yIZLnnP+DVBqf9BXWeelYkaenU39gxH9Sb8dnBMR31FnXibUjrRXYB0t7a4Fl+ZLT3U7l1BHjqXJ2WO5/hybQ/dxUOJCoT93z9MLFegQfIx7AfJkQ/6xwKTgt7iCFFOswzPcvw/hzx//Cu2JxEaunYdHiJiQgDdZtIPn22BjJ2v2gxjKGUIascDmC78VH5ZA40XCXewHma6CLOWQ8FggKzYWr0WwCu+J/EmqDDPuZE/Qlz6ij2akfUh2LRpFZF5coKy9vpxiyeak9+3lKrTWkdflyd2uBhsqPoeXNvwrf4yC4TPNuIDGNYgstq80uCmaK4qBh+TGvnpeD8/3F+7q/t10hNJDftuKgz4zmIugcBs6x7CTMZjhJ+7bBAbzI4IJwIDAQABo1MwUTAdBgNVHQ4EFgQUVXGXpXGp2c8JC9+y/8a1t68Op54wHwYDVR0jBBgwFoAUVXGXpXGp2c8JC9+y/8a1t68Op54wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAudPK04qXdjVNSBS6kA2eitkePDfbn61uIe8zXUYMsXYXD97qrwuzKU4vPpvP9zjjRm24hYAuOQ6VARNBHfD2VDXcg/J2r8EuVS+/acElb3TIDJmFNYxVwahhC3ZQ27q8BOVWEUR22biloAkTAqbpZeugHVOCMRxS9DvBTOjw9RFV15qc7nzs9P9yM3Kss+TM6hAFetCi0LIhOTujv3j6GPzMQ9jITb4T+EdjvmazzjSEYPmm5QwVaL98hTlHfTSB8Gsx6Vh/K859ZDrNyzbqck4DKd1WcGjykmcEQQx6ixGGDx/nRKQyW5aYKD2a+AL5WcFqwIc974kH3fNKYyeIgucVmjeJsivzMx8u29AQ5RPLRW8iCGuX2+igNGG7NaHN2psaSnYW9Z8NCO7R9AQHuc9s5TJfV60gJ5JqxARL45veeE6ALiXGKEHMHSXBpHWKSF04eTNgGhq8IkJeQPR8Gv7aGu6lMn040C/YtwgYVuqsgtYRylhdPBUEHGhjdFBUlmcSnaDv8ro7J8IkafMACHgp8U27C7bHg6bwAbpiKYojKvCpZDBpGsAQui4JaCR1Z6CGdkTAXzArRIxgNG17m4vhJQOMyQCeIbryy510mjEWwircPQ2lFpO1KEIL7QXUVUxbpRCGfsEg4Oeqvhl57az2/UG/dSadIJLuVOxHDdc=</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://0.0.0.0:8000/saml2_auth/acs/" index="1"/>
</md:SPSSODescriptor>
</md:EntityDescriptor>
当我访问0.0.0.0:8000/saml2_auth/login时,我被重定向到我登录并返回到127.0.0.1:8080/simplesaml/saml2/idp/SSOService.php的0.0.0.0:8000/saml2_auth/acs/,但是当我返回时,收到以下错误:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/django_saml2_auth/views.py", line 159, in acs
resp, entity.BINDING_HTTP_POST)
File "/usr/local/lib/python3.7/site-packages/saml2/client_base.py", line 714, in parse_authn_request_response
binding, **kwargs)
File "/usr/local/lib/python3.7/site-packages/saml2/entity.py", line 1205, in _parse_response
response.require_signature = require_signature
AttributeError: 'NoneType' object has no attribute 'require_signature'
我已经读过'NoneType' object has no attribute 'require_signature',但这没有帮助。如何解决此问题。
Obs¹:证书是使用openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -days 365
生成的
Obs²:我也用JavaScript创建了example,并且一切正常
Obs³:回到/ asc时,会话已在IDP中设置,并且也返回到SP:
[当我将一些为Flask编写的示例代码移植到Django / DRF时,我没有得到正确的表单信息,这意味着SAMLResponse只是一个乱码,而不是字典,因此对于'require'没有任何价值>
更改从request.body["SAMLResponse"]
到request.POST["SAMLResponse"]
以获取信息就可以了。