diff --git a/CHANGES.rst b/CHANGES.rst index a6c8eef..cd98152 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,8 @@ +1.3.9 beta (2023-10-25) +================== + +Python 3.9 and Pyramid 1.10 support verified, moved most providers from lib to main directory as possibly outdated (openid), Google, Gitub and Facebook (unverified) remaining. Twitter kicked us out, so moved too. Simply copy a provider back if you need it. + 1.1.1 (2013-08-29) ================== diff --git a/README.rst b/README.rst index 08bb293..72b775b 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,7 @@ +I verified that velruse works with Pyramid 1.10 and Python 2.7 - 3.9 without additional changes. +I removed most providers to the root directory, many are completely outdated. +Google works with localhost. Apple provider is missing badly! + Velruse is a set of authentication routines that provide a unified way to have a website user authenticate to a variety of different identity providers and/or a variety of different authentication schemes. diff --git a/velruse/providers/bitbucket.py b/unsupported-providers/bitbucket.py similarity index 100% rename from velruse/providers/bitbucket.py rename to unsupported-providers/bitbucket.py diff --git a/velruse/providers/douban.py b/unsupported-providers/douban.py similarity index 100% rename from velruse/providers/douban.py rename to unsupported-providers/douban.py diff --git a/velruse/providers/google.py b/unsupported-providers/google.py similarity index 100% rename from velruse/providers/google.py rename to unsupported-providers/google.py diff --git a/velruse/providers/google_hybrid.py b/unsupported-providers/google_hybrid.py similarity index 100% rename from velruse/providers/google_hybrid.py rename to unsupported-providers/google_hybrid.py diff --git a/velruse/providers/identica_.py b/unsupported-providers/identica_.py similarity index 100% rename from velruse/providers/identica_.py rename to unsupported-providers/identica_.py diff --git a/velruse/providers/lastfm.py b/unsupported-providers/lastfm.py similarity index 100% rename from velruse/providers/lastfm.py rename to unsupported-providers/lastfm.py diff --git a/velruse/providers/linkedin.py b/unsupported-providers/linkedin.py similarity index 100% rename from velruse/providers/linkedin.py rename to unsupported-providers/linkedin.py diff --git a/velruse/providers/live.py b/unsupported-providers/live.py similarity index 100% rename from velruse/providers/live.py rename to unsupported-providers/live.py diff --git a/velruse/providers/mailru.py b/unsupported-providers/mailru.py similarity index 100% rename from velruse/providers/mailru.py rename to unsupported-providers/mailru.py diff --git a/velruse/providers/oid_extensions.py b/unsupported-providers/oid_extensions.py similarity index 100% rename from velruse/providers/oid_extensions.py rename to unsupported-providers/oid_extensions.py diff --git a/velruse/providers/openid.py b/unsupported-providers/openid.py similarity index 100% rename from velruse/providers/openid.py rename to unsupported-providers/openid.py diff --git a/velruse/providers/qq.py b/unsupported-providers/qq.py similarity index 100% rename from velruse/providers/qq.py rename to unsupported-providers/qq.py diff --git a/velruse/providers/renren.py b/unsupported-providers/renren.py similarity index 100% rename from velruse/providers/renren.py rename to unsupported-providers/renren.py diff --git a/velruse/providers/taobao.py b/unsupported-providers/taobao.py similarity index 100% rename from velruse/providers/taobao.py rename to unsupported-providers/taobao.py diff --git a/velruse/providers/twitter.py b/unsupported-providers/twitter.py similarity index 100% rename from velruse/providers/twitter.py rename to unsupported-providers/twitter.py diff --git a/velruse/providers/vk.py b/unsupported-providers/vk.py similarity index 100% rename from velruse/providers/vk.py rename to unsupported-providers/vk.py diff --git a/velruse/providers/weibo.py b/unsupported-providers/weibo.py similarity index 100% rename from velruse/providers/weibo.py rename to unsupported-providers/weibo.py diff --git a/velruse/providers/yahoo.py b/unsupported-providers/yahoo.py similarity index 100% rename from velruse/providers/yahoo.py rename to unsupported-providers/yahoo.py diff --git a/velruse/providers/yandex.py b/unsupported-providers/yandex.py similarity index 100% rename from velruse/providers/yandex.py rename to unsupported-providers/yandex.py diff --git a/velruse/providers/facebook.py b/velruse/providers/facebook.py index 24fd266..7514ed4 100644 --- a/velruse/providers/facebook.py +++ b/velruse/providers/facebook.py @@ -80,7 +80,8 @@ def login(self, request): display = request.POST.get('display', self.display) request.session['velruse.state'] = state = uuid.uuid4().hex fb_url = flat_url( - 'https://www.facebook.com/dialog/oauth/', + 'https://www.facebook.com/dialog/oauth/', + # We refer to an API call made without specifying a version as an unversioned call. An unversioned call will always point to the oldest available version. scope=scope, display=display, client_id=self.consumer_key, @@ -118,9 +119,11 @@ def callback(self, request): if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % ( r.status_code, r.content)) - access_token = dict(parse_qsl(r.text))['access_token'] + rbody = r.json() + access_token = rbody['access_token'] # Retrieve profile data + # We refer to an API call made without specifying a version as an unversioned call. An unversioned call will always point to the oldest available version. graph_url = flat_url('https://graph.facebook.com/me', access_token=access_token) r = requests.get(graph_url) diff --git a/velruse/providers/github.py b/velruse/providers/github.py index 47f767e..469cd2b 100644 --- a/velruse/providers/github.py +++ b/velruse/providers/github.py @@ -107,9 +107,13 @@ def callback(self, request): sess_state = request.session.pop('velruse.state', None) req_state = request.GET.get('state') if not sess_state or sess_state != req_state: + err_id = request.GET.get('error', 'CSRF Validation check failed') + err_desc = request.GET.get('error_description', '') raise CSRFError( - 'CSRF Validation check failed. Request state {req_state} is ' + '{err_id}: {err_desc} Request state {req_state} is ' 'not the same as session state {sess_state}'.format( + err_id=err_id, + err_desc=err_desc, req_state=req_state, sess_state=sess_state ) @@ -122,22 +126,20 @@ def callback(self, request): provider_type=self.type) # Now retrieve the access token with the code - access_url = flat_url( - '%s://%s/login/oauth/access_token' % (self.protocol, self.domain), - client_id=self.consumer_key, - client_secret=self.consumer_secret, - redirect_uri=request.route_url(self.callback_route), - code=code) - r = requests.get(access_url) + access_url = flat_url('%s://%s/login/oauth/access_token' % (self.protocol, self.domain)) + payload = { "client_id": self.consumer_key, + "client_secret": self.consumer_secret, + "redirect_uri": request.route_url(self.callback_route), + "code": code} + r = requests.post(access_url, data=payload) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % ( r.status_code, r.content)) access_token = dict(parse_qsl(r.text))['access_token'] # Retrieve profile data - graph_url = flat_url('%s://api.%s/user' % (self.protocol, self.domain), - access_token=access_token) - graph_headers = dict(Accept='application/vnd.github.v3+json') + graph_url = flat_url('%s://api.%s/user' % (self.protocol, self.domain)) + graph_headers = { "Accept":'application/vnd.github.v3+json', "Authorization": "token " + access_token} r = requests.get(graph_url, headers=graph_headers) if r.status_code != 200: raise ThirdPartyFailure("Status %s: %s" % ( diff --git a/velruse/providers/google_oauth2.py b/velruse/providers/google_oauth2.py index 06f59e1..8d3e1a0 100644 --- a/velruse/providers/google_oauth2.py +++ b/velruse/providers/google_oauth2.py @@ -161,19 +161,23 @@ def callback(self, request): if r.status_code == 200: data = r.json() + + #import logging + #logging.info('Google Oauth2 Response JSON: %s', data) + # {u'name': u'John Smith', u'picture': u'https://lh3.googleusercontent.com/a-/oijf2UoVzoEvq1LyuR0u', u'id': u'8281828828827363', u'verified_email': True, u'locale': u'de', u'given_name': u'John', u'email': u'js@gmail.com', u'family_name': u'Smith'} + profile['accounts'] = [{ 'domain': self.domain, - 'username': data['email'], - 'userid': data['id'] + 'username': data.get('email'), + 'userid': data.get('id'), + 'data': data # someone might need the raw data (e.g. for locale) }] - if 'name' in data: - profile['displayName'] = data['name'] - else: - profile['displayName'] = data['email'] - profile['preferredUsername'] = data['email'] - profile['verifiedEmail'] = data['email'] - profile['emails'] = [{'value': data['email']}] - + + profile['displayName'] = data.get('name') + profile['preferredUsername'] = data.get('email') + profile['verifiedEmail'] = data.get('email') + profile['emails'] = [{'value': data.get('email')}] + cred = {'oauthAccessToken': access_token, 'oauthRefreshToken': refresh_token} return GoogleAuthenticationComplete(profile=profile,