Пример #1
0
class UserPassTokenProvider(TokenProviderBase):
    """ Acquire a token from MSAL with username and password """

    def __init__(self, kusto_uri: str, authority_uri: str, username: str, password: str):
        super().__init__(kusto_uri)
        self._msal_client = None
        self._auth = authority_uri
        self._user = username
        self._pass = password

    @staticmethod
    def name() -> str:
        return "UserPassTokenProvider"

    def context(self) -> dict:
        return {"authority": self._auth, "client_id": self._cloud_info.kusto_client_app_id, "username": self._user}

    def _init_impl(self):
        self._msal_client = PublicClientApplication(client_id=self._cloud_info.kusto_client_app_id, authority=self._auth)

    def _get_token_impl(self) -> dict:
        token = self._msal_client.acquire_token_by_username_password(username=self._user, password=self._pass, scopes=self._scopes)
        return self._valid_token_or_throw(token)

    def _get_token_from_cache_impl(self) -> dict:
        account = None
        if self._user is not None:
            accounts = self._msal_client.get_accounts(self._user)
            if len(accounts) > 0:
                account = accounts[0]

        token = self._msal_client.acquire_token_silent(scopes=self._scopes, account=account)
        return self._valid_token_or_none(token)
Пример #2
0
    def getPublicAccessToken(self) -> Optional[str]:
        # Initialise the app if not already exist
        if not self.app:
            print("Initialise msal connection app")
            self.app = PublicClientApplication(client_id=self.app_id,
                                               authority=self.authority)

        result = None
        accounts = self.app.get_accounts()
        if accounts:
            # TODO: need to pick the relevant account to proceed
            chosen = accounts[0]

            # try to get the token from cache if already exist
            result = self.app.acquire_token_silent(scopes=self.scopes,
                                                   account=chosen)

        if not result:
            print(
                "No suitable token exists in cache. Let's get a new one from AAD."
            )
            if self.username and self.password:
                result = self.getUsernamePasswordAccessToken()
            else:
                result = self.getDeviceFlowAccessToken()

        if "access_token" in result:
            return result["access_token"]
        return None
class InteractiveLoginTokenProvider(TokenProviderBase):
    """Acquire a token from MSAL with Device Login flow"""

    def __init__(self, kusto_uri: str, authority_uri: str, login_hint: Optional[str] = None, domain_hint: Optional[str] = None):
        super().__init__(kusto_uri)
        self._msal_client = None
        self._auth = authority_uri
        self._login_hint = login_hint
        self._domain_hint = domain_hint
        self._account = None

    @staticmethod
    def name() -> str:
        return "InteractiveLoginTokenProvider"

    def context(self) -> dict:
        return {"authority": self._auth, "client_id": self._cloud_info.kusto_client_app_id}

    def _init_impl(self):
        self._msal_client = PublicClientApplication(client_id=self._cloud_info.kusto_client_app_id, authority=self._auth)

    def _get_token_impl(self) -> dict:
        token = self._msal_client.acquire_token_interactive(
            scopes=self._scopes, prompt=TokenConstants.MSAL_INTERACTIVE_PROMPT, login_hint=self._login_hint, domain_hint=self._domain_hint
        )
        return self._valid_token_or_throw(token)

    def _get_token_from_cache_impl(self) -> dict:
        account = None
        accounts = self._msal_client.get_accounts(self._login_hint)
        if len(accounts) > 0:
            account = accounts[0]

        token = self._msal_client.acquire_token_silent(scopes=self._scopes, account=account)
        return self._valid_token_or_none(token)
    async def get_token_for_teams_user(self):
        if (os.getenv("SKIP_INT_IDENTITY_EXCHANGE_TOKEN_TEST") == "true"):
            print("Skipping the Get Access Token for Teams User sample")
            return
        from azure.communication.identity.aio import CommunicationIdentityClient
        if self.client_id is not None and self.client_secret is not None and self.tenant_id is not None:
            from azure.identity.aio import DefaultAzureCredential
            endpoint, _ = parse_connection_str(self.connection_string)
            identity_client = CommunicationIdentityClient(
                endpoint, DefaultAzureCredential())
        else:
            identity_client = CommunicationIdentityClient.from_connection_string(
                self.connection_string)

        async with identity_client:
            msal_app = PublicClientApplication(client_id=self.m365_app_id,
                                               authority="{}/{}".format(
                                                   self.m365_aad_authority,
                                                   self.m365_aad_tenant))
            result = msal_app.acquire_token_by_username_password(
                username=self.msal_username,
                password=self.msal_password,
                scopes=[self.m365_scope])
            add_token = result["access_token"]
            print("AAD access token of a Teams User: "******"AAD access token of a Teams User: "******"Token issued with value: " + tokenresponse.token)
    def _get_token_impl(self) -> dict:
        # try and obtain the refresh token from AzCli
        refresh_token = None
        token = None
        stored_token = self._get_azure_cli_auth_token()
        if TokenConstants.AZ_REFRESH_TOKEN in stored_token and TokenConstants.AZ_CLIENT_ID in stored_token and TokenConstants.AZ_AUTHORITY in stored_token:
            refresh_token = stored_token[TokenConstants.AZ_REFRESH_TOKEN]
            self._client_id = stored_token[TokenConstants.AZ_CLIENT_ID]
            self._authority_uri = stored_token[TokenConstants.AZ_AUTHORITY]
            self._username = stored_token[TokenConstants.AZ_USER_ID]
        else:
            raise KustoClientError(
                "Unable to obtain a refresh token from Az-Cli. Calling 'az login' may fix this issue."
            )

        if self._msal_client is None:
            self._msal_client = PublicClientApplication(
                client_id=self._client_id, authority=self._authority_uri)

        try:
            token = self._msal_client.acquire_token_by_refresh_token(
                refresh_token, self._scopes)
        except Exception as ex:
            raise KustoClientError(
                "Unable to obtain with Az-Cli refresh token. Calling 'az login' may fix this issue.\n"
                + str(ex))

        return self._valid_token_or_throw(
            token, "Calling 'az login' may fix this issue.")
Пример #6
0
    def __init__(self, tenant_id: Optional[str] = None):

        # cache file should be written to home directory
        home = os.path.expanduser('~')
        if home:
            self._cache_file = os.path.join(home, '.bonsaicache')
        else:
            raise RuntimeError('Unable to find home directory.')
        self.cache = TokenCache(self._cache_file)

        retry_count = 1

        effective_tenant_id = tenant_id if tenant_id is not None and tenant_id != 'None' else 'organizations'

        _AAD_AUTHORITY = 'https://login.microsoftonline.com/' + effective_tenant_id

        while True:
            try:
                self._app = PublicClientApplication(_AAD_CLIENT_ID,
                                                    authority=_AAD_AUTHORITY,
                                                    token_cache=self.cache)
                if self._app:
                    break
            except ConnectionError as e:
                log.info('ConnectionError on attempt {} to '
                         'create msal PublicClientApplication, '
                         'retrying...'.format(retry_count))
                if retry_count >= 5:
                    raise e
            retry_count += 1
Пример #7
0
class DeviceLoginTokenProvider(CloudInfoTokenProvider):
    """Acquire a token from MSAL with Device Login flow"""
    def __init__(self,
                 kusto_uri: str,
                 authority_id: str,
                 device_code_callback=None,
                 is_async: bool = False):
        super().__init__(kusto_uri, is_async)
        self._msal_client = None
        self._auth = authority_id
        self._account = None
        self._device_code_callback = device_code_callback

    @staticmethod
    def name() -> str:
        return "DeviceLoginTokenProvider"

    def _context_impl(self) -> dict:
        return {
            "authority": self._cloud_info.authority_uri(self._auth),
            "client_id": self._cloud_info.kusto_client_app_id
        }

    def _init_impl(self):
        self._msal_client = PublicClientApplication(
            client_id=self._cloud_info.kusto_client_app_id,
            authority=self._cloud_info.authority_uri(self._auth),
            proxies=self._proxy_dict)

    def _get_token_impl(self) -> Optional[dict]:
        flow = self._msal_client.initiate_device_flow(scopes=self._scopes)
        try:
            if self._device_code_callback:
                self._device_code_callback(
                    flow[TokenConstants.MSAL_DEVICE_MSG])
            else:
                print(flow[TokenConstants.MSAL_DEVICE_MSG])

            webbrowser.open(flow[TokenConstants.MSAL_DEVICE_URI])
        except KeyError:
            raise KustoClientError("Failed to initiate device code flow")

        token = self._msal_client.acquire_token_by_device_flow(flow)

        # Keep the account for silent login
        if self._valid_token_or_none(token) is not None:
            accounts = self._msal_client.get_accounts()
            if len(accounts) == 1:
                self._account = accounts[0]

        return self._valid_token_or_throw(token)

    def _get_token_from_cache_impl(self) -> dict:
        token = self._msal_client.acquire_token_silent(scopes=self._scopes,
                                                       account=self._account)
        return self._valid_token_or_none(token)
Пример #8
0
async def get_current_user(
        auth_settings: AuthSettings = Depends(get_auth_settings),
        msal_app: msal.PublicClientApplication = Depends(get_public_app),
        authorization: Optional[str] = Header(None),
        x_ms_token_aad_id_token: Optional[str] = Header(None),
):
    tenant = urlparse(auth_settings.b2c_endpoint).path.lstrip('/')
    scopes = [
        f'https://{tenant}/{auth_settings.b2c_client_id}/user.impersonate',
    ]
    if payload := msal_app.acquire_token_silent(scopes, None):
        return f'{payload["given_name"]} {payload["family_name"]}'
Пример #9
0
def get_token_from_cache(app: msal.PublicClientApplication,
                         token_scope: List[str]) -> Union[str, None]:
    """Try to get an API access token from a local cache. If the access token is expired
     a refresh token will automatically be used to get a new access token. If the refresh token
     is expired then the user will have to reauthenticate."""
    accounts = app.get_accounts()
    if accounts:
        result = app.acquire_token_silent(token_scope, account=accounts[0])
        # Method returns None if no token can be acquired
        if result and "access_token" in result:
            return result["access_token"]
        else:
            return None
Пример #10
0
 def _get_token():
     auth_client = PublicClientApplication(
         client_id=current_app.config["AUTH_CLIENT_ID"],
         authority=current_app.config["AUTH_CLIENT_TENANCY"])
     auth_flow = auth_client.initiate_device_flow(
         scopes=current_app.config["AUTH_CLIENT_SCOPES"])
     click.pause(
         f"To sign-in, visit 'https://microsoft.com/devicelogin', enter this code '{auth_flow['user_code']}' and then press any key..."
     )
     auth_payload = auth_client.acquire_token_by_device_flow(auth_flow)
     current_app.config["AUTH_TOKEN"] = auth_payload["access_token"]
     click.echo(current_app.config["AUTH_TOKEN"])
     click.echo(f"Ok. Access token set.")
 def generate_teams_user_aad_token(self):
     if self.is_playback():
         teams_user_aad_token = "sanitized"
     else:
         msal_app = PublicClientApplication(client_id=self.m365_app_id,
                                            authority="{}/{}".format(
                                                self.m365_aad_authority,
                                                self.m365_aad_tenant))
         result = msal_app.acquire_token_by_username_password(
             username=self.msal_username,
             password=self.msal_password,
             scopes=[self.m365_scope])
         teams_user_aad_token = result["access_token"]
     return teams_user_aad_token
Пример #12
0
 def _msal_app(self):
     """A PublicClientApplication instance for user login/logout.
     The instance is lazily created.
     """
     if not self._msal_app_instance:
         self._msal_app_instance = PublicClientApplication(self.client_id, **self._msal_app_kwargs)
     return self._msal_app_instance
Пример #13
0
    def Authorize(self):

        bSDD_ClientID = '4aba821f-d4ff-498b-a462-c2837dbbba70'
        bSDD_Scope = "https://buildingsmartservices.onmicrosoft.com/api/read"

        from msal import PublicClientApplication

        bSDD_authority = 'https://buildingsmartservices.b2clogin.com/tfp/buildingsmartservices.onmicrosoft.com/b2c_1_signupsignin'

        app = PublicClientApplication(
            bSDD_ClientID, authority=bSDD_authority
        )  #need localhost redirection on azure portal for the client ID
        flow = app.initiate_auth_code_flow(scopes=[bSDD_Scope])
        self.Token = app.acquire_token_interactive(scopes=[bSDD_Scope])

        print('logged in')
Пример #14
0
def get_token_by_device_flow(app: msal.PublicClientApplication,
                             token_scope: List[str]) -> str:
    flow = app.initiate_device_flow(scopes=token_scope)
    if "user_code" not in flow:
        raise ValueError("Fail to create device flow. Err: %s" %
                         json.dumps(flow, indent=4))
    print(flow["message"])
    print(
        "Program execution will continue automatically after authentication.")

    # This function polls every 5 seconds to see if the user has completed the authentication
    result = app.acquire_token_by_device_flow(flow)

    if "access_token" in result:
        return result["access_token"]
    else:
        print(result.get("error"))
        print(result.get("error_description"))
        raise ValueError()
Пример #15
0
    def __init__(self, url: str):
        self._base_url = url
        self.cache = BonsaiTokenCache()
        atexit.register(write_cache_to_file, self.cache)

        retry_count = 1
        while True:
            try:
                self._app = PublicClientApplication(_AAD_CLIENT_ID,
                                                    authority=_AAD_AUTHORITY,
                                                    token_cache=self.cache)
                if self._app:
                    break
            except ConnectionError as e:
                log.info('ConnectionError on attempt {} to '
                         'create msal PublicClientApplication, '
                         'retrying...'.format(retry_count))
                if retry_count >= 5:
                    raise e
            retry_count += 1
Пример #16
0
    def _get_token_impl(self) -> dict:
        # try and obtain the refresh token from AzCli
        refresh_token = None
        token = None
        stored_token = self._get_azure_cli_auth_token()
        if TokenConstants.AZ_REFRESH_TOKEN in stored_token and TokenConstants.AZ_CLIENT_ID in stored_token and TokenConstants.AZ_AUTHORITY in stored_token:
            refresh_token = stored_token[TokenConstants.AZ_REFRESH_TOKEN]
            self._client_id = stored_token[TokenConstants.AZ_CLIENT_ID]
            self._authority_uri = stored_token[TokenConstants.AZ_AUTHORITY]
            self._username = stored_token[TokenConstants.AZ_USER_ID]
        else:
            raise KustoClientError("Unable to obtain a refresh token from Az-Cli")

        if self._msal_client is None:
            self._msal_client = PublicClientApplication(client_id=self._client_id, authority=self._authority_uri)

        if refresh_token is not None:
            token = self._msal_client.acquire_token_by_refresh_token(refresh_token, self._scopes)

        return self._valid_token_or_throw(token)
Пример #17
0
    def auth_callback():
        if request.args.get("state") != session.get("state"):
            return "Sign-in failed, state doesn't match.", 403
        if request.args.get("error"):
            return request.args.get("error"), 403
        if not request.args.get("code"):
            return "Sign-in failed, no auth code.", 403

        auth_client = PublicClientApplication(
            client_id=app.config["AUTH_CLIENT_ID"],
            authority=current_app.config["AUTH_CLIENT_TENANCY"])
        result = auth_client.acquire_token_by_auth_code_flow(
            auth_code_flow=session.get("auth_code_flow"),
            auth_response=request.args,
            scopes=current_app.config["AUTH_CLIENT_SCOPES"],
        )
        if result.get("error"):
            return "Sign-in failed.", 403
        if not result.get("access_token"):
            return "Sign-in failed, no access token.", 403

        session["access_token"] = result.get("access_token")
        return "Signed-in"
Пример #18
0
    def get_access_token(self):
        result = None

        app = PublicClientApplication(
            self.config['CLIENT_ID'],
            authority=self.config['AUTHORITY'],
        )

        accounts = app.get_accounts()

        if accounts:
            chosen_account = accounts[0]
            result = app.acquire_token_silent(self.config['scopes'], account=chosen_account)

        if not result:
            result = app.acquire_token_by_username_password(
                self.config['USERNAME'],
                self.config['SECRET'],
                scopes=self.config['scopes']
            )

            print(result)
        return result['access_token']
Пример #19
0
    def get_access_token(self):
        result = None

        app = PublicClientApplication(
            self.config['CLIENT_ID'],
            authority=self.config['AUTHORITY'],
        )

        accounts = app.get_accounts()

        if accounts:
            chosen_account = accounts[0]
            result = app.acquire_token_silent(self.config['scopes'],
                                              account=chosen_account)

        if not result:
            result = app.acquire_token_by_username_password(
                self.config['USERNAME'],
                self.config['SECRET'],
                scopes=self.config['scopes'])

            print(result)
        return result['access_token']
Пример #20
0
    def msal_connect(self):

        app = PublicClientApplication(self.client_id, authority=self.authority)

        result = None

        accounts = app.get_accounts()
        if accounts:
            # If so, you could then somehow display these accounts and let end user choose
            print("Pick the account you want to use to proceed:")
            for a in accounts:
                print(a["username"])
            # Assuming the end user chose this one
            chosen = accounts[0]
            # Now let's try to find a token in cache for this account
            result = app.acquire_token_silent(self.scopes, account=chosen)

        if not result:
            # So no suitable token exists in cache. Let's get a new one from AAD.
            result = app.acquire_token_by_username_password(self.username,
                                                            self.password,
                                                            scopes=self.scopes)
        return result
Пример #21
0
def TestInput(input_bytes):
    if len(input_bytes) < 32:
        return
    fdp = atheris.FuzzedDataProvider(input_bytes)
    authority = AuthorityBuilder(fdp.ConsumeString(50), fdp.ConsumeString(50))
    try:
        app = PublicClientApplication(
            client_id=fdp.ConsumeString(32),
            authority=authority,
            http_client=FuzzHttpClient(fdp)  # Use fake Fuzz HTTP client
        )
        app.get_accounts()
    except (ValueError, KeyError) as e:
        error_list = [
            "tenant_discovery_endpoint", "Invalid IPv6 URL",
            "should consist of an https url with a minimum of one segment in a path",
            "netloc"
        ]
        if not is_expected(error_list, str(e)):
            raise e

    cert = "-----BEGIN CERTIFICATE-----%s-----END CERTIFICATE-----" % fdp.ConsumeString(
        200)
    extract_certs(cert)
Пример #22
0
 def _get_client_application(self, **kwargs):
     tenant_id = resolve_tenant(self._tenant_id, **kwargs)
     if tenant_id not in self._client_applications:
         # CP1 = can handle claims challenges (CAE)
         capabilities = None if "AZURE_IDENTITY_DISABLE_CP1" in os.environ else [
             "CP1"
         ]
         self._client_applications[tenant_id] = PublicClientApplication(
             client_id=self._auth_record.client_id,
             authority="https://{}/{}".format(self._auth_record.authority,
                                              tenant_id),
             token_cache=self._cache,
             http_client=self._client,
             client_capabilities=capabilities)
     return self._client_applications[tenant_id]
Пример #23
0
def access_account(token):
    if not token:
        return ""
    else:
        ''' tenantid and appid are Azure AD internal data, 
            it is internal information, do not leave it exposed in the code, 
            it is here to use as an example I advise to have it recorded in a safe.'''

        appid = "your_app_id"
        tenantid = "yout_tenant_id"
        ''' The username and password encoding was used base64 but you can use one of your own.'''

        auth_decode = base64.b64decode(token).decode()
        username, password = auth_decode.split(":")

        if appid and tenantid:
            ''' O scopo você define dentro do Azure AD. '''
            scope = ["User.ReadBasic.All"]

            app = PublicClientApplication(
                appid,
                authority="https://login.microsoftonline.com/" + tenantid)

            result = None

            accounts = app.get_accounts(username=username)
            if accounts:
                logging.info(
                    "Account(s) exists in cache, probably with token too. Let's try."
                )
                result = app.acquire_token_silent(scope, account=accounts[0])

            if not result:
                logging.info(
                    "No suitable token exists in cache. Let's get a new one from AAD."
                )
                result = app.acquire_token_by_username_password(username,
                                                                password,
                                                                scopes=scope)
            ''' If the validation is successful it returns the token, otherwise it prints the errors found. '''

            if "access_token" in result:
                return result
            else:
                print(result.get("error"))
                print(result.get("error_description"))
                print(result.get("correlation_id"))
                if 65001 in result.get("error_codes", []):
                    print("Visit this to consent:",
                          app.get_authorization_request_url(scope))

                return ""
        else:
            return ""
Пример #24
0
    def CLIENT_AUTH(self) -> PublicClientApplication:
        """
        Azure auth provider (client)

        Uses the Microsoft Authentication Library (MSAL) for Python to simplify requesting access tokens from Azure.

        This is used for the client/editor component of this application, which is considered a 'public' client as this
        application runs on the user's device, and therefore isn't confidential.

        Note: The Flask Azure OAuth provider is used for the server/catalogue component, instantiated in the
        application factor method.

        :rtype PublicClientApplication
        :return: Microsoft Authentication Library Public Client application
        """
        return PublicClientApplication(client_id=self.AUTH_CLIENT_ID,
                                       authority=self.AUTH_CLIENT_TENANCY)
Пример #25
0
    def getConfidentialClientAccessToken(self) -> Optional[str]:
        # Initialise the app if not already exist
        if not self.app:
            logging.info("Initialise msal connection app")
            self.app = ConfidentialClientApplication(
                client_id=self.app_id,
                authority=self.authority,
                client_credential=self.app_secret)
        # try to get the token from cache if already exist
        result = self.app.acquire_token_silent(scopes=self.scopes,
                                               account=None)
        if not result:
            logging.info(
                "No suitable token exists in cache. Let's get a new one from AAD."
            )
            result = self.app.acquire_token_for_client(scopes=self.scopes)

        if "access_token" in result:
            return result["access_token"]
        return None
Пример #26
0
    def get_access_token(self):
        '''Get access token from cache or request new'''
        cache = SerializableTokenCache()
        if os.path.exists('token_cache.bin'):
            cache.deserialize(open('token_cache.bin', 'r').read())
        if cache.has_state_changed:
            atexit.register(
                lambda: open('token_cache.bin', 'w').write(cache.serialize()))

        app = PublicClientApplication(self.CLIENT_ID,
                                      authority=self.AUTHORITY,
                                      token_cache=cache)

        token_response = None
        accounts = app.get_accounts()
        if accounts:
            print("Pick the account you want to use to proceed:")
            for index, account in enumerate(accounts):
                print(index, account["username"])
            account_nr = int(input("Type number: "))
            chosen = accounts[account_nr]
            token_response = app.acquire_token_silent(["Notes.Read"],
                                                      account=chosen)

        if not token_response:
            print('Trying to get token...')
            flow = app.initiate_device_flow(scopes=["Notes.Read"])
            print(flow['message'])
            if 'enter the code ' in flow['message']:
                auth_code = flow['message'].split(
                    'enter the code ')[1].split()[0]
                pyperclip.copy(auth_code)
                print(f'Code {auth_code} has been copied to clipboard.')

            token_response = app.acquire_token_by_device_flow(flow)
        if "access_token" in token_response:
            return token_response["access_token"]
        else:
            print(token_response.get("error"))
            print(token_response.get("error_description"))
            print(token_response.get("correlation_id"))
from msal import PublicClientApplication
import requests
import uuid
import json

client_id = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX'  # Or App Id from Portal Azure
client_secret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
directory_id = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX'  # Also known as: tenant
authority = 'https://login.microsoftonline.com/' + directory_id
username = '******'  # Office365/Outlook Email account
result = None
graph_endpoint = 'https://graph.microsoft.com/v1.0{0}'

app = PublicClientApplication(client_id,
                              client_credential=None,
                              authority=authority)

# We now check the cache to see
# whether we already have some accounts that the end user already used to sign in before.
accounts = app.get_accounts()
if accounts:
    result = app.acquire_token_silent(config["scope"], account=username)

if not result:
    # So no suitable token exists in cache. Let's get a new one from AAD.
    flow = app.initiate_device_flow(scopes=["User.Read", "Calendars.Read"])
    print(flow)
    result = app.acquire_token_by_device_flow(flow)

if "access_token" in result:
    print(result["access_token"])  # Yay!
Пример #28
0
class AADClient(object):
    """
    This object uses the Microsoft Authentication Library for Python (MSAL)
    to log in and authenticate users using AAD.

    The only public method is get_access_token(), which returns an access token
    if one already exists in the cache, else it will fill the cache by
    prompting the user to log in.
    """

    def __init__(self, url: str):
        self._base_url = url
        self.cache = BonsaiTokenCache()
        atexit.register(write_cache_to_file, self.cache)

        retry_count = 1
        while True:
            try:
                self._app = PublicClientApplication(_AAD_CLIENT_ID,
                                                    authority=_AAD_AUTHORITY,
                                                    token_cache=self.cache)
                if self._app:
                    break
            except ConnectionError as e:
                log.info('ConnectionError on attempt {} to '
                         'create msal PublicClientApplication, '
                         'retrying...'.format(retry_count))
                if retry_count >= 5:
                    raise e
            retry_count += 1

    def _log_in_with_device_code(self) -> dict:
        """ Recommended login method. The user must open a browser to
            https://microsoft.com/devicelogin and enter a unique device code to
            begin authentication. """
        flow = self._app.initiate_device_flow(_AAD_SCOPE)
        print(flow["message"])
        sys.stdout.flush()  # needed to print on Windows
        return self._app.acquire_token_by_device_flow(flow)

    def _log_in_with_password(self) -> dict:
        """ This login method is less secure and should be used for
            automation only. """
        return self._app.acquire_token_by_username_password(
            os.environ['BONSAI_AAD_USER'],
            os.environ['BONSAI_AAD_PASSWORD'],
            _AAD_SCOPE)

    def _get_access_token_from_cache(self):
        """ This also does a token refresh if the access token has expired. """
        result = None
        accounts = self._app.get_accounts()
        if accounts:
            """ Bonsai config only gives us the short username, and token cache
            stores accounts by email address (e.g. soc-auto vs
            [email protected]). So, if there are multiple accounts, assume
            the first one for now. """
            chosen = accounts[0]
            result = self._app.acquire_token_silent(_AAD_SCOPE, account=chosen)
        return result

    def get_access_token(self):

        # attempt to get token from cache
        token = self._get_access_token_from_cache()
        if token:
            return 'Bearer {}'.format(token['access_token'])

        # no token found in cache, user must sign in and try again
        if (use_password_auth()):
            self._log_in_with_password()
        else:
            print('No access token found in cache, please sign in.')
            self._log_in_with_device_code()
        token = self._get_access_token_from_cache()
        if token:
            return "Bearer {}".format(token['access_token'])

        message = 'Error: could not fetch AAD access token after login.'
        raise AuthenticationError(message)

    def get_workspace(self):

        # make sure we have access token to request workspace
        auth_token = self.get_access_token()

        # get workspace, store to cache and return
        helper = AADRequestHelper(self._base_url, auth_token)
        self.workspace = helper.get_workspace()
        return self.workspace
Пример #29
0
class AADClient(object):
    """
    This object uses the Microsoft Authentication Library for Python (MSAL)
    to log in and authenticate users using AAD.

    The only public method is get_access_token(), which returns an access token
    if one already exists in the cache, else it will fill the cache by
    prompting the user to log in.
    """
    def __init__(self, tenant_id: Optional[str] = None):

        # cache file should be written to home directory
        home = os.path.expanduser('~')
        if home:
            self._cache_file = os.path.join(home, '.bonsaicache')
        else:
            raise RuntimeError('Unable to find home directory.')
        self.cache = TokenCache(self._cache_file)

        retry_count = 1

        effective_tenant_id = tenant_id if tenant_id is not None and tenant_id != 'None' else 'organizations'

        _AAD_AUTHORITY = 'https://login.microsoftonline.com/' + effective_tenant_id

        while True:
            try:
                self._app = PublicClientApplication(_AAD_CLIENT_ID,
                                                    authority=_AAD_AUTHORITY,
                                                    token_cache=self.cache)
                if self._app:
                    break
            except ConnectionError as e:
                log.info('ConnectionError on attempt {} to '
                         'create msal PublicClientApplication, '
                         'retrying...'.format(retry_count))
                if retry_count >= 5:
                    raise e
            retry_count += 1

    def _log_in_with_device_code(self) -> Dict[str, str]:
        """ Recommended login method. The user must open a browser to
            https://microsoft.com/devicelogin and enter a unique device code to
            begin authentication. """
        flow = self._app.initiate_device_flow(_AAD_SCOPE)
        print(flow["message"])
        sys.stdout.flush()  # needed to print on Windows
        return self._app.acquire_token_by_device_flow(flow)

    def _log_in_with_password(self) -> Dict[str, str]:
        """ This login method is less secure and should be used for
            automation only. """
        return self._app.acquire_token_by_username_password(
            os.environ['BONSAI_AAD_USER'], os.environ['BONSAI_AAD_PASSWORD'],
            _AAD_SCOPE)

    def _get_access_token_from_cache(self):
        """ This also does a token refresh if the access token has expired. """
        result = None
        accounts = self._app.get_accounts()
        if accounts:
            """ Bonsai config only gives us the short username, and token cache
            stores accounts by email address (e.g. soc-auto vs
            [email protected]). So, if there are multiple accounts, assume
            the first one for now. """
            chosen = accounts[0]
            result = self._app.acquire_token_silent(_AAD_SCOPE, account=chosen)
        return result

    def get_access_token(self):

        # attempt to get token from cache
        token = self._get_access_token_from_cache()
        if token:
            return 'Bearer {}'.format(token['access_token'])

        # no token found in cache, user must sign in and try again
        if use_password_auth():
            self._log_in_with_password()
        else:
            print('No access token found in cache, please sign in.')
            self._log_in_with_device_code()
        token = self._get_access_token_from_cache()
        if token:
            return "Bearer {}".format(token['access_token'])

        message = 'Error: could not fetch AAD access token after login.'
        raise AuthenticationError(message)
Пример #30
0
 def _init_impl(self):
     self._msal_client = PublicClientApplication(
         client_id=self._cloud_info.kusto_client_app_id,
         authority=self._cloud_info.authority_uri(self._auth),
         proxies=self._proxy_dict)
Пример #31
0
 def _init_impl(self):
     self._msal_client = PublicClientApplication(client_id=self._cloud_info.kusto_client_app_id, authority=self._auth)