111 lines
3.9 KiB
Python
111 lines
3.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Tests for OAuth2 permission delegation."""
|
|
|
|
|
|
from six.moves.urllib.parse import parse_qsl, urlparse # pylint: disable=import-error
|
|
|
|
from common.test.acceptance.pages.common.auto_auth import AutoAuthPage
|
|
from common.test.acceptance.pages.lms.oauth2_confirmation import OAuth2Confirmation
|
|
from common.test.acceptance.tests.helpers import AcceptanceTest
|
|
|
|
|
|
class OAuth2PermissionDelegationTests(AcceptanceTest):
|
|
"""
|
|
Tests for acceptance/denial of permission delegation requests.
|
|
"""
|
|
shard = 16
|
|
|
|
def setUp(self):
|
|
super(OAuth2PermissionDelegationTests, self).setUp()
|
|
self.oauth_page = OAuth2Confirmation(self.browser)
|
|
|
|
def _auth(self):
|
|
"""Authenticate the user."""
|
|
AutoAuthPage(self.browser).visit()
|
|
|
|
def _qs(self, url):
|
|
"""Parse url's querystring into a dict."""
|
|
return dict(parse_qsl(urlparse(url).query))
|
|
|
|
def test_error_for_invalid_scopes(self):
|
|
"""Requests for invalid scopes throw errors."""
|
|
self._auth()
|
|
self.oauth_page.scopes = ('email', 'does-not-exist')
|
|
assert self.oauth_page.visit()
|
|
|
|
self.assertTrue(self.oauth_page.has_error)
|
|
self.assertIn('not a valid scope', self.oauth_page.error_message)
|
|
|
|
def test_cancelling_redirects(self):
|
|
"""
|
|
If you cancel the request, you're redirected to the redirect_url with a
|
|
denied query param.
|
|
"""
|
|
self._auth()
|
|
assert self.oauth_page.visit()
|
|
self.oauth_page.cancel()
|
|
|
|
def check_redirect():
|
|
"""
|
|
Checks that the page correctly redirects to a url with a
|
|
denied query param.
|
|
"""
|
|
query = self._qs(self.browser.current_url)
|
|
return 'access_denied' in query['error']
|
|
|
|
def check_redirect_chrome():
|
|
"""
|
|
Similar to `check_redirect`, but, due to a bug in ChromeDriver,
|
|
we use `self.browser.title` here instead of `self.browser.current_url`
|
|
"""
|
|
query = self._qs(self.browser.title)
|
|
return 'access_denied' in query['error']
|
|
|
|
# This redirects to an invalid URI. For chrome verify title, current_url otherwise
|
|
if self.browser.name == 'chrome':
|
|
self.oauth_page.wait_for(check_redirect_chrome, 'redirected to invalid URL (chrome)')
|
|
else:
|
|
self.oauth_page.wait_for(check_redirect, 'redirected to invalid URL')
|
|
|
|
def test_accepting_redirects(self):
|
|
"""
|
|
If you accept the request, you're redirected to the redirect_url with
|
|
the correct query params.
|
|
"""
|
|
self._auth()
|
|
assert self.oauth_page.visit()
|
|
|
|
# This redirects to an invalid URI.
|
|
self.oauth_page.confirm()
|
|
self.oauth_page.wait_for_element_absence(
|
|
'input[name=authorize]', 'Authorization button is not present'
|
|
)
|
|
|
|
def check_query_string():
|
|
"""
|
|
Checks that 'code' appears in the browser's current url.
|
|
"""
|
|
query = self._qs(self.browser.current_url)
|
|
return 'code' in query
|
|
|
|
def check_query_string_chrome():
|
|
"""
|
|
Similar to check_query_string, but, due to a bug in ChromeDriver,
|
|
when chrome is on an invalid URI, `self.browser.current_url` outputs
|
|
"data:text/html,chromewebdata" instead of the current URI.
|
|
|
|
However, since the query string is present in the `title`, we use
|
|
that for chrome.
|
|
"""
|
|
query = self._qs(self.browser.title)
|
|
return 'code' in query
|
|
|
|
if self.browser.name == 'chrome':
|
|
self.oauth_page.wait_for(
|
|
check_query_string_chrome, 'redirected with correct query parameters (chrome)'
|
|
)
|
|
else:
|
|
self.oauth_page.wait_for(
|
|
check_query_string, 'redirected with correct query parameters'
|
|
)
|