aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin/oauth
diff options
context:
space:
mode:
authorJessica Tallon <tsyesika@tsyesika.se>2015-08-21 17:57:39 +0200
committerJessica Tallon <tsyesika@tsyesika.se>2015-08-21 17:57:39 +0200
commite9bb5879f772e4d546aadb4bb6f935c7c55b8000 (patch)
tree28a6c88d8b5e21bf4c0c4fbffdea4689595dd535 /mediagoblin/oauth
parent3b4ad554c7ae17b1b6e431e235e7744e7670be89 (diff)
downloadmediagoblin-e9bb5879f772e4d546aadb4bb6f935c7c55b8000.tar.lz
mediagoblin-e9bb5879f772e4d546aadb4bb6f935c7c55b8000.tar.xz
mediagoblin-e9bb5879f772e4d546aadb4bb6f935c7c55b8000.zip
Fix #5344 - OAuth NotImplemented exception
This introduces a migration which adds a dummy Client, RequestToken and AccessToken. These are used when an invalid request comes in, instead of bailing early, it needs dummy data to prevent timing attacks. This then implements the methods which get the IDs of the dummy objects. If these are changed in the future a migration which checks for the previous dummy object should be created and updates them to reflect the new IDs/tokens.
Diffstat (limited to 'mediagoblin/oauth')
-rw-r--r--mediagoblin/oauth/__init__.py6
-rw-r--r--mediagoblin/oauth/oauth.py43
-rw-r--r--mediagoblin/oauth/views.py2
3 files changed, 43 insertions, 8 deletions
diff --git a/mediagoblin/oauth/__init__.py b/mediagoblin/oauth/__init__.py
index 719b56e7..6dfafea2 100644
--- a/mediagoblin/oauth/__init__.py
+++ b/mediagoblin/oauth/__init__.py
@@ -14,3 +14,9 @@
# 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/>.
+# This represents a dummy ID for the Client, RequestToken and AccessToken
+# WARNING: Do not change these without providing a data migration to migrate
+# existing dummy clients already in the database.
+DUMMY_CLIENT_ID = "dummy-client"
+DUMMY_ACCESS_TOKEN = "dummy-access-token"
+DUMMY_REQUEST_TOKEN = "dummy-request-token"
diff --git a/mediagoblin/oauth/oauth.py b/mediagoblin/oauth/oauth.py
index c7951734..2cc4e790 100644
--- a/mediagoblin/oauth/oauth.py
+++ b/mediagoblin/oauth/oauth.py
@@ -18,6 +18,7 @@ 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):
@@ -94,7 +95,8 @@ class GMGRequestValidator(RequestValidator):
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
@@ -102,15 +104,30 @@ class GMGRequestValidator(RequestValidator):
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
@@ -131,6 +148,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
diff --git a/mediagoblin/oauth/views.py b/mediagoblin/oauth/views.py
index 1b4787d6..2bfaab3e 100644
--- a/mediagoblin/oauth/views.py
+++ b/mediagoblin/oauth/views.py
@@ -211,7 +211,7 @@ def request_token(request):
error = "Invalid client_id"
return json_response({"error": error}, status=400)
- # make request token and return to client
+ # make request token and return to client
request_validator = GMGRequestValidator(authorization)
rv = RequestTokenEndpoint(request_validator)
tokens = rv.create_request_token(request, authorization)