1"""Client authentication tests across all endpoints.
2
3Client authentication in OAuth2 serve two purposes, to authenticate
4confidential clients and to ensure public clients are in fact public. The
5latter is achieved with authenticate_client_id and the former with
6authenticate_client.
7
8We make sure authentication is done by requiring a client object to be set
9on the request object with a client_id parameter. The client_id attribute
10prevents this check from being circumvented with a client form parameter.
11"""
12from __future__ import absolute_import, unicode_literals
13import json
14import mock
15
16from .test_utils import get_fragment_credentials
17from ....unittest import TestCase
18
19from oauthlib.oauth2 import RequestValidator
20from oauthlib.oauth2 import WebApplicationServer, MobileApplicationServer
21from oauthlib.oauth2 import LegacyApplicationServer, BackendApplicationServer
22
23
24class ClientAuthenticationTest(TestCase):
25
26    def inspect_client(self, request, refresh_token=False):
27        if not request.client or not request.client.client_id:
28            raise ValueError()
29        return 'abc'
30
31    def setUp(self):
32        self.validator = mock.MagicMock(spec=RequestValidator)
33        self.validator.get_default_redirect_uri.return_value = 'http://i.b./path'
34        self.web = WebApplicationServer(self.validator,
35                token_generator=self.inspect_client)
36        self.mobile = MobileApplicationServer(self.validator,
37                token_generator=self.inspect_client)
38        self.legacy = LegacyApplicationServer(self.validator,
39                token_generator=self.inspect_client)
40        self.backend = BackendApplicationServer(self.validator,
41                token_generator=self.inspect_client)
42
43    def set_client(self, request):
44        request.client = mock.MagicMock()
45        request.client.client_id = 'mocked'
46        return True
47
48    def set_client_id(self, client_id, request):
49        request.client = mock.MagicMock()
50        request.client.client_id = 'mocked'
51        return True
52
53    def set_username(self, username, password, client, request):
54        request.client = mock.MagicMock()
55        request.client.client_id = 'mocked'
56        return True
57
58    def test_client_id_authentication(self):
59        token_uri = 'http://example.com/path'
60
61        # authorization code grant
62        self.validator.authenticate_client.return_value = False
63        self.validator.authenticate_client_id.return_value = False
64        _, body, _ = self.web.create_token_response(token_uri,
65                body='grant_type=authorization_code&code=mock')
66        self.assertEqual(json.loads(body)['error'], 'invalid_client')
67
68        self.validator.authenticate_client_id.return_value = True
69        self.validator.authenticate_client.side_effect = self.set_client
70        _, body, _ = self.web.create_token_response(token_uri,
71                body='grant_type=authorization_code&code=mock')
72        self.assertIn('access_token', json.loads(body))
73
74        # implicit grant
75        auth_uri = 'http://example.com/path?client_id=abc&response_type=token'
76        self.assertRaises(ValueError, self.mobile.create_authorization_response,
77                auth_uri, scopes=['random'])
78
79        self.validator.validate_client_id.side_effect = self.set_client_id
80        h, _, s = self.mobile.create_authorization_response(auth_uri, scopes=['random'])
81        self.assertEqual(302, s)
82        self.assertIn('Location', h)
83        self.assertIn('access_token', get_fragment_credentials(h['Location']))
84
85    def test_custom_authentication(self):
86        token_uri = 'http://example.com/path'
87
88        # authorization code grant
89        self.assertRaises(NotImplementedError,
90                self.web.create_token_response, token_uri,
91                body='grant_type=authorization_code&code=mock')
92
93        # password grant
94        self.validator.authenticate_client.return_value = True
95        self.assertRaises(NotImplementedError,
96                self.legacy.create_token_response, token_uri,
97                body='grant_type=password&username=abc&password=secret')
98
99        # client credentials grant
100        self.validator.authenticate_client.return_value = True
101        self.assertRaises(NotImplementedError,
102                self.backend.create_token_response, token_uri,
103                body='grant_type=client_credentials')
104