def request_refresh_token(self):
        # TODO turned off for now this function
        return

        # Check needed vars on OpenIDAuthentication class
        check_needed_class_vars(self, ['auth_code'])

        # Check needed vars on RESO class
        check_needed_class_vars(self.reso,
                                ['client_id', 'client_secret', 'access_token'])
        auth_string = '{}:{}'.format(self.reso.client_id,
                                     self.reso.client_secret)
        headers = {
            'Authorization':
            'Basic {}'.format(
                b64encode(auth_string.encode('utf-8')).decode('utf-8'))
        }
        url_parameters = {
            'client_id': self.reso.client_id,
            'grant_type': 'refresh_token',
            'refresh_token': self.reso.access_token,
        }

        refresh_token_response = self.context.post(self.reso.api_token_url,
                                                   headers=headers,
                                                   data=url_parameters)
        self.reso.logger.info('Got response {}'.format(refresh_token_response))

        if refresh_token_response.status_code != 200:
            raise ValueError(
                refresh_token_response.json().get('error_description'))

        return refresh_token_response.json().get('refresh_token')
Esempio n. 2
0
    def test_validate_missing_variable(self):
        reso = RESO()
        variable = 'client_id'
        with self.assertRaises(MissingVariables) as context:
            check_needed_class_vars(reso, [variable])

        self.assertEqual(
            'Missing {} on {}'.format(variable, reso.__class__.__name__),
            str(context.exception))
    def get_login_url(self):
        """
        Forms login url for web integrations.
        :return: formed url
        """
        # Check needed vars on OpenIDAuthentication class
        check_needed_class_vars(self, ['scope', 'redirect_uri'])

        # Check needed vars on RESO class
        check_needed_class_vars(self.reso, ['client_id', 'api_auth_url'])
        url_parameters = {
            'client_id': self.reso.client_id,
            'scope': self.scope,
            'response_type': self.response_type,
            'redirect_uri': self.redirect_uri,
        }
        return self.reso.api_auth_url + '?' + parse.urlencode(url_parameters)
    def request_post(self, request_url, request_accept_type, post_data):
        """
        Executes POST request on specified request_url
        :param request_url: path where to execute POST request
        :param request_accept_type: request accept type header value
        :param post_data: data which should be sent via POST request
        :return: returns response object on successful HTTP 200 request
        """
        if not isinstance(post_data, dict):
            raise ParsingError('\'post_data\' must be of instance dict')
        # Check needed vars on RESO class
        check_needed_class_vars(self.reso, ['api_request_url', 'access_token'])

        self.reso.logger.debug('Forming request url')
        formed_request_url = self._return_formed_url(request_url)

        request_accept_type = self._form_request_accept_type(
            request_accept_type)

        headers = {
            'Accept': request_accept_type,
            'Authorization': 'Bearer ' + self.reso.access_token
        }

        self.reso.logger.debug(
            'Sending POST request to {}'.format(formed_request_url))
        response = requests.post(formed_request_url,
                                 headers=headers,
                                 data=post_data,
                                 verify=self.reso.verify_ssl)
        self.reso.logger.info('Got POST {} response {}'.format(
            formed_request_url, response))
        if not response or response.status_code != 200:
            if response.status_code == 406:
                raise RequestError(
                    "API returned HTTP code 406 - Not Acceptable. "
                    "Please, setup a valid request accept type, current - {}".
                    format(request_accept_type))
            else:
                raise RequestError(
                    "Could not retrieve API response. "
                    "Response: {}".format(
                        response.json() if response.json() else response))
        return response
    def request(self, request_url, request_accept_type):
        """
        Executes GET request on specified request_url
        :param request_url: path where to execute GET request
        :param request_accept_type: request accept type header value
        :return: returns response object on successful HTTP 200 request
        """
        # Check needed vars on RESO class
        check_needed_class_vars(self.reso, ['api_request_url', 'access_token'])

        self.reso.logger.debug('Forming request url')
        formed_request_url = self._return_formed_url(request_url)

        request_accept_type = self._form_request_accept_type(
            request_accept_type)
        headers = {
            'Accept': request_accept_type,
            'Authorization': 'Bearer ' + self.reso.access_token
        }

        self.reso.logger.debug(
            'Sending GET request to {}'.format(formed_request_url))
        response = requests.get(formed_request_url,
                                headers=headers,
                                verify=self.reso.verify_ssl)
        self.reso.logger.info('Got GET {} response {}'.format(
            formed_request_url, response))
        if not response or response.status_code != 200:
            if response.status_code == 406:
                raise RequestError(
                    "API returned HTTP code 406 - Not Acceptable. "
                    "Please, setup a valid request accept type, current - {}".
                    format(request_accept_type))
            else:
                try:
                    msg = response.json()
                except json.decoder.JSONDecodeError:
                    msg = response
                raise RequestError("Could not retrieve API response. "
                                   "Response: {}".format(msg))
        return response
    def request_access_token(self):
        """
        Requests access token from the server provided as 'api_token_url' parameter
        :return: access_token
        """
        # Check needed vars on OpenIDAuthentication class
        check_needed_class_vars(self, ['auth_code', 'redirect_uri'])

        # Check needed vars on RESO class
        check_needed_class_vars(
            self.reso, ['client_id', 'client_secret', 'api_token_url'])

        auth_string = '{}:{}'.format(self.reso.client_id,
                                     self.reso.client_secret)
        headers = {
            'Authorization':
            'Basic {}'.format(
                b64encode(auth_string.encode('utf-8')).decode('utf-8'))
        }
        url_parameters = {
            'client_id': self.reso.client_id,
            'grant_type': self.grant_type,
            'code': self.auth_code,
            'redirect_uri': self.redirect_uri,
        }
        self.reso.logger.info(
            'Retrieving access token: {} with headers {} and parameters {}'.
            format(self.reso.api_token_url, headers, url_parameters))
        access_token_response = self.context.post(self.reso.api_token_url,
                                                  headers=headers,
                                                  data=url_parameters)
        self.reso.logger.info(
            'Got access_token response {}'.format(access_token_response))
        if access_token_response.status_code != 200:
            raise ValueError(
                access_token_response.json().get('error_description')
                or access_token_response.json())

        return access_token_response.json().get('access_token')
Esempio n. 7
0
 def test_validate_no_missing_variable(self):
     reso = RESO(client_id='some-client-id')
     variable = 'client_id'
     check_needed_class_vars(reso, [variable])
    def authorize(self, username, password):
        """
        This function is dedicated for retrieving needed authorization code from OpenID server.
        :param username: username of a user
        :param password: password of a user
        :return: authorization_code
        """
        if not username or not password:
            raise ValueError('Username or password was not supplied')

        self.reso.logger.info(
            "Getting auth code for client {} (username {}) with scope {} and redirect_uri {}"
            .format(self.reso.client_id, username, self.scope,
                    self.redirect_uri))

        # Check needed vars on OpenIDAuthentication class
        check_needed_class_vars(self, ['scope', 'redirect_uri'])
        # Check needed vars on RESO class
        check_needed_class_vars(self.reso, ['client_id', 'api_auth_url'])

        url_parameters = {
            'client_id': self.reso.client_id,
            'scope': self.scope,
            'response_type': self.response_type,
            'redirect_uri': self.redirect_uri,
        }

        # all cookies received will be stored in the session object to allow redirects form server

        self.reso.logger.info(
            'Getting response from {} with parameters {}'.format(
                self.reso.api_auth_url, url_parameters))
        response = self.context.get(self.reso.api_auth_url,
                                    params=url_parameters)

        self.reso.logger.debug('Parsing html response for form inputs')
        bs = BeautifulSoup(response.content, 'html.parser')
        raw_form = bs.find('form')
        if not raw_form:
            raise ParsingError(
                'Could not receive authorization form. Check credentials')
        form_inputs = {
            raw_input.attrs.get('name'): raw_input.attrs.get('value')
            for raw_input in raw_form.find_all('input')
        }

        return_response = {
            'url': raw_form.attrs.get('action'),
            'method': raw_form.attrs.get('method'),
            'inputs': form_inputs
        }

        self.reso.logger.debug('Forming login url for posting credentials')
        url = self._form_authentication_url(bs, return_response)

        headers = {"Content-Type": "application/x-www-form-urlencoded"}

        self._fill_authentication_data(return_response, username, password)
        auth_code_response = self.context.post(url,
                                               data=return_response['inputs'],
                                               headers=headers,
                                               verify=self.reso.verify_ssl)
        self.reso.logger.info('Getting auth code from the latest redirect')
        parsed_parameters = parse.parse_qs(
            parse.urlparse(auth_code_response.url,
                           allow_fragments=False).query)
        if parsed_parameters.keys():
            auth_code = parsed_parameters[list(parsed_parameters.keys())[0]]
            self.reso.logger.info('Parsed auth code from url parameters')
            return auth_code if not isinstance(auth_code,
                                               list) else auth_code[0]

        self.reso.logger.error(
            'Could not find any parameter in url parameters.')
        raise ParsingError('Could not find any parameter in the redirect uri')