1717from functools import partial
1818import json
1919import os
20+ import re
2021
2122import mock
2223import pytest
@@ -87,6 +88,7 @@ def test_redirect_uri(self, instance):
8788 def test_authorization_url (self , instance ):
8889 scope = 'scope_one'
8990 instance .oauth2session .scope = [scope ]
91+ instance .code_verifier = 'amanaplanacanalpanama'
9092 authorization_url_patch = mock .patch .object (
9193 instance .oauth2session , 'authorization_url' ,
9294 wraps = instance .oauth2session .authorization_url )
@@ -99,11 +101,14 @@ def test_authorization_url(self, instance):
99101 authorization_url_spy .assert_called_with (
100102 CLIENT_SECRETS_INFO ['web' ]['auth_uri' ],
101103 access_type = 'offline' ,
102- prompt = 'consent' )
104+ prompt = 'consent' ,
105+ code_challenge = '2yN0TOdl0gkGwFOmtfx3f913tgEaLM2d2S0WlmG1Z6Q' ,
106+ code_challenge_method = 'S256' )
103107
104108 def test_authorization_url_access_type (self , instance ):
105109 scope = 'scope_one'
106110 instance .oauth2session .scope = [scope ]
111+ instance .code_verifier = 'amanaplanacanalpanama'
107112 authorization_url_patch = mock .patch .object (
108113 instance .oauth2session , 'authorization_url' ,
109114 wraps = instance .oauth2session .authorization_url )
@@ -115,9 +120,31 @@ def test_authorization_url_access_type(self, instance):
115120 assert scope in url
116121 authorization_url_spy .assert_called_with (
117122 CLIENT_SECRETS_INFO ['web' ]['auth_uri' ],
118- access_type = 'meep' )
123+ access_type = 'meep' ,
124+ code_challenge = '2yN0TOdl0gkGwFOmtfx3f913tgEaLM2d2S0WlmG1Z6Q' ,
125+ code_challenge_method = 'S256' )
126+
127+ def test_authorization_url_generated_verifier (self , instance ):
128+ scope = 'scope_one'
129+ instance .oauth2session .scope = [scope ]
130+ authorization_url_path = mock .patch .object (
131+ instance .oauth2session , 'authorization_url' ,
132+ wraps = instance .oauth2session .authorization_url )
133+
134+ with authorization_url_path as authorization_url_spy :
135+ instance .authorization_url ()
136+
137+ _ , kwargs = authorization_url_spy .call_args_list [0 ]
138+ assert kwargs ['code_challenge_method' ] == 'S256'
139+ assert len (instance .code_verifier ) == 128
140+ assert len (kwargs ['code_challenge' ]) == 43
141+ valid_verifier = r'^[A-Za-z0-9-._~]*$'
142+ valid_challenge = r'^[A-Za-z0-9-_]*$'
143+ assert re .match (valid_verifier , instance .code_verifier )
144+ assert re .match (valid_challenge , kwargs ['code_challenge' ])
119145
120146 def test_fetch_token (self , instance ):
147+ instance .code_verifier = 'amanaplanacanalpanama'
121148 fetch_token_patch = mock .patch .object (
122149 instance .oauth2session , 'fetch_token' , autospec = True ,
123150 return_value = mock .sentinel .token )
@@ -129,7 +156,8 @@ def test_fetch_token(self, instance):
129156 fetch_token_mock .assert_called_with (
130157 CLIENT_SECRETS_INFO ['web' ]['token_uri' ],
131158 client_secret = CLIENT_SECRETS_INFO ['web' ]['client_secret' ],
132- code = mock .sentinel .code )
159+ code = mock .sentinel .code ,
160+ code_verifier = 'amanaplanacanalpanama' )
133161
134162 def test_credentials (self , instance ):
135163 instance .oauth2session .token = {
@@ -194,7 +222,7 @@ def set_token(*args, **kwargs):
194222 @mock .patch ('google_auth_oauthlib.flow.input' , autospec = True )
195223 def test_run_console (self , input_mock , instance , mock_fetch_token ):
196224 input_mock .return_value = mock .sentinel .code
197-
225+ instance . code_verifier = 'amanaplanacanalpanama'
198226 credentials = instance .run_console ()
199227
200228 assert credentials .token == mock .sentinel .access_token
@@ -204,7 +232,8 @@ def test_run_console(self, input_mock, instance, mock_fetch_token):
204232 mock_fetch_token .assert_called_with (
205233 CLIENT_SECRETS_INFO ['web' ]['token_uri' ],
206234 client_secret = CLIENT_SECRETS_INFO ['web' ]['client_secret' ],
207- code = mock .sentinel .code )
235+ code = mock .sentinel .code ,
236+ code_verifier = 'amanaplanacanalpanama' )
208237
209238 @pytest .mark .webtest
210239 @mock .patch ('google_auth_oauthlib.flow.webbrowser' , autospec = True )
@@ -213,6 +242,7 @@ def test_run_local_server(
213242 auth_redirect_url = urllib .parse .urljoin (
214243 'http://localhost:60452' ,
215244 self .REDIRECT_REQUEST_PATH )
245+ instance .code_verifier = 'amanaplanacanalpanama'
216246
217247 with concurrent .futures .ThreadPoolExecutor (max_workers = 1 ) as pool :
218248 future = pool .submit (partial (
@@ -235,7 +265,8 @@ def test_run_local_server(
235265 mock_fetch_token .assert_called_with (
236266 CLIENT_SECRETS_INFO ['web' ]['token_uri' ],
237267 client_secret = CLIENT_SECRETS_INFO ['web' ]['client_secret' ],
238- authorization_response = expected_auth_response )
268+ authorization_response = expected_auth_response ,
269+ code_verifier = 'amanaplanacanalpanama' )
239270
240271 @mock .patch ('google_auth_oauthlib.flow.webbrowser' , autospec = True )
241272 @mock .patch ('wsgiref.simple_server.make_server' , autospec = True )
0 commit comments