def create_light_request(self) -> LightRequest: """ Convert SAML Request to Light Request. :return: A Light Request. :raise ValidationError: If the SAML Request cannot be parsed correctly. """ request = LightRequest(requested_attributes=OrderedDict(), citizen_country_code=self.citizen_country_code, relay_state=self.relay_state) root = self.document.getroot() if root.tag != Q_NAMES['saml2p:AuthnRequest']: raise ValidationError({get_element_path(root): 'Wrong root element: {!r}'.format(root.tag)}) request.id = root.attrib.get('ID') request.provider_name = root.attrib.get('ProviderName') request.issuer = self.issuer name_id_format = root.find('./{}'.format(Q_NAMES['saml2p:NameIDPolicy'])) if name_id_format is not None: request.name_id_format = NameIdFormat(name_id_format.attrib.get('Format')) level_of_assurance = root.find( './{}/{}'.format(Q_NAMES['saml2p:RequestedAuthnContext'], Q_NAMES['saml2:AuthnContextClassRef'])) if level_of_assurance is not None: request.level_of_assurance = LevelOfAssurance(level_of_assurance.text) extensions = root.find('./{}'.format(Q_NAMES['saml2p:Extensions'])) if extensions is not None: sp_type = extensions.find('./{}'.format(Q_NAMES['eidas:SPType'])) if sp_type is not None: request.sp_type = ServiceProviderType(sp_type.text) sp_country = extensions.find('./{}'.format(Q_NAMES['eidas:SPCountry'])) if sp_country is not None: request.origin_country_code = sp_country.text requested_attributes = request.requested_attributes attributes = extensions.findall( './{}/{}'.format(Q_NAMES['eidas:RequestedAttributes'], Q_NAMES['eidas:RequestedAttribute'])) for attribute in attributes: name = attribute.attrib.get('Name') if not name: raise ValidationError({ get_element_path(attribute): "Missing attribute 'Name'"}) values = requested_attributes[name] = [] for value in attribute.findall('./{}'.format(Q_NAMES['eidas:AttributeValue'])): values.append(value.text) return request
def test_post_remember_country_codes(self, uuid_mock): self.maxDiff = None saml_request_xml, saml_request_encoded = self.load_saml_request( signed=True) light_request = LightRequest(**LIGHT_REQUEST_DICT) light_request.issuer = 'https://example.net/EidasNode/ConnectorMetadata' self.cache_mock.get_and_remove.return_value = dump_xml( light_request.export_xml()).decode('utf-8') response = self.client.post( self.url, { 'SAMLRequest': saml_request_encoded, 'RelayState': 'relay123', 'country_param': 'ca' }) self.assertEqual(response.status_code, 200) self.assertSequenceEqual(self.client_mock.mock_calls[-3:], [ call.connect('test.example.net', 1234), call.get_cache('aux-cache'), call.get_cache().put( 'aux-test-saml-request-id', '{"citizen_country": "CA", "origin_country": "CA"}'), ])
def test_post_success(self, uuid_mock: MagicMock): self.maxDiff = None saml_request_xml, saml_request_encoded = self.load_saml_request( signed=True) light_request = LightRequest(**LIGHT_REQUEST_DICT) light_request.issuer = 'https://example.net/EidasNode/ConnectorMetadata' self.cache_mock.get_and_remove.return_value = dump_xml( light_request.export_xml()).decode('utf-8') response = self.client.post( self.url, { 'SAMLRequest': saml_request_encoded, 'RelayState': 'relay123', 'country_param': 'ca' }) # Context self.assertIn('token', response.context) self.assertEqual(response.context['token_parameter'], 'test_request_token') self.assertEqual(response.context['eidas_url'], 'http://test.example.net/SpecificConnectorRequest') self.assertEqual(response.context['error'], None) # Token encoded_token = response.context['token'] token = LightToken.decode(encoded_token, 'sha256', 'request-token-secret') self.assertEqual(token.id, 'T0uuid4') self.assertEqual(token.issuer, 'request-token-issuer') self.assertEqual(token.created, datetime(2017, 12, 11, 14, 12, 5)) # Storing light request light_request_data = LIGHT_REQUEST_DICT.copy() light_request_data.update({ 'id': 'test-saml-request-id', 'issuer': 'test-connector-request-issuer', }) light_request = LightRequest(**light_request_data) light_request.requested_attributes = light_request.requested_attributes.copy( ) del light_request.requested_attributes[ 'http://eidas.europa.eu/attributes/naturalperson/AdditionalAttribute'] del light_request.requested_attributes[ 'http://eidas.europa.eu/attributes/legalperson/LegalAdditionalAttribute'] self.assertEqual(self.client_class_mock.mock_calls, [call(timeout=66)]) self.assertEqual(self.client_mock.mock_calls, [ call.connect('test.example.net', 1234), call.get_cache('test-connector-request-cache'), call.get_cache().put( 'T0uuid4', dump_xml(light_request.export_xml()).decode('utf-8')) ]) # Rendering self.assertContains(response, 'Redirect to eIDAS Node is in progress') self.assertContains(response, 'eidas_node/connector/formautosubmit.js') self.assertContains( response, '<form class="auto-submit" ' 'action="http://test.example.net/SpecificConnectorRequest"') self.assertContains( response, '<input type="hidden" name="test_request_token" value="{}"'.format( encoded_token)) self.assertNotIn(b'An error occurred', response.content)