def test_resource_access_allowed(self): self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { "client_id": self.application.client_id, "state": "random_state_string", "scope": "read write", "redirect_uri": "http://example.org", "response_type": "token", "allow": True, } response = self.client.post(reverse("oauth2_provider:authorize"), data=authcode_data) # within implicit grant, access token is in the url fragment frag_dict = parse_qs(urlparse(response["Location"]).fragment) access_token = frag_dict["access_token"].pop() # use token to access the resource auth_headers = { "HTTP_AUTHORIZATION": "Bearer " + access_token, } request = self.factory.get("/fake-resource", **auth_headers) request.user = self.test_user view = ResourceView.as_view() response = view(request) self.assertEqual(response, "This is a protected resource")
def get_access_token(self, scopes): self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { 'client_id': self.application.client_id, 'state': 'random_state_string', 'scope': scopes, 'redirect_uri': 'http://example.it', 'response_type': 'code', 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=authcode_data) query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict['code'].pop() # exchange authorization code for a valid access token token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': 'http://example.it' } auth_headers = self.get_basic_auth_header( self.application.client_id, self.application.client_secret) response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data, **auth_headers) content = json.loads(response.content.decode("utf-8")) return content['access_token']
def _authorize_and_request_token(self, payload, application): response = self.client.post(reverse('oauth2_provider:authorize'), data=payload) self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': 'http://example.it', 'client_id': application.client_id, } response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data) response.status_code content = json.loads(response.content.decode("utf-8")) token = AccessToken.objects.get(token=content['access_token']) refresh_token = content['refresh_token'] response_scopes = sorted(content['scope'].split()) access_token_scopes = sorted(token.scope.split()) return token, refresh_token, response.status_code, response_scopes, access_token_scopes
def test_code_exchange_fails_when_redirect_uri_does_not_match(self): """ Tests code exchange fails when redirect uri does not match the one used for code request """ self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { 'client_id': self.application.client_id, 'state': 'random_state_string', 'scope': 'read write', 'redirect_uri': 'http://example.it?foo=bar', 'response_type': 'code', 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=authcode_data) query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict['code'].pop() # exchange authorization code for a valid access token token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': 'http://example.it?foo=baraa' } auth_headers = get_basic_auth_header(self.application.client_id, self.application.client_secret) response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data, **auth_headers) self.assertEqual(response.status_code, 401)
def test_access_token_and_id_token_skip_authorization_completely(self): """ If application.skip_authorization = True, should skip the authorization page. """ self.client.login(username="******", password="******") self.application.skip_authorization = True self.application.save() query_string = urlencode({ "client_id": self.application.client_id, "response_type": "id_token token", "state": "random_state_string", "nonce": "random_nonce_string", "scope": "openid", "redirect_uri": "http://example.org", }) url = "{url}?{qs}".format(url=reverse("oauth2_provider:authorize"), qs=query_string) response = self.client.get(url) self.assertEqual(response.status_code, 302) self.assertIn("http://example.org#", response["Location"]) self.assertIn("access_token=", response["Location"]) self.assertIn("id_token=", response["Location"]) self.assertIn("state=random_state_string", response["Location"]) uri_query = urlparse(response["Location"]).fragment uri_query_params = dict( parse_qs(uri_query, keep_blank_values=True, strict_parsing=True)) id_token = uri_query_params["id_token"][0] jwt_token = jwt.JWT(key=self.key, jwt=id_token) claims = json.loads(jwt_token.claims) self.assertIn("nonce", claims) self.assertIn("at_hash", claims)
def test_access_token_and_id_token_post_auth_allow(self): """ Test authorization code is given for an allowed request with response_type: token """ self.client.login(username="******", password="******") form_data = { "client_id": self.application.client_id, "state": "random_state_string", "nonce": "random_nonce_string", "scope": "openid", "redirect_uri": "http://example.org", "response_type": "id_token token", "allow": True, } response = self.client.post(reverse("oauth2_provider:authorize"), data=form_data) self.assertEqual(response.status_code, 302) self.assertIn("http://example.org#", response["Location"]) self.assertIn("access_token=", response["Location"]) self.assertIn("id_token=", response["Location"]) self.assertIn("state=random_state_string", response["Location"]) uri_query = urlparse(response["Location"]).fragment uri_query_params = dict( parse_qs(uri_query, keep_blank_values=True, strict_parsing=True)) id_token = uri_query_params["id_token"][0] jwt_token = jwt.JWT(key=self.key, jwt=id_token) claims = json.loads(jwt_token.claims) self.assertIn("nonce", claims) self.assertIn("at_hash", claims)
def test_scopes_save_in_access_token(self): """ Test scopes are properly saved in access token """ self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { 'client_id': self.application.client_id, 'state': 'random_state_string', 'scope': 'scope1 scope2', 'redirect_uri': 'http://example.it', 'response_type': 'code', 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=authcode_data) query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict['code'].pop() # exchange authorization code for a valid access token token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': 'http://example.it' } auth_headers = get_basic_auth_header(self.application.client_id, self.application.client_secret) response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data, **auth_headers) content = json.loads(response.content.decode("utf-8")) access_token = content['access_token'] at = AccessToken.objects.get(token=access_token) self.assertEqual(at.scope, "scope1 scope2")
def test_resource_access_allowed(self): self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { 'client_id': self.application.client_id, 'state': 'random_state_string', 'scope': 'read write', 'redirect_uri': 'http://example.it', 'response_type': 'token', 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=authcode_data) # within implicit grant, access token is in the url fragment frag_dict = parse_qs(urlparse(response['Location']).fragment) access_token = frag_dict['access_token'].pop() # use token to access the resource auth_headers = { 'HTTP_AUTHORIZATION': 'Bearer ' + access_token, } request = self.factory.get("/fake-resource", **auth_headers) request.user = self.test_user view = ResourceView.as_view() response = view(request) self.assertEqual(response, "This is a protected resource")
def get_access_token(self, scopes): self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { "client_id": self.application.client_id, "state": "random_state_string", "scope": scopes, "redirect_uri": "http://example.org", "response_type": "code", "allow": True, } response = self.client.post(reverse("oauth2_provider:authorize"), data=authcode_data) query_dict = parse_qs(urlparse(response["Location"]).query) authorization_code = query_dict["code"].pop() # exchange authorization code for a valid access token token_request_data = { "grant_type": "authorization_code", "code": authorization_code, "redirect_uri": "http://example.org" } auth_headers = get_basic_auth_header(self.application.client_id, self.application.client_secret) response = self.client.post(reverse("oauth2_provider:token"), data=token_request_data, **auth_headers) content = json.loads(response.content.decode("utf-8")) return content["access_token"]
def test_code_exchange_succeed_when_redirect_uri_match(self): """ Tests code exchange succeed when redirect uri matches the one used for code request """ self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { 'client_id': self.application.client_id, 'state': 'random_state_string', 'scope': 'read write', 'redirect_uri': 'http://example.it?foo=bar', 'response_type': 'code', 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=authcode_data) query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict['code'].pop() # exchange authorization code for a valid access token token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': 'http://example.it?foo=bar' } auth_headers = self.get_basic_auth_header(self.application.client_id, self.application.client_secret) response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data, **auth_headers) self.assertEqual(response.status_code, 200) content = json.loads(response.content.decode("utf-8")) self.assertEqual(content['token_type'], "Bearer") self.assertEqual(content['scope'], "read write") self.assertEqual(content['expires_in'], oauth2_settings.ACCESS_TOKEN_EXPIRE_SECONDS)
def test_scopes_save_in_access_token(self): """ Test scopes are properly saved in access token """ self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { "client_id": self.application.client_id, "state": "random_state_string", "scope": "scope1 scope2", "redirect_uri": "http://example.org", "response_type": "code", "allow": True, } response = self.client.post(reverse("oauth2_provider:authorize"), data=authcode_data) query_dict = parse_qs(urlparse(response["Location"]).query) authorization_code = query_dict["code"].pop() # exchange authorization code for a valid access token token_request_data = { "grant_type": "authorization_code", "code": authorization_code, "redirect_uri": "http://example.org" } auth_headers = get_basic_auth_header(self.application.client_id, self.application.client_secret) response = self.client.post(reverse("oauth2_provider:token"), data=token_request_data, **auth_headers) content = json.loads(response.content.decode("utf-8")) access_token = content["access_token"] at = AccessToken.objects.get(token=access_token) self.assertEqual(at.scope, "scope1 scope2")
def test_application_delete_after_auth(self): # Test that there are no errors with cascading deletes redirect_uri = 'http://localhost' # create a user self._create_user('anna', '123456') capability_a = self._create_capability('Capability A', []) capability_b = self._create_capability('Capability B', []) # create an application and add capabilities application = self._create_application( 'an app', grant_type=Application.GRANT_AUTHORIZATION_CODE, client_type=Application.CLIENT_CONFIDENTIAL, redirect_uris=redirect_uri) application.scope.add(capability_a, capability_b) # user logs in self.client.login(username='******', password='******') # post the authorization form with only one scope selected payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': redirect_uri, 'scope': ['capability-a'], 'expires_in': 86400, 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=payload) self.client.logout() self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': redirect_uri, 'client_id': application.client_id, 'client_secret': application.client_secret, } c = Client() response = c.post('/v1/o/token/', data=token_request_data) self.assertEqual(response.status_code, 200) # Now we have a token and refresh token tkn = response.json()['access_token'] refresh_tkn = response.json()['refresh_token'] # Test for cascading contraint errors. application_pk = application.pk application.delete() # Test related objects are deleted self.assertFalse(AccessToken.objects.filter(token=tkn).exists()) self.assertTrue(ArchivedToken.objects.filter(token=tkn).exists()) self.assertFalse( RefreshToken.objects.filter(token=refresh_tkn).exists()) self.assertFalse( DataAccessGrant.objects.filter( application__pk=application_pk).exists()) self.assertTrue( ArchivedDataAccessGrant.objects.filter( application__pk=application_pk).exists())
def test_code_exchange_fails_when_redirect_uri_does_not_match(self): """ Tests code exchange fails when redirect uri does not match the one used for code request """ self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { "client_id": self.application.client_id, "state": "random_state_string", "scope": "read write", "redirect_uri": "http://example.org?foo=bar", "response_type": "code", "allow": True, } response = self.client.post(reverse("oauth2_provider:authorize"), data=authcode_data) query_dict = parse_qs(urlparse(response["Location"]).query) authorization_code = query_dict["code"].pop() # exchange authorization code for a valid access token token_request_data = { "grant_type": "authorization_code", "code": authorization_code, "redirect_uri": "http://example.org?foo=baraa" } auth_headers = get_basic_auth_header(self.application.client_id, self.application.client_secret) response = self.client.post(reverse("oauth2_provider:token"), data=token_request_data, **auth_headers) self.assertEqual(response.status_code, 401)
def test_refresh_with_expired_token(self): redirect_uri = 'http://localhost' # create a user self._create_user('anna', '123456') capability_a = self._create_capability('Capability A', []) capability_b = self._create_capability('Capability B', []) # create an application and add capabilities application = self._create_application( 'an app', grant_type=Application.GRANT_AUTHORIZATION_CODE, client_type=Application.CLIENT_CONFIDENTIAL, redirect_uris=redirect_uri) application.scope.add(capability_a, capability_b) # user logs in self.client.login(username='******', password='******') # post the authorization form with only one scope selected payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': redirect_uri, 'scope': ['capability-a'], 'expires_in': 86400, 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=payload) self.client.logout() self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': redirect_uri, 'client_id': application.client_id, 'client_secret': application.client_secret, } c = Client() response = c.post('/v1/o/token/', data=token_request_data) self.assertEqual(response.status_code, 200) # Now we have a token and refresh token tkn = response.json()['access_token'] refresh_tkn = response.json()['refresh_token'] at = AccessToken.objects.get(token=tkn) at.delete() refresh_request_data = { 'grant_type': 'refresh_token', 'refresh_token': refresh_tkn, 'redirect_uri': redirect_uri, 'client_id': application.client_id, 'client_secret': application.client_secret, } response = self.client.post(reverse('oauth2_provider:token'), data=refresh_request_data) self.assertEqual(response.status_code, 401)
def _create_test_token(self, user, application): # user logs in self.client.force_login(user) # post the authorization form with only one scope selected payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': application.redirect_uris, 'scope': application.scopes().split(" "), 'expires_in': 86400, 'allow': True, } if application.authorization_grant_type == Application.GRANT_IMPLICIT: payload['response_type'] = 'token' response = self.client.post('/v1/o/authorize/', data=payload) self.client.logout() if response.status_code != 302: raise Exception(response.context_data) self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token if application.authorization_grant_type == Application.GRANT_IMPLICIT: fragment = parse_qs(urlparse(response['Location']).fragment) tkn = fragment.pop('access_token')[0] else: query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': application.redirect_uris, 'client_id': application.client_id, 'client_secret': application.client_secret, } response = self.client.post('/v1/o/token/', data=token_request_data) self.assertEqual(response.status_code, 200) # Now we have a token and refresh token tkn = response.json()['access_token'] t = AccessToken.objects.get(token=tkn) return t
def test_post_with_valid_non_standard_scheme(self): redirect_uri = 'com.custom.bluebutton://example.it' # create a user self._create_user('anna', '123456') capability_a = self._create_capability('Capability A', []) capability_b = self._create_capability('Capability B', []) # create an application and add capabilities application = self._create_application( 'an app', grant_type=Application.GRANT_AUTHORIZATION_CODE, redirect_uris=redirect_uri) application.scope.add(capability_a, capability_b) # user logs in self.client.login(username='******', password='******') code_challenge = "sZrievZsrYqxdnu2NVD603EiYBM18CuzZpwB-pOSZjo" payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': redirect_uri, 'code_challenge': code_challenge, 'code_challenge_method': 'S256', } response = self.client.get('/v1/o/authorize', data=payload) # post the authorization form with only one scope selected payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': redirect_uri, 'scope': ['capability-a'], 'expires_in': 86400, 'allow': True, 'code_challenge': code_challenge, 'code_challenge_method': 'S256', } response = self.client.post(response['Location'], data=payload) self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': redirect_uri, 'client_id': application.client_id, 'code_verifier': 'test123456789123456789123456789123456789123456789', } response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data) self.assertEqual(response.status_code, 200)
def test_creation_on_approval(self): redirect_uri = 'http://localhost' # create a user user = self._create_user('anna', '123456') capability_a = self._create_capability('Capability A', []) capability_b = self._create_capability('Capability B', []) # create an application and add capabilities application = self._create_application( 'an app', grant_type=Application.GRANT_AUTHORIZATION_CODE, redirect_uris=redirect_uri) application.scope.add(capability_a, capability_b) # user logs in self.client.login(username='******', password='******') payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': redirect_uri, } response = self.client.get('/v1/o/authorize', data=payload) # post the authorization form with only one scope selected payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': redirect_uri, 'scope': ['capability-a'], 'expires_in': 86400, 'allow': True, } response = self.client.post(response['Location'], data=payload) self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': redirect_uri, 'client_id': application.client_id, } response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data) self.assertEqual(response.status_code, 200) # errors if DNE or more than one is found DataAccessGrant.objects.get(beneficiary=user.id, application=application.id)
def _authorize_and_request_token(self, payload, application): response = self.client.post(reverse('oauth2_provider:authorize'), data=payload) self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': 'http://example.it', 'client_id': application.client_id, } return self.client.post(reverse('oauth2_provider:token'), data=token_request_data)
def get_auth(self): """ Helper method to retrieve a valid authorization code """ authcode_data = { 'client_id': self.application.client_id, 'state': 'random_state_string', 'scope': 'read write', 'redirect_uri': 'http://example.it', 'response_type': 'code', 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=authcode_data) query_dict = parse_qs(urlparse(response['Location']).query) return query_dict['code'].pop()
def get_auth(self): """ Helper method to retrieve a valid authorization code """ authcode_data = { "client_id": self.application.client_id, "state": "random_state_string", "scope": "read write", "redirect_uri": "http://example.org", "response_type": "code", "allow": True, } response = self.client.post(reverse("oauth2_provider:authorize"), data=authcode_data) query_dict = parse_qs(urlparse(response["Location"]).query) return query_dict["code"].pop()
def test_post_with_restricted_scopes_issues_token_with_same_scopes(self): """ Test that when user unchecks some of the scopes the token is issued with the checked scopes only. """ # create a user self._create_user('anna', '123456') # create a couple of capabilities capability_a = self._create_capability('Capability A', []) capability_b = self._create_capability('Capability B', []) # create an application and add capabilities application = self._create_application( 'an app', grant_type=Application.GRANT_AUTHORIZATION_CODE, redirect_uris='http://example.it') application.scope.add(capability_a, capability_b) # user logs in self.client.login(username='******', password='******') # post the authorization form with only one scope selected payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': 'http://example.it', 'scope': ['capability-a'], 'expires_in': 86400, 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=payload) self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': 'http://example.it', 'client_id': application.client_id, } response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data) self.assertEqual(response.status_code, 200) content = json.loads(response.content.decode("utf-8")) # and here we test that only the capability-a scope has been issued self.assertEqual(content['scope'], "capability-a")
def test_multi_scope_valid(self): """ Test access to a multi-scope protected resource with correct scopes provided """ self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { "client_id": self.application.client_id, "state": "random_state_string", "scope": "scope1 scope2", "redirect_uri": "http://example.org", "response_type": "code", "allow": True, } response = self.client.post(reverse("oauth2_provider:authorize"), data=authcode_data) query_dict = parse_qs(urlparse(response["Location"]).query) authorization_code = query_dict["code"].pop() # exchange authorization code for a valid access token token_request_data = { "grant_type": "authorization_code", "code": authorization_code, "redirect_uri": "http://example.org" } auth_headers = get_basic_auth_header(self.application.client_id, self.application.client_secret) response = self.client.post(reverse("oauth2_provider:token"), data=token_request_data, **auth_headers) content = json.loads(response.content.decode("utf-8")) access_token = content["access_token"] # use token to access the resource auth_headers = { "HTTP_AUTHORIZATION": "Bearer " + access_token, } request = self.factory.get("/fake-resource", **auth_headers) request.user = self.test_user view = MultiScopeResourceView.as_view() response = view(request) self.assertEqual(response, "This is a protected resource")
def test_multi_scope_valid(self): """ Test access to a multi-scope protected resource with correct scopes provided """ self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { 'client_id': self.application.client_id, 'state': 'random_state_string', 'scope': 'scope1 scope2', 'redirect_uri': 'http://example.it', 'response_type': 'code', 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=authcode_data) query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict['code'].pop() # exchange authorization code for a valid access token token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': 'http://example.it' } auth_headers = self.get_basic_auth_header( self.application.client_id, self.application.client_secret) response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data, **auth_headers) content = json.loads(response.content.decode("utf-8")) access_token = content['access_token'] # use token to access the resource auth_headers = { 'HTTP_AUTHORIZATION': 'Bearer ' + access_token, } request = self.factory.get("/fake-resource", **auth_headers) request.user = self.test_user view = MultiScopeResourceView.as_view() response = view(request) self.assertEqual(response, "This is a protected resource")
def test_code_exchange_succeed_when_redirect_uri_match_with_multiple_query_params( self): """ Tests code exchange succeed when redirect uri matches the one used for code request """ self.client.login(username="******", password="******") self.application.redirect_uris = "http://localhost http://example.com?foo=bar" self.application.save() # retrieve a valid authorization code authcode_data = { "client_id": self.application.client_id, "state": "random_state_string", "scope": "read write", "redirect_uri": "http://example.com?bar=baz&foo=bar", "response_type": "code", "allow": True, } response = self.client.post(reverse("oauth2_provider:authorize"), data=authcode_data) query_dict = parse_qs(urlparse(response["Location"]).query) authorization_code = query_dict["code"].pop() # exchange authorization code for a valid access token token_request_data = { "grant_type": "authorization_code", "code": authorization_code, "redirect_uri": "http://example.com?bar=baz&foo=bar" } auth_headers = get_basic_auth_header(self.application.client_id, self.application.client_secret) response = self.client.post(reverse("oauth2_provider:token"), data=token_request_data, **auth_headers) self.assertEqual(response.status_code, 200) content = json.loads(response.content.decode("utf-8")) self.assertEqual(content["token_type"], "Bearer") self.assertEqual(content["scope"], "read write") self.assertEqual(content["expires_in"], oauth2_settings.ACCESS_TOKEN_EXPIRE_SECONDS)
def test_post_with_restricted_scopes_issues_token_with_same_scopes(self): """ Test that when user unchecks some of the scopes the token is issued with the checked scopes only. """ # create a user self._create_user('anna', '123456') # create a couple of capabilities capability_a = self._create_capability('Capability A', []) capability_b = self._create_capability('Capability B', []) # create an application and add capabilities application = self._create_application( 'an app', grant_type=Application.GRANT_AUTHORIZATION_CODE, redirect_uris='http://example.it') application.scope.add(capability_a, capability_b) # user logs in self.client.login(username='******', password='******') # post the authorization form with only one scope selected payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': 'http://example.it', 'scope': ['capability-a'], 'expires_in': 86400, 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=payload) self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': 'http://example.it', 'client_id': application.client_id, } response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data) self.assertEqual(response.status_code, 200) content = json.loads(response.content.decode("utf-8")) # and here we test that only the capability-a scope has been issued self.assertEqual(content['scope'], "capability-a")
def test_scopes_saved_in_grant(self): """ Test scopes are properly saved in grant """ self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { "client_id": self.application.client_id, "state": "random_state_string", "scope": "scope1 scope2", "redirect_uri": "http://example.org", "response_type": "code", "allow": True, } response = self.client.post(reverse("oauth2_provider:authorize"), data=authcode_data) query_dict = parse_qs(urlparse(response["Location"]).query) authorization_code = query_dict["code"].pop() grant = Grant.objects.get(code=authorization_code) self.assertEqual(grant.scope, "scope1 scope2")
def test_scopes_saved_in_grant(self): """ Test scopes are properly saved in grant """ self.client.login(username="******", password="******") # retrieve a valid authorization code authcode_data = { 'client_id': self.application.client_id, 'state': 'random_state_string', 'scope': 'scope1 scope2', 'redirect_uri': 'http://example.it', 'response_type': 'code', 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=authcode_data) query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict['code'].pop() grant = Grant.objects.get(code=authorization_code) self.assertEqual(grant.scope, "scope1 scope2")
def test_post_with_valid_non_standard_scheme_granttype_authcode_clienttype_confidential(self): # Test with application setup as grant_type=authorization_code and client_type=confidential redirect_uri = 'com.custom.bluebutton://example.it' # create a user self._create_user('anna', '123456') capability_a = self._create_capability('Capability A', []) capability_b = self._create_capability('Capability B', []) # create an application and add capabilities application = self._create_application( 'an app', grant_type=Application.GRANT_AUTHORIZATION_CODE, client_type=Application.CLIENT_CONFIDENTIAL, redirect_uris=redirect_uri) application.scope.add(capability_a, capability_b) # user logs in self.client.login(username='******', password='******') code_challenge = "sZrievZsrYqxdnu2NVD603EiYBM18CuzZpwB-pOSZjo" payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': redirect_uri, 'code_challenge': code_challenge, 'code_challenge_method': 'S256', } response = self.client.get('/v1/o/authorize', data=payload) # post the authorization form with only one scope selected payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': redirect_uri, 'scope': ['capability-a'], 'expires_in': 86400, 'allow': True, 'code_challenge': code_challenge, 'code_challenge_method': 'S256', } response = self.client.post(response['Location'], data=payload) self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': redirect_uri, 'client_id': application.client_id, } # Test that request is unauthorized WITH OUT the client_secret. token_request_data.update({'code_verifier': 'test123456789123456789123456789123456789123456789'}) response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data) self.assertEqual(response.status_code, 401) # Setup application's client_secret token_request_data.update({'client_secret': application.client_secret}) # Test that using a BAD code_verifier has a bad request response token_request_data.update({'code_verifier': 'test1234567bad9verifier23456789123456789123456789'}) response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data) self.assertEqual(response.status_code, 400) # Test that request is successful WITH the client_secret and GOOD code_verifier token_request_data.update({'code_verifier': 'test123456789123456789123456789123456789123456789'}) response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data) self.assertEqual(response.status_code, 200) # Test 2nd access token request is unauthorized response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data) self.assertEqual(response.status_code, 401)
def test_introspect_token_on_inactive_app(self): ''' BB2-149: adapted from token auth test but test token introspect on a inactive app, 403 customized permission denied message expected. ''' redirect_uri = 'http://localhost' # create a user self._create_user('anna', '123456') capability_a = self._create_capability('Capability A', []) capability_b = self._create_capability('Capability B', []) capability_introspect = self._create_capability('introspection', []) # create an application and add capabilities application = self._create_application( 'an app', grant_type=Application.GRANT_AUTHORIZATION_CODE, client_type=Application.CLIENT_CONFIDENTIAL, redirect_uris=redirect_uri) application.scope.add(capability_a, capability_b, capability_introspect) # user logs in self.client.login(username='******', password='******') # post the authorization form with only one scope selected payload = { 'client_id': application.client_id, 'response_type': 'code', 'redirect_uri': redirect_uri, 'scope': ['capability-a', 'capability-b', 'introspection'], 'expires_in': 86400, 'allow': True, } response = self.client.post(reverse('oauth2_provider:authorize'), data=payload) self.client.logout() self.assertEqual(response.status_code, 302) # now extract the authorization code and use it to request an access_token query_dict = parse_qs(urlparse(response['Location']).query) authorization_code = query_dict.pop('code') token_request_data = { 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': redirect_uri, 'client_id': application.client_id, 'client_secret': application.client_secret, } c = Client() response = c.post('/v1/o/token/', data=token_request_data) self.assertEqual(response.status_code, 200) # Now we have a token and refresh token tkn = response.json()['access_token'] introspect_request_data = { 'token': tkn, 'client_id': application.client_id, 'client_secret': application.client_secret, } auth_headers = {'Authorization': 'Bearer %s' % tkn} # set app to inactive before introspect application.active = False application.save() msg_expected = settings.APPLICATION_TEMPORARILY_INACTIVE.format("an app") response = c.post('/v1/o/introspect/', data=introspect_request_data, **auth_headers) # asssert 403 and content json message self.assertEqual(response.status_code, 403) content = json.loads(response.content.decode("utf-8")) self.assertEqual(content['detail'], msg_expected) # revert app to active in case not to impact other tests application.active = True application.save()