async def test_refresh_with_session_data(client: TestClient): async with request_mock() as mock_request: start_st() mock_request.post( url='https://' + AUTH0_DOMAIN + '/oauth/token', name="t1" ).respond( status_code=200, json={ 'id_token': TEST_ID_TOKEN, 'expires_in': get_timestamp_ms() + 30000, 'access_token': 'test-access-token', 'refresh_token': 'test-refresh-token' } ) r1 = client.post("/login-without-callback", json={ 'action': 'login', 'redirect_uri': 'http://localhost:3000', 'code': 'randomString' }) c1 = extract_all_cookies(r1) mock_request.pop('t1') mock_request.post( url='https://' + AUTH0_DOMAIN + '/oauth/token', name="t2" ).respond( status_code=200, json={ 'id_token': 'custom-token', 'expires_in': get_timestamp_ms() + 30000, 'access_token': 'test-access-token', 'refresh_token': 'test-refresh-token' } ) r2 = client.post( url="/refresh-auth0", cookies={ 'sAccessToken': c1['sAccessToken']['value'], 'sIdRefreshToken': c1['sIdRefreshToken']['value'] }, headers={ 'anti-csrf': r1.headers.get('anti-csrf') }, json={ 'action': 'refresh' } ) assert r2.status_code == 200 assert r2.json()['id_token'] == 'custom-token'
async def test_refresh_non_200_response(client: TestClient): async with request_mock() as mock: start_st() mock.post(url='https://' + AUTH0_DOMAIN + '/oauth/token', status_code=200, content={ 'id_token': TEST_ID_TOKEN, 'expires_in': get_timestamp_ms() + 30000, 'access_token': 'test-access-token', 'refresh_token': 'test-refresh-token' }, alias='t1') r1 = client.post("/login-without-callback", json={ 'action': 'login', 'redirect_uri': 'http://localhost:3000', 'code': 'randomString' }) c1 = extract_all_cookies(r1) mock.pop('t1') mock.post(url='https://' + AUTH0_DOMAIN + '/oauth/token', status_code=403, content={}, alias='t2') r2 = client.post(url="/refresh-auth0", cookies={ 'sAccessToken': c1['sAccessToken']['value'], 'sIdRefreshToken': c1['sIdRefreshToken']['value'] }, headers={'anti-csrf': r1.headers.get('anti-csrf')}, json={'action': 'refresh'}) assert r2.status_code == 403
async def test_login_with_callback(client: TestClient): async with request_mock() as mock_request: start_st() mock_request.post( url='https://' + AUTH0_DOMAIN + '/oauth/token' ).respond( status_code=200, json={ 'id_token': TEST_ID_TOKEN, 'expires_in': get_timestamp_ms() + 30000, 'access_token': 'test-access-token', 'refresh_token': 'test-refresh-token' } ) r1 = client.post("/login-with-callback-save-rt", json={ 'action': 'login', 'redirect_uri': 'http://localhost:3000', 'code': 'randomString' }) c1 = extract_all_cookies(r1) r2 = client.get( url="/get-session-data", cookies={ 'sAccessToken': c1['sAccessToken']['value'], 'sIdRefreshToken': c1['sIdRefreshToken']['value'] } ) assert r2.json() == { 'access_token': 'test-access-token', 'refresh_token': 'test-refresh-token' }
async def set_cookie(response: Response, key, value, expires, path, domain, secure, http_only, same_site): response.delete_cookie(key) # Delete earlier cookies if CookieConfig.get_instance().cookie_domain is not None: domain = CookieConfig.get_instance().cookie_domain if CookieConfig.get_instance().cookie_secure is not None: secure = CookieConfig.get_instance().cookie_secure if CookieConfig.get_instance().cookie_same_site is not None: same_site = CookieConfig.get_instance().cookie_same_site handshake_info = await HandshakeInfo.get_instance() if path in { handshake_info.refresh_token_path, handshake_info.access_token_path }: if path == handshake_info.access_token_path and CookieConfig.get_instance( ).access_token_path is not None: path = CookieConfig.get_instance().access_token_path elif path == handshake_info.refresh_token_path and CookieConfig.get_instance( ).refresh_token_path is not None: path = CookieConfig.get_instance().refresh_token_path response.set_cookie(key=key, value=quote(value, encoding='utf-8'), expires=((expires - get_timestamp_ms()) // 1000), path=path, domain=domain, secure=secure, httponly=http_only, samesite=same_site)
async def test_logout_without_depends(client: TestClient): async with request_mock() as mock_request: start_st() mock_request.post( url='https://' + AUTH0_DOMAIN + '/oauth/token' ).respond( status_code=200, json={ 'id_token': TEST_ID_TOKEN, 'expires_in': get_timestamp_ms() + 30000, 'access_token': 'test-access-token', 'refresh_token': 'test-refresh-token' } ) r1 = client.post("/login-without-callback", json={ 'action': 'login', 'redirect_uri': 'http://localhost:3000', 'code': 'randomString' }) c1 = extract_all_cookies(r1) r2 = client.post( url="/logout-without-depends", cookies={ 'sAccessToken': c1['sAccessToken']['value'], 'sIdRefreshToken': c1['sIdRefreshToken']['value'] }, headers={ 'anti-csrf': r1.headers.get('anti-csrf') }, json={ 'action': 'logout' } ) c2 = extract_all_cookies(r2) assert r2.headers.get('anti-csrf') is None assert c2['sAccessToken']['value'] == '' assert c2['sRefreshToken']['value'] == '' assert c2['sIdRefreshToken']['value'] == '' assert c2['sAccessToken']['path'] == '/' assert c2['sRefreshToken']['path'] == '/refresh' assert c2['sIdRefreshToken']['path'] == '/' assert c2['sAccessToken']['httponly'] assert c2['sRefreshToken']['httponly'] assert c2['sIdRefreshToken']['httponly'] assert c2['sAccessToken']['secure'] is None assert c2['sRefreshToken']['secure'] is None assert c2['sIdRefreshToken']['secure'] is None assert verify_within_5_second_diff( get_unix_timestamp(c2['sAccessToken']['expires']), 0 ) assert verify_within_5_second_diff( get_unix_timestamp(c2['sRefreshToken']['expires']), 0 ) assert verify_within_5_second_diff( get_unix_timestamp(c2['sIdRefreshToken']['expires']), 0 ) assert r2.headers['Id-Refresh-Token'] == 'remove'
async def get_session(access_token: str, anti_csrf_token: Union[str, None], do_anti_csrf_check: bool): handshake_info = await HandshakeInfo.get_instance() try: if handshake_info.jwt_signing_public_key_expiry_time > get_timestamp_ms(): access_token_info = get_info_from_access_token(access_token, handshake_info.jwt_signing_public_key, handshake_info.enable_anti_csrf and do_anti_csrf_check) if handshake_info.enable_anti_csrf and do_anti_csrf_check and \ (anti_csrf_token is None or anti_csrf_token != access_token_info['antiCsrfToken']): if anti_csrf_token is None: raise_try_refresh_token_exception('anti_csrf_token is undefined') raise_try_refresh_token_exception('anti-csrf check failed') if not handshake_info.access_token_blacklisting_enabled and \ access_token_info['parentRefreshTokenHash1'] is None: ProcessState.update_service_called(False) return { 'session': { 'handle': access_token_info['sessionHandle'], 'userId': access_token_info['userId'], 'userDataInJWT': access_token_info['userData'] } } except SuperTokensTryRefreshTokenError: pass ProcessState.update_service_called(True) data = { 'accessToken': access_token, 'doAntiCsrfCheck': do_anti_csrf_check } if anti_csrf_token is not None: data['antiCsrfToken'] = anti_csrf_token response = await Querier.get_instance().send_post_request(SESSION_VERIFY, data) if response['status'] == 'OK': handshake_info = await HandshakeInfo.get_instance() handshake_info.update_jwt_signing_public_key_info(response['jwtSigningPublicKey'], response['jwtSigningPublicKeyExpiryTime']) response.pop('status', None) response.pop('jwtSigningPublicKey', None) response.pop('jwtSigningPublicKeyExpiryTime', None) return response elif response['status'] == 'UNAUTHORISED': raise_unauthorised_exception(response['message']) else: raise_try_refresh_token_exception(response['message'])
def test_set_cookie(client: TestClient): start_st() expiry = get_timestamp_ms() response = client.get('/?expiry=' + str(expiry)) test_cookie = get_cookie_from_response(response, 'test') assert test_cookie is not None assert test_cookie['value'] == 'value' assert test_cookie['domain'] == 'localhost.org' assert test_cookie['path'] == '/' assert test_cookie['samesite'] == 'none' or test_cookie['samesite'] == 'lax' assert test_cookie['secure'] assert test_cookie.get('httponly') is None assert verify_within_5_second_diff( get_unix_timestamp(test_cookie['expires']), floor(expiry / 1000) )
async def test_login_invalid_id_token(client: TestClient): async with request_mock() as mock: start_st() mock.post(url='https://' + AUTH0_DOMAIN + '/oauth/token', status_code=200, content={ 'id_token': 'invalid token', 'expires_in': get_timestamp_ms() + 30000, 'access_token': 'test-access-token', 'refresh_token': 'test-refresh-token' }) r1 = client.post("/login-without-callback", json={ 'action': 'login', 'redirect_uri': 'http://localhost:3000', 'code': 'randomString' }) assert r1.status_code == 500
async def test_login_with_callback_error_thrown(client: TestClient): async with request_mock() as mock: start_st() mock.post(url='https://' + AUTH0_DOMAIN + '/oauth/token', status_code=200, content={ 'id_token': TEST_ID_TOKEN, 'expires_in': get_timestamp_ms() + 30000, 'access_token': 'test-access-token', 'refresh_token': 'test-refresh-token' }) r1 = client.post("/login-with-error-callback", json={ 'action': 'login', 'redirect_uri': 'http://localhost:3000', 'code': 'randomString' }) assert r1.status_code == 500 assert r1.json() == {'detail': 'access token not matching'}
async def test_login_without_callback(client: TestClient): async with request_mock() as mock_request: start_st() mock_request.post( url='https://' + AUTH0_DOMAIN + '/oauth/token' ).respond( status_code=200, json={ 'id_token': TEST_ID_TOKEN, 'expires_in': get_timestamp_ms() + 30000, 'access_token': 'test-access-token', 'refresh_token': 'test-refresh-token' } ) r = client.post("/login-without-callback", json={ 'action': 'login', 'redirect_uri': 'http://localhost:3000', 'code': 'randomString' }) assert r.json()['id_token'] == TEST_ID_TOKEN
def get_info_from_access_token(token, jwt_signing_public_key, do_anti_csrf_check): try: payload = get_payload(token, jwt_signing_public_key) session_handle = sanitize_string(payload.get('sessionHandle')) user_id = sanitize_string(payload.get('userId')) refresh_token_hash_1 = sanitize_string( payload.get('refreshTokenHash1')) parent_refresh_token_hash_1 = sanitize_string( payload.get('parentRefreshTokenHash1')) user_data = payload.get('userData') anti_csrf_token = sanitize_string(payload.get('antiCsrfToken')) expiry_time = sanitize_number(payload.get('expiryTime')) time_created = sanitize_number(payload.get('timeCreated')) if (session_handle is None) or \ (user_data is None) or \ (refresh_token_hash_1 is None) or \ (user_data is None) or \ (anti_csrf_token is None and do_anti_csrf_check) or \ (expiry_time is None) or \ (time_created is None): raise Exception( 'Access token does not contain all the information. Maybe the structure has changed?' ) if expiry_time < get_timestamp_ms(): raise Exception('Access token expired') return { 'sessionHandle': session_handle, 'userId': user_id, 'refreshTokenHash1': refresh_token_hash_1, 'parentRefreshTokenHash1': parent_refresh_token_hash_1, 'userData': user_data, 'antiCsrfToken': anti_csrf_token, 'expiryTime': expiry_time, 'timeCreated': time_created } except Exception as e: raise_try_refresh_token_exception(e)