Source code for azure.identity._credentials.user_password

# ------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------
import time
from typing import TYPE_CHECKING

from azure.core.credentials import AccessToken
from azure.core.exceptions import ClientAuthenticationError

from .._internal import wrap_exceptions, PublicClientCredential

if TYPE_CHECKING:
    from typing import Any


[docs]class UsernamePasswordCredential(PublicClientCredential): """Authenticates a user with a username and password. In general, Microsoft doesn't recommend this kind of authentication, because it's less secure than other authentication flows. Authentication with this credential is not interactive, so it is **not compatible with any form of multi-factor authentication or consent prompting**. The application must already have consent from the user or a directory admin. This credential can only authenticate work and school accounts; Microsoft accounts are not supported. See this document for more information about account types: https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/sign-up-organization :param str client_id: the application's client ID :param str username: the user's username (usually an email address) :param str password: the user's password :keyword str authority: Authority of an Azure Active Directory endpoint, for example 'login.microsoftonline.com', the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.KnownAuthorities` defines authorities for other clouds. :keyword str tenant_id: tenant ID or a domain associated with a tenant. If not provided, defaults to the 'organizations' tenant, which supports only Azure Active Directory work or school accounts. """ def __init__(self, client_id, username, password, **kwargs): # type: (str, str, str, Any) -> None super(UsernamePasswordCredential, self).__init__(client_id=client_id, **kwargs) self._username = username self._password = password
[docs] @wrap_exceptions def get_token(self, *scopes, **kwargs): # pylint:disable=unused-argument # type: (*str, **Any) -> AccessToken """Request an access token for `scopes`. .. note:: This method is called by Azure SDK clients. It isn't intended for use in application code. :param str scopes: desired scopes for the access token. This method requires at least one scope. :rtype: :class:`azure.core.credentials.AccessToken` :raises ~azure.core.exceptions.ClientAuthenticationError: authentication failed. The error's ``message`` attribute gives a reason. Any error response from Azure Active Directory is available as the error's ``response`` attribute. """ if not scopes: raise ValueError("'get_token' requires at least one scope") # MSAL requires scopes be a list scopes = list(scopes) # type: ignore now = int(time.time()) app = self._get_app() accounts = app.get_accounts(username=self._username) result = None for account in accounts: result = app.acquire_token_silent(scopes, account=account) if result: break if not result: # cache miss -> request a new token with self._adapter: result = app.acquire_token_by_username_password( username=self._username, password=self._password, scopes=scopes ) if "access_token" not in result: raise ClientAuthenticationError(message="authentication failed: {}".format(result.get("error_description"))) return AccessToken(result["access_token"], now + int(result["expires_in"]))