Fix #5391 - Alembic migrations would only work for SQLite
[larjonas-mediagoblin.git] / mediagoblin / oauth / oauth.py
blobcdd8c842eed2ee679a87bbd8e7a3e8675eeda41d
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 import datetime
18 from oauthlib.common import Request
19 from oauthlib.oauth1 import RequestValidator
21 from mediagoblin import oauth
22 from mediagoblin.db.models import NonceTimestamp, Client, RequestToken, AccessToken
24 class GMGRequestValidator(RequestValidator):
26 enforce_ssl = False
28 def __init__(self, data=None, *args, **kwargs):
29 self.POST = data
30 super(GMGRequestValidator, self).__init__(*args, **kwargs)
32 def check_nonce(self, nonce):
33 """
34 This checks that the nonce given is a valid nonce
36 RequestValidator.check_nonce checks that it's between a maximum and
37 minimum length which, not only does pump.io not do this from what
38 I can see but there is nothing in rfc5849 which suggests a maximum or
39 minium length should be required so I'm removing that check
40 """
41 # Check the nonce only contains a subset of the safe characters.
42 return set(nonce) <= self.safe_characters
44 def save_request_token(self, token, request):
45 """ Saves request token in db """
46 client_id = self.POST[u"oauth_consumer_key"]
48 request_token = RequestToken(
49 token=token["oauth_token"],
50 secret=token["oauth_token_secret"],
52 request_token.client = client_id
53 if u"oauth_callback" in self.POST:
54 request_token.callback = self.POST[u"oauth_callback"]
55 request_token.save()
57 def save_verifier(self, token, verifier, request):
58 """ Saves the oauth request verifier """
59 request_token = RequestToken.query.filter_by(token=token).first()
60 request_token.verifier = verifier["oauth_verifier"]
61 request_token.save()
63 def save_access_token(self, token, request):
64 """ Saves access token in db """
65 access_token = AccessToken(
66 token=token["oauth_token"],
67 secret=token["oauth_token_secret"],
69 access_token.request_token = request.oauth_token
70 request_token = RequestToken.query.filter_by(token=request.oauth_token).first()
71 access_token.actor = request_token.actor
72 access_token.save()
74 def get_realms(*args, **kwargs):
75 """ Currently a stub - called when making AccessTokens """
76 return list()
78 def validate_timestamp_and_nonce(self, client_key, timestamp,
79 nonce, request, request_token=None,
80 access_token=None):
81 # RFC5849 (OAuth 1.0) section 3.3 says the timestamp is going
82 # to be seconds after the epoch, we need to convert for postgres
83 try:
84 timestamp = datetime.datetime.fromtimestamp(float(timestamp))
85 except ValueError:
86 # Well, the client must have passed up something ridiculous
87 return False
89 nc = NonceTimestamp.query.filter_by(timestamp=timestamp, nonce=nonce)
90 nc = nc.first()
91 if nc is None:
92 return True
94 return False
96 def validate_client_key(self, client_key, request):
97 """ Verifies client exists with id of client_key """
98 client_query = Client.query.filter(Client.id != oauth.DUMMY_CLIENT_ID)
99 client = client_query.filter_by(id=client_key).first()
100 if client is None:
101 return False
103 return True
105 def validate_verifier(self, token, verifier):
106 """ Verifies the verifier token is correct. """
107 request_token = RequestToken.query.filter_by(token=token).first()
108 if request_token is None:
109 return False
111 if request_token.verifier != verifier:
112 return False
114 return True
116 def validate_access_token(self, client_key, token, request):
117 """ Verifies token exists for client with id of client_key """
118 # Get the client for the request
119 client_query = Client.query.filter(Client.id != oauth.DUMMY_CLIENT_ID)
120 client = client_query.filter_by(id=client_key).first()
122 # If the client is invalid then it's invalid
123 if client is None:
124 return False
126 # Look up the AccessToken
127 access_token_query = AccessToken.query.filter(
128 AccessToken.token != oauth.DUMMY_ACCESS_TOKEN
130 access_token = access_token_query.filter_by(token=token).first()
132 # If there isn't one - we can't validate.
133 if access_token is None:
134 return False
136 # Check that the client matches the on
137 request_token_query = RequestToken.query.filter(
138 RequestToken.token != oauth.DUMMY_REQUEST_TOKEN,
139 RequestToken.token == access_token.request_token
141 request_token = request_token_query.first()
143 if client.id != request_token.client:
144 return False
146 return True
148 def validate_realms(self, *args, **kwargs):
149 """ Would validate reals however not using these yet. """
150 return True # implement when realms are implemented
153 def get_client_secret(self, client_key, request):
154 """ Retrives a client secret with from a client with an id of client_key """
155 client = Client.query.filter_by(id=client_key).first()
156 return client.secret
158 def get_access_token_secret(self, client_key, token, request):
159 access_token = AccessToken.query.filter_by(token=token).first()
160 return access_token.secret
162 @property
163 def dummy_client(self):
164 return oauth.DUMMY_CLIENT_ID
166 @property
167 def dummy_request_token(self):
168 return oauth.DUMMY_REQUEST_TOKEN
170 @property
171 def dummy_access_token(self):
172 return oauth.DUMMY_ACCESS_TOKEN
174 class GMGRequest(Request):
176 Fills in data to produce a oauth.common.Request object from a
177 werkzeug Request object
180 def __init__(self, request, *args, **kwargs):
182 :param request: werkzeug request object
184 any extra params are passed to oauthlib.common.Request object
186 kwargs["uri"] = kwargs.get("uri", request.url)
187 kwargs["http_method"] = kwargs.get("http_method", request.method)
188 kwargs["body"] = kwargs.get("body", request.data)
189 kwargs["headers"] = kwargs.get("headers", dict(request.headers))
191 super(GMGRequest, self).__init__(*args, **kwargs)