Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
challenges.py204 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""" Challenges for reauthentication.16"""17 18import abc19import base6420import getpass21import sys22 23from google.auth import _helpers24from google.auth import exceptions25 26 27REAUTH_ORIGIN = "https://accounts.google.com"28SAML_CHALLENGE_MESSAGE = (29    "Please run `gcloud auth login` to complete reauthentication with SAML."30)31 32 33def get_user_password(text):34    """Get password from user.35 36    Override this function with a different logic if you are using this library37    outside a CLI.38 39    Args:40        text (str): message for the password prompt.41 42    Returns:43        str: password string.44    """45    return getpass.getpass(text)46 47 48class ReauthChallenge(metaclass=abc.ABCMeta):49    """Base class for reauth challenges."""50 51    @property52    @abc.abstractmethod53    def name(self):  # pragma: NO COVER54        """Returns the name of the challenge."""55        raise NotImplementedError("name property must be implemented")56 57    @property58    @abc.abstractmethod59    def is_locally_eligible(self):  # pragma: NO COVER60        """Returns true if a challenge is supported locally on this machine."""61        raise NotImplementedError("is_locally_eligible property must be implemented")62 63    @abc.abstractmethod64    def obtain_challenge_input(self, metadata):  # pragma: NO COVER65        """Performs logic required to obtain credentials and returns it.66 67        Args:68            metadata (Mapping): challenge metadata returned in the 'challenges' field in69                the initial reauth request. Includes the 'challengeType' field70                and other challenge-specific fields.71 72        Returns:73            response that will be send to the reauth service as the content of74            the 'proposalResponse' field in the request body. Usually a dict75            with the keys specific to the challenge. For example,76            ``{'credential': password}`` for password challenge.77        """78        raise NotImplementedError("obtain_challenge_input method must be implemented")79 80 81class PasswordChallenge(ReauthChallenge):82    """Challenge that asks for user's password."""83 84    @property85    def name(self):86        return "PASSWORD"87 88    @property89    def is_locally_eligible(self):90        return True91 92    @_helpers.copy_docstring(ReauthChallenge)93    def obtain_challenge_input(self, unused_metadata):94        passwd = get_user_password("Please enter your password:")95        if not passwd:96            passwd = " "  # avoid the server crashing in case of no password :D97        return {"credential": passwd}98 99 100class SecurityKeyChallenge(ReauthChallenge):101    """Challenge that asks for user's security key touch."""102 103    @property104    def name(self):105        return "SECURITY_KEY"106 107    @property108    def is_locally_eligible(self):109        return True110 111    @_helpers.copy_docstring(ReauthChallenge)112    def obtain_challenge_input(self, metadata):113        try:114            import pyu2f.convenience.authenticator  # type: ignore115            import pyu2f.errors  # type: ignore116            import pyu2f.model  # type: ignore117        except ImportError:118            raise exceptions.ReauthFailError(119                "pyu2f dependency is required to use Security key reauth feature. "120                "It can be installed via `pip install pyu2f` or `pip install google-auth[reauth]`."121            )122        sk = metadata["securityKey"]123        challenges = sk["challenges"]124        # Read both 'applicationId' and 'relyingPartyId', if they are the same, use125        # applicationId, if they are different, use relyingPartyId first and retry126        # with applicationId127        application_id = sk["applicationId"]128        relying_party_id = sk["relyingPartyId"]129 130        if application_id != relying_party_id:131            application_parameters = [relying_party_id, application_id]132        else:133            application_parameters = [application_id]134 135        challenge_data = []136        for c in challenges:137            kh = c["keyHandle"].encode("ascii")138            key = pyu2f.model.RegisteredKey(bytearray(base64.urlsafe_b64decode(kh)))139            challenge = c["challenge"].encode("ascii")140            challenge = base64.urlsafe_b64decode(challenge)141            challenge_data.append({"key": key, "challenge": challenge})142 143        # Track number of tries to suppress error message until all application_parameters144        # are tried.145        tries = 0146        for app_id in application_parameters:147            try:148                tries += 1149                api = pyu2f.convenience.authenticator.CreateCompositeAuthenticator(150                    REAUTH_ORIGIN151                )152                response = api.Authenticate(153                    app_id, challenge_data, print_callback=sys.stderr.write154                )155                return {"securityKey": response}156            except pyu2f.errors.U2FError as e:157                if e.code == pyu2f.errors.U2FError.DEVICE_INELIGIBLE:158                    # Only show error if all app_ids have been tried159                    if tries == len(application_parameters):160                        sys.stderr.write("Ineligible security key.\n")161                        return None162                    continue163                if e.code == pyu2f.errors.U2FError.TIMEOUT:164                    sys.stderr.write(165                        "Timed out while waiting for security key touch.\n"166                    )167                else:168                    raise e169            except pyu2f.errors.PluginError as e:170                sys.stderr.write("Plugin error: {}.\n".format(e))171                continue172            except pyu2f.errors.NoDeviceFoundError:173                sys.stderr.write("No security key found.\n")174            return None175 176 177class SamlChallenge(ReauthChallenge):178    """Challenge that asks the users to browse to their ID Providers.179 180    Currently SAML challenge is not supported. When obtaining the challenge181    input, exception will be raised to instruct the users to run182    `gcloud auth login` for reauthentication.183    """184 185    @property186    def name(self):187        return "SAML"188 189    @property190    def is_locally_eligible(self):191        return True192 193    def obtain_challenge_input(self, metadata):194        # Magic Arch has not fully supported returning a proper dedirect URL195        # for programmatic SAML users today. So we error our here and request196        # users to use gcloud to complete a login.197        raise exceptions.ReauthSamlChallengeFailError(SAML_CHALLENGE_MESSAGE)198 199 200AVAILABLE_CHALLENGES = {201    challenge.name: challenge202    for challenge in [SecurityKeyChallenge(), PasswordChallenge(), SamlChallenge()]203}204 
codekingpro/portable-devtools · Team Ai