diff --git a/gluon/contrib/login_methods/oauth10a_account.py b/gluon/contrib/login_methods/oauth10a_account.py
index 1f464f8c..d3341570 100644
--- a/gluon/contrib/login_methods/oauth10a_account.py
+++ b/gluon/contrib/login_methods/oauth10a_account.py
@@ -19,6 +19,7 @@ from urllib2 import urlopen
import urllib2
from urllib import urlencode
+from gluon import current
class OAuthAccount(object):
"""
@@ -117,8 +118,8 @@ class OAuthAccount(object):
self.client_id = client_id
self.client_secret = client_secret
self.code = None
- self.request = g['request']
- self.session = g['session']
+ self.request = current.request
+ self.session = current.session
self.auth_url = auth_url
self.token_url = token_url
self.access_token_url = access_token_url
diff --git a/gluon/contrib/login_methods/oauth20_account.py b/gluon/contrib/login_methods/oauth20_account.py
index 788f08d0..195590a8 100644
--- a/gluon/contrib/login_methods/oauth20_account.py
+++ b/gluon/contrib/login_methods/oauth20_account.py
@@ -7,7 +7,8 @@ License: LGPL v3
Adds support for OAuth 2.0 authentication to web2py.
-OAuth 2.0 Draft: http://tools.ietf.org/html/draft-ietf-oauth-v2-10
+OAuth 2.0 spec: http://tools.ietf.org/html/rfc6749
+
"""
import time
@@ -17,6 +18,7 @@ import urllib2
from urllib import urlencode
from gluon import current, redirect, HTTP
+import json
class OAuthAccount(object):
"""
@@ -105,7 +107,10 @@ server for requests. It can be used for the optional"scope" parameters for Face
if not http_host:
http_host = r.env.http_host
- url_scheme = r.env.wsgi_url_scheme
+ if r.env.https == 'on':
+ url_scheme = 'https'
+ else:
+ url_scheme = r.env.wsgi_url_scheme
if next:
path_info = next
else:
@@ -144,31 +149,45 @@ server for requests. It can be used for the optional"scope" parameters for Face
# reuse token until expiration
if expires == 0 or expires > time.time():
return current.session.token['access_token']
- if current.session.code:
+
+ code = current.request.vars.code
+
+ if code:
data = dict(client_id=self.client_id,
client_secret=self.client_secret,
redirect_uri=current.session.redirect_uri,
- response_type='token', code=current.session.code)
+ code=code,
+ grant_type='authorization_code'
+ )
- if self.args:
- data.update(self.args)
open_url = None
opener = self.__build_url_opener(self.token_url)
try:
open_url = opener.open(self.token_url, urlencode(data))
except urllib2.HTTPError, e:
tmp = e.read()
- print tmp
raise Exception(tmp)
finally:
- del current.session.code # throw it away
+ if current.session.code:
+ del current.session.code # throw it away
if open_url:
try:
data = open_url.read()
- tokendata = cgi.parse_qs(data)
- current.session.token = \
- dict([(k, v[-1]) for k, v in tokendata.items()])
+ resp_type = open_url.info().get('Content-Type')
+ # try json style first
+ if not resp_type or resp_type == 'application/json':
+ try:
+ tokendata = json.loads(data)
+ current.session.token = tokendata
+ except Exception, e:
+ raise Exception("Cannot parse oauth server response %s %s" % (data, e))
+ else: # try facebook style first with x-www-form-encoded
+ tokendata = cgi.parse_qs(data)
+ current.session.token = \
+ dict([(k, v[-1]) for k, v in tokendata.items()])
+ if not tokendata: # parsing failed?
+ raise Exception("Cannot parse oauth server response %s" % data)
# set expiration absolute time try to avoid broken
# implementations where "expires_in" becomes "expires"
if 'expires_in' in current.session.token:
@@ -258,20 +277,16 @@ server for requests. It can be used for the optional"scope" parameters for Face
accessToken()
"""
- if not self.accessToken():
- if not current.request.vars.code:
- current.session.redirect_uri = self.__redirect_uri(next)
- data = dict(redirect_uri=current.session.redirect_uri,
- response_type='code',
- client_id=self.client_id)
- if self.args:
- data.update(self.args)
- auth_request_url = self.auth_url + "?" + urlencode(data)
- raise HTTP(307,
- "You are not authenticated: you are being redirected to the authentication server",
- Location=auth_request_url)
- else:
- current.session.code = current.request.vars.code
- self.accessToken()
- return current.session.code
- return None
+ token = self.accessToken()
+ if not token:
+ current.session.redirect_uri = self.__redirect_uri(next)
+ data = dict(redirect_uri=current.session.redirect_uri,
+ response_type='code',
+ client_id=self.client_id)
+ if self.args:
+ data.update(self.args)
+ auth_request_url = self.auth_url + "?" + urlencode(data)
+ raise HTTP(307,
+ "You are not authenticated: you are being redirected to the authentication server",
+ Location=auth_request_url)
+ return
diff --git a/gluon/tools.py b/gluon/tools.py
index eb3489b2..9fc9201f 100644
--- a/gluon/tools.py
+++ b/gluon/tools.py
@@ -4434,12 +4434,12 @@ class Service(object):
return return_error(id, e.code, e.info)
except BaseException:
etype, eval, etb = sys.exc_info()
- code = -32001
- data = '%s: %s\n' % (etype.__name__, eval) + request.is_local and traceback.format_tb(etb)
+ code = -32099
+ data = '%s: %s\n' % (etype.__name__, eval) + str(request.is_local and traceback.format_tb(etb))
return return_error(id, code, data=data)
except:
etype, eval, etb = sys.exc_info()
- return return_error(id, 32099, data='Exception %s: %s' % (etype, eval))
+ return return_error(id, -32099, data='Exception %s: %s' % (etype, eval))
def serve_xmlrpc(self):