Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / oa2 / tests / djangobackend.py @ 698016f7

History | View | Annotate | Download (18.9 kB)

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