Merge pull request #572 from jonparrott/auth-approval-prompt

Add warnings and helpers for prompt='consent'.
This commit is contained in:
Nathaniel Manista
2016-07-27 15:43:22 -07:00
committed by GitHub
3 changed files with 48 additions and 11 deletions

View File

@@ -1770,6 +1770,33 @@ class DeviceFlowInfo(collections.namedtuple('DeviceFlowInfo', (
return cls(**kwargs) return cls(**kwargs)
def _oauth2_web_server_flow_params(kwargs):
"""Configures redirect URI parameters for OAuth2WebServerFlow."""
params = {
'access_type': 'offline',
'response_type': 'code',
}
params.update(kwargs)
# Check for the presence of the deprecated approval_prompt param and
# warn appropriately.
approval_prompt = params.get('approval_prompt')
if approval_prompt is not None:
logger.warning(
'The approval_prompt parameter for OAuth2WebServerFlow is '
'deprecated. Please use the prompt parameter instead.')
if approval_prompt == 'force':
logger.warning(
'approval_prompt="force" has been adjusted to '
'prompt="consent"')
params['prompt'] = 'consent'
del params['approval_prompt']
return params
class OAuth2WebServerFlow(Flow): class OAuth2WebServerFlow(Flow):
"""Does the Web Server Flow for OAuth 2.0. """Does the Web Server Flow for OAuth 2.0.
@@ -1793,7 +1820,7 @@ class OAuth2WebServerFlow(Flow):
"""Constructor for OAuth2WebServerFlow. """Constructor for OAuth2WebServerFlow.
The kwargs argument is used to set extra query parameters on the The kwargs argument is used to set extra query parameters on the
auth_uri. For example, the access_type and approval_prompt auth_uri. For example, the access_type and prompt
query parameters can be set via kwargs. query parameters can be set via kwargs.
Args: Args:
@@ -1845,11 +1872,7 @@ class OAuth2WebServerFlow(Flow):
self.device_uri = device_uri self.device_uri = device_uri
self.token_info_uri = token_info_uri self.token_info_uri = token_info_uri
self.authorization_header = authorization_header self.authorization_header = authorization_header
self.params = { self.params = _oauth2_web_server_flow_params(kwargs)
'access_type': 'offline',
'response_type': 'code',
}
self.params.update(kwargs)
@util.positional(1) @util.positional(1)
def step1_get_authorize_url(self, redirect_uri=None, state=None): def step1_get_authorize_url(self, redirect_uri=None, state=None):
@@ -2009,7 +2032,7 @@ class OAuth2WebServerFlow(Flow):
if not refresh_token: if not refresh_token:
logger.info( logger.info(
'Received token response with no refresh_token. Consider ' 'Received token response with no refresh_token. Consider '
"reauthenticating with approval_prompt='force'.") "reauthenticating with prompt='consent'.")
token_expiry = None token_expiry = None
if 'expires_in' in d: if 'expires_in' in d:
delta = datetime.timedelta(seconds=int(d['expires_in'])) delta = datetime.timedelta(seconds=int(d['expires_in']))

View File

@@ -840,7 +840,7 @@ class DecoratorTests(unittest2.TestCase):
decorator = appengine.OAuth2Decorator( decorator = appengine.OAuth2Decorator(
client_id='foo_client_id', client_secret='foo_client_secret', client_id='foo_client_id', client_secret='foo_client_secret',
user_agent='foo_user_agent', scope=['foo_scope', 'bar_scope'], user_agent='foo_user_agent', scope=['foo_scope', 'bar_scope'],
access_type='offline', approval_prompt='force', access_type='offline', prompt='consent',
revoke_uri='dummy_revoke_uri') revoke_uri='dummy_revoke_uri')
request_handler = MockRequestHandler() request_handler = MockRequestHandler()
decorator._create_flow(request_handler) decorator._create_flow(request_handler)
@@ -848,7 +848,7 @@ class DecoratorTests(unittest2.TestCase):
self.assertEqual('https://example.org/oauth2callback', self.assertEqual('https://example.org/oauth2callback',
decorator.flow.redirect_uri) decorator.flow.redirect_uri)
self.assertEqual('offline', decorator.flow.params['access_type']) self.assertEqual('offline', decorator.flow.params['access_type'])
self.assertEqual('force', decorator.flow.params['approval_prompt']) self.assertEqual('consent', decorator.flow.params['prompt'])
self.assertEqual('foo_user_agent', decorator.flow.user_agent) self.assertEqual('foo_user_agent', decorator.flow.user_agent)
self.assertEqual('dummy_revoke_uri', decorator.flow.revoke_uri) self.assertEqual('dummy_revoke_uri', decorator.flow.revoke_uri)
self.assertEqual(None, decorator.flow.params.get('user_agent', None)) self.assertEqual(None, decorator.flow.params.get('user_agent', None))
@@ -911,8 +911,8 @@ class DecoratorTests(unittest2.TestCase):
decorator = appengine.OAuth2DecoratorFromClientSecrets( decorator = appengine.OAuth2DecoratorFromClientSecrets(
datafile('client_secrets.json'), datafile('client_secrets.json'),
scope=['foo_scope', 'bar_scope'], scope=['foo_scope', 'bar_scope'],
approval_prompt='force') prompt='consent')
self.assertTrue('approval_prompt' in decorator._kwargs) self.assertIn('prompt', decorator._kwargs)
def test_decorator_from_cached_client_secrets(self): def test_decorator_from_cached_client_secrets(self):
cache_mock = CacheMock() cache_mock = CacheMock()

View File

@@ -1681,6 +1681,20 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
self.assertEqual(client.OOB_CALLBACK_URN, q['redirect_uri'][0]) self.assertEqual(client.OOB_CALLBACK_URN, q['redirect_uri'][0])
self.assertEqual('online', q['access_type'][0]) self.assertEqual('online', q['access_type'][0])
def test__oauth2_web_server_flow_params(self):
params = client._oauth2_web_server_flow_params({})
self.assertEqual(params['access_type'], 'offline')
self.assertEqual(params['response_type'], 'code')
params = client._oauth2_web_server_flow_params({
'approval_prompt': 'force'})
self.assertEqual(params['prompt'], 'consent')
self.assertNotIn('approval_prompt', params)
params = client._oauth2_web_server_flow_params({
'approval_prompt': 'other'})
self.assertEqual(params['approval_prompt'], 'other')
@mock.patch('oauth2client.client.logger') @mock.patch('oauth2client.client.logger')
def test_step1_get_authorize_url_redirect_override(self, logger): def test_step1_get_authorize_url_redirect_override(self, logger):
flow = client.OAuth2WebServerFlow('client_id+1', scope='foo', flow = client.OAuth2WebServerFlow('client_id+1', scope='foo',