Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
_reauth_async.py329 linesDownload Raw Back to oauth2
1# Copyright 2021 Google LLC2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7#      http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14 15"""A module that provides functions for handling rapt authentication.16 17Reauth is a process of obtaining additional authentication (such as password,18security token, etc.) while refreshing OAuth 2.0 credentials for a user.19 20Credentials that use the Reauth flow must have the reauth scope,21``https://www.googleapis.com/auth/accounts.reauth``.22 23This module provides a high-level function for executing the Reauth process,24:func:`refresh_grant`, and lower-level helpers for doing the individual25steps of the reauth process.26 27Those steps are:28 291. Obtaining a list of challenges from the reauth server.302. Running through each challenge and sending the result back to the reauth31   server.323. Refreshing the access token using the returned rapt token.33"""34 35import sys36 37from google.auth import exceptions38from google.oauth2 import _client39from google.oauth2 import _client_async40from google.oauth2 import challenges41from google.oauth2 import reauth42 43 44async def _get_challenges(45    request, supported_challenge_types, access_token, requested_scopes=None46):47    """Does initial request to reauth API to get the challenges.48 49    Args:50        request (google.auth.transport.Request): A callable used to make51            HTTP requests. This must be an aiohttp request.52        supported_challenge_types (Sequence[str]): list of challenge names53            supported by the manager.54        access_token (str): Access token with reauth scopes.55        requested_scopes (Optional(Sequence[str])): Authorized scopes for the credentials.56 57    Returns:58        dict: The response from the reauth API.59    """60    body = {"supportedChallengeTypes": supported_challenge_types}61    if requested_scopes:62        body["oauthScopesForDomainPolicyLookup"] = requested_scopes63 64    return await _client_async._token_endpoint_request(65        request,66        reauth._REAUTH_API + ":start",67        body,68        access_token=access_token,69        use_json=True,70    )71 72 73async def _send_challenge_result(74    request, session_id, challenge_id, client_input, access_token75):76    """Attempt to refresh access token by sending next challenge result.77 78    Args:79        request (google.auth.transport.Request): A callable used to make80            HTTP requests. This must be an aiohttp request.81        session_id (str): session id returned by the initial reauth call.82        challenge_id (str): challenge id returned by the initial reauth call.83        client_input: dict with a challenge-specific client input. For example:84            ``{'credential': password}`` for password challenge.85        access_token (str): Access token with reauth scopes.86 87    Returns:88        dict: The response from the reauth API.89    """90    body = {91        "sessionId": session_id,92        "challengeId": challenge_id,93        "action": "RESPOND",94        "proposalResponse": client_input,95    }96 97    return await _client_async._token_endpoint_request(98        request,99        reauth._REAUTH_API + "/{}:continue".format(session_id),100        body,101        access_token=access_token,102        use_json=True,103    )104 105 106async def _run_next_challenge(msg, request, access_token):107    """Get the next challenge from msg and run it.108 109    Args:110        msg (dict): Reauth API response body (either from the initial request to111            https://reauth.googleapis.com/v2/sessions:start or from sending the112            previous challenge response to113            https://reauth.googleapis.com/v2/sessions/id:continue)114        request (google.auth.transport.Request): A callable used to make115            HTTP requests. This must be an aiohttp request.116        access_token (str): reauth access token117 118    Returns:119        dict: The response from the reauth API.120 121    Raises:122        google.auth.exceptions.ReauthError: if reauth failed.123    """124    for challenge in msg["challenges"]:125        if challenge["status"] != "READY":126            # Skip non-activated challenges.127            continue128        c = challenges.AVAILABLE_CHALLENGES.get(challenge["challengeType"], None)129        if not c:130            raise exceptions.ReauthFailError(131                "Unsupported challenge type {0}. Supported types: {1}".format(132                    challenge["challengeType"],133                    ",".join(list(challenges.AVAILABLE_CHALLENGES.keys())),134                )135            )136        if not c.is_locally_eligible:137            raise exceptions.ReauthFailError(138                "Challenge {0} is not locally eligible".format(139                    challenge["challengeType"]140                )141            )142        client_input = c.obtain_challenge_input(challenge)143        if not client_input:144            return None145        return await _send_challenge_result(146            request,147            msg["sessionId"],148            challenge["challengeId"],149            client_input,150            access_token,151        )152    return None153 154 155async def _obtain_rapt(request, access_token, requested_scopes):156    """Given an http request method and reauth access token, get rapt token.157 158    Args:159        request (google.auth.transport.Request): A callable used to make160            HTTP requests. This must be an aiohttp request.161        access_token (str): reauth access token162        requested_scopes (Sequence[str]): scopes required by the client application163 164    Returns:165        str: The rapt token.166 167    Raises:168        google.auth.exceptions.ReauthError: if reauth failed169    """170    msg = await _get_challenges(171        request,172        list(challenges.AVAILABLE_CHALLENGES.keys()),173        access_token,174        requested_scopes,175    )176 177    if msg["status"] == reauth._AUTHENTICATED:178        return msg["encodedProofOfReauthToken"]179 180    for _ in range(0, reauth.RUN_CHALLENGE_RETRY_LIMIT):181        if not (182            msg["status"] == reauth._CHALLENGE_REQUIRED183            or msg["status"] == reauth._CHALLENGE_PENDING184        ):185            raise exceptions.ReauthFailError(186                "Reauthentication challenge failed due to API error: {}".format(187                    msg["status"]188                )189            )190 191        if not reauth.is_interactive():192            raise exceptions.ReauthFailError(193                "Reauthentication challenge could not be answered because you are not"194                " in an interactive session."195            )196 197        msg = await _run_next_challenge(msg, request, access_token)198 199        if msg["status"] == reauth._AUTHENTICATED:200            return msg["encodedProofOfReauthToken"]201 202    # If we got here it means we didn't get authenticated.203    raise exceptions.ReauthFailError("Failed to obtain rapt token.")204 205 206async def get_rapt_token(207    request, client_id, client_secret, refresh_token, token_uri, scopes=None208):209    """Given an http request method and refresh_token, get rapt token.210 211    Args:212        request (google.auth.transport.Request): A callable used to make213            HTTP requests. This must be an aiohttp request.214        client_id (str): client id to get access token for reauth scope.215        client_secret (str): client secret for the client_id216        refresh_token (str): refresh token to refresh access token217        token_uri (str): uri to refresh access token218        scopes (Optional(Sequence[str])): scopes required by the client application219 220    Returns:221        str: The rapt token.222    Raises:223        google.auth.exceptions.RefreshError: If reauth failed.224    """225    sys.stderr.write("Reauthentication required.\n")226 227    # Get access token for reauth.228    access_token, _, _, _ = await _client_async.refresh_grant(229        request=request,230        client_id=client_id,231        client_secret=client_secret,232        refresh_token=refresh_token,233        token_uri=token_uri,234        scopes=[reauth._REAUTH_SCOPE],235    )236 237    # Get rapt token from reauth API.238    rapt_token = await _obtain_rapt(request, access_token, requested_scopes=scopes)239 240    return rapt_token241 242 243async def refresh_grant(244    request,245    token_uri,246    refresh_token,247    client_id,248    client_secret,249    scopes=None,250    rapt_token=None,251    enable_reauth_refresh=False,252):253    """Implements the reauthentication flow.254 255    Args:256        request (google.auth.transport.Request): A callable used to make257            HTTP requests. This must be an aiohttp request.258        token_uri (str): The OAuth 2.0 authorizations server's token endpoint259            URI.260        refresh_token (str): The refresh token to use to get a new access261            token.262        client_id (str): The OAuth 2.0 application's client ID.263        client_secret (str): The Oauth 2.0 appliaction's client secret.264        scopes (Optional(Sequence[str])): Scopes to request. If present, all265            scopes must be authorized for the refresh token. Useful if refresh266            token has a wild card scope (e.g.267            'https://www.googleapis.com/auth/any-api').268        rapt_token (Optional(str)): The rapt token for reauth.269        enable_reauth_refresh (Optional[bool]): Whether reauth refresh flow270            should be used. The default value is False. This option is for271            gcloud only, other users should use the default value.272 273    Returns:274        Tuple[str, Optional[str], Optional[datetime], Mapping[str, str], str]: The275            access token, new refresh token, expiration, the additional data276            returned by the token endpoint, and the rapt token.277 278    Raises:279        google.auth.exceptions.RefreshError: If the token endpoint returned280            an error.281    """282    body = {283        "grant_type": _client._REFRESH_GRANT_TYPE,284        "client_id": client_id,285        "client_secret": client_secret,286        "refresh_token": refresh_token,287    }288    if scopes:289        body["scope"] = " ".join(scopes)290    if rapt_token:291        body["rapt"] = rapt_token292 293    response_status_ok, response_data, retryable_error = await _client_async._token_endpoint_request_no_throw(294        request, token_uri, body295    )296    if (297        not response_status_ok298        and response_data.get("error") == reauth._REAUTH_NEEDED_ERROR299        and (300            response_data.get("error_subtype")301            == reauth._REAUTH_NEEDED_ERROR_INVALID_RAPT302            or response_data.get("error_subtype")303            == reauth._REAUTH_NEEDED_ERROR_RAPT_REQUIRED304        )305    ):306        if not enable_reauth_refresh:307            raise exceptions.RefreshError(308                "Reauthentication is needed. Please run `gcloud auth application-default login` to reauthenticate."309            )310 311        rapt_token = await get_rapt_token(312            request, client_id, client_secret, refresh_token, token_uri, scopes=scopes313        )314        body["rapt"] = rapt_token315        (316            response_status_ok,317            response_data,318            retryable_error,319        ) = await _client_async._token_endpoint_request_no_throw(320            request, token_uri, body321        )322 323    if not response_status_ok:324        _client._handle_error_response(response_data, retryable_error)325    refresh_response = _client._handle_refresh_grant_response(326        response_data, refresh_token327    )328    return refresh_response + (rapt_token,)329 
codekingpro/portable-devtools · Team Ai