# 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 datetime from oauthlib.common import Request from oauthlib.oauth1 import RequestValidator from mediagoblin import oauth from mediagoblin.db.models import NonceTimestamp, Client, RequestToken, AccessToken class GMGRequestValidator(RequestValidator): enforce_ssl = False def __init__(self, data=None, *args, **kwargs): self.POST = data super(GMGRequestValidator, self).__init__(*args, **kwargs) def check_nonce(self, nonce): """ This checks that the nonce given is a valid nonce RequestValidator.check_nonce checks that it's between a maximum and minimum length which, not only does pump.io not do this from what I can see but there is nothing in rfc5849 which suggests a maximum or minium length should be required so I'm removing that check """ # Check the nonce only contains a subset of the safe characters. return set(nonce) <= self.safe_characters 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 if u"oauth_callback" in self.POST: request_token.callback = self.POST[u"oauth_callback"] 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.actor = request_token.actor access_token.save() def get_realms(*args, **kwargs): """ Currently a stub - called when making AccessTokens """ return list() def validate_timestamp_and_nonce(self, client_key, timestamp, nonce, request, request_token=None, access_token=None): # RFC5849 (OAuth 1.0) section 3.3 says the timestamp is going # to be seconds after the epoch, we need to convert for postgres try: timestamp = datetime.datetime.fromtimestamp(float(timestamp)) except ValueError: # Well, the client must have passed up something ridiculous return False nc = NonceTimestamp.query.filter_by(timestamp=timestamp, nonce=nonce) nc = nc.first() if nc is None: return True return False def validate_client_key(self, client_key, request): """ Verifies client exists with id of client_key """ client_query = Client.query.filter(Client.id != oauth.DUMMY_CLIENT_ID) client = client_query.filter_by(id=client_key).first() if client is None: return False return True def validate_verifier(self, token, verifier): """ Verifies the verifier token is correct. """ request_token = RequestToken.query.filter_by(token=token).first() if request_token is None: return False if request_token.verifier != verifier: return False return True def validate_access_token(self, client_key, token, request): """ Verifies token exists for client with id of client_key """ # Get the client for the request client_query = Client.query.filter(Client.id != oauth.DUMMY_CLIENT_ID) client = client_query.filter_by(id=client_key).first() # If the client is invalid then it's invalid if client is None: return False # Look up the AccessToken access_token_query = AccessToken.query.filter( AccessToken.token != oauth.DUMMY_ACCESS_TOKEN ) access_token = access_token_query.filter_by(token=token).first() # If there isn't one - we can't validate. if access_token is None: return False # Check that the client matches the on request_token_query = RequestToken.query.filter( RequestToken.token != oauth.DUMMY_REQUEST_TOKEN, RequestToken.token == access_token.request_token ) request_token = request_token_query.first() if client.id != request_token.client: return False return True def validate_realms(self, *args, **kwargs): """ Would validate reals however not using these yet. """ return True # implement when realms are implemented def get_client_secret(self, client_key, request): """ Retrives a client secret with from a client with an id of client_key """ client = Client.query.filter_by(id=client_key).first() return client.secret def get_access_token_secret(self, client_key, token, request): access_token = AccessToken.query.filter_by(token=token).first() return access_token.secret @property def dummy_client(self): return oauth.DUMMY_CLIENT_ID @property def dummy_request_token(self): return oauth.DUMMY_REQUEST_TOKEN @property def dummy_access_token(self): return oauth.DUMMY_ACCESS_TOKEN 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.data) kwargs["headers"] = kwargs.get("headers", dict(request.headers)) super(GMGRequest, self).__init__(*args, **kwargs)