aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxray7224 <jessica@megworld.co.uk>2013-07-11 17:58:58 +0100
committerxray7224 <jessica@megworld.co.uk>2013-07-11 18:21:43 +0100
commit2b60a56cbec44f789ee2efe71294979d7784515c (patch)
treecf2476a7301fa71d18385ace757c2633cf8d7f82
parent405aa45adc14d3c67a120618ecc0ae792f5881de (diff)
downloadmediagoblin-2b60a56cbec44f789ee2efe71294979d7784515c.tar.lz
mediagoblin-2b60a56cbec44f789ee2efe71294979d7784515c.tar.xz
mediagoblin-2b60a56cbec44f789ee2efe71294979d7784515c.zip
Finishes most of oauth, just decorator to complete
-rw-r--r--mediagoblin/decorators.py16
-rw-r--r--mediagoblin/federation/views.py76
-rw-r--r--mediagoblin/tools/request.py10
-rw-r--r--mediagoblin/tools/response.py19
4 files changed, 80 insertions, 41 deletions
diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py
index ece222f5..ce26e46c 100644
--- a/mediagoblin/decorators.py
+++ b/mediagoblin/decorators.py
@@ -22,7 +22,8 @@ from werkzeug.exceptions import Forbidden, NotFound
from mediagoblin import mg_globals as mgg
from mediagoblin import messages
from mediagoblin.db.models import MediaEntry, User
-from mediagoblin.tools.response import redirect, render_404
+from mediagoblin.tools.request import decode_authorization_header
+from mediagoblin.tools.response import json_response, redirect, render_404
from mediagoblin.tools.translate import pass_to_ugettext as _
@@ -268,3 +269,16 @@ def auth_enabled(controller):
return controller(request, *args, **kwargs)
return wrapper
+
+def oauth_requeired(controller):
+ """ Used to wrap API endpoints where oauth is required """
+ @wraps(controller)
+ def wrapper(request, *args, **kwargs):
+ data = request.headers
+ authorization = decode_authorization_header(data)
+
+ if authorization == dict():
+ error = "Missing required parameter."
+ return json_response({"error": error}, status=400)
+
+
diff --git a/mediagoblin/federation/views.py b/mediagoblin/federation/views.py
index 9559df10..a6dcc79b 100644
--- a/mediagoblin/federation/views.py
+++ b/mediagoblin/federation/views.py
@@ -18,14 +18,15 @@ import datetime
import oauthlib.common
from oauthlib.oauth1 import (AuthorizationEndpoint, RequestValidator,
- RequestTokenEndpoint)
+ RequestTokenEndpoint, AccessTokenEndpoint)
from mediagoblin.decorators import require_active_login
from mediagoblin.tools.translate import pass_to_ugettext
from mediagoblin.meddleware.csrf import csrf_exempt
-from mediagoblin.tools.request import decode_request
+from mediagoblin.tools.request import decode_request, decode_authorization_header
from mediagoblin.tools.response import (render_to_response, redirect,
- json_response, render_400)
+ json_response, render_400,
+ form_response)
from mediagoblin.tools.crypto import random_string
from mediagoblin.tools.validator import validate_email, validate_url
from mediagoblin.db.models import User, Client, RequestToken, AccessToken
@@ -184,7 +185,7 @@ class GMGRequestValidator(RequestValidator):
def save_request_token(self, token, request):
""" Saves request token in db """
- client_id = self.POST[u"Authorization"][u"oauth_consumer_key"]
+ client_id = self.POST[u"oauth_consumer_key"]
request_token = RequestToken(
token=token["oauth_token"],
@@ -200,17 +201,21 @@ class GMGRequestValidator(RequestValidator):
request_token.verifier = verifier["oauth_verifier"]
request_token.save()
-
def save_access_token(self, token, request):
""" Saves access token in db """
access_token = AccessToken(
token=token["oauth_token"],
- secret=token["oauth_secret"],
+ secret=token["oauth_token_secret"],
)
- access_token.request_token = request.body["oauth_token"]
- access_token.user = token["user"].id
+ access_token.request_token = request.oauth_token
+ request_token = RequestToken.query.filter_by(token=request.oauth_token).first()
+ access_token.user = request_token.user
access_token.save()
+ def get_realms(*args, **kwargs):
+ """ Currently a stub - called when making AccessTokens """
+ return list()
+
@csrf_exempt
def request_token(request):
""" Returns request token """
@@ -224,45 +229,32 @@ def request_token(request):
error = "Unknown Content-Type"
return json_response({"error": error}, status=400)
- print data
-
- if "Authorization" not in data:
- error = "Missing required parameter."
- return json_response({"error": error}, status=400)
+ if not data and request.headers:
+ data = request.headers
+
+ data = dict(data) # mutableifying
+ authorization = decode_authorization_header(data)
- # Convert 'Authorization' to a dictionary
- authorization = {}
- for item in data["Authorization"].split(","):
- key, value = item.split("=", 1)
- authorization[key] = value
- data[u"Authorization"] = authorization
- if "oauth_consumer_key" not in data[u"Authorization"]:
+ if authorization == dict() or u"oauth_consumer_key" not in authorization:
error = "Missing required parameter."
- return json_respinse({"error": error}, status=400)
+ return json_response({"error": error}, status=400)
# check the client_id
- client_id = data[u"Authorization"][u"oauth_consumer_key"]
+ client_id = authorization[u"oauth_consumer_key"]
client = Client.query.filter_by(id=client_id).first()
if client is None:
# client_id is invalid
error = "Invalid client_id"
return json_response({"error": error}, status=400)
- request_validator = GMGRequestValidator(data)
+ # make request token and return to client
+ request_validator = GMGRequestValidator(authorization)
rv = RequestTokenEndpoint(request_validator)
tokens = rv.create_request_token(request, authorization)
- tokenized = {}
- for t in tokens.split("&"):
- key, value = t.split("=")
- tokenized[key] = value
-
- print "[DEBUG] %s" % tokenized
-
- # check what encoding to return them in
- return json_response(tokenized)
+ return form_response(tokens)
class WTFormData(dict):
"""
@@ -375,14 +367,18 @@ def authorize_finish(request):
@csrf_exempt
def access_token(request):
""" Provides an access token based on a valid verifier and request token """
- try:
- data = decode_request(request)
- except ValueError:
- error = "Could not decode data."
- return json_response({"error": error}, status=400)
+ data = request.headers
- if data == "":
- error = "Unknown Content-Type"
+ parsed_tokens = decode_authorization_header(data)
+
+ if parsed_tokens == dict() or "oauth_token" not in parsed_tokens:
+ error = "Missing required parameter."
return json_response({"error": error}, status=400)
- print "debug: %s" % data
+
+ request.oauth_token = parsed_tokens["oauth_token"]
+ request_validator = GMGRequestValidator(data)
+ av = AccessTokenEndpoint(request_validator)
+ tokens = av.create_access_token(request, {})
+ return form_response(tokens)
+
diff --git a/mediagoblin/tools/request.py b/mediagoblin/tools/request.py
index 2c9e609d..0c0fc557 100644
--- a/mediagoblin/tools/request.py
+++ b/mediagoblin/tools/request.py
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import re
import json
import logging
from mediagoblin.db.models import User
@@ -25,6 +26,9 @@ _log = logging.getLogger(__name__)
form_encoded = "application/x-www-form-urlencoded"
json_encoded = "application/json"
+# Regex for Authorization header
+auth_header_re = re.compile('(\w+)[:=] ?"?(\w+)"?')
+
def setup_user_in_request(request):
"""
Examine a request and tack on a request.user parameter if that's
@@ -53,3 +57,9 @@ def decode_request(request):
else:
data = ""
return data
+
+def decode_authorization_header(header):
+ """ Decodes a HTTP Authorization Header to python dictionary """
+ authorization = header.get("Authorization", "")
+ tokens = dict(auth_header_re.findall(authorization))
+ return tokens
diff --git a/mediagoblin/tools/response.py b/mediagoblin/tools/response.py
index db8fc388..b0401e08 100644
--- a/mediagoblin/tools/response.py
+++ b/mediagoblin/tools/response.py
@@ -138,3 +138,22 @@ def json_response(serializable, _disable_cors=False, *args, **kw):
response.headers.set(key, value)
return response
+
+def form_response(data, *args, **kwargs):
+ """
+ Responds using application/x-www-form-urlencoded and returns a werkzeug
+ Response object with the data argument as the body
+ and 'application/x-www-form-urlencoded' as the Content-Type.
+
+ Any extra arguments and keyword arguments are passed to the
+ Response.__init__ method.
+ """
+
+ response = wz_Response(
+ data,
+ content_type="application/x-www-form-urlencoded",
+ *args,
+ **kwargs
+ )
+
+ return response