def test_existing_token_enabled_for_external_accounts(oauth_application, get, post, admin): UserEnterpriseAuth(user=admin, provider='radius').save() url = drf_reverse('api:oauth_authorization_root_view') + 'token/' with override_settings(RADIUS_SERVER='example.org', ALLOW_OAUTH2_FOR_EXTERNAL_USERS=True): resp = post( url, data='grant_type=password&username=admin&password=admin&scope=read', content_type='application/x-www-form-urlencoded', HTTP_AUTHORIZATION='Basic ' + smart_str(base64.b64encode(smart_bytes(':'.join([ oauth_application.client_id, oauth_application.client_secret ])))), status=201 ) token = json.loads(resp.content)['access_token'] assert AccessToken.objects.count() == 1 with immediate_on_commit(): resp = get( drf_reverse('api:user_me_list', kwargs={'version': 'v2'}), HTTP_AUTHORIZATION='Bearer ' + token, status=200 ) assert json.loads(resp.content)['results'][0]['username'] == 'admin' with override_settings(RADIUS_SERVER='example.org', ALLOW_OAUTH2_FOR_EXTERNAL_USER=False): with immediate_on_commit(): resp = get( drf_reverse('api:user_me_list', kwargs={'version': 'v2'}), HTTP_AUTHORIZATION='Bearer ' + token, status=200 ) assert json.loads(resp.content)['results'][0]['username'] == 'admin'
def test_refresh_accesstoken(oauth_application, post, get, delete, admin): response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) assert AccessToken.objects.count() == 1 assert RefreshToken.objects.count() == 1 token = AccessToken.objects.get(token=response.data['token']) refresh_token = RefreshToken.objects.get(token=response.data['refresh_token']) refresh_url = drf_reverse('api:oauth_authorization_root_view') + 'token/' response = post( refresh_url, data='grant_type=refresh_token&refresh_token=' + refresh_token.token, content_type='application/x-www-form-urlencoded', HTTP_AUTHORIZATION='Basic ' + smart_str(base64.b64encode(smart_bytes(':'.join([oauth_application.client_id, oauth_application.client_secret])))), ) assert RefreshToken.objects.filter(token=refresh_token).exists() original_refresh_token = RefreshToken.objects.get(token=refresh_token) assert token not in AccessToken.objects.all() assert AccessToken.objects.count() == 1 # the same RefreshToken remains but is marked revoked assert RefreshToken.objects.count() == 2 new_token = json.loads(response._container[0])['access_token'] new_refresh_token = json.loads(response._container[0])['refresh_token'] assert AccessToken.objects.filter(token=new_token).count() == 1 # checks that RefreshTokens are rotated (new RefreshToken issued) assert RefreshToken.objects.filter(token=new_refresh_token).count() == 1 assert original_refresh_token.revoked # is not None
def test_token_creation_disabled_for_external_accounts(oauth_application, post, alice, allow_oauth, status): UserEnterpriseAuth(user=alice, provider='radius').save() url = drf_reverse('api:oauth_authorization_root_view') + 'token/' with override_settings(RADIUS_SERVER='example.org', ALLOW_OAUTH2_FOR_EXTERNAL_USERS=allow_oauth): resp = post( url, data='grant_type=password&username=alice&password=alice&scope=read', content_type='application/x-www-form-urlencoded', HTTP_AUTHORIZATION='Basic ' + smart_str( base64.b64encode( smart_bytes(':'.join([ oauth_application.client_id, oauth_application.client_secret ])))), status=status) if allow_oauth: assert AccessToken.objects.count() == 1 else: assert 'OAuth2 Tokens cannot be created by users associated with an external authentication provider' in smart_str( resp.content) # noqa assert AccessToken.objects.count() == 0
def test_refresh_token_expiration_is_respected(oauth_application, post, get, delete, admin): response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) assert AccessToken.objects.count() == 1 assert RefreshToken.objects.count() == 1 refresh_token = RefreshToken.objects.get( token=response.data['refresh_token']) refresh_url = drf_reverse('api:oauth_authorization_root_view') + 'token/' short_lived = { 'ACCESS_TOKEN_EXPIRE_SECONDS': 1, 'AUTHORIZATION_CODE_EXPIRE_SECONDS': 1, 'REFRESH_TOKEN_EXPIRE_SECONDS': 1 } time.sleep(1) with override_settings(OAUTH2_PROVIDER=short_lived): response = post(refresh_url, data='grant_type=refresh_token&refresh_token=' + refresh_token.token, content_type='application/x-www-form-urlencoded', HTTP_AUTHORIZATION='Basic ' + smart_str( base64.b64encode( smart_bytes(':'.join([ oauth_application.client_id, oauth_application.client_secret ]))))) assert response.status_code == 403 assert b'The refresh token has expired.' in response.content assert RefreshToken.objects.filter(token=refresh_token).exists() assert AccessToken.objects.count() == 1 assert RefreshToken.objects.count() == 1
def _prepare(self, get, admin): if not self.__class__.JSON: url = drf_reverse('api:swagger_view') + '?format=openapi' response = get(url, user=admin) data = generate_swagger_object(response.data) if response.has_header('X-Deprecated-Paths'): data['deprecated_paths'] = json.loads(response['X-Deprecated-Paths']) data.update(response.accepted_renderer.get_customizations() or {}) data['host'] = None data['schemes'] = ['https'] data['consumes'] = ['application/json'] revised_paths = {} deprecated_paths = data.pop('deprecated_paths', []) for path, node in data['paths'].items(): # change {version} in paths to the actual default API version (e.g., v2) revised_paths[path.replace('{version}', settings.REST_FRAMEWORK['DEFAULT_VERSION'])] = node for method in node: if path in deprecated_paths: node[method]['deprecated'] = True if 'description' in node[method]: # Pop off the first line and use that as the summary lines = node[method]['description'].splitlines() node[method]['summary'] = lines.pop(0).strip('#:') node[method]['description'] = '\n'.join(lines) # remove the required `version` parameter for param in node[method].get('parameters'): if param['in'] == 'path' and param['name'] == 'version': node[method]['parameters'].remove(param) data['paths'] = revised_paths self.__class__.JSON = data
def test_refresh_accesstoken(oauth_application, post, get, delete, admin): response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) token = AccessToken.objects.get(token=response.data['token']) refresh_token = RefreshToken.objects.get( token=response.data['refresh_token']) assert AccessToken.objects.count() == 1 assert RefreshToken.objects.count() == 1 refresh_url = drf_reverse('api:oauth_authorization_root_view') + 'token/' response = post( refresh_url, data='grant_type=refresh_token&refresh_token=' + refresh_token.token, content_type='application/x-www-form-urlencoded', HTTP_AUTHORIZATION='Basic ' + base64.b64encode(':'.join( [oauth_application.client_id, oauth_application.client_secret]))) new_token = json.loads(response._container[0])['access_token'] new_refresh_token = json.loads(response._container[0])['refresh_token'] assert token not in AccessToken.objects.all() assert AccessToken.objects.get(token=new_token) != 0 assert RefreshToken.objects.get(token=new_refresh_token) != 0 refresh_token = RefreshToken.objects.get(token=refresh_token) assert refresh_token.revoked
def test_personal_access_token_creation(oauth_application, post, alice): url = drf_reverse('api:oauth_authorization_root_view') + 'token/' resp = post( url, data='grant_type=password&username=alice&password=alice&scope=read', content_type='application/x-www-form-urlencoded', HTTP_AUTHORIZATION='Basic ' + smart_str(base64.b64encode(smart_bytes(':'.join([oauth_application.client_id, oauth_application.client_secret])))), ) resp_json = smart_str(resp._container[0]) assert 'access_token' in resp_json assert 'scope' in resp_json assert 'refresh_token' in resp_json
def get(self, request, format=None): ''' List supported API versions ''' v2 = reverse('api:api_v2_root_view', kwargs={'version': 'v2'}) data = OrderedDict() data['description'] = _('AWX REST API') data['current_version'] = v2 data['available_versions'] = dict(v2 = v2) data['oauth2'] = drf_reverse('api:oauth_authorization_root_view') data['custom_logo'] = settings.CUSTOM_LOGO data['custom_login_info'] = settings.CUSTOM_LOGIN_INFO return Response(data)
def _prepare(self, get, admin): if not self.__class__.JSON: url = drf_reverse('api:swagger_view') + '?format=openapi' response = get(url, user=admin) data = generate_swagger_object(response.data) if response.has_header('X-Deprecated-Paths'): data['deprecated_paths'] = json.loads( response['X-Deprecated-Paths']) data.update(response.accepted_renderer.get_customizations() or {}) data['host'] = None data['schemes'] = ['https'] data['consumes'] = ['application/json'] # Inject a top-level description into the OpenAPI document if os.path.exists(description_file): with open(description_file, 'r') as f: data['info']['description'] = f.read() # Write tags in the order we want them sorted if os.path.exists(config_file): with open(config_file, 'r') as f: config = yaml.load(f.read()) for category in config.get('categories', []): tag = {'name': category['name']} if 'description' in category: tag['description'] = category['description'] data.setdefault('tags', []).append(tag) revised_paths = {} deprecated_paths = data.pop('deprecated_paths', []) for path, node in data['paths'].items(): # change {version} in paths to the actual default API version (e.g., v2) revised_paths[path.replace( '{version}', settings.REST_FRAMEWORK['DEFAULT_VERSION'])] = node for method in node: if path in deprecated_paths: node[method]['deprecated'] = True if 'description' in node[method]: # Pop off the first line and use that as the summary lines = node[method]['description'].splitlines() node[method]['summary'] = lines.pop(0).strip('#:') node[method]['description'] = '\n'.join(lines) # remove the required `version` parameter for param in node[method].get('parameters'): if param['in'] == 'path' and param['name'] == 'version': node[method]['parameters'].remove(param) data['paths'] = revised_paths self.__class__.JSON = data
def test_invalid_login(): anon = auth.get_user(Client()) url = drf_reverse('api:login') factory = APIRequestFactory() data = {'userame': 'invalid', 'password': '******'} request = factory.post(url, data) request.user = anon response = LoggedLoginView.as_view()(request) assert response.status_code == 401
def test_implicit_authorization(oauth_application, admin): oauth_application.client_type = 'confidential' oauth_application.authorization_grant_type = 'implicit' oauth_application.redirect_uris = 'http://test.com' oauth_application.save() data = { 'response_type': 'token', 'client_id': oauth_application.client_id, 'client_secret': oauth_application.client_secret, 'scope': 'read', 'redirect_uri': 'http://test.com', 'allow': True } request_client = Client() request_client.force_login(admin, 'django.contrib.auth.backends.ModelBackend') refresh_token_count = RefreshToken.objects.count() response = request_client.post(drf_reverse('api:authorize'), data) assert 'http://test.com' in response.url and 'access_token' in response.url # Make sure no refresh token is created for app with implicit grant type. assert refresh_token_count == RefreshToken.objects.count()
def get(self, request, format=None): data = OrderedDict() data['authorize'] = drf_reverse('api:authorize') data['token'] = drf_reverse('api:token') data['revoke_token'] = drf_reverse('api:revoke-token') return Response(data)