Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / oa2 / backends / base.py @ 75e0551c

History | View | Annotate | Download (21 kB)

1 3fc7fd80 Kostas Papadimitriou
import urllib
2 3fc7fd80 Kostas Papadimitriou
import urlparse
3 3fc7fd80 Kostas Papadimitriou
import uuid
4 3fc7fd80 Kostas Papadimitriou
import datetime
5 3fc7fd80 Kostas Papadimitriou
import json
6 3fc7fd80 Kostas Papadimitriou
7 3fc7fd80 Kostas Papadimitriou
from base64 import b64encode, b64decode
8 3fc7fd80 Kostas Papadimitriou
from hashlib import sha512
9 e28a4841 Sofia Papagiannaki
from time import time, mktime
10 e28a4841 Sofia Papagiannaki
11 3fc7fd80 Kostas Papadimitriou
12 3fc7fd80 Kostas Papadimitriou
import logging
13 3fc7fd80 Kostas Papadimitriou
logger = logging.getLogger(__name__)
14 3fc7fd80 Kostas Papadimitriou
15 3fc7fd80 Kostas Papadimitriou
16 3fc7fd80 Kostas Papadimitriou
def handles_oa2_requests(func):
17 3fc7fd80 Kostas Papadimitriou
    def wrapper(self, *args, **kwargs):
18 3fc7fd80 Kostas Papadimitriou
        if not self._errors_to_http:
19 3fc7fd80 Kostas Papadimitriou
            return func(self, *args, **kwargs)
20 3fc7fd80 Kostas Papadimitriou
        try:
21 3fc7fd80 Kostas Papadimitriou
            return func(self, *args, **kwargs)
22 3fc7fd80 Kostas Papadimitriou
        except OA2Error, e:
23 3fc7fd80 Kostas Papadimitriou
            return self.build_response_from_error(e)
24 3fc7fd80 Kostas Papadimitriou
    return wrapper
25 3fc7fd80 Kostas Papadimitriou
26 3fc7fd80 Kostas Papadimitriou
27 3fc7fd80 Kostas Papadimitriou
class OA2Error(Exception):
28 3fc7fd80 Kostas Papadimitriou
    error = None
29 3fc7fd80 Kostas Papadimitriou
30 3fc7fd80 Kostas Papadimitriou
31 3fc7fd80 Kostas Papadimitriou
class InvalidClientID(OA2Error):
32 3fc7fd80 Kostas Papadimitriou
    pass
33 3fc7fd80 Kostas Papadimitriou
34 3fc7fd80 Kostas Papadimitriou
35 3fc7fd80 Kostas Papadimitriou
class NotAuthenticatedError(OA2Error):
36 3fc7fd80 Kostas Papadimitriou
    pass
37 3fc7fd80 Kostas Papadimitriou
38 3fc7fd80 Kostas Papadimitriou
39 3fc7fd80 Kostas Papadimitriou
class InvalidClientRedirectUrl(OA2Error):
40 3fc7fd80 Kostas Papadimitriou
    pass
41 3fc7fd80 Kostas Papadimitriou
42 3fc7fd80 Kostas Papadimitriou
43 3fc7fd80 Kostas Papadimitriou
class InvalidAuthorizationRequest(OA2Error):
44 3fc7fd80 Kostas Papadimitriou
    pass
45 3fc7fd80 Kostas Papadimitriou
46 3fc7fd80 Kostas Papadimitriou
47 3fc7fd80 Kostas Papadimitriou
class Response(object):
48 3fc7fd80 Kostas Papadimitriou
49 3fc7fd80 Kostas Papadimitriou
    def __init__(self, status, body='', headers=None,
50 3fc7fd80 Kostas Papadimitriou
                 content_type='plain/text'):
51 3fc7fd80 Kostas Papadimitriou
        if not body:
52 3fc7fd80 Kostas Papadimitriou
            body = ''
53 3fc7fd80 Kostas Papadimitriou
        if not headers:
54 3fc7fd80 Kostas Papadimitriou
            headers = {}
55 3fc7fd80 Kostas Papadimitriou
56 3fc7fd80 Kostas Papadimitriou
        self.status = status
57 3fc7fd80 Kostas Papadimitriou
        self.body = body
58 3fc7fd80 Kostas Papadimitriou
        self.headers = headers
59 3fc7fd80 Kostas Papadimitriou
        self.content_type = content_type
60 3fc7fd80 Kostas Papadimitriou
61 3fc7fd80 Kostas Papadimitriou
    def __repr__(self):
62 3fc7fd80 Kostas Papadimitriou
        return "%d RESPONSE (BODY: %r, HEADERS: %r)" % (self.status,
63 3fc7fd80 Kostas Papadimitriou
                                                        self.body,
64 3fc7fd80 Kostas Papadimitriou
                                                        self.headers)
65 3fc7fd80 Kostas Papadimitriou
66 3fc7fd80 Kostas Papadimitriou
67 3fc7fd80 Kostas Papadimitriou
class Request(object):
68 3fc7fd80 Kostas Papadimitriou
69 e28a4841 Sofia Papagiannaki
    def __init__(self, method, path, GET=None, POST=None, META=None,
70 e28a4841 Sofia Papagiannaki
                 secure=False, user=None):
71 3fc7fd80 Kostas Papadimitriou
        self.method = method
72 e28a4841 Sofia Papagiannaki
        self.path = path
73 3fc7fd80 Kostas Papadimitriou
74 3fc7fd80 Kostas Papadimitriou
        if not GET:
75 3fc7fd80 Kostas Papadimitriou
            GET = {}
76 3fc7fd80 Kostas Papadimitriou
        if not POST:
77 3fc7fd80 Kostas Papadimitriou
            POST = {}
78 3fc7fd80 Kostas Papadimitriou
        if not META:
79 3fc7fd80 Kostas Papadimitriou
            META = {}
80 3fc7fd80 Kostas Papadimitriou
81 3fc7fd80 Kostas Papadimitriou
        self.secure = secure
82 3fc7fd80 Kostas Papadimitriou
        self.GET = GET
83 3fc7fd80 Kostas Papadimitriou
        self.POST = POST
84 3fc7fd80 Kostas Papadimitriou
        self.META = META
85 3fc7fd80 Kostas Papadimitriou
        self.user = user
86 3fc7fd80 Kostas Papadimitriou
87 3fc7fd80 Kostas Papadimitriou
    def __repr__(self):
88 3fc7fd80 Kostas Papadimitriou
        prepend = ""
89 3fc7fd80 Kostas Papadimitriou
        if self.secure:
90 3fc7fd80 Kostas Papadimitriou
            prepend = "SECURE "
91 3fc7fd80 Kostas Papadimitriou
        return "%s%s REQUEST (POST: %r, GET:%r, HEADERS:%r, " % (prepend,
92 3fc7fd80 Kostas Papadimitriou
                                                                 self.method,
93 3fc7fd80 Kostas Papadimitriou
                                                                 self.POST,
94 3fc7fd80 Kostas Papadimitriou
                                                                 self.GET,
95 3fc7fd80 Kostas Papadimitriou
                                                                 self.META)
96 3fc7fd80 Kostas Papadimitriou
97 3fc7fd80 Kostas Papadimitriou
98 3fc7fd80 Kostas Papadimitriou
class ORMAbstractBase(type):
99 3fc7fd80 Kostas Papadimitriou
100 3fc7fd80 Kostas Papadimitriou
    def __new__(cls, name, bases, attrs):
101 3fc7fd80 Kostas Papadimitriou
        attrs['ENTRIES'] = {}
102 3fc7fd80 Kostas Papadimitriou
        return super(ORMAbstractBase, cls).__new__(cls, name, bases, attrs)
103 3fc7fd80 Kostas Papadimitriou
104 3fc7fd80 Kostas Papadimitriou
105 3fc7fd80 Kostas Papadimitriou
class ORMAbstract(object):
106 3fc7fd80 Kostas Papadimitriou
107 3fc7fd80 Kostas Papadimitriou
    ENTRIES = {}
108 3fc7fd80 Kostas Papadimitriou
109 3fc7fd80 Kostas Papadimitriou
    __metaclass__ = ORMAbstractBase
110 3fc7fd80 Kostas Papadimitriou
111 3fc7fd80 Kostas Papadimitriou
    def __init__(self, **kwargs):
112 3fc7fd80 Kostas Papadimitriou
        for key, value in kwargs.iteritems():
113 3fc7fd80 Kostas Papadimitriou
            setattr(self, key, value)
114 3fc7fd80 Kostas Papadimitriou
115 3fc7fd80 Kostas Papadimitriou
    @classmethod
116 3fc7fd80 Kostas Papadimitriou
    def create(cls, id, **params):
117 3fc7fd80 Kostas Papadimitriou
        params = cls.clean_params(params)
118 3fc7fd80 Kostas Papadimitriou
        params['id'] = id
119 3fc7fd80 Kostas Papadimitriou
        cls.ENTRIES[id] = cls(**params)
120 3fc7fd80 Kostas Papadimitriou
        return cls.get(id)
121 3fc7fd80 Kostas Papadimitriou
122 3fc7fd80 Kostas Papadimitriou
    @classmethod
123 3fc7fd80 Kostas Papadimitriou
    def get(cls, pk):
124 3fc7fd80 Kostas Papadimitriou
        return cls.ENTRIES.get(pk)
125 3fc7fd80 Kostas Papadimitriou
126 3fc7fd80 Kostas Papadimitriou
    @classmethod
127 3fc7fd80 Kostas Papadimitriou
    def clean_params(cls, params):
128 3fc7fd80 Kostas Papadimitriou
        return params
129 3fc7fd80 Kostas Papadimitriou
130 3fc7fd80 Kostas Papadimitriou
131 3fc7fd80 Kostas Papadimitriou
class Client(ORMAbstract):
132 3fc7fd80 Kostas Papadimitriou
133 3fc7fd80 Kostas Papadimitriou
    def get_id(self):
134 3fc7fd80 Kostas Papadimitriou
        return self.id
135 3fc7fd80 Kostas Papadimitriou
136 3fc7fd80 Kostas Papadimitriou
    def get_redirect_uris(self):
137 3fc7fd80 Kostas Papadimitriou
        return self.uris
138 3fc7fd80 Kostas Papadimitriou
139 3fc7fd80 Kostas Papadimitriou
    def get_default_redirect_uri(self):
140 3fc7fd80 Kostas Papadimitriou
        return self.uris[0]
141 3fc7fd80 Kostas Papadimitriou
142 3fc7fd80 Kostas Papadimitriou
    def redirect_uri_is_valid(self, redirect_uri):
143 3fc7fd80 Kostas Papadimitriou
        split = urlparse.urlsplit(redirect_uri)
144 3fc7fd80 Kostas Papadimitriou
        if split.scheme not in urlparse.uses_query:
145 3fc7fd80 Kostas Papadimitriou
            raise OA2Error("Invalid redirect url scheme")
146 3fc7fd80 Kostas Papadimitriou
        uris = self.get_redirect_uris()
147 3fc7fd80 Kostas Papadimitriou
        return redirect_uri in uris
148 3fc7fd80 Kostas Papadimitriou
149 3fc7fd80 Kostas Papadimitriou
    def requires_auth(self):
150 3fc7fd80 Kostas Papadimitriou
        if self.client_type == 'confidential':
151 3fc7fd80 Kostas Papadimitriou
            return True
152 3fc7fd80 Kostas Papadimitriou
        return 'secret' in dir(self)
153 3fc7fd80 Kostas Papadimitriou
154 3fc7fd80 Kostas Papadimitriou
    def check_credentials(self, username, secret):
155 3fc7fd80 Kostas Papadimitriou
        return username == self.id and secret == self.secret
156 3fc7fd80 Kostas Papadimitriou
157 3fc7fd80 Kostas Papadimitriou
158 3fc7fd80 Kostas Papadimitriou
class Token(ORMAbstract):
159 3fc7fd80 Kostas Papadimitriou
160 3fc7fd80 Kostas Papadimitriou
    def to_dict(self):
161 3fc7fd80 Kostas Papadimitriou
        params = {
162 3fc7fd80 Kostas Papadimitriou
            'access_token': self.token,
163 3fc7fd80 Kostas Papadimitriou
            'token_type': self.token_type,
164 3fc7fd80 Kostas Papadimitriou
            'expires_in': self.expires,
165 3fc7fd80 Kostas Papadimitriou
        }
166 3fc7fd80 Kostas Papadimitriou
        if self.refresh_token:
167 3fc7fd80 Kostas Papadimitriou
            params['refresh_token'] = self.refresh_token
168 3fc7fd80 Kostas Papadimitriou
        return params
169 3fc7fd80 Kostas Papadimitriou
170 3fc7fd80 Kostas Papadimitriou
171 3fc7fd80 Kostas Papadimitriou
class AuthorizationCode(ORMAbstract):
172 3fc7fd80 Kostas Papadimitriou
    pass
173 3fc7fd80 Kostas Papadimitriou
174 3fc7fd80 Kostas Papadimitriou
175 3fc7fd80 Kostas Papadimitriou
class User(ORMAbstract):
176 3fc7fd80 Kostas Papadimitriou
    pass
177 3fc7fd80 Kostas Papadimitriou
178 3fc7fd80 Kostas Papadimitriou
179 3fc7fd80 Kostas Papadimitriou
class BackendBase(type):
180 3fc7fd80 Kostas Papadimitriou
181 3fc7fd80 Kostas Papadimitriou
    def __new__(cls, name, bases, attrs):
182 3fc7fd80 Kostas Papadimitriou
        super_new = super(BackendBase, cls).__new__
183 e28a4841 Sofia Papagiannaki
        #parents = [b for b in bases if isinstance(b, BackendBase)]
184 e28a4841 Sofia Papagiannaki
        #meta = attrs.pop('Meta', None)
185 3fc7fd80 Kostas Papadimitriou
        return super_new(cls, name, bases, attrs)
186 3fc7fd80 Kostas Papadimitriou
187 3fc7fd80 Kostas Papadimitriou
    @classmethod
188 3fc7fd80 Kostas Papadimitriou
    def get_orm_options(cls, attrs):
189 3fc7fd80 Kostas Papadimitriou
        meta = attrs.pop('ORM', None)
190 3fc7fd80 Kostas Papadimitriou
        orm = {}
191 3fc7fd80 Kostas Papadimitriou
        if meta:
192 3fc7fd80 Kostas Papadimitriou
            for attr in dir(meta):
193 3fc7fd80 Kostas Papadimitriou
                orm[attr] = getattr(meta, attr)
194 3fc7fd80 Kostas Papadimitriou
        return orm
195 3fc7fd80 Kostas Papadimitriou
196 3fc7fd80 Kostas Papadimitriou
197 3fc7fd80 Kostas Papadimitriou
class SimpleBackend(object):
198 3fc7fd80 Kostas Papadimitriou
199 3fc7fd80 Kostas Papadimitriou
    __metaclass__ = BackendBase
200 3fc7fd80 Kostas Papadimitriou
201 3fc7fd80 Kostas Papadimitriou
    base_url = ''
202 3fc7fd80 Kostas Papadimitriou
    endpoints_prefix = '/oa2/'
203 3fc7fd80 Kostas Papadimitriou
204 3fc7fd80 Kostas Papadimitriou
    token_endpoint = 'token/'
205 3fc7fd80 Kostas Papadimitriou
    token_length = 30
206 e28a4841 Sofia Papagiannaki
    token_expires = 300
207 3fc7fd80 Kostas Papadimitriou
208 3fc7fd80 Kostas Papadimitriou
    authorization_endpoint = 'auth/'
209 3fc7fd80 Kostas Papadimitriou
    authorization_code_length = 60
210 3fc7fd80 Kostas Papadimitriou
    authorization_response_types = ['code', 'token']
211 3fc7fd80 Kostas Papadimitriou
212 e28a4841 Sofia Papagiannaki
    grant_types = ['authorization_code']
213 3fc7fd80 Kostas Papadimitriou
214 3fc7fd80 Kostas Papadimitriou
    response_cls = Response
215 3fc7fd80 Kostas Papadimitriou
    request_cls = Request
216 3fc7fd80 Kostas Papadimitriou
217 3fc7fd80 Kostas Papadimitriou
    client_model = Client
218 3fc7fd80 Kostas Papadimitriou
    token_model = Token
219 3fc7fd80 Kostas Papadimitriou
    code_model = AuthorizationCode
220 3fc7fd80 Kostas Papadimitriou
    user_model = User
221 3fc7fd80 Kostas Papadimitriou
222 3fc7fd80 Kostas Papadimitriou
    def __init__(self, base_url='', endpoints_prefix='/oa2/', id='oa2',
223 3fc7fd80 Kostas Papadimitriou
                 **kwargs):
224 3fc7fd80 Kostas Papadimitriou
        self.base_url = base_url
225 3fc7fd80 Kostas Papadimitriou
        self.endpoints_prefix = endpoints_prefix
226 3fc7fd80 Kostas Papadimitriou
        self.id = id
227 3fc7fd80 Kostas Papadimitriou
        self._errors_to_http = kwargs.get('errors_to_http', True)
228 3fc7fd80 Kostas Papadimitriou
229 3fc7fd80 Kostas Papadimitriou
    # Request/response builders
230 3fc7fd80 Kostas Papadimitriou
    def build_request(self, method, get, post, meta):
231 3fc7fd80 Kostas Papadimitriou
        return self.request_cls(method=method, GET=get, POST=post, META=meta)
232 3fc7fd80 Kostas Papadimitriou
233 3fc7fd80 Kostas Papadimitriou
    def build_response(self, status, headers=None, body=''):
234 3fc7fd80 Kostas Papadimitriou
        return self.response_cls(status=status, headers=headers, body=body)
235 3fc7fd80 Kostas Papadimitriou
236 3fc7fd80 Kostas Papadimitriou
    # ORM Methods
237 e28a4841 Sofia Papagiannaki
    def create_authorization_code(self, user, client, code, redirect_uri,
238 e28a4841 Sofia Papagiannaki
                                  scope, state, **kwargs):
239 3fc7fd80 Kostas Papadimitriou
        code_params = {
240 3fc7fd80 Kostas Papadimitriou
            'code': code,
241 3fc7fd80 Kostas Papadimitriou
            'redirect_uri': redirect_uri,
242 e28a4841 Sofia Papagiannaki
            'client': client,
243 3fc7fd80 Kostas Papadimitriou
            'scope': scope,
244 e28a4841 Sofia Papagiannaki
            'state': state,
245 e28a4841 Sofia Papagiannaki
            'user': user
246 3fc7fd80 Kostas Papadimitriou
        }
247 3fc7fd80 Kostas Papadimitriou
        code_params.update(kwargs)
248 e28a4841 Sofia Papagiannaki
        code_instance = self.code_model.create(**code_params)
249 e28a4841 Sofia Papagiannaki
        logger.info('%r created' % code_instance)
250 e28a4841 Sofia Papagiannaki
        return code_instance
251 3fc7fd80 Kostas Papadimitriou
252 e28a4841 Sofia Papagiannaki
    def _token_params(self, value, token_type, authorization, scope):
253 3fc7fd80 Kostas Papadimitriou
        created_at = datetime.datetime.now()
254 3fc7fd80 Kostas Papadimitriou
        expires = self.token_expires
255 3fc7fd80 Kostas Papadimitriou
        expires_at = created_at + datetime.timedelta(seconds=expires)
256 3fc7fd80 Kostas Papadimitriou
        token_params = {
257 e28a4841 Sofia Papagiannaki
            'code': value,
258 3fc7fd80 Kostas Papadimitriou
            'token_type': token_type,
259 3fc7fd80 Kostas Papadimitriou
            'created_at': created_at,
260 e28a4841 Sofia Papagiannaki
            'expires_at': expires_at,
261 e28a4841 Sofia Papagiannaki
            'user': authorization.user,
262 e28a4841 Sofia Papagiannaki
            'redirect_uri': authorization.redirect_uri,
263 e28a4841 Sofia Papagiannaki
            'client': authorization.client,
264 e28a4841 Sofia Papagiannaki
            'scope': authorization.scope,
265 3fc7fd80 Kostas Papadimitriou
        }
266 3fc7fd80 Kostas Papadimitriou
        return token_params
267 3fc7fd80 Kostas Papadimitriou
268 e28a4841 Sofia Papagiannaki
    def create_token(self, value, token_type, authorization, scope,
269 e28a4841 Sofia Papagiannaki
                     refresh=False):
270 e28a4841 Sofia Papagiannaki
        params = self._token_params(value, token_type, authorization, scope)
271 3fc7fd80 Kostas Papadimitriou
        if refresh:
272 3fc7fd80 Kostas Papadimitriou
            refresh_token = self.generate_token()
273 3fc7fd80 Kostas Papadimitriou
            params['refresh_token'] = refresh_token
274 3fc7fd80 Kostas Papadimitriou
            # TODO: refresh token expires ???
275 e28a4841 Sofia Papagiannaki
        token = self.token_model.create(**params)
276 e28a4841 Sofia Papagiannaki
        logger.info('%r created' % token)
277 e28a4841 Sofia Papagiannaki
        return token
278 3fc7fd80 Kostas Papadimitriou
279 e28a4841 Sofia Papagiannaki
#    def delete_authorization_code(self, code):
280 e28a4841 Sofia Papagiannaki
#        del self.code_model.ENTRIES[code]
281 3fc7fd80 Kostas Papadimitriou
282 3fc7fd80 Kostas Papadimitriou
    def get_client_by_id(self, client_id):
283 3fc7fd80 Kostas Papadimitriou
        return self.client_model.get(client_id)
284 3fc7fd80 Kostas Papadimitriou
285 3fc7fd80 Kostas Papadimitriou
    def get_client_by_credentials(self, username, password):
286 3fc7fd80 Kostas Papadimitriou
        return None
287 3fc7fd80 Kostas Papadimitriou
288 3fc7fd80 Kostas Papadimitriou
    def get_authorization_code(self, code):
289 3fc7fd80 Kostas Papadimitriou
        return self.code_model.get(code)
290 3fc7fd80 Kostas Papadimitriou
291 3fc7fd80 Kostas Papadimitriou
    def get_client_authorization_code(self, client, code):
292 3fc7fd80 Kostas Papadimitriou
        code_instance = self.get_authorization_code(code)
293 3fc7fd80 Kostas Papadimitriou
        if not code_instance:
294 3fc7fd80 Kostas Papadimitriou
            raise OA2Error("Invalid code", code)
295 3fc7fd80 Kostas Papadimitriou
296 e28a4841 Sofia Papagiannaki
        if client.get_id() != code_instance.client.get_id():
297 3fc7fd80 Kostas Papadimitriou
            raise OA2Error("Invalid code for client", code, client)
298 3fc7fd80 Kostas Papadimitriou
        return code_instance
299 3fc7fd80 Kostas Papadimitriou
300 3fc7fd80 Kostas Papadimitriou
    def client_id_exists(self, client_id):
301 3fc7fd80 Kostas Papadimitriou
        return bool(self.get_client_by_id(client_id))
302 3fc7fd80 Kostas Papadimitriou
303 3fc7fd80 Kostas Papadimitriou
    def build_site_url(self, prefix='', **params):
304 3fc7fd80 Kostas Papadimitriou
        params = urllib.urlencode(params)
305 3fc7fd80 Kostas Papadimitriou
        return "%s%s%s%s" % (self.base_url, self.endpoints_prefix, prefix,
306 3fc7fd80 Kostas Papadimitriou
                             params)
307 3fc7fd80 Kostas Papadimitriou
308 3fc7fd80 Kostas Papadimitriou
    def _get_uri_base(self, uri):
309 3fc7fd80 Kostas Papadimitriou
        split = urlparse.urlsplit(uri)
310 3fc7fd80 Kostas Papadimitriou
        return "%s://%s%s" % (split.scheme, split.netloc, split.path)
311 3fc7fd80 Kostas Papadimitriou
312 3fc7fd80 Kostas Papadimitriou
    def build_client_redirect_uri(self, client, uri, **params):
313 3fc7fd80 Kostas Papadimitriou
        if not client.redirect_uri_is_valid(uri):
314 3fc7fd80 Kostas Papadimitriou
            raise OA2Error("Invalid redirect uri")
315 3fc7fd80 Kostas Papadimitriou
        params = urllib.urlencode(params)
316 3fc7fd80 Kostas Papadimitriou
        uri = self._get_uri_base(uri)
317 3fc7fd80 Kostas Papadimitriou
        return "%s?%s" % (uri, params)
318 3fc7fd80 Kostas Papadimitriou
319 3fc7fd80 Kostas Papadimitriou
    def generate_authorization_code(self):
320 3fc7fd80 Kostas Papadimitriou
        dg64 = b64encode(sha512(str(uuid.uuid4())).hexdigest())
321 3fc7fd80 Kostas Papadimitriou
        return dg64[:self.authorization_code_length]
322 3fc7fd80 Kostas Papadimitriou
323 3fc7fd80 Kostas Papadimitriou
    def generate_token(self, *args, **kwargs):
324 3fc7fd80 Kostas Papadimitriou
        dg64 = b64encode(sha512(str(uuid.uuid4())).hexdigest())
325 3fc7fd80 Kostas Papadimitriou
        return dg64[:self.token_length]
326 3fc7fd80 Kostas Papadimitriou
327 3fc7fd80 Kostas Papadimitriou
    def add_authorization_code(self, user, client, redirect_uri, scope, state,
328 3fc7fd80 Kostas Papadimitriou
                               **kwargs):
329 3fc7fd80 Kostas Papadimitriou
        code = self.generate_authorization_code()
330 3fc7fd80 Kostas Papadimitriou
        self.create_authorization_code(user, client, code, redirect_uri, scope,
331 3fc7fd80 Kostas Papadimitriou
                                       state, **kwargs)
332 3fc7fd80 Kostas Papadimitriou
        return code
333 3fc7fd80 Kostas Papadimitriou
334 e28a4841 Sofia Papagiannaki
    def add_token_for_client(self, token_type, authorization, refresh=False):
335 e28a4841 Sofia Papagiannaki
        token = self.generate_token()
336 e28a4841 Sofia Papagiannaki
        self.create_token(token, token_type, authorization, refresh)
337 e28a4841 Sofia Papagiannaki
        return token
338 e28a4841 Sofia Papagiannaki
339 3fc7fd80 Kostas Papadimitriou
    #
340 3fc7fd80 Kostas Papadimitriou
    # Response helpers
341 3fc7fd80 Kostas Papadimitriou
    #
342 3fc7fd80 Kostas Papadimitriou
343 e28a4841 Sofia Papagiannaki
    def grant_accept_response(self, client, redirect_uri, scope, state):
344 3fc7fd80 Kostas Papadimitriou
        context = {'client': client.get_id(), 'redirect_uri': redirect_uri,
345 e28a4841 Sofia Papagiannaki
                   'scope': scope, 'state': state,
346 e28a4841 Sofia Papagiannaki
                   #'url': url,
347 e28a4841 Sofia Papagiannaki
                   }
348 e28a4841 Sofia Papagiannaki
        json_content = json.dumps(context)
349 e28a4841 Sofia Papagiannaki
        return self.response_cls(status=200, body=json_content)
350 e28a4841 Sofia Papagiannaki
351 e28a4841 Sofia Papagiannaki
    def grant_token_response(self, token, token_type):
352 e28a4841 Sofia Papagiannaki
        context = {'access_token': token, 'token_type': token_type,
353 e28a4841 Sofia Papagiannaki
                   'expires_in': self.token_expires}
354 3fc7fd80 Kostas Papadimitriou
        json_content = json.dumps(context)
355 3fc7fd80 Kostas Papadimitriou
        return self.response_cls(status=200, body=json_content)
356 3fc7fd80 Kostas Papadimitriou
357 e28a4841 Sofia Papagiannaki
    def redirect_to_login_response(self, request, params):
358 e28a4841 Sofia Papagiannaki
        parts = list(urlparse.urlsplit(request.path))
359 e28a4841 Sofia Papagiannaki
        parts[3] = urllib.urlencode(params)
360 e28a4841 Sofia Papagiannaki
        query = {'next': urlparse.urlunsplit(parts)}
361 e28a4841 Sofia Papagiannaki
        return Response(302,
362 e28a4841 Sofia Papagiannaki
                        headers={'Location': '%s?%s' %
363 e28a4841 Sofia Papagiannaki
                                 (self.get_login_uri(),
364 e28a4841 Sofia Papagiannaki
                                  urllib.urlencode(query))})
365 e28a4841 Sofia Papagiannaki
366 e28a4841 Sofia Papagiannaki
    def redirect_to_uri(self, redirect_uri, code, state=None):
367 e28a4841 Sofia Papagiannaki
        parts = list(urlparse.urlsplit(redirect_uri))
368 e28a4841 Sofia Papagiannaki
        params = dict(urlparse.parse_qsl(parts[3], keep_blank_values=True))
369 e28a4841 Sofia Papagiannaki
        params['code'] = code
370 e28a4841 Sofia Papagiannaki
        if state is not None:
371 e28a4841 Sofia Papagiannaki
            params['state'] = state
372 e28a4841 Sofia Papagiannaki
        parts[3] = urllib.urlencode(params)
373 e28a4841 Sofia Papagiannaki
        return Response(302,
374 e28a4841 Sofia Papagiannaki
                        headers={'Location': '%s' %
375 e28a4841 Sofia Papagiannaki
                                 urlparse.urlunsplit(parts)})
376 3fc7fd80 Kostas Papadimitriou
377 3fc7fd80 Kostas Papadimitriou
    def build_response_from_error(self, exception):
378 3fc7fd80 Kostas Papadimitriou
        response = Response(400)
379 3fc7fd80 Kostas Papadimitriou
        logger.exception(exception)
380 3fc7fd80 Kostas Papadimitriou
        error = 'generic_error'
381 3fc7fd80 Kostas Papadimitriou
        if exception.error:
382 3fc7fd80 Kostas Papadimitriou
            error = exception.error
383 3fc7fd80 Kostas Papadimitriou
        body = {
384 3fc7fd80 Kostas Papadimitriou
            'error': error,
385 3fc7fd80 Kostas Papadimitriou
            'exception': exception.message,
386 3fc7fd80 Kostas Papadimitriou
        }
387 3fc7fd80 Kostas Papadimitriou
        response.body = json.dumps(body)
388 3fc7fd80 Kostas Papadimitriou
        response.content_type = "application/json"
389 3fc7fd80 Kostas Papadimitriou
        return response
390 3fc7fd80 Kostas Papadimitriou
391 3fc7fd80 Kostas Papadimitriou
    #
392 3fc7fd80 Kostas Papadimitriou
    # Processor methods
393 3fc7fd80 Kostas Papadimitriou
    #
394 3fc7fd80 Kostas Papadimitriou
395 e28a4841 Sofia Papagiannaki
    def process_code_request(self, user, client, uri, scope, state):
396 e28a4841 Sofia Papagiannaki
        code = self.add_authorization_code(user, client, uri, scope, state)
397 e28a4841 Sofia Papagiannaki
        return self.redirect_to_uri(uri, code, state)
398 3fc7fd80 Kostas Papadimitriou
399 3fc7fd80 Kostas Papadimitriou
    #
400 3fc7fd80 Kostas Papadimitriou
    # Helpers
401 3fc7fd80 Kostas Papadimitriou
    #
402 3fc7fd80 Kostas Papadimitriou
403 e28a4841 Sofia Papagiannaki
    def grant_authorization_code(self, client, code_instance, redirect_uri,
404 e28a4841 Sofia Papagiannaki
                                 scope=None, token_type="Bearer"):
405 e28a4841 Sofia Papagiannaki
        if scope and code_instance.scope != scope:
406 e28a4841 Sofia Papagiannaki
            raise OA2Error("Invalid scope")
407 e28a4841 Sofia Papagiannaki
        if redirect_uri != code_instance.redirect_uri:
408 e28a4841 Sofia Papagiannaki
            raise OA2Error("The redirect uri does not match "
409 e28a4841 Sofia Papagiannaki
                           "the one used during authorization")
410 e28a4841 Sofia Papagiannaki
        token = self.add_token_for_client(token_type, code_instance)
411 e28a4841 Sofia Papagiannaki
        self.delete_authorization_code(code_instance)  # use only once
412 e28a4841 Sofia Papagiannaki
        return token, token_type
413 e28a4841 Sofia Papagiannaki
414 e28a4841 Sofia Papagiannaki
    def consume_token(self, token):
415 e28a4841 Sofia Papagiannaki
        token_instance = self.get_token(token)
416 e28a4841 Sofia Papagiannaki
        expires_at = mktime(token_instance.expires_at.timetuple())
417 e28a4841 Sofia Papagiannaki
        if time() > expires_at:
418 e28a4841 Sofia Papagiannaki
            self.delete_token(token_instance)  # delete expired token
419 e28a4841 Sofia Papagiannaki
            raise OA2Error("Token has expired")
420 e28a4841 Sofia Papagiannaki
        # TODO: delete token?
421 e28a4841 Sofia Papagiannaki
        return token_instance
422 e28a4841 Sofia Papagiannaki
423 3fc7fd80 Kostas Papadimitriou
    def _get_credentials(self, params, headers):
424 3fc7fd80 Kostas Papadimitriou
        if 'HTTP_AUTHORIZATION' in headers:
425 3fc7fd80 Kostas Papadimitriou
            scheme, b64credentials = headers.get(
426 3fc7fd80 Kostas Papadimitriou
                'HTTP_AUTHORIZATION').split(" ")
427 e28a4841 Sofia Papagiannaki
            if scheme != 'Basic':
428 e28a4841 Sofia Papagiannaki
                # TODO: raise 401 + WWW-Authenticate
429 e28a4841 Sofia Papagiannaki
                raise OA2Error("Unsupported authorization scheme")
430 3fc7fd80 Kostas Papadimitriou
            credentials = b64decode(b64credentials).split(":")
431 3fc7fd80 Kostas Papadimitriou
            return scheme, credentials
432 3fc7fd80 Kostas Papadimitriou
        else:
433 3fc7fd80 Kostas Papadimitriou
            return None, None
434 3fc7fd80 Kostas Papadimitriou
        pass
435 3fc7fd80 Kostas Papadimitriou
436 e28a4841 Sofia Papagiannaki
    def _get_authorization(self, params, headers):
437 e28a4841 Sofia Papagiannaki
        scheme, client_credentials = self._get_credentials(params, headers)
438 e28a4841 Sofia Papagiannaki
        no_authorization = scheme is None and client_credentials is None
439 e28a4841 Sofia Papagiannaki
        if no_authorization:
440 e28a4841 Sofia Papagiannaki
            raise OA2Error("Missing authorization header")
441 e28a4841 Sofia Papagiannaki
        return client_credentials
442 e28a4841 Sofia Papagiannaki
443 3fc7fd80 Kostas Papadimitriou
    def get_redirect_uri_from_params(self, client, params, default=True):
444 3fc7fd80 Kostas Papadimitriou
        """
445 3fc7fd80 Kostas Papadimitriou
        Accepts a client instance and request parameters.
446 3fc7fd80 Kostas Papadimitriou
        """
447 3fc7fd80 Kostas Papadimitriou
        redirect_uri = params.get('redirect_uri', None)
448 3fc7fd80 Kostas Papadimitriou
        if not redirect_uri and default:
449 3fc7fd80 Kostas Papadimitriou
            redirect_uri = client.get_default_redirect_uri()
450 3fc7fd80 Kostas Papadimitriou
        else:
451 3fc7fd80 Kostas Papadimitriou
            # TODO: sanitize redirect_uri (self.clean_redirect_uri ???)
452 3fc7fd80 Kostas Papadimitriou
            # clean and validate
453 3fc7fd80 Kostas Papadimitriou
            if not client.redirect_uri_is_valid(redirect_uri):
454 3fc7fd80 Kostas Papadimitriou
                raise OA2Error("Invalid client redirect uri")
455 3fc7fd80 Kostas Papadimitriou
        return redirect_uri
456 3fc7fd80 Kostas Papadimitriou
457 3fc7fd80 Kostas Papadimitriou
    #
458 e28a4841 Sofia Papagiannaki
    # Request identifiers
459 3fc7fd80 Kostas Papadimitriou
    #
460 3fc7fd80 Kostas Papadimitriou
461 e28a4841 Sofia Papagiannaki
    def identify_authorize_request(self, params, headers):
462 e28a4841 Sofia Papagiannaki
        return params.get('response_type'), params
463 3fc7fd80 Kostas Papadimitriou
464 e28a4841 Sofia Papagiannaki
    def identify_token_request(self, headers, params):
465 e28a4841 Sofia Papagiannaki
        content_type = headers.get('CONTENT_TYPE')
466 e28a4841 Sofia Papagiannaki
        if content_type != 'application/x-www-form-urlencoded':
467 e28a4841 Sofia Papagiannaki
            raise OA2Error("Invalid Content-Type header")
468 e28a4841 Sofia Papagiannaki
        return params.get('grant_type')
469 3fc7fd80 Kostas Papadimitriou
470 e28a4841 Sofia Papagiannaki
    #
471 e28a4841 Sofia Papagiannaki
    # Parameters validation methods
472 e28a4841 Sofia Papagiannaki
    #
473 3fc7fd80 Kostas Papadimitriou
474 e28a4841 Sofia Papagiannaki
    def validate_client(self, params, meta, requires_auth=True,
475 e28a4841 Sofia Papagiannaki
                        client_id_required=True):
476 e28a4841 Sofia Papagiannaki
        client_id = params.get('client_id')
477 e28a4841 Sofia Papagiannaki
        if client_id is None and client_id_required:
478 e28a4841 Sofia Papagiannaki
            raise OA2Error("Client identification is required")
479 e28a4841 Sofia Papagiannaki
480 e28a4841 Sofia Papagiannaki
        client_credentials = None
481 e28a4841 Sofia Papagiannaki
        try:  # check authorization header
482 e28a4841 Sofia Papagiannaki
            client_credentials = self._get_authorization(params, meta)
483 e28a4841 Sofia Papagiannaki
            if client_credentials is not None:
484 e28a4841 Sofia Papagiannaki
                _client_id = client_credentials[0]
485 e28a4841 Sofia Papagiannaki
                if client_id is not None and client_id != _client_id:
486 e28a4841 Sofia Papagiannaki
                    raise OA2Error("Client identification conflicts "
487 e28a4841 Sofia Papagiannaki
                                   "with client authorization")
488 e28a4841 Sofia Papagiannaki
                client_id = _client_id
489 e28a4841 Sofia Papagiannaki
        except:
490 e28a4841 Sofia Papagiannaki
            pass
491 e28a4841 Sofia Papagiannaki
492 e28a4841 Sofia Papagiannaki
        if client_id is None:
493 e28a4841 Sofia Papagiannaki
            raise OA2Error("Missing client identification")
494 e28a4841 Sofia Papagiannaki
495 e28a4841 Sofia Papagiannaki
        client = self.get_client_by_id(client_id)
496 e28a4841 Sofia Papagiannaki
497 e28a4841 Sofia Papagiannaki
        if requires_auth and client.requires_auth:
498 e28a4841 Sofia Papagiannaki
            if client_credentials is None:
499 e28a4841 Sofia Papagiannaki
                raise OA2Error("Client authentication in required")
500 e28a4841 Sofia Papagiannaki
501 e28a4841 Sofia Papagiannaki
        if client_credentials is not None:
502 e28a4841 Sofia Papagiannaki
            self.check_credentials(client, *client_credentials)
503 e28a4841 Sofia Papagiannaki
        return client
504 e28a4841 Sofia Papagiannaki
505 e28a4841 Sofia Papagiannaki
    def validate_redirect_uri(self, client, params, headers,
506 e28a4841 Sofia Papagiannaki
                              allow_default=True, is_required=False,
507 e28a4841 Sofia Papagiannaki
                              expected_value=None):
508 e28a4841 Sofia Papagiannaki
        redirect_uri = params.get('redirect_uri')
509 e28a4841 Sofia Papagiannaki
        if is_required and redirect_uri is None:
510 e28a4841 Sofia Papagiannaki
            raise OA2Error("Missing redirect uri")
511 e28a4841 Sofia Papagiannaki
        if redirect_uri is not None:
512 e28a4841 Sofia Papagiannaki
            if not bool(urlparse.urlparse(redirect_uri).scheme):
513 e28a4841 Sofia Papagiannaki
                raise OA2Error("Redirect uri should be an absolute URI")
514 e28a4841 Sofia Papagiannaki
            if not client.redirect_uri_is_valid(redirect_uri):
515 e28a4841 Sofia Papagiannaki
                raise OA2Error("Mismatching redirect uri")
516 e28a4841 Sofia Papagiannaki
            if expected_value is not None and redirect_uri != expected_value:
517 e28a4841 Sofia Papagiannaki
                raise OA2Error("Invalid redirect uri")
518 e28a4841 Sofia Papagiannaki
        return redirect_uri
519 e28a4841 Sofia Papagiannaki
520 e28a4841 Sofia Papagiannaki
    def validate_state(self, client, params, headers):
521 e28a4841 Sofia Papagiannaki
        return params.get('state')
522 3fc7fd80 Kostas Papadimitriou
        raise OA2Error("Invalid state")
523 3fc7fd80 Kostas Papadimitriou
524 e28a4841 Sofia Papagiannaki
    def validate_scope(self, client, params, headers):
525 e28a4841 Sofia Papagiannaki
        scope = params.get('scope')
526 e28a4841 Sofia Papagiannaki
        if scope is not None:
527 e28a4841 Sofia Papagiannaki
            scope = scope.split(' ')[0]  # keep only the first
528 e28a4841 Sofia Papagiannaki
        # TODO: check for invalid characters
529 e28a4841 Sofia Papagiannaki
        return scope
530 e28a4841 Sofia Papagiannaki
531 e28a4841 Sofia Papagiannaki
    def validate_code(self, client, params, headers):
532 e28a4841 Sofia Papagiannaki
        code = params.get('code')
533 e28a4841 Sofia Papagiannaki
        if code is None:
534 e28a4841 Sofia Papagiannaki
            raise OA2Error("Missing authorization code")
535 e28a4841 Sofia Papagiannaki
        return self.get_client_authorization_code(client, code)
536 e28a4841 Sofia Papagiannaki
537 3fc7fd80 Kostas Papadimitriou
    #
538 3fc7fd80 Kostas Papadimitriou
    # Requests validation methods
539 3fc7fd80 Kostas Papadimitriou
    #
540 3fc7fd80 Kostas Papadimitriou
541 e28a4841 Sofia Papagiannaki
    def validate_code_request(self, params, headers):
542 e28a4841 Sofia Papagiannaki
        client = self.validate_client(params, headers, requires_auth=False)
543 3fc7fd80 Kostas Papadimitriou
        redirect_uri = self.validate_redirect_uri(client, params, headers)
544 3fc7fd80 Kostas Papadimitriou
        scope = self.validate_scope(client, params, headers)
545 3fc7fd80 Kostas Papadimitriou
        state = self.validate_state(client, params, headers)
546 3fc7fd80 Kostas Papadimitriou
        return client, redirect_uri, scope, state
547 3fc7fd80 Kostas Papadimitriou
548 e28a4841 Sofia Papagiannaki
    def validate_token_request(self, params, headers, requires_auth=False):
549 e28a4841 Sofia Papagiannaki
        client = self.validate_client(params, headers)
550 3fc7fd80 Kostas Papadimitriou
        redirect_uri = self.validate_redirect_uri(client, params, headers)
551 3fc7fd80 Kostas Papadimitriou
        scope = self.validate_scope(client, params, headers)
552 3fc7fd80 Kostas Papadimitriou
        state = self.validate_state(client, params, headers)
553 3fc7fd80 Kostas Papadimitriou
        return client, redirect_uri, scope, state
554 3fc7fd80 Kostas Papadimitriou
555 e28a4841 Sofia Papagiannaki
    def validate_code_grant(self, params, headers):
556 e28a4841 Sofia Papagiannaki
        client = self.validate_client(params, headers,
557 e28a4841 Sofia Papagiannaki
                                      client_id_required=False)
558 e28a4841 Sofia Papagiannaki
        code_instance = self.validate_code(client, params, headers)
559 e28a4841 Sofia Papagiannaki
        redirect_uri = self.validate_redirect_uri(
560 e28a4841 Sofia Papagiannaki
            client, params, headers,
561 e28a4841 Sofia Papagiannaki
            expected_value=code_instance.redirect_uri)
562 e28a4841 Sofia Papagiannaki
        return client, redirect_uri, code_instance
563 e28a4841 Sofia Papagiannaki
564 3fc7fd80 Kostas Papadimitriou
    #
565 3fc7fd80 Kostas Papadimitriou
    # Endpoint methods
566 3fc7fd80 Kostas Papadimitriou
    #
567 3fc7fd80 Kostas Papadimitriou
568 3fc7fd80 Kostas Papadimitriou
    @handles_oa2_requests
569 3fc7fd80 Kostas Papadimitriou
    def authorize(self, request, **extra):
570 3fc7fd80 Kostas Papadimitriou
        """
571 3fc7fd80 Kostas Papadimitriou
        Used in the following cases
572 3fc7fd80 Kostas Papadimitriou
        """
573 3fc7fd80 Kostas Papadimitriou
        if not request.secure:
574 3fc7fd80 Kostas Papadimitriou
            raise OA2Error("Secure request required")
575 3fc7fd80 Kostas Papadimitriou
576 3fc7fd80 Kostas Papadimitriou
        # identify
577 3fc7fd80 Kostas Papadimitriou
        request_params = request.GET
578 3fc7fd80 Kostas Papadimitriou
        if request.method == "POST":
579 3fc7fd80 Kostas Papadimitriou
            request_params = request.POST
580 3fc7fd80 Kostas Papadimitriou
581 3fc7fd80 Kostas Papadimitriou
        auth_type, params = self.identify_authorize_request(request_params,
582 3fc7fd80 Kostas Papadimitriou
                                                            request.META)
583 3fc7fd80 Kostas Papadimitriou
584 3fc7fd80 Kostas Papadimitriou
        if auth_type == 'code':
585 3fc7fd80 Kostas Papadimitriou
            client, uri, scope, state = \
586 e28a4841 Sofia Papagiannaki
                self.validate_code_request(params, request.META)
587 3fc7fd80 Kostas Papadimitriou
        elif auth_type == 'token':
588 e28a4841 Sofia Papagiannaki
            raise OA2Error("Unsupported response type")
589 e28a4841 Sofia Papagiannaki
#            client, uri, scope, state = \
590 e28a4841 Sofia Papagiannaki
#                self.validate_token_request(params, request.META)
591 3fc7fd80 Kostas Papadimitriou
        else:
592 3fc7fd80 Kostas Papadimitriou
            #TODO: handle custom type
593 3fc7fd80 Kostas Papadimitriou
            raise OA2Error("Invalid authorization type")
594 3fc7fd80 Kostas Papadimitriou
595 e28a4841 Sofia Papagiannaki
        user = getattr(request, 'user', None)
596 3fc7fd80 Kostas Papadimitriou
        if not user:
597 e28a4841 Sofia Papagiannaki
            return self.redirect_to_login_response(request, params)
598 3fc7fd80 Kostas Papadimitriou
599 3fc7fd80 Kostas Papadimitriou
        if request.method == 'POST':
600 3fc7fd80 Kostas Papadimitriou
            if auth_type == 'code':
601 3fc7fd80 Kostas Papadimitriou
                return self.process_code_request(user, client, uri, scope,
602 3fc7fd80 Kostas Papadimitriou
                                                 state)
603 3fc7fd80 Kostas Papadimitriou
            elif auth_type == 'token':
604 e28a4841 Sofia Papagiannaki
                raise OA2Error("Unsupported response type")
605 e28a4841 Sofia Papagiannaki
#                return self.process_token_request(user, client, uri, scope,
606 e28a4841 Sofia Papagiannaki
#                                                 state)
607 3fc7fd80 Kostas Papadimitriou
            else:
608 3fc7fd80 Kostas Papadimitriou
                #TODO: handle custom type
609 3fc7fd80 Kostas Papadimitriou
                raise OA2Error("Invalid authorization type")
610 3fc7fd80 Kostas Papadimitriou
        else:
611 e28a4841 Sofia Papagiannaki
            if client.is_trusted:
612 e28a4841 Sofia Papagiannaki
                return self.process_code_request(user, client, uri, scope,
613 e28a4841 Sofia Papagiannaki
                                                 state)
614 e28a4841 Sofia Papagiannaki
            else:
615 e28a4841 Sofia Papagiannaki
                return self.grant_accept_response(client, uri, scope, state)
616 e28a4841 Sofia Papagiannaki
617 e28a4841 Sofia Papagiannaki
    @handles_oa2_requests
618 e28a4841 Sofia Papagiannaki
    def grant_token(self, request, **extra):
619 e28a4841 Sofia Papagiannaki
        """
620 e28a4841 Sofia Papagiannaki
        Used in the following cases
621 e28a4841 Sofia Papagiannaki
        """
622 e28a4841 Sofia Papagiannaki
        if not request.secure:
623 e28a4841 Sofia Papagiannaki
            raise OA2Error("Secure request required")
624 e28a4841 Sofia Papagiannaki
625 e28a4841 Sofia Papagiannaki
        grant_type = self.identify_token_request(request.META, request.POST)
626 e28a4841 Sofia Papagiannaki
627 e28a4841 Sofia Papagiannaki
        if grant_type == 'authorization_code':
628 e28a4841 Sofia Papagiannaki
            client, redirect_uri, code = \
629 e28a4841 Sofia Papagiannaki
                self.validate_code_grant(request.POST, request.META)
630 e28a4841 Sofia Papagiannaki
            token, token_type = \
631 e28a4841 Sofia Papagiannaki
                self.grant_authorization_code(client, code, redirect_uri)
632 e28a4841 Sofia Papagiannaki
            return self.grant_token_response(token, token_type)
633 e28a4841 Sofia Papagiannaki
        elif (grant_type in ['client_credentials', 'token'] or
634 e28a4841 Sofia Papagiannaki
              self.is_uri(grant_type)):
635 e28a4841 Sofia Papagiannaki
            raise OA2Error("Unsupported grant type")
636 e28a4841 Sofia Papagiannaki
        else:
637 e28a4841 Sofia Papagiannaki
            #TODO: handle custom type
638 e28a4841 Sofia Papagiannaki
            raise OA2Error("Invalid grant type")