Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / oa2 / tests / djangobackend.py @ 68122bae

History | View | Annotate | Download (20.9 kB)

1 68122bae Sofia Papagiannaki
# -*- coding: utf8 -*-
2 64a45988 Sofia Papagiannaki
# Copyright 2013 GRNET S.A. All rights reserved.
3 64a45988 Sofia Papagiannaki
#
4 64a45988 Sofia Papagiannaki
# Redistribution and use in source and binary forms, with or
5 64a45988 Sofia Papagiannaki
# without modification, are permitted provided that the following
6 64a45988 Sofia Papagiannaki
# conditions are met:
7 64a45988 Sofia Papagiannaki
#
8 64a45988 Sofia Papagiannaki
#   1. Redistributions of source code must retain the above
9 64a45988 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
10 64a45988 Sofia Papagiannaki
#      disclaimer.
11 64a45988 Sofia Papagiannaki
#
12 64a45988 Sofia Papagiannaki
#   2. Redistributions in binary form must reproduce the above
13 64a45988 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
14 64a45988 Sofia Papagiannaki
#      disclaimer in the documentation and/or other materials
15 64a45988 Sofia Papagiannaki
#      provided with the distribution.
16 64a45988 Sofia Papagiannaki
#
17 64a45988 Sofia Papagiannaki
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18 64a45988 Sofia Papagiannaki
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 64a45988 Sofia Papagiannaki
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 64a45988 Sofia Papagiannaki
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21 64a45988 Sofia Papagiannaki
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 64a45988 Sofia Papagiannaki
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 64a45988 Sofia Papagiannaki
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24 64a45988 Sofia Papagiannaki
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 64a45988 Sofia Papagiannaki
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 64a45988 Sofia Papagiannaki
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 64a45988 Sofia Papagiannaki
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 64a45988 Sofia Papagiannaki
# POSSIBILITY OF SUCH DAMAGE.
29 64a45988 Sofia Papagiannaki
#
30 64a45988 Sofia Papagiannaki
# The views and conclusions contained in the software and
31 64a45988 Sofia Papagiannaki
# documentation are those of the authors and should not be
32 64a45988 Sofia Papagiannaki
# interpreted as representing official policies, either expressed
33 64a45988 Sofia Papagiannaki
# or implied, of GRNET S.A.
34 64a45988 Sofia Papagiannaki
35 3fc7fd80 Kostas Papadimitriou
import urllib
36 3fc7fd80 Kostas Papadimitriou
import urlparse
37 3fc7fd80 Kostas Papadimitriou
import base64
38 c1e4d459 Sofia Papagiannaki
import datetime
39 3fc7fd80 Kostas Papadimitriou
40 3fc7fd80 Kostas Papadimitriou
from collections import namedtuple
41 3fc7fd80 Kostas Papadimitriou
42 3fc7fd80 Kostas Papadimitriou
from django.test import TransactionTestCase as TestCase
43 3fc7fd80 Kostas Papadimitriou
from django.test import Client as TestClient
44 3fc7fd80 Kostas Papadimitriou
45 3fc7fd80 Kostas Papadimitriou
from django.core.urlresolvers import reverse
46 c1e4d459 Sofia Papagiannaki
from django.utils import simplejson as json
47 3fc7fd80 Kostas Papadimitriou
48 c985de5c Sofia Papagiannaki
from astakos.oa2 import settings
49 c1e4d459 Sofia Papagiannaki
from astakos.oa2.models import Client, AuthorizationCode, Token
50 0d9523c3 Giorgos Korfiatis
from astakos.im.tests import common
51 3fc7fd80 Kostas Papadimitriou
52 3fc7fd80 Kostas Papadimitriou
53 3fc7fd80 Kostas Papadimitriou
ParsedURL = namedtuple('ParsedURL', ['host', 'scheme', 'path', 'params',
54 3fc7fd80 Kostas Papadimitriou
                                     'url'])
55 3fc7fd80 Kostas Papadimitriou
56 3fc7fd80 Kostas Papadimitriou
57 3fc7fd80 Kostas Papadimitriou
def parsed_url_wrapper(func):
58 3fc7fd80 Kostas Papadimitriou
    def wrapper(self, url, *args, **kwargs):
59 3fc7fd80 Kostas Papadimitriou
        url = self.parse_url(url)
60 3fc7fd80 Kostas Papadimitriou
        return func(self, url, *args, **kwargs)
61 3fc7fd80 Kostas Papadimitriou
    return wrapper
62 3fc7fd80 Kostas Papadimitriou
63 3fc7fd80 Kostas Papadimitriou
64 3fc7fd80 Kostas Papadimitriou
class URLAssertionsMixin(object):
65 3fc7fd80 Kostas Papadimitriou
66 3fc7fd80 Kostas Papadimitriou
    def get_redirect_url(self, request):
67 3fc7fd80 Kostas Papadimitriou
        return self.parse_url(request['Location'])
68 3fc7fd80 Kostas Papadimitriou
69 3fc7fd80 Kostas Papadimitriou
    def parse_url(self, url):
70 3fc7fd80 Kostas Papadimitriou
        if isinstance(url, ParsedURL):
71 3fc7fd80 Kostas Papadimitriou
            return url
72 3fc7fd80 Kostas Papadimitriou
        result = urlparse.urlparse(url)
73 3fc7fd80 Kostas Papadimitriou
        parsed = {
74 3fc7fd80 Kostas Papadimitriou
            'url': url,
75 3fc7fd80 Kostas Papadimitriou
            'host': result.netloc,
76 3fc7fd80 Kostas Papadimitriou
            'scheme': result.scheme,
77 3fc7fd80 Kostas Papadimitriou
            'path': result.path,
78 3fc7fd80 Kostas Papadimitriou
        }
79 3fc7fd80 Kostas Papadimitriou
        parsed['params'] = urlparse.parse_qs(result.query)
80 3fc7fd80 Kostas Papadimitriou
        return ParsedURL(**parsed)
81 3fc7fd80 Kostas Papadimitriou
82 3fc7fd80 Kostas Papadimitriou
    @parsed_url_wrapper
83 3fc7fd80 Kostas Papadimitriou
    def assertParamEqual(self, url, key, value):
84 3fc7fd80 Kostas Papadimitriou
        self.assertParam(url, key)
85 3fc7fd80 Kostas Papadimitriou
        self.assertEqual(url.params[key][0], value)
86 3fc7fd80 Kostas Papadimitriou
87 3fc7fd80 Kostas Papadimitriou
    @parsed_url_wrapper
88 3fc7fd80 Kostas Papadimitriou
    def assertNoParam(self, url, key):
89 3fc7fd80 Kostas Papadimitriou
        self.assertFalse(key in url.params,
90 3fc7fd80 Kostas Papadimitriou
                         "Url '%s' does contain '%s' parameter" % (url.url,
91 3fc7fd80 Kostas Papadimitriou
                                                                   key))
92 3fc7fd80 Kostas Papadimitriou
93 3fc7fd80 Kostas Papadimitriou
    @parsed_url_wrapper
94 3fc7fd80 Kostas Papadimitriou
    def assertParam(self, url, key):
95 3fc7fd80 Kostas Papadimitriou
        self.assertTrue(key in url.params,
96 3fc7fd80 Kostas Papadimitriou
                        "Url '%s' does not contain '%s' parameter" % (url.url,
97 3fc7fd80 Kostas Papadimitriou
                                                                      key))
98 3fc7fd80 Kostas Papadimitriou
99 3fc7fd80 Kostas Papadimitriou
    @parsed_url_wrapper
100 3fc7fd80 Kostas Papadimitriou
    def assertHost(self, url, host):
101 3fc7fd80 Kostas Papadimitriou
        self.assertEqual(url.host, host)
102 3fc7fd80 Kostas Papadimitriou
103 3fc7fd80 Kostas Papadimitriou
    @parsed_url_wrapper
104 3fc7fd80 Kostas Papadimitriou
    def assertPath(self, url, path):
105 3fc7fd80 Kostas Papadimitriou
        self.assertEqual(url.path, path)
106 3fc7fd80 Kostas Papadimitriou
107 3fc7fd80 Kostas Papadimitriou
    @parsed_url_wrapper
108 3fc7fd80 Kostas Papadimitriou
    def assertSecure(self, url, key):
109 3fc7fd80 Kostas Papadimitriou
        self.assertEqual(url.scheme, "https")
110 3fc7fd80 Kostas Papadimitriou
111 3fc7fd80 Kostas Papadimitriou
112 3fc7fd80 Kostas Papadimitriou
class OA2Client(TestClient):
113 3fc7fd80 Kostas Papadimitriou
    """
114 3fc7fd80 Kostas Papadimitriou
    An OAuth2 agnostic test client.
115 3fc7fd80 Kostas Papadimitriou
    """
116 3fc7fd80 Kostas Papadimitriou
    def __init__(self, baseurl, *args, **kwargs):
117 3fc7fd80 Kostas Papadimitriou
        self.oa2_url = baseurl
118 3fc7fd80 Kostas Papadimitriou
        self.token_url = self.oa2_url + 'token/'
119 3fc7fd80 Kostas Papadimitriou
        self.auth_url = self.oa2_url + 'auth/'
120 3fc7fd80 Kostas Papadimitriou
        self.credentials = kwargs.pop('credentials', ())
121 3fc7fd80 Kostas Papadimitriou
122 3fc7fd80 Kostas Papadimitriou
        kwargs['wsgi.url_scheme'] = 'https'
123 3fc7fd80 Kostas Papadimitriou
        return super(OA2Client, self).__init__(*args, **kwargs)
124 3fc7fd80 Kostas Papadimitriou
125 3fc7fd80 Kostas Papadimitriou
    def request(self, *args, **kwargs):
126 3fc7fd80 Kostas Papadimitriou
        #print kwargs.get('PATH_INFO') + '?' + kwargs.get('QUERY_STRING'), \
127 3fc7fd80 Kostas Papadimitriou
            #kwargs.get('HTTP_AUTHORIZATION', None)
128 3fc7fd80 Kostas Papadimitriou
        return super(OA2Client, self).request(*args, **kwargs)
129 3fc7fd80 Kostas Papadimitriou
130 3fc7fd80 Kostas Papadimitriou
    def get_url(self, token_or_auth, **params):
131 3fc7fd80 Kostas Papadimitriou
        return token_or_auth + '?' + urllib.urlencode(params)
132 3fc7fd80 Kostas Papadimitriou
133 3fc7fd80 Kostas Papadimitriou
    def grant(self, clientid, *args, **kwargs):
134 3fc7fd80 Kostas Papadimitriou
        """
135 3fc7fd80 Kostas Papadimitriou
        Do an authorization grant request.
136 3fc7fd80 Kostas Papadimitriou
        """
137 3fc7fd80 Kostas Papadimitriou
        params = {
138 3fc7fd80 Kostas Papadimitriou
            'grant_type': 'authorization_code',
139 3fc7fd80 Kostas Papadimitriou
            'client_id': clientid
140 3fc7fd80 Kostas Papadimitriou
        }
141 3fc7fd80 Kostas Papadimitriou
        urlparams = kwargs.pop('urlparams', {})
142 3fc7fd80 Kostas Papadimitriou
        params.update(urlparams)
143 3fc7fd80 Kostas Papadimitriou
        self.set_auth_headers(kwargs)
144 3fc7fd80 Kostas Papadimitriou
        return self.get(self.get_url(self.token_url, **params), *args,
145 3fc7fd80 Kostas Papadimitriou
                        **kwargs)
146 3fc7fd80 Kostas Papadimitriou
147 3fc7fd80 Kostas Papadimitriou
    def authorize_code(self, clientid, *args, **kwargs):
148 3fc7fd80 Kostas Papadimitriou
        """
149 3fc7fd80 Kostas Papadimitriou
        Do an authorization code request.
150 3fc7fd80 Kostas Papadimitriou
        """
151 3fc7fd80 Kostas Papadimitriou
        params = {
152 3fc7fd80 Kostas Papadimitriou
            'response_type': 'code',
153 3fc7fd80 Kostas Papadimitriou
            'client_id': clientid
154 3fc7fd80 Kostas Papadimitriou
        }
155 3fc7fd80 Kostas Papadimitriou
        urlparams = kwargs.pop('urlparams', {})
156 3fc7fd80 Kostas Papadimitriou
        urlparams.update(kwargs.pop('extraparams', {}))
157 3fc7fd80 Kostas Papadimitriou
        params.update(urlparams)
158 3fc7fd80 Kostas Papadimitriou
        self.set_auth_headers(kwargs)
159 3fc7fd80 Kostas Papadimitriou
        if 'reject' in params:
160 e28a4841 Sofia Papagiannaki
            return self.post(self.get_url(self.auth_url), data=params,
161 e28a4841 Sofia Papagiannaki
                             **kwargs)
162 3fc7fd80 Kostas Papadimitriou
        return self.get(self.get_url(self.auth_url, **params), *args, **kwargs)
163 3fc7fd80 Kostas Papadimitriou
164 c1e4d459 Sofia Papagiannaki
    def access_token(self, code,
165 c1e4d459 Sofia Papagiannaki
                     content_type='application/x-www-form-urlencoded',
166 c1e4d459 Sofia Papagiannaki
                     **kwargs):
167 c1e4d459 Sofia Papagiannaki
        """
168 c1e4d459 Sofia Papagiannaki
        Do an get token request.
169 c1e4d459 Sofia Papagiannaki
        """
170 c1e4d459 Sofia Papagiannaki
        params = {
171 c1e4d459 Sofia Papagiannaki
            'grant_type': 'authorization_code',
172 c1e4d459 Sofia Papagiannaki
            'code': code
173 c1e4d459 Sofia Papagiannaki
        }
174 c1e4d459 Sofia Papagiannaki
        params.update(kwargs)
175 c1e4d459 Sofia Papagiannaki
        self.set_auth_headers(kwargs)
176 c1e4d459 Sofia Papagiannaki
        return self.post(self.token_url, data=urllib.urlencode(params),
177 c1e4d459 Sofia Papagiannaki
                         content_type=content_type, **kwargs)
178 c1e4d459 Sofia Papagiannaki
179 3fc7fd80 Kostas Papadimitriou
    def set_auth_headers(self, params):
180 3fc7fd80 Kostas Papadimitriou
        if not self.credentials:
181 3fc7fd80 Kostas Papadimitriou
            return
182 3fc7fd80 Kostas Papadimitriou
        credentials = base64.encodestring('%s:%s' % self.credentials).strip()
183 3fc7fd80 Kostas Papadimitriou
        params['HTTP_AUTHORIZATION'] = 'Basic %s' % credentials
184 3fc7fd80 Kostas Papadimitriou
        return params
185 3fc7fd80 Kostas Papadimitriou
186 3fc7fd80 Kostas Papadimitriou
    def set_credentials(self, user=None, pwd=None):
187 3fc7fd80 Kostas Papadimitriou
        self.credentials = (user, pwd)
188 3fc7fd80 Kostas Papadimitriou
        if not user and not pwd:
189 3fc7fd80 Kostas Papadimitriou
            self.credentials = ()
190 3fc7fd80 Kostas Papadimitriou
191 3fc7fd80 Kostas Papadimitriou
192 3fc7fd80 Kostas Papadimitriou
class TestOA2(TestCase, URLAssertionsMixin):
193 3fc7fd80 Kostas Papadimitriou
194 3fc7fd80 Kostas Papadimitriou
    def assertCount(self, model, count):
195 3fc7fd80 Kostas Papadimitriou
        self.assertEqual(model.objects.count(), count)
196 3fc7fd80 Kostas Papadimitriou
197 c1e4d459 Sofia Papagiannaki
    def assert_access_token_response(self, r, expected):
198 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 200)
199 c1e4d459 Sofia Papagiannaki
        try:
200 c1e4d459 Sofia Papagiannaki
            data = json.loads(r.content)
201 c1e4d459 Sofia Papagiannaki
        except:
202 c1e4d459 Sofia Papagiannaki
            self.fail("Unexpected response content")
203 c1e4d459 Sofia Papagiannaki
204 c1e4d459 Sofia Papagiannaki
        self.assertTrue('access_token' in data)
205 c1e4d459 Sofia Papagiannaki
        access_token = data['access_token']
206 c1e4d459 Sofia Papagiannaki
        self.assertTrue('token_type' in data)
207 c1e4d459 Sofia Papagiannaki
        token_type = data['token_type']
208 c1e4d459 Sofia Papagiannaki
        self.assertTrue('expires_in' in data)
209 c1e4d459 Sofia Papagiannaki
        expires_in = data['expires_in']
210 c1e4d459 Sofia Papagiannaki
211 c1e4d459 Sofia Papagiannaki
        try:
212 c1e4d459 Sofia Papagiannaki
            token = Token.objects.get(code=access_token)
213 c1e4d459 Sofia Papagiannaki
            self.assertEqual(token.expires_at,
214 c1e4d459 Sofia Papagiannaki
                             token.created_at +
215 c1e4d459 Sofia Papagiannaki
                             datetime.timedelta(seconds=expires_in))
216 c1e4d459 Sofia Papagiannaki
            self.assertEqual(token.token_type, token_type)
217 c1e4d459 Sofia Papagiannaki
            self.assertEqual(token.grant_type, 'authorization_code')
218 c1e4d459 Sofia Papagiannaki
            #self.assertEqual(token.user, expected.get('user'))
219 c1e4d459 Sofia Papagiannaki
            self.assertEqual(token.redirect_uri, expected.get('redirect_uri'))
220 c1e4d459 Sofia Papagiannaki
            self.assertEqual(token.scope, expected.get('scope'))
221 c1e4d459 Sofia Papagiannaki
            self.assertEqual(token.state, expected.get('state'))
222 c1e4d459 Sofia Papagiannaki
        except Token.DoesNotExist:
223 c1e4d459 Sofia Papagiannaki
            self.fail("Invalid access_token")
224 c1e4d459 Sofia Papagiannaki
225 3fc7fd80 Kostas Papadimitriou
    def setUp(self):
226 dfdd413b Sofia Papagiannaki
        baseurl = reverse('oauth2_authenticate').replace('/auth', '/')
227 3fc7fd80 Kostas Papadimitriou
        self.client = OA2Client(baseurl)
228 3fc7fd80 Kostas Papadimitriou
        client1 = Client.objects.create(identifier="client1", secret="secret")
229 e28a4841 Sofia Papagiannaki
        self.client1_redirect_uri = "https://server.com/handle_code"
230 e28a4841 Sofia Papagiannaki
        client1.redirecturl_set.create(url=self.client1_redirect_uri)
231 e28a4841 Sofia Papagiannaki
232 3fc7fd80 Kostas Papadimitriou
        client2 = Client.objects.create(identifier="client2", type='public')
233 3fc7fd80 Kostas Papadimitriou
        self.client2_redirect_uri = "https://server2.com/handle_code"
234 3fc7fd80 Kostas Papadimitriou
        client2.redirecturl_set.create(url=self.client2_redirect_uri)
235 e28a4841 Sofia Papagiannaki
236 e28a4841 Sofia Papagiannaki
        client3 = Client.objects.create(identifier="client3", secret='secret',
237 e28a4841 Sofia Papagiannaki
                                        is_trusted=True)
238 e28a4841 Sofia Papagiannaki
        self.client3_redirect_uri = "https://server3.com/handle_code"
239 e28a4841 Sofia Papagiannaki
        client3.redirecturl_set.create(url=self.client3_redirect_uri)
240 3fc7fd80 Kostas Papadimitriou
241 0d9523c3 Giorgos Korfiatis
        common.get_local_user("user@synnefo.org", password="password")
242 3fc7fd80 Kostas Papadimitriou
243 3fc7fd80 Kostas Papadimitriou
    def test_code_authorization(self):
244 c1e4d459 Sofia Papagiannaki
        # missing response_type
245 c1e4d459 Sofia Papagiannaki
        r = self.client.get(self.client.get_url(self.client.auth_url))
246 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
247 c1e4d459 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 0)
248 c1e4d459 Sofia Papagiannaki
249 c1e4d459 Sofia Papagiannaki
        # invalid response_type
250 c1e4d459 Sofia Papagiannaki
        r = self.client.get(self.client.get_url(self.client.auth_url,
251 c1e4d459 Sofia Papagiannaki
                                                response_type='invalid'))
252 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
253 c1e4d459 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 0)
254 c1e4d459 Sofia Papagiannaki
255 c1e4d459 Sofia Papagiannaki
        # unsupported response_type
256 c1e4d459 Sofia Papagiannaki
        r = self.client.get(self.client.get_url(self.client.auth_url,
257 c1e4d459 Sofia Papagiannaki
                                                response_type='token'))
258 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
259 c1e4d459 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 0)
260 c1e4d459 Sofia Papagiannaki
261 c1e4d459 Sofia Papagiannaki
        # missing client_id
262 c1e4d459 Sofia Papagiannaki
        r = self.client.get(self.client.get_url(self.client.auth_url,
263 c1e4d459 Sofia Papagiannaki
                                                response_type='code'))
264 3fc7fd80 Kostas Papadimitriou
        self.assertEqual(r.status_code, 400)
265 3fc7fd80 Kostas Papadimitriou
        self.assertCount(AuthorizationCode, 0)
266 3fc7fd80 Kostas Papadimitriou
267 c1e4d459 Sofia Papagiannaki
        # fake client
268 c1e4d459 Sofia Papagiannaki
        r = self.client.authorize_code('client-fake')
269 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
270 c1e4d459 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 0)
271 3fc7fd80 Kostas Papadimitriou
272 3fc7fd80 Kostas Papadimitriou
        # mixed up credentials/client_id's
273 3fc7fd80 Kostas Papadimitriou
        self.client.set_credentials('client1', 'secret')
274 3fc7fd80 Kostas Papadimitriou
        r = self.client.authorize_code('client2')
275 3fc7fd80 Kostas Papadimitriou
        self.assertEqual(r.status_code, 400)
276 3fc7fd80 Kostas Papadimitriou
        self.assertCount(AuthorizationCode, 0)
277 3fc7fd80 Kostas Papadimitriou
278 c1e4d459 Sofia Papagiannaki
        # invalid credentials
279 3fc7fd80 Kostas Papadimitriou
        self.client.set_credentials('client2', '')
280 3fc7fd80 Kostas Papadimitriou
        r = self.client.authorize_code('client2')
281 3fc7fd80 Kostas Papadimitriou
        self.assertEqual(r.status_code, 400)
282 3fc7fd80 Kostas Papadimitriou
        self.assertCount(AuthorizationCode, 0)
283 3fc7fd80 Kostas Papadimitriou
284 c1e4d459 Sofia Papagiannaki
        # invalid redirect_uri: not absolute URI
285 c1e4d459 Sofia Papagiannaki
        self.client.set_credentials()
286 c1e4d459 Sofia Papagiannaki
        params = {'redirect_uri':
287 c1e4d459 Sofia Papagiannaki
                  urlparse.urlparse(self.client1_redirect_uri).path}
288 c1e4d459 Sofia Papagiannaki
        r = self.client.authorize_code('client1', urlparams=params)
289 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
290 c1e4d459 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 0)
291 3fc7fd80 Kostas Papadimitriou
292 c1e4d459 Sofia Papagiannaki
        # mismatching redirect uri
293 c1e4d459 Sofia Papagiannaki
        self.client.set_credentials()
294 c1e4d459 Sofia Papagiannaki
        params = {'redirect_uri': self.client1_redirect_uri[1:]}
295 c1e4d459 Sofia Papagiannaki
        r = self.client.authorize_code('client1', urlparams=params)
296 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
297 c1e4d459 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 0)
298 c1e4d459 Sofia Papagiannaki
299 c1e4d459 Sofia Papagiannaki
        # valid request: untrusted client
300 3fc7fd80 Kostas Papadimitriou
        params = {'redirect_uri': self.client1_redirect_uri,
301 c1e4d459 Sofia Papagiannaki
                  'scope': self.client1_redirect_uri,
302 68122bae Sofia Papagiannaki
                  'extra_param': 'γιουνικοντ'}
303 3fc7fd80 Kostas Papadimitriou
        self.client.set_credentials('client1', 'secret')
304 3fc7fd80 Kostas Papadimitriou
        r = self.client.authorize_code('client1', urlparams=params)
305 3fc7fd80 Kostas Papadimitriou
        self.assertEqual(r.status_code, 302)
306 e28a4841 Sofia Papagiannaki
        self.assertTrue('Location' in r)
307 c1e4d459 Sofia Papagiannaki
        self.assertHost(r['Location'], "testserver:80")
308 c1e4d459 Sofia Papagiannaki
        self.assertPath(r['Location'], reverse('login'))
309 3fc7fd80 Kostas Papadimitriou
310 e28a4841 Sofia Papagiannaki
        self.client.set_credentials('client1', 'secret')
311 3fc7fd80 Kostas Papadimitriou
        self.client.login(username="user@synnefo.org", password="password")
312 3fc7fd80 Kostas Papadimitriou
        r = self.client.authorize_code('client1', urlparams=params)
313 3fc7fd80 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
314 3fc7fd80 Kostas Papadimitriou
315 3fc7fd80 Kostas Papadimitriou
        r = self.client.authorize_code('client1', urlparams=params,
316 3fc7fd80 Kostas Papadimitriou
                                       extraparams={'reject': 0})
317 3fc7fd80 Kostas Papadimitriou
        self.assertCount(AuthorizationCode, 1)
318 3fc7fd80 Kostas Papadimitriou
319 3fc7fd80 Kostas Papadimitriou
        # redirect is valid
320 b806a15a Sofia Papagiannaki
        redirect = self.get_redirect_url(r)
321 b806a15a Sofia Papagiannaki
        self.assertParam(redirect, "code")
322 b806a15a Sofia Papagiannaki
        self.assertNoParam(redirect, "extra_param")
323 b806a15a Sofia Papagiannaki
        self.assertHost(redirect, "server.com")
324 b806a15a Sofia Papagiannaki
        self.assertPath(redirect, "/handle_code")
325 b806a15a Sofia Papagiannaki
326 b806a15a Sofia Papagiannaki
        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
327 b806a15a Sofia Papagiannaki
        #self.assertEqual(code.state, '')
328 b806a15a Sofia Papagiannaki
        self.assertEqual(code.state, None)
329 b806a15a Sofia Papagiannaki
        self.assertEqual(code.redirect_uri, self.client1_redirect_uri)
330 3fc7fd80 Kostas Papadimitriou
331 3fc7fd80 Kostas Papadimitriou
        params['state'] = 'csrfstate'
332 3fc7fd80 Kostas Papadimitriou
        params['scope'] = 'resource1'
333 3fc7fd80 Kostas Papadimitriou
        r = self.client.authorize_code('client1', urlparams=params)
334 b806a15a Sofia Papagiannaki
        redirect = self.get_redirect_url(r)
335 b806a15a Sofia Papagiannaki
        self.assertParamEqual(redirect, "state", 'csrfstate')
336 3fc7fd80 Kostas Papadimitriou
        self.assertCount(AuthorizationCode, 2)
337 3fc7fd80 Kostas Papadimitriou
338 b806a15a Sofia Papagiannaki
        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
339 b806a15a Sofia Papagiannaki
        self.assertEqual(code.state, 'csrfstate')
340 b806a15a Sofia Papagiannaki
        self.assertEqual(code.redirect_uri, self.client1_redirect_uri)
341 c1e4d459 Sofia Papagiannaki
342 c1e4d459 Sofia Papagiannaki
        # valid request: trusted client
343 c1e4d459 Sofia Papagiannaki
        params = {'redirect_uri': self.client3_redirect_uri,
344 c1e4d459 Sofia Papagiannaki
                  'scope': self.client3_redirect_uri,
345 c1e4d459 Sofia Papagiannaki
                  'extra_param': '123'}
346 c1e4d459 Sofia Papagiannaki
        self.client.set_credentials('client3', 'secret')
347 c1e4d459 Sofia Papagiannaki
        r = self.client.authorize_code('client3', urlparams=params)
348 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 302)
349 c1e4d459 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 3)
350 c1e4d459 Sofia Papagiannaki
351 c1e4d459 Sofia Papagiannaki
        # redirect is valid
352 b806a15a Sofia Papagiannaki
        redirect = self.get_redirect_url(r)
353 b806a15a Sofia Papagiannaki
        self.assertParam(redirect, "code")
354 b806a15a Sofia Papagiannaki
        self.assertNoParam(redirect, "state")
355 b806a15a Sofia Papagiannaki
        self.assertNoParam(redirect, "extra_param")
356 b806a15a Sofia Papagiannaki
        self.assertHost(redirect, "server3.com")
357 b806a15a Sofia Papagiannaki
        self.assertPath(redirect, "/handle_code")
358 c1e4d459 Sofia Papagiannaki
359 b806a15a Sofia Papagiannaki
        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
360 b806a15a Sofia Papagiannaki
        self.assertEqual(code.state, None)
361 b806a15a Sofia Papagiannaki
        self.assertEqual(code.redirect_uri, self.client3_redirect_uri)
362 c1e4d459 Sofia Papagiannaki
363 c1e4d459 Sofia Papagiannaki
        # valid request: trusted client
364 c1e4d459 Sofia Papagiannaki
        params['state'] = 'csrfstate'
365 c1e4d459 Sofia Papagiannaki
        self.client.set_credentials('client3', 'secret')
366 c1e4d459 Sofia Papagiannaki
        r = self.client.authorize_code('client3', urlparams=params)
367 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 302)
368 c1e4d459 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 4)
369 c1e4d459 Sofia Papagiannaki
370 c1e4d459 Sofia Papagiannaki
        # redirect is valid
371 b806a15a Sofia Papagiannaki
        redirect = self.get_redirect_url(r)
372 b806a15a Sofia Papagiannaki
        self.assertParam(redirect, "code")
373 b806a15a Sofia Papagiannaki
        self.assertParamEqual(redirect, "state", 'csrfstate')
374 b806a15a Sofia Papagiannaki
        self.assertNoParam(redirect, "extra_param")
375 b806a15a Sofia Papagiannaki
        self.assertHost(redirect, "server3.com")
376 b806a15a Sofia Papagiannaki
        self.assertPath(redirect, "/handle_code")
377 c1e4d459 Sofia Papagiannaki
378 b806a15a Sofia Papagiannaki
        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
379 b806a15a Sofia Papagiannaki
        self.assertEqual(code.state, 'csrfstate')
380 b806a15a Sofia Papagiannaki
        self.assertEqual(code.redirect_uri, self.client3_redirect_uri)
381 c1e4d459 Sofia Papagiannaki
382 ed9223c7 Sofia Papagiannaki
        # redirect uri startswith the client's registered redirect url
383 ed9223c7 Sofia Papagiannaki
        params['redirect_uri'] = '%smore' % self.client3_redirect_uri
384 ed9223c7 Sofia Papagiannaki
        self.client.set_credentials('client3', 'secret')
385 ed9223c7 Sofia Papagiannaki
        r = self.client.authorize_code('client3', urlparams=params)
386 ed9223c7 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
387 ed9223c7 Sofia Papagiannaki
388 ed9223c7 Sofia Papagiannaki
        # redirect uri descendant
389 c985de5c Sofia Papagiannaki
        redirect_uri = '%s/' % self.client3_redirect_uri
390 c985de5c Sofia Papagiannaki
        rest = settings.MAXIMUM_ALLOWED_REDIRECT_URI_LENGTH - len(redirect_uri)
391 c985de5c Sofia Papagiannaki
        redirect_uri = '%s%s' % (redirect_uri, 'a'*rest)
392 ed9223c7 Sofia Papagiannaki
        params['redirect_uri'] = redirect_uri
393 698016f7 Sofia Papagiannaki
        self.client.set_credentials('client3', 'secret')
394 698016f7 Sofia Papagiannaki
        r = self.client.authorize_code('client3', urlparams=params)
395 698016f7 Sofia Papagiannaki
        self.assertEqual(r.status_code, 302)
396 698016f7 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 5)
397 698016f7 Sofia Papagiannaki
398 698016f7 Sofia Papagiannaki
        # redirect is valid
399 b806a15a Sofia Papagiannaki
        redirect = self.get_redirect_url(r)
400 b806a15a Sofia Papagiannaki
        self.assertParam(redirect, "code")
401 b806a15a Sofia Papagiannaki
        self.assertParamEqual(redirect, "state", 'csrfstate')
402 b806a15a Sofia Papagiannaki
        self.assertNoParam(redirect, "extra_param")
403 b806a15a Sofia Papagiannaki
        self.assertHost(redirect, "server3.com")
404 b806a15a Sofia Papagiannaki
        self.assertPath(redirect, urlparse.urlparse(redirect_uri).path)
405 b806a15a Sofia Papagiannaki
406 b806a15a Sofia Papagiannaki
        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
407 b806a15a Sofia Papagiannaki
        self.assertEqual(code.state, 'csrfstate')
408 c985de5c Sofia Papagiannaki
        self.assertEqual(code.redirect_uri, redirect_uri)
409 698016f7 Sofia Papagiannaki
410 ed9223c7 Sofia Papagiannaki
        # too long redirect uri
411 c985de5c Sofia Papagiannaki
        params['redirect_uri'] = '%sa' % redirect_uri
412 ed9223c7 Sofia Papagiannaki
        self.client.set_credentials('client3', 'secret')
413 ed9223c7 Sofia Papagiannaki
        r = self.client.authorize_code('client3', urlparams=params)
414 b806a15a Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
415 ed9223c7 Sofia Papagiannaki
416 c1e4d459 Sofia Papagiannaki
    def test_get_token(self):
417 c1e4d459 Sofia Papagiannaki
        # invalid method
418 c1e4d459 Sofia Papagiannaki
        r = self.client.get(self.client.token_url)
419 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 405)
420 c1e4d459 Sofia Papagiannaki
        self.assertTrue('Allow' in r)
421 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r['Allow'], 'POST')
422 c1e4d459 Sofia Papagiannaki
423 c1e4d459 Sofia Papagiannaki
        # invalid content type
424 c1e4d459 Sofia Papagiannaki
        r = self.client.post(self.client.token_url)
425 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
426 c1e4d459 Sofia Papagiannaki
427 c1e4d459 Sofia Papagiannaki
        # missing grant type
428 c1e4d459 Sofia Papagiannaki
        r = self.client.post(self.client.token_url,
429 c1e4d459 Sofia Papagiannaki
                             content_type='application/x-www-form-urlencoded')
430 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
431 c1e4d459 Sofia Papagiannaki
432 c1e4d459 Sofia Papagiannaki
        # unsupported grant type: client_credentials
433 c1e4d459 Sofia Papagiannaki
        r = self.client.post(self.client.token_url,
434 c1e4d459 Sofia Papagiannaki
                             data='grant_type=client_credentials',
435 c1e4d459 Sofia Papagiannaki
                             content_type='application/x-www-form-urlencoded')
436 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
437 c1e4d459 Sofia Papagiannaki
438 c1e4d459 Sofia Papagiannaki
        # unsupported grant type: token
439 c1e4d459 Sofia Papagiannaki
        r = self.client.post(self.client.token_url,
440 c1e4d459 Sofia Papagiannaki
                             data='grant_type=token',
441 c1e4d459 Sofia Papagiannaki
                             content_type='application/x-www-form-urlencoded')
442 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
443 c1e4d459 Sofia Papagiannaki
444 c1e4d459 Sofia Papagiannaki
        # invalid grant type
445 c1e4d459 Sofia Papagiannaki
        r = self.client.post(self.client.token_url,
446 c1e4d459 Sofia Papagiannaki
                             data='grant_type=invalid',
447 c1e4d459 Sofia Papagiannaki
                             content_type='application/x-www-form-urlencoded')
448 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
449 c1e4d459 Sofia Papagiannaki
450 c1e4d459 Sofia Papagiannaki
        # generate authorization code: without redirect_uri
451 c1e4d459 Sofia Papagiannaki
        self.client.login(username="user@synnefo.org", password="password")
452 c1e4d459 Sofia Papagiannaki
        r = self.client.authorize_code('client3')
453 c1e4d459 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 1)
454 c1e4d459 Sofia Papagiannaki
        redirect = self.get_redirect_url(r)
455 c1e4d459 Sofia Papagiannaki
        code_instance = AuthorizationCode.objects.get(
456 c1e4d459 Sofia Papagiannaki
            code=redirect.params['code'][0])
457 c1e4d459 Sofia Papagiannaki
458 c1e4d459 Sofia Papagiannaki
        # no client_id & no client authorization
459 c1e4d459 Sofia Papagiannaki
        r = self.client.access_token(code_instance.code)
460 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
461 c1e4d459 Sofia Papagiannaki
462 c1e4d459 Sofia Papagiannaki
        # invalid client_id
463 c1e4d459 Sofia Papagiannaki
        r = self.client.access_token(code_instance.code, client_id='client2')
464 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
465 c1e4d459 Sofia Papagiannaki
466 c1e4d459 Sofia Papagiannaki
        # inexistent client_id
467 c1e4d459 Sofia Papagiannaki
        r = self.client.access_token(code_instance.code, client_id='client42')
468 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
469 c1e4d459 Sofia Papagiannaki
470 c1e4d459 Sofia Papagiannaki
        # no client authorization
471 c1e4d459 Sofia Papagiannaki
        r = self.client.access_token(code_instance.code, client_id='client3')
472 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
473 c1e4d459 Sofia Papagiannaki
474 c1e4d459 Sofia Papagiannaki
        # mixed up credentials/client_id's
475 c1e4d459 Sofia Papagiannaki
        self.client.set_credentials('client1', 'secret')
476 c1e4d459 Sofia Papagiannaki
        r = self.client.access_token(code_instance.code, client_id='client3')
477 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
478 c1e4d459 Sofia Papagiannaki
479 c1e4d459 Sofia Papagiannaki
        # mixed up credentials/client_id's
480 c1e4d459 Sofia Papagiannaki
        self.client.set_credentials('client3', 'secret')
481 c1e4d459 Sofia Papagiannaki
        r = self.client.access_token(code_instance.code, client_id='client1')
482 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
483 c1e4d459 Sofia Papagiannaki
484 c1e4d459 Sofia Papagiannaki
        # mismatching client
485 c1e4d459 Sofia Papagiannaki
        self.client.set_credentials('client1', 'secret')
486 c1e4d459 Sofia Papagiannaki
        r = self.client.access_token(code_instance.code, client_id='client1')
487 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
488 c1e4d459 Sofia Papagiannaki
489 c1e4d459 Sofia Papagiannaki
        # invalid code
490 c1e4d459 Sofia Papagiannaki
        self.client.set_credentials('client3', 'secret')
491 c1e4d459 Sofia Papagiannaki
        r = self.client.access_token('invalid')
492 c1e4d459 Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
493 c1e4d459 Sofia Papagiannaki
494 c1e4d459 Sofia Papagiannaki
        # valid request
495 c1e4d459 Sofia Papagiannaki
        self.client.set_credentials('client3', 'secret')
496 c1e4d459 Sofia Papagiannaki
        r = self.client.access_token(code_instance.code)
497 c1e4d459 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 0)  # assert code is consumed
498 c1e4d459 Sofia Papagiannaki
        self.assertCount(Token, 1)
499 c1e4d459 Sofia Papagiannaki
        expected = {'redirect_uri': self.client3_redirect_uri,
500 c1e4d459 Sofia Papagiannaki
                    'scope': self.client3_redirect_uri,
501 c1e4d459 Sofia Papagiannaki
                    'state': None}
502 c1e4d459 Sofia Papagiannaki
        self.assert_access_token_response(r, expected)
503 ed9223c7 Sofia Papagiannaki
504 ed9223c7 Sofia Papagiannaki
        # generate authorization code with too long redirect_uri
505 c985de5c Sofia Papagiannaki
        redirect_uri = '%s/' % self.client3_redirect_uri
506 c985de5c Sofia Papagiannaki
        rest = settings.MAXIMUM_ALLOWED_REDIRECT_URI_LENGTH - len(redirect_uri)
507 c985de5c Sofia Papagiannaki
        redirect_uri = '%s%s' % (redirect_uri, 'a'*rest)
508 ed9223c7 Sofia Papagiannaki
        params = {'redirect_uri': redirect_uri}
509 ed9223c7 Sofia Papagiannaki
        r = self.client.authorize_code('client3', urlparams=params)
510 ed9223c7 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 1)
511 ed9223c7 Sofia Papagiannaki
        redirect = self.get_redirect_url(r)
512 ed9223c7 Sofia Papagiannaki
        code_instance = AuthorizationCode.objects.get(
513 ed9223c7 Sofia Papagiannaki
            code=redirect.params['code'][0])
514 ed9223c7 Sofia Papagiannaki
515 ed9223c7 Sofia Papagiannaki
        # valid request
516 ed9223c7 Sofia Papagiannaki
        self.client.set_credentials('client3', 'secret')
517 ed9223c7 Sofia Papagiannaki
        r = self.client.access_token(code_instance.code,
518 c985de5c Sofia Papagiannaki
                                     redirect_uri='%sa' % redirect_uri)
519 c985de5c Sofia Papagiannaki
        self.assertEqual(r.status_code, 400)
520 c985de5c Sofia Papagiannaki
521 c985de5c Sofia Papagiannaki
        r = self.client.access_token(code_instance.code,
522 ed9223c7 Sofia Papagiannaki
                                     redirect_uri=redirect_uri)
523 ed9223c7 Sofia Papagiannaki
        self.assertCount(AuthorizationCode, 0)  # assert code is consumed
524 ed9223c7 Sofia Papagiannaki
        self.assertCount(Token, 2)
525 ed9223c7 Sofia Papagiannaki
        expected = {'redirect_uri': redirect_uri,
526 ed9223c7 Sofia Papagiannaki
                    'scope': redirect_uri,
527 ed9223c7 Sofia Papagiannaki
                    'state': None}
528 ed9223c7 Sofia Papagiannaki
        self.assert_access_token_response(r, expected)