示例#1
0
    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)