33# Licensed under the MIT License.
44# ------------------------------------
55import socket
6- import time
76import uuid
87import webbrowser
98
10- from azure .core .credentials import AccessToken
119from azure .core .exceptions import ClientAuthenticationError
1210
1311from .. import CredentialUnavailableError
1412from .._constants import AZURE_CLI_CLIENT_ID
15- from .._internal import AuthCodeRedirectServer , PublicClientCredential , wrap_exceptions
13+ from .._internal import AuthCodeRedirectServer , InteractiveCredential , wrap_exceptions
1614
1715try :
1816 from typing import TYPE_CHECKING
2422 from typing import Any , List , Mapping
2523
2624
27- class InteractiveBrowserCredential (PublicClientCredential ):
25+ class InteractiveBrowserCredential (InteractiveCredential ):
2826 """Opens a browser to interactively authenticate a user.
2927
3028 :func:`~get_token` opens a browser to a login URL provided by Azure Active Directory and authenticates a user
@@ -38,6 +36,11 @@ class InteractiveBrowserCredential(PublicClientCredential):
3836 authenticate work or school accounts.
3937 :keyword str client_id: Client ID of the Azure Active Directory application users will sign in to. If
4038 unspecified, the Azure CLI's ID will be used.
39+ :keyword AuthenticationRecord authentication_record: :class:`AuthenticationRecord` returned by :func:`authenticate`
40+ :keyword bool disable_automatic_authentication: if True, :func:`get_token` will raise
41+ :class:`AuthenticationRequiredError` when user interaction is required to acquire a token. Defaults to False.
42+ :keyword bool enable_persistent_cache: if True, the credential will store tokens in a persistent cache shared by
43+ other user credentials. **This is only supported on Windows.** Defaults to False.
4144 :keyword int timeout: seconds to wait for the user to complete authentication. Defaults to 300 (5 minutes).
4245 """
4346
@@ -49,42 +52,9 @@ def __init__(self, **kwargs):
4952 super (InteractiveBrowserCredential , self ).__init__ (client_id = client_id , ** kwargs )
5053
5154 @wrap_exceptions
52- def get_token (self , * scopes , ** kwargs ): # pylint:disable=unused-argument
53- # type: (*str, **Any) -> AccessToken
54- """Request an access token for `scopes`.
55-
56- This will open a browser to a login page and listen on localhost for a request indicating authentication has
57- completed.
58-
59- .. note:: This method is called by Azure SDK clients. It isn't intended for use in application code.
60-
61- :param str scopes: desired scopes for the access token. This method requires at least one scope.
62- :rtype: :class:`azure.core.credentials.AccessToken`
63- :raises ~azure.identity.CredentialUnavailableError: the credential is unable to start an HTTP server on
64- localhost, or is unable to open a browser
65- :raises ~azure.core.exceptions.ClientAuthenticationError: authentication failed. The error's ``message``
66- attribute gives a reason. Any error response from Azure Active Directory is available as the error's
67- ``response`` attribute.
68- """
69- if not scopes :
70- raise ValueError ("'get_token' requires at least one scope" )
71-
72- return self ._get_token_from_cache (scopes , ** kwargs ) or self ._get_token_by_auth_code (scopes , ** kwargs )
55+ def _request_token (self , * scopes , ** kwargs ):
56+ # type: (*str, **Any) -> dict
7357
74- def _get_token_from_cache (self , scopes , ** kwargs ):
75- """if the user has already signed in, we can redeem a refresh token for a new access token"""
76- app = self ._get_app ()
77- accounts = app .get_accounts ()
78- if accounts : # => user has already authenticated
79- # MSAL asserts scopes is a list
80- scopes = list (scopes ) # type: ignore
81- now = int (time .time ())
82- token = app .acquire_token_silent (scopes , account = accounts [0 ], ** kwargs )
83- if token and "access_token" in token and "expires_in" in token :
84- return AccessToken (token ["access_token" ], now + int (token ["expires_in" ]))
85- return None
86-
87- def _get_token_by_auth_code (self , scopes , ** kwargs ):
8858 # start an HTTP server on localhost to receive the redirect
8959 for port in range (8400 , 9000 ):
9060 try :
@@ -118,13 +88,8 @@ def _get_token_by_auth_code(self, scopes, **kwargs):
11888
11989 # redeem the authorization code for a token
12090 code = self ._parse_response (request_state , response )
121- now = int (time .time ())
122- result = app .acquire_token_by_authorization_code (code , scopes = scopes , redirect_uri = redirect_uri , ** kwargs )
123-
124- if "access_token" not in result :
125- raise ClientAuthenticationError (message = "Authentication failed: {}" .format (result .get ("error_description" )))
91+ return app .acquire_token_by_authorization_code (code , scopes = scopes , redirect_uri = redirect_uri , ** kwargs )
12692
127- return AccessToken (result ["access_token" ], now + int (result ["expires_in" ]))
12893
12994 @staticmethod
13095 def _parse_response (request_state , response ):
0 commit comments