def handle_oauth2_response_discord(self, args): """Handles an oauth2 authorization response.""" client = self.make_client() remote_args = { "client_id": self.consumer_key, "client_secret": self.consumer_secret, "code": args.get("code"), "redirect_uri": session.get("%s_oauthredir" % self.name), "scope": "identify", } log.debug("Prepare oauth2 remote args %r", remote_args) remote_args.update(self.access_token_params) headers = copy(self._access_token_headers) if self.access_token_method == "POST": headers.update( {"Content-Type": "application/x-www-form-urlencoded"}) body = client.prepare_request_body(**remote_args) response = requests.request( self.access_token_method, self.expand_url(self.access_token_url), headers=headers, data=to_bytes(body, self.encoding), ) if response.status_code not in (200, 201): raise OAuthException( "Invalid response from %s" % self.name, type="invalid_response", data=to_bytes(body, self.encoding), ) return jsonify(response.text.encode("utf8")) elif self.access_token_method == "GET": qs = client.prepare_request_body(**remote_args) url = self.expand_url(self.access_token_url) url += ("?" in url and "&" or "?") + qs response = requests.request(self.access_token_method, url, headers=headers) if response.status_code not in (200, 201): raise OAuthException( "Invalid response from %s" % self.name, type="invalid_response", data=to_bytes(body, self.encoding), ) return jsonify(response.text.encode("utf8")) else: raise OAuthException("Unsupported access_token_method: %s" % self.access_token_method)
def test_server_login(app): headers = { 'X-Forwarded-Path': 'http://localhost:8090/auctions/11111111111111111111111111111111' '/authorized?code=HVRviZDxswGzM8AYN3rz0qMLrh6rhY' } res = app.post('/login', headers=headers) assert res.status == '405 METHOD NOT ALLOWED' assert res.status_code == 405 res = app.get('/login') assert res.status == '401 UNAUTHORIZED' assert res.status_code == 401 res = app.get('/login?bidder_id=5675acc9232942e8940a034994ad883e&' 'hash=bd4a790aac32b73e853c26424b032e5a29143d1f') assert res.status == '302 FOUND' assert res.status_code == 302 assert res.location == 'https://my.test.url' with app.application.test_request_context(): session['login_bidder_id'] = u'5675acc9232942e8940a034994ad883e' session['login_hash'] = u'bd4a790aac32b73e853c26424b032e5a29143d1f' session['login_callback'] = 'http://localhost/authorized' log_message = 'Session: {}'.format(repr(session)) app.application.logger.debug.assert_called_with(log_message) res = app.get( '/login?bidder_id=5675acc9232942e8940a034994ad883e&' 'hash=bd4a790aac32b73e853c26424b032e5a29143d1f', headers=headers) assert res.status == '302 FOUND' assert res.status_code == 302 assert res.location == 'https://my.test.url' with app.application.test_request_context(): session[u'login_bidder_id'] = u'5675acc9232942e8940a034994ad883e' session[u'login_hash'] = u'bd4a790aac32b73e853c26424b032e5a29143d1f' session[u'login_callback'] = u'http://localhost:8090/auctions/' \ '11111111111111111111111111111111/authorized' log_message = 'Session: {}'.format(repr(session)) app.application.logger.debug.assert_called_with(log_message) res = app.get('/login?bidder_id=5675acc9232942e8940a034994ad883e&' 'hash=bd4a790aac32b73e853c26424b032e5a29143d1f&' 'return_url=https://my.secret.url/') assert res.status == '302 FOUND' assert res.status_code == 302 assert res.location == 'https://my.test.url' with app.application.test_request_context(): session['return_url'] = u'https://my.secret.url/' session['login_bidder_id'] = u'5675acc9232942e8940a034994ad883e' session['login_hash'] = u'bd4a790aac32b73e853c26424b032e5a29143d1f' session['login_callback'] = 'http://localhost/authorized' app.application.remote_oauth.authorize.side_effect = OAuthException( "Invalid response") res = app.get( '/login?bidder_id=5675acc9232942e8940a034994ad883e&' 'hash=bd4a790aac32b73e853c26424b032e5a29143d1f', headers=headers) assert res.status == "503 SERVICE UNAVAILABLE"
def test_server_relogin(app): headers = { 'X-Forwarded-Path': 'http://localhost:8090/auctions/11111111111111111111111111111111' '/authorized?code=HVRviZDxswGzM8AYN3rz0qMLrh6rhY' } res = app.post('/relogin', headers=headers) assert res.status == '405 METHOD NOT ALLOWED' assert res.status_code == 405 res = app.get('/relogin', headers=headers) assert res.status_code == 302 assert res.status == '302 FOUND' assert res.location == \ 'http://localhost:8090/auctions/11111111111111111111111111111111' s = { 'login_callback': 'https://some.url/', 'login_bidder_id': 'some_id', 'login_hash': 'some_cache', 'amount': 100 } with patch('openprocurement.auction.worker.server.session', s): res = app.get('/relogin?amount=100', headers=headers) assert res.status_code == 302 assert res.status == '302 FOUND' assert res.location == 'https://my.test.url' app.application.remote_oauth.authorize.side_effect = OAuthException( "Invalid response") with patch('openprocurement.auction.worker.server.session', s): res = app.get('/relogin', headers=headers) assert res.status == "503 SERVICE UNAVAILABLE"
def get_user_info(user): # https://developer-programs.linkedin.com/documents/field-selectors url = 'v1/people/~:(%s)?format=json' % ','.join(USER_INFO_FIELDS) token = retrieve_access_token(user) if token is None: raise OAuthException('Access token unavailable or expired for %s' % user.email) res = linkedin.get(url, token=token) if res.status != 200: raise OAuthException('Server returned HTTP %d: %s' % (res.status, repr(res.data)), data=res.data) return res.data
def handle_oauth2_response(self): """Handles an oauth2 authorization response. This method overrides the one provided by OAuthRemoteApp in order to support Basic HTTP Authentication. """ if self.access_token_method != 'POST': raise OAuthException( ('Unsupported access_token_method: {}. ' 'Only POST is supported.').format(self.access_token_method)) client = self.make_client() remote_args = { 'code': request.args.get('code'), 'client_secret': self.consumer_secret, 'redirect_uri': (session.get('%s_oauthredir' % self.name) or url_for('invenio_oauthclient.authorized', remote_app=self.name, _external=True)), } remote_args.update(self.access_token_params) # build the Basic HTTP Authentication code b2access_basic_auth = base64.encodestring( bytes('{0}:{1}'.format(self.consumer_key, self.consumer_secret), 'utf-8')).decode('ascii').replace('\n', '') body = client.prepare_request_body(**remote_args) resp, content = self.http_request( self.expand_url(self.access_token_url), # set the Authentication header headers={ 'Authorization': 'Basic {}'.format(b2access_basic_auth), }, data=to_bytes(body, self.encoding), method=self.access_token_method, ) data = parse_response(resp, content, content_type=self.content_type) if resp.code not in (200, 201): raise OAuthException('Invalid response from %s' % self.name, type='invalid_response', data=data) return data
def handle_oauth2_response_spotify(self, args): """Handles an oauth2 authorization response.""" client = self.make_client() remote_args = { "code": args.get("code"), "redirect_uri": session.get("%s_oauthredir" % self.name), } log.debug("Prepare oauth2 remote args %r", remote_args) remote_args.update(self.access_token_params) data = f"{self._consumer_key}:{self._consumer_secret}" encoded = str(base64.b64encode(data.encode("utf-8")), "utf-8") headers = {"Authorization": f"Basic {encoded}"} if self.access_token_method == "POST": headers.update( {"Content-Type": "application/x-www-form-urlencoded"}) body = client.prepare_request_body(**remote_args) resp, content = self.http_request( self.expand_url(self.access_token_url), headers=headers, data=to_bytes(body, self.encoding), method=self.access_token_method, ) elif self.access_token_method == "GET": qs = client.prepare_request_body(**remote_args) url = self.expand_url(self.access_token_url) url += ("?" in url and "&" or "?") + qs resp, content = self.http_request(url, headers=headers, method=self.access_token_method) else: raise OAuthException("Unsupported access_token_method: %s" % self.access_token_method) data = OAuth.parse_response(resp, content, content_type=self.content_type) if resp.code not in (200, 201): raise OAuthException( "Invalid response from %s" % self.name, type="invalid_response", data=data, ) return data
def get_dict_from_response(response: OAuthResponse) -> dict: """Check for errors in the response and return the resulting dict. :param response: The OAuth response. :returns: Response data dict """ if getattr(response, '_resp') and response._resp.code > 400: raise OAuthException( 'OpenID Remote Application failed to parse response', None, response) return response.data
def test_if_get_profile_error_is_caught_return_false(self, app): from flask import current_app as flask_app flask_app.sso_client = unittest.mock.Mock() handled_exceptions = [ URLError('e'), OAuthException('e'), HTTPException('e') ] flask_app.sso_client.get_profile.side_effect = handled_exceptions for e in handled_exceptions: response = token.is_authenticated() assert response is False
def handle_oauth2_response(self): if self.access_token_method != 'POST': raise OAuthException('Unsupported access_token_method: %s' % self.access_token_method) client = self.make_client() remote_args = { 'code': request.args.get('code'), 'client_secret': self.consumer_secret, 'redirect_uri': session.get('%s_oauthredir' % self.name) } remote_args.update(self.access_token_params) reddit_basic_auth = base64.encodestring( '%s:%s' % (REDDIT_APP_ID, REDDIT_APP_SECRET)).replace('\n', '') body = client.prepare_request_body(**remote_args) while True: resp, content = self.http_request( self.expand_url(self.access_token_url), headers={ 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic %s' % reddit_basic_auth, 'User-Agent': REDDIT_USER_AGENT }, data=to_bytes(body, self.encoding), method=self.access_token_method, ) # Reddit API is rate-limited, so if we get 429, we need to retry if resp.code != 429: break time.sleep(1) data = parse_response(resp, content, content_type=self.content_type) if resp.code not in (200, 201): raise OAuthException('Invalid response from %s' % self.name, type='invalid_response', data=data) return data
def get_user_id(self, remote, email: str = None) -> str: """Determine ID for a given user/email. :param id_claim: Claim name containing user ID :param remote: The remote application. :param email: (optional) User e-mail address :returns: User ID """ user_id = self.get_userinfo(remote).sub if not user_id: raise OAuthException( 'User {} is missing *sub* attribute for ' '{} Remote Application'.format(email, self.name), None, None) return user_id
def handle_unknown_response(self): if request.args.get('authorize') == 0: return None print "lkjalskdjflkjasdf" consumer = oldOauth.Consumer(key=self.consumer_key, secret=self.consumer_secret) client = oldOauth.Client(consumer, oldOauth.Token(*session['%s_oauthtok' % self.name])) response, content = client.request(self.access_token_url, 'POST') print response if response['status'] not in ('200', '201'): raise OAuthException( 'Invalid response from %s' % self.name, type='invalid_response', data=response) decoded = url_decode(content).to_dict() return decoded
def test_server_authorized(app): headers = { 'X-Forwarded-Path': 'http://localhost:8090/auctions/11111111111111111111111111111111' '/authorized?code=HVRviZDxswGzM8AYN3rz0qMLrh6rhY' } res = app.post('/authorized', headers=headers) assert res.status == '405 METHOD NOT ALLOWED' assert res.status_code == 405 res = app.get('/authorized', headers=headers) assert res.status_code == 403 assert res.status == '403 FORBIDDEN' res = app.get('/authorized?error=access_denied') assert res.status_code == 403 assert res.status == '403 FORBIDDEN' res = app.get('/authorized', headers=headers) assert res.status_code == 302 assert res.status == '302 FOUND' assert res.location == \ 'http://localhost:8090/auctions/11111111111111111111111111111111' auctions_loggedin = False auction_session = False path = False for h in res.headers: if h[1].startswith('auctions_loggedin=1'): auctions_loggedin = True if h[1].index('Path=/auctions/UA-11111'): path = True if h[1].startswith('auction_session='): auction_session = True assert auction_session is True assert auctions_loggedin is True assert path is True app.application.remote_oauth.authorized_response.side_effect = OAuthException( "Invalid response") res = app.get('/authorized', headers=headers) assert res.status == "503 SERVICE UNAVAILABLE"
def request( self, url, data=None, headers=None, format="urlencoded", method="GET", content_type=None, token=None, discord=False, ): """ Sends a request to the remote server with OAuth tokens attached. :param data: the data to be sent to the server. :param headers: an optional dictionary of headers. :param format: the format for the `data`. Can be `urlencoded` for URL encoded data or `json` for JSON. :param method: the HTTP request method to use. :param content_type: an optional content type. If a content type is provided, the data is passed as it, and the `format` is ignored. :param token: an optional token to pass, if it is None, token will be generated by tokengetter. """ headers = dict(headers or {}) if token is None: token = self.get_request_token() client = self.make_client(token) url = self.expand_url(url) if method == "GET": assert format == "urlencoded" if data: url = add_params_to_uri(url, data) data = None else: if content_type is None: data, content_type = OAuth.encode_request_data(data, format) if content_type is not None: headers["Content-Type"] = content_type if self.request_token_url: # oauth1 uri, headers, body = client.sign(url, http_method=method, body=data, headers=headers) else: # oauth2 uri, headers, body = client.add_token(url, http_method=method, body=data, headers=headers) if hasattr(self, "pre_request"): # This is designed for some rubbish services like weibo. # Since they don't follow the standards, we need to # change the uri, headers, or body. uri, headers, body = self.pre_request(uri, headers, body) if body: data = to_bytes(body, self.encoding) else: data = None if discord: response = requests.request(method, uri, headers=headers, data=to_bytes(body, self.encoding)) if response.status_code not in (200, 201): raise OAuthException("Invalid response from %s" % self.name, type="invalid_response", data=data) return jsonify(response.text.encode("utf8")) resp, content = self.http_request(uri, headers, data=to_bytes(body, self.encoding), method=method) return OAuthResponse(resp, content, self.content_type)