Finishes most of oauth, just decorator to complete

This commit is contained in:
xray7224 2013-07-11 17:58:58 +01:00
parent 405aa45adc
commit 2b60a56cbe
4 changed files with 81 additions and 42 deletions

View File

@ -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)

View File

@ -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 not data and request.headers:
data = request.headers
data = dict(data) # mutableifying
if "Authorization" not in data:
authorization = decode_authorization_header(data)
if authorization == dict() or u"oauth_consumer_key" not in authorization:
error = "Missing required parameter."
return json_response({"error": error}, status=400)
# 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"]:
error = "Missing required parameter."
return json_respinse({"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."
data = request.headers
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)
if data == "":
error = "Unknown Content-Type"
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)

View File

@ -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

View File

@ -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