diff --git a/README.md b/README.md
index 2b25f961..404712e2 100644
--- a/README.md
+++ b/README.md
@@ -151,7 +151,7 @@ If our environment requires sign or encrypt support, the certs folder may contai
* sp.crt The public cert of the SP
* sp.key The private key of the SP
-Or also we can provide those data in the setting file at the ``X.509cert`` and the ``privateKey`` JSON parameters of the ``sp`` element.
+Or also we can provide those data in the setting file at the ``x509cert`` and the ``privateKey`` JSON parameters of the ``sp`` element.
Sometimes we could need a signature on the metadata published by the SP, in this case we could use the X.509 cert previously mentioned or use a new X.509 cert: ``metadata.crt`` and ``metadata.key``.
@@ -161,7 +161,7 @@ publish that X.509 certificate on Service Provider metadata.
If you want to create self-signed certs, you can do it at the https://www.samltool.com/self_signed_certs.php service, or using the command:
```bash
-openssl req -new -X.509 -days 3652 -nodes -out sp.crt -keyout saml.key
+openssl req -new -x509 -days 3652 -nodes -out sp.crt -keyout saml.key
```
#### demo-flask ####
@@ -264,7 +264,7 @@ This is the ``settings.json`` file:
// represent the requested subject.
// Take a look on src/onelogin/saml2/constants.py to see the NameIdFormat that are supported.
"NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
- // Usually X.509cert and privateKey of the SP are provided by files placed at
+ // Usually X.509 cert and privateKey of the SP are provided by files placed at
// the certs folder. But we can also provide them with the following parameters
"x509cert": "",
"privateKey": ""
@@ -310,7 +310,7 @@ This is the ``settings.json`` file:
* But take in mind that the fingerprint, is a hash, so at the end is open to a collision attack that can end on a signature validation bypass,
* that why we don't recommend it use for production environments.
*
- * (openssl X.509 -noout -fingerprint -in "idp.crt" to generate it,
+ * (openssl x509 -noout -fingerprint -in "idp.crt" to generate it,
* or add for example the -sha256 , -sha384 or -sha512 parameter)
*
* If a fingerprint is provided, then the certFingerprintAlgorithm is required in order to
@@ -343,7 +343,7 @@ This is the ``settings.json`` file:
}
```
-In addition to the required settings data (IdP, SP), extra settings can be defined in `advanced_settings.json`:
+In addition to the required settings data (idp, sp), extra settings can be defined in `advanced_settings.json`:
```javascript
{
@@ -865,7 +865,7 @@ else:
### SP Key rollover ###
-If you plan to update the SP ``X.509cert`` and ``privateKey`` you can define the new ``X.509cert`` as ``settings['sp']['X.509certNew']`` and it will be
+If you plan to update the SP ``x509cert`` and ``privateKey`` you can define the new ``x509cert`` as ``settings['sp']['x509certNew']`` and it will be
published on the SP metadata so Identity Providers can read them and get ready for rollover.
@@ -874,11 +874,11 @@ published on the SP metadata so Identity Providers can read them and get ready f
In some scenarios the IdP uses different certificates for
signing/encryption, or is under key rollover phase and more than one certificate is published on IdP metadata.
-In order to handle that the toolkit offers the ``settings['idp']['X.509certMulti']`` parameter.
+In order to handle that the toolkit offers the ``settings['idp']['x509certMulti']`` parameter.
-When that parameter is used, ``X.509cert`` and ``certFingerprint`` values will be ignored by the toolkit.
+When that parameter is used, ``x509cert`` and ``certFingerprint`` values will be ignored by the toolkit.
-The ``X.509certMulti`` is an array with 2 keys:
+The ``x509certMulti`` is an array with 2 keys:
- ``signing``: An array of certs that will be used to validate IdP signature
- ``encryption``: An array with one unique cert that will be used to encrypt data to be sent to the IdP.
@@ -1026,7 +1026,7 @@ A class that contains functionality related to the metadata of the SP
* ***builder*** Generates the metadata of the SP based on the settings.
* ***sign_metadata*** Signs the metadata with the key/cert provided.
-* ***add_X.509_key_descriptors*** Adds the X.509 descriptors (sign/encryption) to the metadata
+* ***add_x509_key_descriptors*** Adds the X.509 descriptors (sign/encryption) to the metadata
#### OneLogin_Saml2_Utils - utils.py ####
diff --git a/src/onelogin/saml2/auth.py b/src/onelogin/saml2/auth.py
index 106aabd8..5d6aa84f 100644
--- a/src/onelogin/saml2/auth.py
+++ b/src/onelogin/saml2/auth.py
@@ -327,7 +327,7 @@ def get_last_authn_contexts(self):
"""
return self.__last_authn_contexts
- def login(self, return_to=None, force_authn=False, is_passive=False, set_nameid_policy=True):
+ def login(self, return_to=None, force_authn=False, is_passive=False, set_nameid_policy=True, name_id_value_req=None):
"""
Initiates the SSO process.
@@ -343,10 +343,13 @@ def login(self, return_to=None, force_authn=False, is_passive=False, set_nameid_
:param set_nameid_policy: Optional argument. When true the AuthNRequest will set a nameIdPolicy element.
:type set_nameid_policy: bool
+ :param name_id_value_req: Optional argument. Indicates to the IdP the subject that should be authenticated
+ :type name_id_value_req: string
+
:returns: Redirection URL
:rtype: string
"""
- authn_request = OneLogin_Saml2_Authn_Request(self.__settings, force_authn, is_passive, set_nameid_policy)
+ authn_request = OneLogin_Saml2_Authn_Request(self.__settings, force_authn, is_passive, set_nameid_policy, name_id_value_req)
self.__last_request = authn_request.get_xml()
self.__last_request_id = authn_request.get_id()
diff --git a/src/onelogin/saml2/authn_request.py b/src/onelogin/saml2/authn_request.py
index 2a1eda88..57da1561 100644
--- a/src/onelogin/saml2/authn_request.py
+++ b/src/onelogin/saml2/authn_request.py
@@ -22,7 +22,7 @@ class OneLogin_Saml2_Authn_Request(object):
"""
- def __init__(self, settings, force_authn=False, is_passive=False, set_nameid_policy=True):
+ def __init__(self, settings, force_authn=False, is_passive=False, set_nameid_policy=True, name_id_value_req=None):
"""
Constructs the AuthnRequest object.
@@ -37,6 +37,9 @@ def __init__(self, settings, force_authn=False, is_passive=False, set_nameid_pol
:param set_nameid_policy: Optional argument. When true the AuthNRequest will set a nameIdPolicy element.
:type set_nameid_policy: bool
+
+ :param name_id_value_req: Optional argument. Indicates to the IdP the subject that should be authenticated
+ :type name_id_value_req: string
"""
self.__settings = settings
@@ -71,6 +74,14 @@ def __init__(self, settings, force_authn=False, is_passive=False, set_nameid_pol
if is_passive is True:
is_passive_str = "\n" + ' IsPassive="true"'
+ subject_str = ''
+ if name_id_value_req:
+ subject_str = """
+
+ %s
+
+ """ % (sp_data['NameIDFormat'], name_id_value_req)
+
nameid_policy_str = ''
if set_nameid_policy:
name_id_policy_format = sp_data['NameIDFormat']
@@ -112,6 +123,7 @@ def __init__(self, settings, force_authn=False, is_passive=False, set_nameid_pol
'destination': destination,
'assertion_url': sp_data['assertionConsumerService']['url'],
'entity_id': sp_data['entityId'],
+ 'subject_str': subject_str,
'nameid_policy_str': nameid_policy_str,
'requested_authn_context_str': requested_authn_context_str,
'attr_consuming_service_str': attr_consuming_service_str,
diff --git a/src/onelogin/saml2/xml_templates.py b/src/onelogin/saml2/xml_templates.py
index 99025546..ec4f6260 100644
--- a/src/onelogin/saml2/xml_templates.py
+++ b/src/onelogin/saml2/xml_templates.py
@@ -29,7 +29,7 @@ class OneLogin_Saml2_Templates(object):
Destination="%(destination)s"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
AssertionConsumerServiceURL="%(assertion_url)s"%(attr_consuming_service_str)s>
- %(entity_id)s%(nameid_policy_str)s
+ %(entity_id)s%(subject_str)s%(nameid_policy_str)s
%(requested_authn_context_str)s
"""
diff --git a/tests/src/OneLogin/saml2_tests/auth_test.py b/tests/src/OneLogin/saml2_tests/auth_test.py
index 2a2b557c..02193ee2 100644
--- a/tests/src/OneLogin/saml2_tests/auth_test.py
+++ b/tests/src/OneLogin/saml2_tests/auth_test.py
@@ -609,7 +609,7 @@ def testLoginSigned(self):
def testLoginForceAuthN(self):
"""
Tests the login method of the OneLogin_Saml2_Auth class
- Case Logout with no parameters. A AuthN Request is built with ForceAuthn and redirect executed
+ Case AuthN Request is built with ForceAuthn and redirect executed
"""
settings_info = self.loadSettingsJSON()
return_to = u'http://example.com/returnto'
@@ -642,7 +642,7 @@ def testLoginForceAuthN(self):
def testLoginIsPassive(self):
"""
Tests the login method of the OneLogin_Saml2_Auth class
- Case Logout with no parameters. A AuthN Request is built with IsPassive and redirect executed
+ Case AuthN Request is built with IsPassive and redirect executed
"""
settings_info = self.loadSettingsJSON()
return_to = u'http://example.com/returnto'
@@ -676,7 +676,7 @@ def testLoginIsPassive(self):
def testLoginSetNameIDPolicy(self):
"""
Tests the login method of the OneLogin_Saml2_Auth class
- Case Logout with no parameters. A AuthN Request is built with and without NameIDPolicy
+ Case AuthN Request is built with and without NameIDPolicy
"""
settings_info = self.loadSettingsJSON()
return_to = u'http://example.com/returnto'
@@ -707,6 +707,46 @@ def testLoginSetNameIDPolicy(self):
request_3 = compat.to_string(OneLogin_Saml2_Utils.decode_base64_and_inflate(parsed_query_3['SAMLRequest'][0]))
self.assertNotIn('', request)
+ self.assertNotIn('', request_2)
+ self.assertIn('Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">testuser@example.com', request_2)
+ self.assertIn('', request_2)
+
+ settings_info['sp']['NameIDFormat'] = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
+ auth_3 = OneLogin_Saml2_Auth(self.get_request(), old_settings=settings_info)
+ target_url_3 = auth_3.login(return_to, name_id_value_req='testuser@example.com')
+ parsed_query_3 = parse_qs(urlparse(target_url_3)[4])
+ self.assertIn(sso_url, target_url_3)
+ self.assertIn('SAMLRequest', parsed_query_3)
+ request_3 = compat.to_string(OneLogin_Saml2_Utils.decode_base64_and_inflate(parsed_query_3['SAMLRequest'][0]))
+ self.assertIn('', request_3)
+ self.assertIn('Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">testuser@example.com', request_3)
+ self.assertIn('', request_3)
+
def testLogout(self):
"""
Tests the logout method of the OneLogin_Saml2_Auth class
diff --git a/tests/src/OneLogin/saml2_tests/authn_request_test.py b/tests/src/OneLogin/saml2_tests/authn_request_test.py
index 71c99539..3f1262f2 100644
--- a/tests/src/OneLogin/saml2_tests/authn_request_test.py
+++ b/tests/src/OneLogin/saml2_tests/authn_request_test.py
@@ -257,6 +257,37 @@ def testCreateRequestSetNameIDPolicy(self):
self.assertRegex(inflated_3, '^', inflated)
+
+ authn_request_2 = OneLogin_Saml2_Authn_Request(settings, name_id_value_req='testuser@example.com')
+ authn_request_encoded_2 = authn_request_2.get_request()
+ inflated_2 = compat.to_string(OneLogin_Saml2_Utils.decode_base64_and_inflate(authn_request_encoded_2))
+ self.assertRegex(inflated_2, '^', inflated_2)
+ self.assertIn('Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">testuser@example.com', inflated_2)
+ self.assertIn('', inflated_2)
+
+ saml_settings['sp']['NameIDFormat'] = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
+ settings = OneLogin_Saml2_Settings(saml_settings)
+ authn_request_3 = OneLogin_Saml2_Authn_Request(settings, name_id_value_req='testuser@example.com')
+ authn_request_encoded_3 = authn_request_3.get_request()
+ inflated_3 = compat.to_string(OneLogin_Saml2_Utils.decode_base64_and_inflate(authn_request_encoded_3))
+ self.assertRegex(inflated_3, '^', inflated_3)
+ self.assertIn('Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">testuser@example.com', inflated_3)
+ self.assertIn('', inflated_3)
+
def testCreateDeflatedSAMLRequestURLParameter(self):
"""
Tests the OneLogin_Saml2_Authn_Request Constructor.