コード例 #1
0
 def _refresh_creds(self):
     context = AuthenticationContext(self.authority_uri)
     self.config_data = context.acquire_token_with_refresh_token(
         self.config_data["refreshToken"], self.client_id, self.client_uri)
     if self.debug:
         print(f"got new token expiring {self.config_data['expiresOn']}")
         self._cache_creds()
    def __do_refresh_token(self):
        auth_context = AuthenticationContext(
            AzureTokenService.authority_url_format.format(self.__tenant_id))
        self.__token = auth_context.acquire_token_with_refresh_token(
            self.__token["refreshToken"], AzureTokenService.client_id,
            AzureTokenService.resource_url)
        self.__credentials = AADTokenCredentials(self.__token,
                                                 AzureTokenService.client_id)

        self.__update_refresh_token_timer()
コード例 #3
0
def ensure_tokens(client_id, tokens):
    expiresOn = parser.parse(tokens['expiresOn'])

    if expiresOn < datetime.now() + timedelta(minutes=10):
        ctx = AuthenticationContext(config.AUTHORITY_URL, api_version=None)

        return ctx.acquire_token_with_refresh_token(tokens['refreshToken'],
                                                    client_id, config.RESOURCE)

    return tokens
コード例 #4
0
def refresh_access_token(refresh_token):
    context = AuthenticationContext(authority_url)
    # function link
    token_response = context.acquire_token_with_refresh_token(
        refresh_token, user_parameters['client_id'],
        azure_databricks_resource_id)
    # print all the fields in the token_response
    for key in token_response.keys():
        print(str(key) + ': ' + str(token_response[key]))

    # the new 'refreshToken' and  'accessToken' will be returned
    return (token_response['refreshToken'], token_response['accessToken'])
コード例 #5
0
ファイル: mru.py プロジェクト: mevtorres/Azure-CLI
    def _get_v2_access_token(self, cli_ctx):
        from adal import AuthenticationContext

        refresh_token_obj = self.profile.get_refresh_token()

        refresh_token = refresh_token_obj[1]
        tenant = refresh_token_obj[3]
        # pylint: disable=protected-access
        client_id = self.profile.get_login_credentials()[0]._token_retriever()[2]['_clientId']

        authority = '{}/{}'.format(cli_ctx.cloud.endpoints.active_directory, tenant)
        context = AuthenticationContext(authority)
        return context.acquire_token_with_refresh_token(refresh_token,
                                                        client_id,
                                                        self.v2_media_api_resource).get('accessToken')
 def do_GET(self):
     if self.path == '/':
         self.send_response(307)
         login_url = 'http://localhost:{}/login'.format(PORT)
         self.send_header('Location', login_url)
         self.end_headers()
     elif self.path == '/login':
         auth_state = (''.join(random.SystemRandom()
                               .choice(string.ascii_uppercase + string.digits)
                               for _ in range(48)))
         cookie = Cookie.SimpleCookie()
         cookie['auth_state'] = auth_state
         authorization_url = TEMPLATE_AUTHZ_URL.format(
             sample_parameters['tenant'],
             sample_parameters['clientId'],
             REDIRECT_URI,
             auth_state,
             RESOURCE)
         self.send_response(307)
         self.send_header('Set-Cookie', cookie.output(header=''))
         self.send_header('Location', authorization_url)
         self.end_headers()
     elif self.path.startswith('/getAToken'):
         is_ok = True
         try:
             token_response = self._acquire_token()
             message = 'response: ' + json.dumps(token_response)
             #Later, if the access token is expired it can be refreshed.
             auth_context = AuthenticationContext(authority_url, api_version=None)
             token_response = auth_context.acquire_token_with_refresh_token(
                 token_response['refreshToken'],
                 sample_parameters['clientId'],
                 RESOURCE,
                 sample_parameters['clientSecret'])
             message = (message + '*** And here is the refresh response:' +
                        json.dumps(token_response))
         except ValueError as exp:
             message = str(exp)
             is_ok = False
         self._send_response(message, is_ok)
コード例 #7
0
 def do_GET(self):
     if self.path == '/':
         self.send_response(307)
         login_url = 'http://localhost:{}/login'.format(PORT)
         self.send_header('Location', login_url)
         self.end_headers()
     elif self.path == '/login':
         auth_state = (''.join(
             random.SystemRandom().choice(string.ascii_uppercase +
                                          string.digits)
             for _ in range(48)))
         cookie = Cookie.SimpleCookie()
         cookie['auth_state'] = auth_state
         authorization_url = TEMPLATE_AUTHZ_URL.format(
             sample_parameters['tenant'], sample_parameters['clientId'],
             REDIRECT_URI, auth_state, RESOURCE)
         self.send_response(307)
         self.send_header('Set-Cookie', cookie.output(header=''))
         self.send_header('Location', authorization_url)
         self.end_headers()
     elif self.path.startswith('/getAToken'):
         is_ok = True
         try:
             token_response = self._acquire_token()
             message = 'response: ' + json.dumps(token_response)
             #Later, if the access token is expired it can be refreshed.
             auth_context = AuthenticationContext(authority_url,
                                                  api_version=None)
             token_response = auth_context.acquire_token_with_refresh_token(
                 token_response['refreshToken'],
                 sample_parameters['clientId'], RESOURCE,
                 sample_parameters['clientSecret'])
             message = (message + '*** And here is the refresh response:' +
                        json.dumps(token_response))
         except ValueError as exp:
             message = str(exp)
             is_ok = False
         self._send_response(message, is_ok)
 def do_GET(self):
     if self.path == "/":
         self.send_response(307)
         login_url = "http://localhost:{}/login".format(PORT)
         self.send_header("Location", login_url)
         self.end_headers()
     elif self.path == "/login":
         auth_state = "".join(
             random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(48)
         )
         cookie = Cookie.SimpleCookie()
         cookie["auth_state"] = auth_state
         authorization_url = TEMPLATE_AUTHZ_URL.format(
             sample_parameters["tenant"], sample_parameters["clientId"], REDIRECT_URI, auth_state, RESOURCE
         )
         self.send_response(307)
         self.send_header("Set-Cookie", cookie.output(header=""))
         self.send_header("Location", authorization_url)
         self.end_headers()
     elif self.path.startswith("/getAToken"):
         is_ok = True
         try:
             token_response = self._acquire_token()
             message = "response: " + json.dumps(token_response)
             # Later, if the access token is expired it can be refreshed.
             auth_context = AuthenticationContext(authority_url)
             token_response = auth_context.acquire_token_with_refresh_token(
                 token_response["refreshToken"],
                 sample_parameters["clientId"],
                 RESOURCE,
                 sample_parameters["clientSecret"],
             )
             message = message + "*** And here is the refresh response:" + json.dumps(token_response)
         except ValueError as exp:
             message = str(exp)
             is_ok = False
         self._send_response(message, is_ok)
コード例 #9
0
def get_a_token():
    '''Handle Azure AD callback.
    Get authorization code from Azure AD response. Use code to get access
    token and validate. If all is good, log user in.
    '''
    try:
        token_response = _aquire_token()
        auth_context = AuthenticationContext(AUTHORITY_URL)
        token_response = auth_context.acquire_token_with_refresh_token(
            token_response['refreshToken'],
            config.CLIENT_ID,
            config.RESOURCE,
            config.CLIENT_SECRET)
        decoded = _validate_access_token(token_response['accessToken'])
        if not _validate_email_domains(decoded['unique_name']):
            raise
        if not _validate_user_exists_in_ckan(
            decoded['unique_name']
            .lower()
            .replace('.', '_')
            .split('@')[0],
            decoded['unique_name']):
            raise

        # By now token is valid and user is valid so login.
        # TODO: change this to set c.user in identify() in the future.
        resp = _ckan_authenticate(
            decoded['unique_name']
            .lower()
            .replace('.', '_')
            .split('@')[0])
    except Exception as e:
        log.error('Exception raised. Unable to authenticate. {}'
                  .format(repr(e)))
        toolkit.abort(403, 'Not authorized.')

    return resp
コード例 #10
0
class _MyAadHelper(object):
    def __init__(self,
                 kcsb,
                 default_clientid,
                 adal_context=None,
                 adal_context_sso=None,
                 **options):
        global global_adal_context
        global global_adal_context_sso

        # to provide stickiness, to avoid switching tokens when not required
        self._current_token = None
        self._current_adal_context = None
        self._current_authentication_method = None
        self._token_claims_cache = (None, None)

        # options are freezed for authentication when object is created,
        # to eliminate the need to specify auth option on each query, and to modify behavior on exah query
        self._options = {**options}

        # track warning to avoid repeating
        self._displayed_warnings = []

        url = urlparse(kcsb.data_source)
        self._resource = f"{url.scheme}://{url.hostname}"

        self._authority = kcsb.authority_id or "common"

        self._aad_login_url = self._get_aad_login_url(
            kcsb.conn_kv.get(ConnStrKeys.AAD_URL))

        self._set_adal_context(adal_context=adal_context,
                               adal_context_sso=adal_context_sso)

        self._client_id = kcsb.application_client_id or default_clientid

        self._username = None
        if all([kcsb.aad_user_id, kcsb.password]):
            self._authentication_method = AuthenticationMethod.aad_username_password
            self._username = kcsb.aad_user_id
            self._password = kcsb.password
        elif all([kcsb.application_client_id, kcsb.application_key]):
            self._authentication_method = AuthenticationMethod.aad_application_key
            self._client_secret = kcsb.application_key
        elif all([
                kcsb.application_client_id, kcsb.application_certificate,
                kcsb.application_certificate_thumbprint
        ]):
            self._authentication_method = AuthenticationMethod.aad_application_certificate
            self._certificate = kcsb.application_certificate
            self._thumbprint = kcsb.application_certificate_thumbprint
        else:
            self._authentication_method = AuthenticationMethod.aad_device_login
            self._username = kcsb.aad_user_id  # optional

    def acquire_token(self):
        """Acquire tokens from AAD."""
        previous_token = self._current_token
        try:
            if self._current_token is not None:
                self._current_token = self._validate_and_refresh_token(
                    self._current_token)

            if self._current_token is None:
                self._current_authentication_method = None
                self._current_adal_context = None

            if self._current_token is None:
                if self._options.get("try_token") is not None:
                    token = self._get_aux_token(
                        token=self._options.get("try_token"))
                    self._current_token = self._validate_and_refresh_token(
                        token)

            if self._current_token is None:
                if self._options.get("try_msi") is not None:
                    token = self._get_msi_token(
                        msi_params=self._options.get("try_msi"))
                    self._current_token = self._validate_and_refresh_token(
                        token)

            if self._current_token is None:
                if self._options.get(
                        "try_azcli_login_subscription") is not None:
                    token = self._get_azcli_token(
                        subscription=self._options.get(
                            "try_azcli_login_subscription"))
                    self._current_token = self._validate_and_refresh_token(
                        token)

            if self._current_token is None:
                if self._options.get("try_azcli_login"):
                    token = self._get_azcli_token()
                    self._current_token = self._validate_and_refresh_token(
                        token)

            if self._current_token is None:
                if self._adal_context_sso is not None:
                    token = self._get_adal_sso_token()
                    self._current_token = self._validate_and_refresh_token(
                        token)

            if self._current_token is None:
                if self._adal_context is not None:
                    token = self._get_adal_token()
                    self._current_token = self._validate_and_refresh_token(
                        token)

            if self._current_token is None:
                token = None
                self._current_authentication_method = self._authentication_method
                self._current_adal_context = self._adal_context_sso or self._adal_context

                if self._authentication_method is AuthenticationMethod.aad_username_password:
                    logger().debug(
                        f"_MyAadHelper::acquire_token - aad/user-password - resource: '{self._resource}', username: '******', password: '******', client: '{self._client_id}'"
                    )
                    token = self._current_adal_context.acquire_token_with_username_password(
                        self._resource, self._username, self._password,
                        self._client_id)

                elif self._authentication_method is AuthenticationMethod.aad_application_key:
                    logger().debug(
                        f"_MyAadHelper::acquire_token - aad/client-secret - resource: '{self._resource}', client: '{self._client_id}', secret: '...'"
                    )
                    token = self._current_adal_context.acquire_token_with_client_credentials(
                        self._resource, self._client_id, self._client_secret)

                elif self._authentication_method is AuthenticationMethod.aad_application_certificate:
                    logger().debug(
                        f"_MyAadHelper::acquire_token - aad/client-certificate - resource: '{self._resource}', client: '{self._client_id}', _certificate: '...', thumbprint: '{self._thumbprint}'"
                    )
                    token = self._current_adal_context.acquire_token_with_client_certificate(
                        self._resource, self._client_id, self._certificate,
                        self._thumbprint)

                elif self._authentication_method is AuthenticationMethod.aad_device_login:
                    logger().debug(
                        f"_MyAadHelper::acquire_token - aad/code - resource: '{self._resource}', client: '{self._client_id}'"
                    )
                    code: dict = self._current_adal_context.acquire_user_code(
                        self._resource, self._client_id)
                    url = code[
                        OAuth2DeviceCodeResponseParameters.VERIFICATION_URL]
                    device_code = code[
                        OAuth2DeviceCodeResponseParameters.USER_CODE].strip()

                    device_code_login_notification = self._options.get(
                        "device_code_login_notification")
                    if device_code_login_notification == "auto":
                        if self._options.get("notebook_app") in ["ipython"]:
                            device_code_login_notification = "popup_interaction"
                        elif self._options.get("notebook_app") in [
                                "visualstudiocode", "azuredatastudio"
                        ]:
                            device_code_login_notification = "popup_interaction"
                        elif self._options.get("notebook_app") in ["nteract"]:

                            if self._options.get("kernel_location") == "local":
                                # ntreact cannot execute authentication script, workaround using temp_file_server webbrowser
                                if self._options.get(
                                        "temp_files_server_address"
                                ) is not None:
                                    import urllib.parse
                                    indirect_url = f'{self._options.get("temp_files_server_address")}/webbrowser?url={urllib.parse.quote(url)}&kernelid={self._options.get("kernel_id")}'
                                    url = indirect_url
                                    device_code_login_notification = "popup_interaction"
                                else:
                                    device_code_login_notification = "browser"
                            else:
                                device_code_login_notification = "terminal"
                        else:
                            device_code_login_notification = "button"

                    if (self._options.get("kernel_location") == "local"
                            or device_code_login_notification in ["browser"] or
                        (device_code_login_notification == "popup_interaction"
                         and self._options.get("popup_interaction")
                         == "webbrowser_open_at_kernel")):
                        # copy code to local clipboard
                        import pyperclip
                        pyperclip.copy(device_code)

                    # if  self._options.get("notebook_app")=="papermill" and self._options.get("login_code_destination") =="browser":
                    #     raise Exception("error: using papermill without an email specified is not supported")
                    if device_code_login_notification == "email":
                        params = Parser.parse_and_get_kv_string(
                            self._options.get(
                                'device_code_notification_email'), {})
                        email_notification = EmailNotification(**params)
                        subject = f"Kqlmagic device_code {device_code} authentication (context: {email_notification.context})"
                        resource = self._resource.replace(
                            "://", ":// "
                        )  # just to make sure it won't be replace in email by safelinks
                        email_message = f"Device_code: {device_code}\n\nYou are asked to authorize access to resource: {resource}\n\nOpen the page {url} and enter the code {device_code} to authenticate\n\nKqlmagic"
                        email_notification.send_email(subject, email_message)
                        info_message = f"An email was sent to {email_notification.send_to} with device_code {device_code} to authenticate"
                        Display.showInfoMessage(
                            info_message,
                            display_handler_name='acquire_token',
                            **self._options)

                    elif device_code_login_notification == "browser":
                        # this print is not for debug
                        print(code[OAuth2DeviceCodeResponseParameters.MESSAGE])
                        webbrowser.open(
                            code[OAuth2DeviceCodeResponseParameters.
                                 VERIFICATION_URL])

                    elif device_code_login_notification == "terminal":
                        # this print is not for debug
                        print(code[OAuth2DeviceCodeResponseParameters.MESSAGE])

                    elif device_code_login_notification == "popup_interaction":
                        before_text = f"<b>{device_code}</b>"
                        button_text = "Copy code to clipboard and authenticate"
                        # before_text = f"Copy code: {device_code} to verification url: {url} and "
                        # button_text='authenticate'
                        # Display.showInfoMessage(f"Copy code: {device_code} to verification url: {url} and authenticate", display_handler_name='acquire_token', **options)
                        Display.show_window(
                            'verification_url',
                            url,
                            button_text=button_text,
                            # palette=Display.info_style,
                            before_text=before_text,
                            display_handler_name='acquire_token',
                            **self._options)

                    else:  # device_code_login_notification == "button":
                        html_str = (f"""<!DOCTYPE html>
                            <html><body>

                            <!-- h1 id="user_code_p"><b>{device_code}</b><br></h1-->

                            <input  id="kql_MagicCodeAuthInput" type="text" readonly style="font-weight: bold; border: none;" size = '{str(len(device_code))}' value='{device_code}'>

                            <button id='kql_MagicCodeAuth_button', onclick="this.style.visibility='hidden';kql_MagicCodeAuthFunction()">Copy code to clipboard and authenticate</button>

                            <script>
                            var kql_MagicUserCodeAuthWindow = null;
                            function kql_MagicCodeAuthFunction() {{
                                /* Get the text field */
                                var copyText = document.getElementById("kql_MagicCodeAuthInput");

                                /* Select the text field */
                                copyText.select();

                                /* Copy the text inside the text field */
                                document.execCommand("copy");

                                /* Alert the copied text */
                                // alert("Copied the text: " + copyText.value);

                                var w = screen.width / 2;
                                var h = screen.height / 2;
                                params = 'width='+w+',height='+h
                                kql_MagicUserCodeAuthWindow = window.open('{url}', 'kql_MagicUserCodeAuthWindow', params);

                                // TODO: save selected cell index, so that the clear will be done on the lince cell
                            }}
                            </script>

                            </body></html>""")
                        Display.show_html(html_str,
                                          display_handler_name='acquire_token',
                                          **self._options)

                    try:
                        token = self._current_adal_context.acquire_token_with_device_code(
                            self._resource, code, self._client_id)
                        logger().debug(
                            f"_MyAadHelper::acquire_token - got token - resource: '{self._resource}', client: '{self._client_id}', token type: '{type(token)}'"
                        )
                        self._username = self._username or token.get(
                            TokenResponseFields.USER_ID)

                    finally:
                        html_str = """<!DOCTYPE html>
                            <html><body><script>

                                // close authentication window
                                if (kql_MagicUserCodeAuthWindow && kql_MagicUserCodeAuthWindow.opener != null && !kql_MagicUserCodeAuthWindow.closed) {
                                    kql_MagicUserCodeAuthWindow.close()
                                }
                                // TODO: make sure, you clear the right cell. BTW, not sure it is a must to do any clearing

                                // clear output cell
                                Jupyter.notebook.clear_output(Jupyter.notebook.get_selected_index())

                                // TODO: if in run all mode, move to last cell, otherwise move to next cell
                                // move to next cell

                            </script></body></html>"""

                        Display.show_html(html_str,
                                          display_handler_name='acquire_token',
                                          **self._options)

                self._current_token = self._validate_and_refresh_token(token)

            if self._current_token is None:
                raise AuthenticationError("No valid token.")

            if self._current_token != previous_token:
                self._warn_token_diff_from_conn_str()
            else:
                logger().debug(
                    f"_MyAadHelper::acquire_token - valid token exist - resource: '{self._resource}', username: '******', client: '{self._client_id}'"
                )

            return self._create_authorization_header()
        except Exception as e:
            kwargs = self._get_authentication_error_kwargs()
            raise AuthenticationError(e, **kwargs)

    # def email_format(self, dest):
    #     return re.match( r'[\w\.-]+@[\w\.-]+(\.[\w]+)+', dest)

    # def check_email_params(self, port, smtp_server, sender_email, receiver_email, password):
    #     if port and smtp_server and sender_email and receiver_email and password:
    #         if self.email_format(sender_email) and self.email_format(receiver_email):
    #             return True
    #     return False

    # def send_email(self, message, key_vals):

    #     port = key_vals.get("smtpport")
    #     smtp_server = key_vals.get("smtpendpoint")
    #     sender_email = key_vals.get("sendfrom")

    #     receiver_email = key_vals.get("sendto")

    #     password = key_vals.get("sendfrompassword")

    #     if not self.check_email_params(port,smtp_server, sender_email, receiver_email, password):
    #         raise ValueError("""
    #             cannot send login code to email because of missing or invalid environmental parameters.
    #             Set KQLMAGIC_CODE_NOTIFICATION_EMAIL in the following way: SMTPEndPoint: \" email server\"; SMTPPort: \"email port\";
    #             sendFrom: \"sender email address \"; sendFromPassword: \"email address password \"; sendTo:\" email address to send to\"""" )

    #     # context = ssl.create_default_context()
    #     # with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:

    #     with smtplib.SMTP(smtp_server, port) as server:
    #         server.starttls()
    #         server.login(sender_email, password)
    #         server.sendmail(sender_email, receiver_email, "\n"+message)

    #
    # Assume OAuth2 format (e.g. MSI Token) too
    #
    def _get_token_access_token(self,
                                token: dict,
                                default_access_token: str = None) -> str:
        return token.get(TokenResponseFields.ACCESS_TOKEN) or token.get(
            OAuth2TokenFields.ACCESS_TOKEN) or default_access_token

    def _get_token_client_id(self,
                             token: dict,
                             default_client_id: str = None) -> str:
        return token.get(TokenResponseFields._CLIENT_ID) or token.get(
            OAuth2TokenFields.CLIENT_ID) or default_client_id

    def _get_token_expires_on(self,
                              token: dict,
                              default_expires_on: str = None) -> str:
        expires_on = default_expires_on
        if token.get(TokenResponseFields.EXPIRES_ON) is not None:
            expires_on = token.get(TokenResponseFields.EXPIRES_ON)
        elif token.get(OAuth2TokenFields.EXPIRES_ON) is not None:
            # The date is represented as the number of seconds from "1970-01-01T0:0:0Z UTC" (corresponds to the token's exp claim).
            expires_on = time.strftime(
                "%Y-%m-%d %H:%M:%S",
                time.localtime(token.get(OAuth2TokenFields.EXPIRES_ON)))
        return expires_on

    def _get_token_not_before(self,
                              token: dict,
                              default_not_before: str = None) -> str:
        not_before = default_not_before
        if token.get(OAuth2TokenFields.NOT_BEFORE) is not None:
            # The date is represented as the number of seconds from "1970-01-01T0:0:0Z UTC" (corresponds to the token's nbf claim).
            not_before = time.strftime(
                "%Y-%m-%d %H:%M:%S",
                time.localtime(token.get(OAuth2TokenFields.NOT_BEFORE)))
        return not_before

    def _get_token_token_type(self,
                              token: dict,
                              default_token_type: str = None) -> str:
        return token.get(TokenResponseFields.TOKEN_TYPE) or token.get(
            OAuth2TokenFields.TOKEN_TYPE) or default_token_type

    def _get_token_resource(self,
                            token: dict,
                            default_resource: str = None) -> str:
        return token.get(TokenResponseFields.RESOURCE) or token.get(
            OAuth2TokenFields.RESOURCE) or default_resource

    def _get_token_user_id(self,
                           token: dict,
                           default_user_id: str = None) -> str:
        return token.get(TokenResponseFields.USER_ID) or default_user_id

    def _get_token_refresh_token(self,
                                 token: dict,
                                 default_refresh_token: str = None) -> str:
        return token.get(TokenResponseFields.REFRESH_TOKEN) or token.get(
            OAuth2TokenFields.REFRESH_TOKEN) or default_refresh_token

    def _get_token_id_token(self,
                            token: dict,
                            default_id_token: str = None) -> str:
        return token.get(OAuth2TokenFields.ID_TOKEN) or default_id_token

    def _get_token_authority(self,
                             token: dict,
                             default_authority: str = None) -> str:
        return token.get(TokenResponseFields._AUTHORITY) or default_authority

    def _create_authorization_header(self) -> str:
        "create content for http authorization header"
        access_token = self._get_token_access_token(self._current_token)
        if access_token is None:
            raise AuthenticationError(
                "Not a valid token, property 'access_token' is not present.")

        token_type = self._get_token_token_type(self._current_token)
        if token_type is None:
            raise AuthenticationError(
                "Unable to determine the token type. Neither 'tokenType' nor 'token_type' property is present."
            )

        return f"{token_type} {access_token}"

    def _get_token_claims(self, token: str) -> dict:
        "get the claims from the token. To optimize it caches the last token/claims"
        claims_token, claims = self._token_claims_cache
        if token == claims_token:
            return claims
        claims = {}
        try:
            claims = jwt.decode(self._get_token_id_token(token)
                                or self._get_token_access_token(token),
                                verify=False)
        except:
            pass
        self._token_claims_cache = (token, claims)
        return claims

    def _get_username_from_token(self, token: str) -> str:
        "retrieves username from in id token or access token claims"
        claims = self._get_token_claims(
            self._get_token_id_token(token)
            or self._get_token_access_token(token))
        username = claims.get("unique_name") or claims.get(
            "upn") or claims.get("email") or claims.get("sub")
        return username

    def _get_expires_on_from_token(self, token: str) -> str:
        "retrieve expires_on from access token claims"
        expires_on = None
        claims = self._get_token_claims(self._get_token_access_token(token))
        exp = claims.get("exp")
        if exp is not None:
            expires_on = time.strftime("%Y-%m-%d %H:%M:%S",
                                       time.localtime(exp))
        return expires_on

    def _get_not_before_from_token(self, token: str) -> str:
        "retrieve not_before from access token claims"
        not_before = None
        claims = self._get_token_claims(self._get_token_access_token(token))
        nbf = claims.get("nbf")
        if nbf is not None:
            not_before = time.strftime("%Y-%m-%d %H:%M:%S",
                                       time.localtime(nbf))
        return not_before

    def _get_client_id_from_token(self, token: str) -> str:
        "retrieve client_id from access token claims"
        claims = self._get_token_claims(self._get_token_access_token(token))
        client_id = claims.get("client_id") or claims.get(
            "appid") or claims.get("azp")
        return client_id

    def _get_resources_from_token(self, token: str) -> list:
        "retrieve resource list from access token claims"
        resources = None
        claims = self._get_token_claims(self._get_token_access_token(token))
        resources = claims.get("aud")
        if type(resources) == str:
            resources = [resources]
        return resources

    def _get_authority_from_token(self, token: str) -> str:
        "retrieve authority_uri from access token claims"
        authority_uri = None
        try:
            claims = self._get_token_claims(
                self._get_token_access_token(token))
            tenant_id = claims.get("tid")
            issuer = claims.get("iss")

            if tenant_id is None and issuer is not None and issuer.startswith(
                    "http"):
                from urllib.parse import urlparse
                url_obj = urlparse(issuer)
                tenant_id = url_obj.path

            if tenant_id is not None:
                if tenant_id.startswith("http"):
                    authority_uri = tenant_id
                else:
                    if tenant_id.startswith("/"):
                        tenant_id = tenant_id[1:]
                    if tenant_id.endswith("/"):
                        tenant_id = tenant_id[:-1]
                    authority_uri = f"{self._aad_login_url}/{tenant_id}"
        except:
            pass

        return authority_uri

    def _get_adal_token(self) -> str:
        "retrieve token from adal cache"
        token = None
        self._current_authentication_method = self._authentication_method
        try:
            self._current_adal_context = self._adal_context
            token = self._current_adal_context.acquire_token(
                self._resource, self._username, self._client_id)
        except:
            pass
        logger().debug(
            f"_MyAadHelper::_get_adal_token {'failed' if token is None else 'succeeded'} to get token"
        )
        return token

    def _get_adal_sso_token(self) -> str:
        "retrieve token from adal sso cache"
        token = None
        self._current_authentication_method = self._authentication_method
        try:
            self._current_adal_context = self._adal_context_sso
            token = self._current_adal_context.acquire_token(
                self._resource, self._username, self._client_id)
        except:
            pass
        logger().debug(
            f"_MyAadHelper::_get_adal_sso_token {'failed' if token is None else 'succeeded'} to get token"
        )
        return token

    def _get_aux_token(self, token: str) -> str:
        "retrieve token from aux token"
        self._current_authentication_method = AuthenticationMethod.aux_token
        try:
            token = token
        except:
            pass
        logger().debug(
            f"_MyAadHelper::_get_aux_token {'failed' if token is None else 'succeeded'} to get token"
        )
        return token

    def _get_azcli_token(self, subscription: str = None) -> str:
        "retrieve token from azcli login"
        token = None
        tenant = self._authority if subscription is None else None
        self._current_authentication_method = self._current_authentication_method = AuthenticationMethod.azcli_login_subscription if subscription is not None else AuthenticationMethod.azcli_login
        try:
            from azure.identity import AzureCliCredential
            try:
                credential = AzureCliCredential()
                access_token = credential.get_token(self._resource)
                expires_datetime = datetime.fromtimestamp(
                    access_token.expires_on)
                token = {
                    'accessToken': access_token.token,
                    'expiresOn':
                    expires_datetime.strftime("%Y-%m-%d %H:%M:%S.%f"),
                    'tokenType': 'Bearer',
                }
            except:
                pass
        except [ImportError, ModuleNotFoundError]:
            raise AuthenticationError(
                "Azure CLI authentication requires 'azure-cli-core' to be installed."
            )
        except:
            pass
        logger().debug(
            f"_MyAadHelper::_get_azcli_token {'failed' if token is None else 'succeeded'} to get token - subscription: '{subscription}', tenant: '{tenant}'"
        )
        return token

    def _get_msi_token(self, msi_params={}) -> str:
        "retrieve token from managed service identity"
        token = None
        self._current_authentication_method = AuthenticationMethod.managed_service_identity
        try:
            from msrestazure.azure_active_directory import MSIAuthentication
            try:
                # allow msi_params to overrite the connection string resource
                credentials = MSIAuthentication(**{
                    "resource": self._resource,
                    **msi_params
                })
                token = credentials.token
            except:
                pass
        except [ImportError, ModuleNotFoundError]:
            raise AuthenticationError(
                "MSI authentication requires 'msrestazure' to be installed.")
        except:
            pass
        logger().debug(
            f"_MyAadHelper::_get_msi_token {'failed' if token is None else 'succeeded'} to get token - msi_params: '{msi_params}'"
        )
        return token

    def _validate_and_refresh_token(self, token: str) -> str:
        "validate token is valid to use now. Now is between not_before and expires_on. If exipred try to refresh"
        valid_token = None
        if token is not None:
            resource = self._get_token_resource(token) or self._resource
            not_before = self._get_token_not_before(
                token) or self._get_not_before_from_token(token)
            if not_before is not None:
                not_before_datetime = dateutil.parser.parse(not_before)
                current_datetime = datetime.now() - timedelta(minutes=1)
                if not_before_datetime > current_datetime:
                    logger().debug(
                        f"_MyAadHelper::_validate_and_refresh_token - failed - token can be used not before {not_before} - resource: '{resource}'"
                    )
                    self._warn_on_token_validation_failure(
                        f"access token cannot be used before {not_before}")
                    return None

            expires_on = self._get_token_expires_on(
                token) or self._get_expires_on_from_token(token)
            if expires_on is not None:
                expiration_datetime = dateutil.parser.parse(expires_on)
            else:
                expiration_datetime = datetime.now() + timedelta(minutes=30)

            current_datetime = datetime.now() + timedelta(minutes=1)
            if expiration_datetime > current_datetime:
                valid_token = token
                logger().debug(
                    f"_MyAadHelper::_validate_and_refresh_token - succeeded, no need to refresh yet, expires on {expires_on} - resource: '{resource}'"
                )
            else:
                logger().debug(
                    f"_MyAadHelper::_validate_and_refresh_token - token expires on {expires_on} need to refresh - resource: '{resource}'"
                )
                refresh_token = self._get_token_refresh_token(token)
                if refresh_token is not None:
                    try:
                        if self._current_adal_context is None:
                            authority_uri = self._get_token_authority(
                                token) or self._get_authority_from_token(
                                    token) or self._authority_uri
                            self._current_adal_context = AuthenticationContext(
                                authority_uri, cache=None)
                        client_id = self._get_token_client_id(
                            token) or self._get_client_id_from_token(
                                token) or self._client_id
                        valid_token = self._current_adal_context.acquire_token_with_refresh_token(
                            refresh_token, client_id, resource)
                    except Exception as e:
                        self._warn_on_token_validation_failure(
                            f"access token expired on {expires_on}, failed to refresh access token, Exception: {e}"
                        )

                    logger().debug(
                        f"_MyAadHelper::_validate_and_refresh_token - {'failed' if token is None else 'succeeded'} to refresh token - resource: '{resource}'"
                    )
                else:
                    logger().debug(
                        f"_MyAadHelper::_validate_and_refresh_token - failed to refresh expired token, token doesn't contain refresh token - resource: '{resource}'"
                    )
                    self._warn_on_token_validation_failure(
                        f"access token expired on {expires_on}, and token entry has no refresh_token"
                    )

        return valid_token

    def _set_adal_context(self, adal_context=None, adal_context_sso=None):
        "set the adal context"
        self._authority_uri = f"{self._aad_login_url}/{self._authority}"

        self._adal_context = adal_context
        if self._adal_context is None:
            if global_adal_context.get(self._authority_uri) is None:
                global_adal_context[
                    self._authority_uri] = AuthenticationContext(
                        self._authority_uri, cache=None)
            self._adal_context = global_adal_context.get(self._authority_uri)

        self._adal_context_sso = None
        if self._options.get("enable_sso"):
            self._adal_context_sso = adal_context_sso
            if self._adal_context_sso is None:
                if global_adal_context_sso.get(self._authority_uri) is None:
                    cache = AdalTokenCache.get_cache(self._authority_uri,
                                                     **self._options)
                    if cache is not None:
                        global_adal_context_sso[
                            self._authority_uri] = AuthenticationContext(
                                self._authority_uri, cache=cache)
                self._adal_context_sso = global_adal_context_sso.get(
                    self._authority_uri)

    def _get_aad_login_url(self, aad_login_url=None):
        if aad_login_url is None:
            cloud = self._options.get("cloud")
            aad_login_url = _CLOUD_AAD_URLS.get(cloud)
            if aad_login_url is None:
                raise KqlEngineError(
                    f"AAD is not known for this cloud '{cloud}', please use aadurl property in connection string."
                )
        return aad_login_url

    def _warn_on_token_validation_failure(self, message) -> None:
        if self._options.get("auth_token_warnings"):
            if self._current_authentication_method is not None and message is not None:
                warn_message = f"Can't use '{self._current_authentication_method}' token entry, {message}'"
                Display.showWarningMessage(
                    warn_message,
                    display_handler_name='acquire_token',
                    **self._options)

    def _warn_token_diff_from_conn_str(self) -> None:
        if self._options.get("auth_token_warnings"):
            token = self._current_token
            if token is not None:
                # to avoid more than one warning per connection, keep track of already displayed warnings
                access_token = self._get_token_access_token(token)
                key = hash((access_token))
                if key in self._displayed_warnings:
                    return
                else:
                    self._displayed_warnings.append(key)

                token_username = self._get_token_user_id(
                    token) or self._get_username_from_token(token)
                if token_username is not None and self._username is not None and token_username != self._username:
                    warn_message = f"authenticated username '{token_username}' is different from connectiion string username '{self._username}'"
                    Display.showWarningMessage(
                        warn_message,
                        display_handler_name='acquire_token',
                        **self._options)

                token_authority_uri = self._get_token_authority(
                    token) or self._get_authority_from_token(token)
                if token_authority_uri != self._authority_uri and not self._authority_uri.endswith(
                        "/common") and not token_authority_uri.endswith(
                            "/common"):
                    warn_message = f"authenticated authority '{token_authority_uri}' is different from connectiion string authority '{self._authority_uri}'"
                    Display.showWarningMessage(
                        warn_message,
                        display_handler_name='acquire_token',
                        **self._options)

                token_client_id = self._get_token_client_id(
                    token) or self._get_client_id_from_token(token)
                if token_client_id is not None and self._client_id is not None and token_client_id != self._client_id:
                    warn_message = f"authenticated client_id '{token_client_id}' is different from connectiion string client_id '{self._client_id}'"
                    Display.showWarningMessage(
                        warn_message,
                        display_handler_name='acquire_token',
                        **self._options)

                token_resources = self._get_token_resource(
                    token) or self._get_resources_from_token(token)
                if type(token_resources) == str:
                    token_resources = [token_resources]
                if token_resources is not None and self._resource is not None and self._resource not in token_resources:
                    warn_message = f"authenticated resources '{token_resources}' does not include connectiion string resource '{self._resource}'"
                    Display.showWarningMessage(
                        warn_message,
                        display_handler_name='acquire_token',
                        **self._options)

    def _get_authentication_error_kwargs(self):
        " collect info for AuthenticationError exception and raise it"
        kwargs = {}
        if self._current_authentication_method is AuthenticationMethod.aad_username_password:
            kwargs = {"username": self._username, "client_id": self._client_id}
        elif self._current_authentication_method is AuthenticationMethod.aad_application_key:
            kwargs = {"client_id": self._client_id}
        elif self._current_authentication_method is AuthenticationMethod.aad_device_login:
            kwargs = {"client_id": self._client_id}
        elif self._current_authentication_method is AuthenticationMethod.aad_application_certificate:
            kwargs = {
                "client_id": self._client_id,
                "thumbprint": self._thumbprint
            }
        elif self._current_authentication_method is AuthenticationMethod.managed_service_identity:
            kwargs = self._options.get("try_msi")
        elif self._current_authentication_method is AuthenticationMethod.azcli_login:
            pass
        elif self._current_authentication_method is AuthenticationMethod.azcli_login_subscription:
            kwargs = {
                "subscription":
                self._options.get("try_azcli_login_subscription")
            }
        elif self._current_authentication_method is AuthenticationMethod.aux_token:
            token_dict = {}
            for key in self._options.get("try_token"):
                if key in [
                        TokenResponseFields.ACCESS_TOKEN,
                        OAuth2TokenFields.ACCESS_TOKEN,
                        TokenResponseFields.REFRESH_TOKEN,
                        OAuth2TokenFields.REFRESH_TOKEN,
                        OAuth2TokenFields.ID_TOKEN
                ]:
                    token_dict[key] = f"..."
                else:
                    token_dict[key] = self._options.get("try_token")[key]
            kwargs = token_dict
        else:
            pass

        authority = None
        if self._current_adal_context is not None:
            authority = self._current_adal_context.authority.url
        elif self._current_authentication_method == self._authentication_method:
            authority = self._authority_uri
        elif self._current_token is not None:
            authority = self._get_authority_from_token(self._current_token)
        else:
            authority = authority or self._current_authentication_method

        if self._current_adal_context is not None:
            authority = self._current_adal_context.authority.url
        elif self._current_token is not None:
            authority = self._get_authority_from_token(self._current_token)
        if authority is None:
            if self._current_authentication_method in [
                    AuthenticationMethod.managed_service_identity,
                    AuthenticationMethod.azcli_login_subscription,
                    AuthenticationMethod.aux_token
            ]:
                authority = self._current_authentication_method
            else:
                authority = self._authority_uri

        kwargs["authority"] = authority
        kwargs["authentication_method"] = self._current_authentication_method
        kwargs["resource"] = self._resource

        return kwargs
コード例 #11
0
class _MyAadHelper(object):
    def __init__(self, kcsb, default_clientid):
        authority = kcsb.authority_id or "common"
        self._resource = "{0.scheme}://{0.hostname}".format(
            urlparse(kcsb.data_source))
        self._adal_context = AuthenticationContext(
            "https://login.microsoftonline.com/{0}".format(authority))
        self._username = None
        if all([kcsb.aad_user_id, kcsb.password]):
            self._authentication_method = AuthenticationMethod.aad_username_password
            self._client_id = default_clientid
            self._username = kcsb.aad_user_id
            self._password = kcsb.password
        elif all([kcsb.application_client_id, kcsb.application_key]):
            self._authentication_method = AuthenticationMethod.aad_application_key
            self._client_id = kcsb.application_client_id
            self._client_secret = kcsb.application_key
        elif all([
                kcsb.application_client_id, kcsb.application_certificate,
                kcsb.application_certificate_thumbprint
        ]):
            self._authentication_method = AuthenticationMethod.aad_application_certificate
            self._client_id = kcsb.application_client_id
            self._certificate = kcsb.application_certificate
            self._thumbprint = kcsb.application_certificate_thumbprint
        else:
            self._authentication_method = AuthenticationMethod.aad_device_login
            self._client_id = default_clientid

    def acquire_token(self, **options):
        """Acquire tokens from AAD."""
        token = self._adal_context.acquire_token(self._resource,
                                                 self._username,
                                                 self._client_id)
        if token is not None:
            expiration_date = dateutil.parser.parse(
                token[TokenResponseFields.EXPIRES_ON])
            if expiration_date > datetime.now() + timedelta(minutes=1):
                return self._get_header(token)
            if TokenResponseFields.REFRESH_TOKEN in token:
                token = self._adal_context.acquire_token_with_refresh_token(
                    token[TokenResponseFields.REFRESH_TOKEN], self._client_id,
                    self._resource)
                if token is not None:
                    return self._get_header(token)

        if self._authentication_method is AuthenticationMethod.aad_username_password:
            token = self._adal_context.acquire_token_with_username_password(
                self._resource, self._username, self._password,
                self._client_id)
        elif self._authentication_method is AuthenticationMethod.aad_application_key:
            token = self._adal_context.acquire_token_with_client_credentials(
                self._resource, self._client_id, self._client_secret)
        elif self._authentication_method is AuthenticationMethod.aad_device_login:
            # print(code[OAuth2DeviceCodeResponseParameters.MESSAGE])
            # webbrowser.open(code[OAuth2DeviceCodeResponseParameters.VERIFICATION_URL])
            # token = self._adal_context.acquire_token_with_device_code(
            #     self._resource, code, self._client_id
            # )
            code: dict = self._adal_context.acquire_user_code(
                self._resource, self._client_id)
            url = code[OAuth2DeviceCodeResponseParameters.VERIFICATION_URL]
            device_code = code[
                OAuth2DeviceCodeResponseParameters.USER_CODE].strip()

            html_str = ("""<!DOCTYPE html>
                <html><body>

                <!-- h1 id="user_code_p"><b>""" + device_code +
                        """</b><br></h1-->

                <input  id="kql_MagicCodeAuthInput" type="text" readonly style="font-weight: bold; border: none;" size = '"""
                        + str(len(device_code)) + """' value='""" +
                        device_code + """'>

                <button id='kql_MagicCodeAuth_button', onclick="this.style.visibility='hidden';kql_MagicCodeAuthFunction()">Copy code to clipboard and authenticate</button>

                <script>
                var kql_MagicUserCodeAuthWindow = null
                function kql_MagicCodeAuthFunction() {
                    /* Get the text field */
                    var copyText = document.getElementById("kql_MagicCodeAuthInput");

                    /* Select the text field */
                    copyText.select();

                    /* Copy the text inside the text field */
                    document.execCommand("copy");

                    /* Alert the copied text */
                    // alert("Copied the text: " + copyText.value);

                    var w = screen.width / 2;
                    var h = screen.height / 2;
                    params = 'width='+w+',height='+h
                    kql_MagicUserCodeAuthWindow = window.open('""" + url +
                        """', 'kql_MagicUserCodeAuthWindow', params);

                    // TODO: save selected cell index, so that the clear will be done on the lince cell
                }
                </script>

                </body></html>""")

            if options.get("notebook_app") in ["visualstudiocode", "ipython"]:
                Display.show_window('verification_url', url, **options)
                # Display.showInfoMessage("Code: {0}".format(device_code))
                Display.showInfoMessage(
                    "Copy code: {0} to verification url: {1} and authenticate".
                    format(device_code, url), **options)
            else:
                Display.show_html(html_str)

            try:
                token = self._adal_context.acquire_token_with_device_code(
                    self._resource, code, self._client_id)
            finally:
                html_str = """<!DOCTYPE html>
                    <html><body><script>

                        // close authentication window
                        if (kql_MagicUserCodeAuthWindow && kql_MagicUserCodeAuthWindow.opener != null && !kql_MagicUserCodeAuthWindow.closed) {
                            kql_MagicUserCodeAuthWindow.close()
                        }
                        // TODO: make sure, you clear the right cell. BTW, not sure it is a must to do any clearing

                        // clear output cell
                        Jupyter.notebook.clear_output(Jupyter.notebook.get_selected_index())

                        // TODO: if in run all mode, move to last cell, otherwise move to next cell
                        // move to next cell

                    </script></body></html>"""

                Display.show_html(html_str)
        elif self._authentication_method is AuthenticationMethod.aad_application_certificate:
            token = self._adal_context.acquire_token_with_client_certificate(
                self._resource, self._client_id, self._certificate,
                self._thumbprint)
        else:
            raise AuthenticationError("Unknown authentication method.")
        return self._get_header(token)

    def _get_header(self, token):
        return "{0} {1}".format(token[TokenResponseFields.TOKEN_TYPE],
                                token[TokenResponseFields.ACCESS_TOKEN])
コード例 #12
0
class _AadHelper(object):
    def __init__(self, kcsb):
        authority = kcsb.authority_id or "microsoft.com"
        self._kusto_cluster = "{0.scheme}://{0.hostname}".format(
            urlparse(kcsb.data_source))
        self._adal_context = AuthenticationContext("https://{0}/{1}".format(
            AADConstants.WORLD_WIDE_AUTHORITY, authority))
        self._username = None
        if all([kcsb.aad_user_id, kcsb.password]):
            self._authentication_method = AuthenticationMethod.aad_username_password
            self._client_id = "db662dc1-0cfe-4e1c-a843-19a68e65be58"
            self._username = kcsb.aad_user_id
            self._password = kcsb.password
        elif all([kcsb.application_client_id, kcsb.application_key]):
            self._authentication_method = AuthenticationMethod.aad_application_key
            self._client_id = kcsb.application_client_id
            self._client_secret = kcsb.application_key
        elif all([
                kcsb.application_client_id,
                kcsb.application_certificate,
                kcsb.application_certificate_thumbprint,
        ]):
            self._authentication_method = AuthenticationMethod.aad_application_certificate
            self._client_id = kcsb.application_client_id
            self._certificate = kcsb.application_certificate
            self._thumbprint = kcsb.application_certificate_thumbprint
        else:
            self._authentication_method = AuthenticationMethod.aad_device_login
            self._client_id = "db662dc1-0cfe-4e1c-a843-19a68e65be58"

    def acquire_token(self):
        """Acquire tokens from AAD."""
        token = self._adal_context.acquire_token(self._kusto_cluster,
                                                 self._username,
                                                 self._client_id)
        if token is not None:
            expiration_date = dateutil.parser.parse(
                token[TokenResponseFields.EXPIRES_ON])
            if expiration_date > datetime.now() + timedelta(minutes=1):
                return _get_header(token)
            if TokenResponseFields.REFRESH_TOKEN in token:
                token = self._adal_context.acquire_token_with_refresh_token(
                    token[TokenResponseFields.REFRESH_TOKEN], self._client_id,
                    self._kusto_cluster)
                if token is not None:
                    return _get_header(token)

        if self._authentication_method is AuthenticationMethod.aad_username_password:
            token = self._adal_context.acquire_token_with_username_password(
                self._kusto_cluster, self._username, self._password,
                self._client_id)
        elif self._authentication_method is AuthenticationMethod.aad_application_key:
            token = self._adal_context.acquire_token_with_client_credentials(
                self._kusto_cluster, self._client_id, self._client_secret)
        elif self._authentication_method is AuthenticationMethod.aad_device_login:
            code = self._adal_context.acquire_user_code(
                self._kusto_cluster, self._client_id)
            print(code[OAuth2DeviceCodeResponseParameters.MESSAGE])
            webbrowser.open(
                code[OAuth2DeviceCodeResponseParameters.VERIFICATION_URL])
            token = self._adal_context.acquire_token_with_device_code(
                self._kusto_cluster, code, self._client_id)
        elif self._authentication_method is AuthenticationMethod.aad_application_certificate:
            token = self._adal_context.acquire_token_with_client_certificate(
                self._kusto_cluster, self._client_id, self._certificate,
                self._thumbprint)
        else:
            raise KustoClientError(
                "Please choose authentication method from azure.kusto.data.security.AuthenticationMethod"
            )

        return _get_header(token)
コード例 #13
0
class _AadHelper:
    authentication_method = None
    auth_context = None
    username = None
    kusto_uri = None
    authority_uri = None
    client_id = None
    password = None
    thumbprint = None
    certificate = None
    msi_params = None
    token_provider = None

    def __init__(self, kcsb):
        self.kusto_uri = "{0.scheme}://{0.hostname}".format(
            urlparse(kcsb.data_source))
        self.username = None

        if all([kcsb.aad_user_id, kcsb.password]):
            self.authentication_method = AuthenticationMethod.aad_username_password
            self.client_id = "db662dc1-0cfe-4e1c-a843-19a68e65be58"
            self.username = kcsb.aad_user_id
            self.password = kcsb.password
        elif all([kcsb.application_client_id, kcsb.application_key]):
            self.authentication_method = AuthenticationMethod.aad_application_key
            self.client_id = kcsb.application_client_id
            self.client_secret = kcsb.application_key
        elif all([
                kcsb.application_client_id, kcsb.application_certificate,
                kcsb.application_certificate_thumbprint
        ]):
            self.authentication_method = AuthenticationMethod.aad_application_certificate
            self.client_id = kcsb.application_client_id
            self.certificate = kcsb.application_certificate
            self.thumbprint = kcsb.application_certificate_thumbprint
        elif kcsb.msi_authentication:
            self.authentication_method = AuthenticationMethod.aad_msi
            self.msi_params = kcsb.msi_parameters
            return
        elif any([kcsb.user_token, kcsb.application_token]):
            self.token = kcsb.user_token or kcsb.application_token
            self.authentication_method = AuthenticationMethod.aad_token
            return
        elif kcsb.az_cli:
            self.authentication_method = AuthenticationMethod.az_cli_profile
            return
        elif kcsb.token_provider:
            self.authentication_method = AuthenticationMethod.token_provider
            self.token_provider = kcsb.token_provider
        else:
            self.authentication_method = AuthenticationMethod.aad_device_login
            self.client_id = "db662dc1-0cfe-4e1c-a843-19a68e65be58"

        authority = kcsb.authority_id or "common"
        aad_authority_uri = os.environ.get("AadAuthorityUri", CLOUD_LOGIN_URL)
        self.authority_uri = aad_authority_uri + authority if aad_authority_uri.endswith(
            "/") else aad_authority_uri + "/" + authority

    def acquire_authorization_header(self):
        """Acquire tokens from AAD."""
        try:
            return self._acquire_authorization_header()
        except (AdalError, KustoClientError) as error:
            if self.authentication_method is AuthenticationMethod.aad_username_password:
                kwargs = {
                    "username": self.username,
                    "client_id": self.client_id
                }
            elif self.authentication_method is AuthenticationMethod.aad_application_key:
                kwargs = {"client_id": self.client_id}
            elif self.authentication_method is AuthenticationMethod.aad_device_login:
                kwargs = {"client_id": self.client_id}
            elif self.authentication_method is AuthenticationMethod.aad_application_certificate:
                kwargs = {
                    "client_id": self.client_id,
                    "thumbprint": self.thumbprint
                }
            elif self.authentication_method is AuthenticationMethod.aad_msi:
                kwargs = self.msi_params
            elif self.authentication_method is AuthenticationMethod.token_provider:
                kwargs = {}
            else:
                raise error

            kwargs["resource"] = self.kusto_uri

            if self.authentication_method is AuthenticationMethod.aad_msi:
                kwargs["authority"] = AuthenticationMethod.aad_msi.value
            elif self.authentication_method is AuthenticationMethod.token_provider:
                kwargs["authority"] = AuthenticationMethod.token_provider.value
            elif self.auth_context is not None:
                kwargs["authority"] = self.auth_context.authority.url

            raise KustoAuthenticationError(self.authentication_method.value,
                                           error, **kwargs)

    def _acquire_authorization_header(self) -> str:
        # Token was provided by caller
        if self.authentication_method is AuthenticationMethod.aad_token:
            return _get_header("Bearer", self.token)

        if self.authentication_method is AuthenticationMethod.token_provider:
            caller_token = self.token_provider()
            if not isinstance(caller_token, str):
                raise KustoClientError(
                    "Token provider returned something that is not a string ["
                    + str(type(caller_token)) + "]")

            return _get_header("Bearer", caller_token)

        # Obtain token from MSI endpoint
        if self.authentication_method == AuthenticationMethod.aad_msi:
            token = self.get_token_from_msi()
            return _get_header_from_dict(token)

        refresh_token = None

        if self.authentication_method == AuthenticationMethod.az_cli_profile:
            stored_token = _get_azure_cli_auth_token()

            if (TokenResponseFields.REFRESH_TOKEN in stored_token
                    and TokenResponseFields._CLIENT_ID in stored_token
                    and TokenResponseFields._AUTHORITY in stored_token):
                self.client_id = stored_token[TokenResponseFields._CLIENT_ID]
                self.username = stored_token[TokenResponseFields.USER_ID]
                self.authority_uri = stored_token[
                    TokenResponseFields._AUTHORITY]
                refresh_token = stored_token[TokenResponseFields.REFRESH_TOKEN]

        if self.auth_context is None:
            self.auth_context = AuthenticationContext(self.authority_uri)

        if refresh_token is not None:
            token = self.auth_context.acquire_token_with_refresh_token(
                refresh_token, self.client_id, self.kusto_uri)
        else:
            token = self.auth_context.acquire_token(self.kusto_uri,
                                                    self.username,
                                                    self.client_id)

        if token is not None:
            expiration_date = dateutil.parser.parse(
                token[TokenResponseFields.EXPIRES_ON])
            if expiration_date > datetime.now() + timedelta(minutes=1):
                return _get_header_from_dict(token)
            if TokenResponseFields.REFRESH_TOKEN in token:
                token = self.auth_context.acquire_token_with_refresh_token(
                    token[TokenResponseFields.REFRESH_TOKEN], self.client_id,
                    self.kusto_uri)
                if token is not None:
                    return _get_header_from_dict(token)

        # obtain token from AAD
        if self.authentication_method is AuthenticationMethod.aad_username_password:
            token = self.auth_context.acquire_token_with_username_password(
                self.kusto_uri, self.username, self.password, self.client_id)
        elif self.authentication_method is AuthenticationMethod.aad_application_key:
            token = self.auth_context.acquire_token_with_client_credentials(
                self.kusto_uri, self.client_id, self.client_secret)
        elif self.authentication_method is AuthenticationMethod.aad_device_login:
            code = self.auth_context.acquire_user_code(self.kusto_uri,
                                                       self.client_id)
            print(code[OAuth2DeviceCodeResponseParameters.MESSAGE])
            webbrowser.open(
                code[OAuth2DeviceCodeResponseParameters.VERIFICATION_URL])
            token = self.auth_context.acquire_token_with_device_code(
                self.kusto_uri, code, self.client_id)
        elif self.authentication_method is AuthenticationMethod.aad_application_certificate:
            token = self.auth_context.acquire_token_with_client_certificate(
                self.kusto_uri, self.client_id, self.certificate,
                self.thumbprint)
        else:
            raise KustoClientError(
                "Please choose authentication method from azure.kusto.data.security.AuthenticationMethod"
            )

        return _get_header_from_dict(token)

    def get_token_from_msi(self) -> dict:
        try:
            credentials = MSIAuthentication(**self.msi_params)
        except Exception as e:
            raise KustoClientError("Failed to obtain MSI context for [" +
                                   str(self.msi_params) + "]\n" + str(e))

        return credentials.token
コード例 #14
0
class _AadHelper(object):
    def __init__(self, kcsb):
        if any([kcsb.user_token, kcsb.application_token]):
            self._token = kcsb.user_token or kcsb.application_token
            self._authentication_method = AuthenticationMethod.aad_token
            return

        authority = kcsb.authority_id or "common"
        self._kusto_cluster = "{0.scheme}://{0.hostname}".format(
            urlparse(kcsb.data_source))
        self._adal_context = AuthenticationContext(
            "https://login.microsoftonline.com/{0}".format(authority))
        self._username = None
        if all([kcsb.aad_user_id, kcsb.password]):
            self._authentication_method = AuthenticationMethod.aad_username_password
            self._client_id = "db662dc1-0cfe-4e1c-a843-19a68e65be58"
            self._username = kcsb.aad_user_id
            self._password = kcsb.password
        elif all([kcsb.application_client_id, kcsb.application_key]):
            self._authentication_method = AuthenticationMethod.aad_application_key
            self._client_id = kcsb.application_client_id
            self._client_secret = kcsb.application_key
        elif all([
                kcsb.application_client_id, kcsb.application_certificate,
                kcsb.application_certificate_thumbprint
        ]):
            self._authentication_method = AuthenticationMethod.aad_application_certificate
            self._client_id = kcsb.application_client_id
            self._certificate = kcsb.application_certificate
            self._thumbprint = kcsb.application_certificate_thumbprint
        else:
            self._authentication_method = AuthenticationMethod.aad_device_login
            self._client_id = "db662dc1-0cfe-4e1c-a843-19a68e65be58"

    def acquire_authorization_header(self):
        """Acquire tokens from AAD."""
        try:
            return self._acquire_authorization_header()
        except AdalError as error:
            if self._authentication_method is AuthenticationMethod.aad_username_password:
                kwargs = {
                    "username": self._username,
                    "client_id": self._client_id
                }
            elif self._authentication_method is AuthenticationMethod.aad_application_key:
                kwargs = {"client_id": self._client_id}
            elif self._authentication_method is AuthenticationMethod.aad_device_login:
                kwargs = {"client_id": self._client_id}
            elif self._authentication_method is AuthenticationMethod.aad_application_certificate:
                kwargs = {
                    "client_id": self._client_id,
                    "thumbprint": self._thumbprint
                }
            else:
                raise error

            kwargs["resource"] = self._kusto_cluster
            kwargs["authority"] = self._adal_context.authority.url

            raise KustoAuthenticationError(self._authentication_method.value,
                                           error, **kwargs)

    def _acquire_authorization_header(self):
        if self._authentication_method is AuthenticationMethod.aad_token:
            return _get_header("Bearer", self._token)

        token = self._adal_context.acquire_token(self._kusto_cluster,
                                                 self._username,
                                                 self._client_id)
        if token is not None:
            expiration_date = dateutil.parser.parse(
                token[TokenResponseFields.EXPIRES_ON])
            if expiration_date > datetime.now() + timedelta(minutes=1):
                return _get_header_from_dict(token)
            if TokenResponseFields.REFRESH_TOKEN in token:
                token = self._adal_context.acquire_token_with_refresh_token(
                    token[TokenResponseFields.REFRESH_TOKEN], self._client_id,
                    self._kusto_cluster)
                if token is not None:
                    return _get_header_from_dict(token)

        if self._authentication_method is AuthenticationMethod.aad_username_password:
            token = self._adal_context.acquire_token_with_username_password(
                self._kusto_cluster, self._username, self._password,
                self._client_id)
        elif self._authentication_method is AuthenticationMethod.aad_application_key:
            token = self._adal_context.acquire_token_with_client_credentials(
                self._kusto_cluster, self._client_id, self._client_secret)
        elif self._authentication_method is AuthenticationMethod.aad_device_login:
            code = self._adal_context.acquire_user_code(
                self._kusto_cluster, self._client_id)
            print(code[OAuth2DeviceCodeResponseParameters.MESSAGE])
            webbrowser.open(
                code[OAuth2DeviceCodeResponseParameters.VERIFICATION_URL])
            token = self._adal_context.acquire_token_with_device_code(
                self._kusto_cluster, code, self._client_id)
        elif self._authentication_method is AuthenticationMethod.aad_application_certificate:
            token = self._adal_context.acquire_token_with_client_certificate(
                self._kusto_cluster, self._client_id, self._certificate,
                self._thumbprint)
        else:
            raise KustoClientError(
                "Please choose authentication method from azure.kusto.data.security.AuthenticationMethod"
            )

        return _get_header_from_dict(token)