def get_authorized_tokens(self, oauth_verifier, extra_args=None): """ Returns a dict of authorized tokens after they go through the :class:`get_authentication_tokens` phase. :param oauth_verifier: (required) The oauth_verifier (or a.k.a PIN for non web-apps) retrieved from the callback url querystring :rtype: dict """ if self.oauth_version != 1: raise ApiError( "This method can only be called when your OAuth version is 1.0." ) request_args = {} if extra_args: for (k, v) in extra_args.items(): if k not in request_args: request_args[k] = v self.client.auth.client.verifier = oauth_verifier response = self.client.get( self.access_token_url, params=request_args, headers={"Content-Type": "application/json"}, ) self.client.auth.client.verifier = None if response.status_code != 200: # we already catch these if response.status_code not in (400, 401): raise ApiError("invalid status code") if response.status_code in (400, 401): try: try: # try to get json content = response.json() except AttributeError: # pragma: no cover # if unicode detected content = json.loads(response.text) except ValueError: content = {} raise ApiError( content.get("error", "Invalid / expired Token"), error_code=response.status_code, ) # requests: response.text is the decoded response; .content is raw bytes # requests/iso-http-spec defaults to latin-1 if no encoding is present # we know this is utf-8 because of the oauth spec # so we force utf-8 here off the .content authorized_tokens = dict(parse_qsl(response.content.decode("utf-8"))) if not authorized_tokens: raise ApiError("Unable to decode authorized tokens.") return authorized_tokens # pragma: no cover
def callback__authorization_base_url_post(req): """POST /authority/oauth2/flow-a/authorization is visited by the USER_BROWSER after doing the GET""" assert req.url.startswith( oauth2_utils.OAUTH2__URL_AUTHORITY_FLOWA_AUTHORIZATION ) payload = dict(parse_qsl(req.body)) testapp_authority = test_env["testapp_authority"] res = testapp_authority.post( "/authority/oauth2/flow-a/authorization", payload, headers=req.headers, extra_environ=test_env["extra_environ_authority"], status=302, ) test_env["requests_session_authority"].cookies.update( testapp_authority.cookies ) # update the session with the cookies from the response # assume this is a valid request # ResponseHeaders([('Location', 'https://app.example.com/application/flow-register/authorized-callback?state=XufmnJbYMKORxkgj1jtfIbojm1YFwm&code=bLE6gTXo7nxvdNlvWzXsIdOh53Xe1f')]) assert "Location" in res.headers _uri_redirect = res.headers["Location"] assert _uri_redirect.startswith( oauth2_model.OAUTH2__URL_APP_FLOW_REGISTER_CALLBACK ) _base, _qs = _uri_redirect.split("?") _qs = dict(parse_qsl(_qs)) assert _qs.get("state") assert _qs.get("code") # status is '200 OK' # return in a format tailored for `requests` return (int(res.status.split(" ")[0]), res.headers, res.body)
def callback__url_revoke_token_post(req): assert req.url == oauth2_utils.OAUTH2__URL_AUTHORITY_REVOKE_TOKEN payload = dict(parse_qsl(req.body)) testapp_authority = test_env["testapp_authority"] res = testapp_authority.post( "/authority/oauth2/revoke_token", payload, headers=req.headers, extra_environ=test_env["extra_environ_authority"], status=200, ) test_env["requests_session_authority"].cookies.update( testapp_authority.cookies ) # update the session with the cookies from the response # status is '200 OK' # return in a format tailored for `requests` return (int(res.status.split(" ")[0]), res.headers, res.body)
def callback__url_token_limited__post(req): assert req.url == apiClient._url_token_limited payload = dict(parse_qsl(req.body)) testapp_authority = test_env["testapp_authority"] res = testapp_authority.post( "/authority/oauth2/flow-c/token_limited", payload, headers=req.headers, extra_environ=test_env["extra_environ_authority"], status=400, ) test_env["requests_session_authority"].cookies.update( testapp_authority.cookies ) # update the session with the cookies from the response # status is '200 OK' # return in a format tailored for `requests` return (int(res.status.split(" ")[0]), res.headers, res.body)
def callback__authenticate_post(req, test_env=test_env): """/authority/oauth1/authorize is visited by the USER""" assert req.url.startswith(OAUTH1__URL_AUTHORITY_AUTHENTICATE) payload = dict(parse_qsl(req.body)) testapp = test_env["testapp_authority"] res = testapp.post( "/authority/oauth1/authorize", payload, headers=req.headers, extra_environ=test_env["extra_environ_authority"], status=302, ) test_env["requests_session_authority"].cookies.update( testapp.cookies ) # update the session with the cookies from the response # status is '200 OK' # return in a format tailored for `requests` return (int(res.status.split(" ")[0]), res.headers, res.body)
def callback__token_url_post(req): """POST /authority/oauth2/flow-a/token is made by the client (IN THE SERVER) to get a token for the code""" assert req.url.startswith(oauth2_utils.OAUTH2__URL_AUTHORITY_FLOWA_TOKEN) payload = dict(parse_qsl(req.body)) _headers = string_headers( req.headers ) # these can end up being unicode in tests testapp_authority = test_env["testapp_authority"] res = testapp_authority.post( "/authority/oauth2/flow-a/token", payload, headers=_headers, extra_environ=test_env["extra_environ_authority"], status=200, ) test_env["requests_session_authority"].cookies.update( testapp_authority.cookies ) # update the session with the cookies from the response return (int(res.status.split(" ")[0]), res.headers, res.body)
def get_authentication_tokens( self, callback_url=None, extra_args=None, force_login=False ): """ Returns a dict including an authorization URL, ``auth_url``, to direct a user to :param callback_url: (optional) Url the user is returned to after they authorize your app (web clients only) :param force_login: (optional) Forces the user to enter their credentials to ensure the correct users account is authorized. :rtype: dict """ if self.oauth_version != 1: raise ApiError( "This method can only be called when your \ OAuth version is 1.0." ) # we toggle this in, then fix _callback_uri_old = self.client.auth.client.callback_uri if callback_url: # python2 - this can be unicode or string # python3 - no issues i think if isinstance(callback_url, six.text_type): callback_url = callback_url else: callback_url = six.u(callback_url) self.client.auth.client.callback_uri = callback_url request_args = {} if extra_args: for (k, v) in extra_args.items(): if k not in request_args: request_args[k] = v response = self.client.get(self.request_token_url, params=request_args) if callback_url: self.client.auth.client.callback_uri = _callback_uri_old if response.status_code == 401: # requests: response.text is the decoded response; .content is raw bytes raise ApiAuthError(response.text, error_code=response.status_code) elif response.status_code != 200: # requests: response.text is the decoded response; .content is raw bytes raise ApiError(response.text, error_code=response.status_code) # requests: response.text is the decoded response; .content is raw bytes # requests/iso-http-spec defaults to latin-1 if no encoding is present # we know this is utf-8 because of the oauth spec # so we force utf-8 here off the .content request_tokens = dict(parse_qsl(response.content.decode("utf-8"))) if not request_tokens: raise ApiError("Unable to decode request tokens.") oauth_callback_confirmed = ( request_tokens.get("oauth_callback_confirmed") == "true" ) auth_url_params = {"oauth_token": request_tokens["oauth_token"]} # Use old-style callback argument if server didn't accept new-style if callback_url and not oauth_callback_confirmed: auth_url_params["oauth_callback"] = self.callback_url request_tokens["auth_url"] = ( self.authenticate_url + "?" + urlencode(auth_url_params, True) ) return request_tokens