aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin/oauth/oauth.py
blob: cdd8c842eed2ee679a87bbd8e7a3e8675eeda41d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# 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 <http://www.gnu.org/licenses/>.
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)