From: xray7224 Date: Thu, 11 Jul 2013 18:43:00 +0000 (+0100) Subject: Cleans up some of the OAuth code X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=786bbd79e8d77c06a9d86aee00edc4dd3e89d651;p=mediagoblin.git Cleans up some of the OAuth code --- diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index ce26e46c..1fdb78d7 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -22,10 +22,11 @@ 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.request import decode_authorization_header from mediagoblin.tools.response import json_response, redirect, render_404 from mediagoblin.tools.translate import pass_to_ugettext as _ +from mediagoblin.federation.tools.request import decode_authorization_header +from mediagoblin.federation.oauth import GMGRequestValidator def require_active_login(controller): """ @@ -282,3 +283,4 @@ def oauth_requeired(controller): return json_response({"error": error}, status=400) + diff --git a/mediagoblin/federation/exceptions.py b/mediagoblin/federation/exceptions.py new file mode 100644 index 00000000..5eccba34 --- /dev/null +++ b/mediagoblin/federation/exceptions.py @@ -0,0 +1,18 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +class ValidationException(Exception): + pass diff --git a/mediagoblin/federation/oauth.py b/mediagoblin/federation/oauth.py new file mode 100644 index 00000000..c94b0a9d --- /dev/null +++ b/mediagoblin/federation/oauth.py @@ -0,0 +1,80 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from oauthlib.common import Request +from oauthlib.oauth1 import (AuthorizationEndpoint, RequestValidator, + RequestTokenEndpoint, AccessTokenEndpoint) + +from mediagoblin.db.models import Client, RequestToken, AccessToken + + + +class GMGRequestValidator(RequestValidator): + + def __init__(self, data=None): + self.POST = data + + def save_request_token(self, token, request): + """ Saves request token in db """ + client_id = self.POST[u"oauth_consumer_key"] + + request_token = RequestToken( + token=token["oauth_token"], + secret=token["oauth_token_secret"], + ) + request_token.client = client_id + request_token.callback = token.get("oauth_callback", None) + request_token.save() + + def save_verifier(self, token, verifier, request): + """ Saves the oauth request verifier """ + request_token = RequestToken.query.filter_by(token=token).first() + 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_token_secret"], + ) + 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() + +class GMGRequest(Request): + """ + Fills in data to produce a oauth.common.Request object from a + werkzeug Request object + """ + + def __init__(self, request, *args, **kwargs): + """ + :param request: werkzeug request object + + any extra params are passed to oauthlib.common.Request object + """ + kwargs["uri"] = kwargs.get("uri", request.url) + kwargs["http_method"] = kwargs.get("http_method", request.method) + kwargs["body"] = kwargs.get("body", request.get_data()) + kwargs["headers"] = kwargs.get("headers", dict(request.headers)) + + super(GMGRequest, self).__init__(*args, **kwargs) diff --git a/mediagoblin/federation/tools/__init__.py b/mediagoblin/federation/tools/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mediagoblin/federation/tools/request.py b/mediagoblin/federation/tools/request.py new file mode 100644 index 00000000..4f5be277 --- /dev/null +++ b/mediagoblin/federation/tools/request.py @@ -0,0 +1,27 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import re + +# Regex for parsing Authorization string +auth_header_re = re.compile('(\w+)[:=] ?"?(\w+)"?') + +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/federation/views.py b/mediagoblin/federation/views.py index a6dcc79b..29b5647e 100644 --- a/mediagoblin/federation/views.py +++ b/mediagoblin/federation/views.py @@ -16,21 +16,23 @@ import datetime -import oauthlib.common from oauthlib.oauth1 import (AuthorizationEndpoint, RequestValidator, 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, decode_authorization_header +from mediagoblin.tools.request import decode_request from mediagoblin.tools.response import (render_to_response, redirect, 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 from mediagoblin.federation.forms import AuthorizeForm +from mediagoblin.federation.exceptions import ValidationException +from mediagoblin.federation.oauth import GMGRequestValidator, GMGRequest +from mediagoblin.federation.tools.request import decode_authorization_header +from mediagoblin.db.models import Client, RequestToken, AccessToken # possible client types client_types = ["web", "native"] # currently what pump supports @@ -175,47 +177,6 @@ def client_register(request): "expires_at": expirey, }) -class ValidationException(Exception): - pass - -class GMGRequestValidator(RequestValidator): - - def __init__(self, data=None): - self.POST = data - - def save_request_token(self, token, request): - """ Saves request token in db """ - client_id = self.POST[u"oauth_consumer_key"] - - request_token = RequestToken( - token=token["oauth_token"], - secret=token["oauth_token_secret"], - ) - request_token.client = client_id - request_token.callback = token.get("oauth_callback", None) - request_token.save() - - def save_verifier(self, token, verifier, request): - """ Saves the oauth request verifier """ - request_token = RequestToken.query.filter_by(token=token).first() - 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_token_secret"], - ) - 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 """ @@ -288,12 +249,7 @@ def authorize(request): return authorize_finish(request) if oauth_request.verifier is None: - orequest = oauthlib.common.Request( - uri=request.url, - http_method=request.method, - body=request.get_data(), - headers=request.headers - ) + orequest = GMGRequest(request) request_validator = GMGRequestValidator() auth_endpoint = AuthorizationEndpoint(request_validator) verifier = auth_endpoint.create_verifier(orequest, {}) diff --git a/mediagoblin/tools/request.py b/mediagoblin/tools/request.py index 0c0fc557..d4739039 100644 --- a/mediagoblin/tools/request.py +++ b/mediagoblin/tools/request.py @@ -14,7 +14,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import re import json import logging from mediagoblin.db.models import User @@ -26,8 +25,6 @@ _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): """ @@ -57,9 +54,3 @@ 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