Пример #1
0
    def get_auth_url(self, state=None, redirect_uri=None):
        """
        Return url which end-user should visit to authorize at ESIA.
        :param str or None state: identifier, will be returned as GET parameter in redirected request after auth.
        :param str or None redirect_uri: uri, where browser will be redirected after authorization.
        :return: url
        :rtype: str
        """
        params = {
            'client_id': self.settings.esia_client_id,
            'client_secret': '',
            'redirect_uri': redirect_uri or self.settings.redirect_uri,
            'scope': self.settings.esia_scope,
            'response_type': 'code',
            'state': state or str(uuid.uuid4()),
            'timestamp': get_timestamp(),
            'access_type': 'offline'
        }
        params = sign_params(params,
                             certificate_file=self.settings.certificate_file,
                             private_key_file=self.settings.private_key_file)

        params = urlencode(sorted(params.items(
        )))  # sorted needed to make uri deterministic for tests.

        return '{base_url}{auth_url}?{params}'.format(
            base_url=self.settings.esia_service_url,
            auth_url=self._AUTHORIZATION_URL,
            params=params)
Пример #2
0
    def get_auth_url(self, state=None):
        """
        Return url which end-user should visit to authorize at ESIA.
        :param str or None state: identifier, will be returned as GET parameter in redirected request after auth..
        :return: url
        :rtype: str
        """
        params = {
            'client_id': self.settings.esia_client_id,
            'client_secret': '',
            'redirect_uri': self.settings.redirect_uri,
            'scope': self.settings.esia_scope,
            'response_type': 'code',
            'state': state or str(uuid.uuid4()),
            'timestamp': get_timestamp(),
            'access_type': 'offline'
        }

        params = sign_params(params,
                             certificate_file=self.settings.certificate_file,
                             private_key_file=self.settings.private_key_file)

        params = urlencode(sorted(params.items()))  # sorted needed to make uri deterministic for tests.

        return '{base_url}{auth_url}?{params}'.format(base_url=self.settings.esia_service_url,
                                                      auth_url=self._AUTHORIZATION_URL,
                                                      params=params)
Пример #3
0
    def test_sign_params(self):

        scope = 'openid http://esia.gosuslugi.ru/usr_inf'
        timestamp = '2015.11.02 09:37:16 +0000'
        client_id = 'YOURID'
        state = 'f918e3be-664e-45db-b5a2-adbf5d6ae3f6'

        params = {
            'redirect_uri': 'http://your-service.ru/redirect_handler',
            'access_type': 'offline',
            'state': state,
            'scope': scope,
            'response_type': 'code',
            'client_id': client_id,
            'timestamp': timestamp,
        }

        signed_params = sign_params(params,
                                    certificate_file=TEST_SETTINGS.certificate_file,
                                    private_key_file=TEST_SETTINGS.private_key_file)

        self.assertIn('client_secret', signed_params)

        signature = signed_params['client_secret']

        message = ''.join([scope, timestamp, client_id, state])

        def write_to_temp_file(content):
            """
            Writes content to temp file and returns file name
            :param content: binary content
            :return: file path
            """
            temp_file = tempfile.NamedTemporaryFile(mode='wb', delete=False)
            temp_file.write(content)
            temp_file.close()
            return temp_file.name

        message_path = write_to_temp_file(message.encode())

        try:
            encoded_signature = base64.urlsafe_b64decode(signature)
        except Exception as e:
            self.fail("client_id is not urlsafe base64 encoded string! (Exc: %s)" % e)

        signature_path = write_to_temp_file(encoded_signature)

        verify_cmd_tpl = "openssl smime -verify -inform DER -in {sig} -content {cnt} -noverify  -certfile {cert_file}"
        verify_cmd = verify_cmd_tpl.format(
            sig=signature_path,
            cnt=message_path,
            cert_file=TEST_SETTINGS.certificate_file
        )
        print(verify_cmd)
        res = os.system(verify_cmd)
        self.assertEqual(res, 0, "Signature verification failed!")
Пример #4
0
    def complete_authorization(self,
                               code,
                               state,
                               validate_token=True,
                               redirect_uri=None):
        """
        Exchanges received code and state to access token, validates token (optionally), extracts ESIA user id from
        token and returns ESIAInformationConnector instance.
        :type code: str
        :type state: str
        :param boolean validate_token: perform token validation
        :param str or None redirect_uri: uri, where browser will be redirected after authorization.
        :rtype: EsiaInformationConnector
        :raises IncorrectJsonError: if response contains invalid json body
        :raises HttpError: if response status code is not 2XX
        :raises IncorrectMarkerError: if validate_token set to True and received token cannot be validated
        """
        params = {
            'client_id': self.settings.esia_client_id,
            'code': code,
            'grant_type': 'authorization_code',
            'redirect_uri': redirect_uri or self.settings.redirect_uri,
            'timestamp': get_timestamp(),
            'token_type': 'Bearer',
            'scope': self.settings.esia_scope,
            'state': state,
        }

        params = sign_params(params,
                             certificate_file=self.settings.certificate_file,
                             private_key_file=self.settings.private_key_file)

        url = '{base_url}{token_url}'.format(
            base_url=self.settings.esia_service_url,
            token_url=self._TOKEN_EXCHANGE_URL)

        response_json = make_request(url=url, method='POST', data=params)

        id_token = response_json['id_token']

        if validate_token:
            payload = self._validate_token(id_token)
        else:
            payload = self._parse_token(id_token)

        return EsiaInformationConnector(
            access_token=response_json['access_token'],
            oid=self._get_user_id(payload),
            settings=self.settings)
Пример #5
0
    def complete_authorization(self, code, state, validate_token=True, redirect_uri=None):
        """
        Exchanges received code and state to access token, validates token (optionally), extracts ESIA user id from
        token and returns ESIAInformationConnector instance.
        :type code: str
        :type state: str
        :param boolean validate_token: perform token validation
        :param str or None redirect_uri: uri, where browser will be redirected after authorization.
        :rtype: EsiaInformationConnector
        :raises IncorrectJsonError: if response contains invalid json body
        :raises HttpError: if response status code is not 2XX
        :raises IncorrectMarkerError: if validate_token set to True and received token cannot be validated
        """
        params = {
            'client_id': self.settings.esia_client_id,
            'code': code,
            'grant_type': 'authorization_code',
            'redirect_uri': redirect_uri or self.settings.redirect_uri,
            'timestamp': get_timestamp(),
            'token_type': 'Bearer',
            'scope': self.settings.esia_scope,
            'state': state,
        }

        params = sign_params(params,
                             certificate_file=self.settings.certificate_file,
                             private_key_file=self.settings.private_key_file)

        url = '{base_url}{token_url}'.format(base_url=self.settings.esia_service_url,
                                             token_url=self._TOKEN_EXCHANGE_URL)

        response_json = make_request(url=url, method='POST', data=params)

        id_token = response_json['id_token']

        if validate_token:
            payload = self._validate_token(id_token)
        else:
            payload = self._parse_token(id_token)

        return EsiaInformationConnector(access_token=response_json['access_token'],
                                        oid=self._get_user_id(payload),
                                        settings=self.settings)