Fixes for small bugs
[mediagoblin.git] / mediagoblin / oauth / oauth.py
index d9defa4b9da56e3ed0ae33b143d1ead6463cc4e7..cdd8c842eed2ee679a87bbd8e7a3e8675eeda41d 100644 (file)
 #
 # 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 datetime
 
 from oauthlib.common import Request
-from oauthlib.oauth1 import RequestValidator 
+from oauthlib.oauth1 import RequestValidator
 
+from mediagoblin import oauth
 from mediagoblin.db.models import NonceTimestamp, Client, RequestToken, AccessToken
 
-
-
 class GMGRequestValidator(RequestValidator):
 
     enforce_ssl = False
@@ -29,14 +29,26 @@ class GMGRequestValidator(RequestValidator):
         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"],
-                )
+            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"]
@@ -51,47 +63,82 @@ class GMGRequestValidator(RequestValidator):
     def save_access_token(self, token, request):
         """ Saves access token in db """
         access_token = AccessToken(
-                token=token["oauth_token"],
-                secret=token["oauth_token_secret"],
+            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.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, 
+    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 = Client.query.filter_by(id=client_key).first()
+        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 """
-        client = Client.query.filter_by(id=client_key).first()
-        token = AccessToken.query.filter_by(token=token)
-        token = token.first()
+        # 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 token is None:
+        # If the client is invalid then it's invalid
+        if client is None:
             return False
 
-        request_token = RequestToken.query.filter_by(token=token.request_token)
-        request_token = request_token.first()
+        # 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
@@ -112,6 +159,18 @@ class GMGRequestValidator(RequestValidator):
         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
@@ -119,9 +178,9 @@ class GMGRequest(Request):
     """
 
     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)