Skip to content

Commit

Permalink
Use auth code flow rather than acquire_token_interactive (#32539)
Browse files Browse the repository at this point in the history
* We moved WAM features into broker package, no need to use `acquire_token_interactive`

* update

* update changelog

* update
  • Loading branch information
xiangyan99 authored Oct 17, 2023
1 parent 9c402ea commit 69d4812
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 64 deletions.
2 changes: 2 additions & 0 deletions sdk/identity/azure-identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

### Bugs Fixed

- Fixed issue InteractiveBrowserCredential does not hand over to next credential in chain if no browser is supported.([#32276](https://github.com/Azure/azure-sdk-for-python/pull/32276))

### Other Changes

## 1.15.0b2 (2023-10-12)
Expand Down
109 changes: 45 additions & 64 deletions sdk/identity/azure-identity/azure/identity/_credentials/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import subprocess
import webbrowser
from urllib.parse import urlparse
import msal

from azure.core.exceptions import ClientAuthenticationError

Expand Down Expand Up @@ -81,77 +80,59 @@ def __init__(self, **kwargs: Any) -> None:
super(InteractiveBrowserCredential, self).__init__(client_id=client_id, **kwargs)

@wrap_exceptions
def _request_token(self, *scopes: str, **kwargs: Any) -> Dict:
scopes = list(scopes) # type: ignore
claims = kwargs.get("claims")
app = self._get_app(**kwargs)
if isinstance(app, msal.ConfidentialClientApplication):
server = None
if self._parsed_url:
def _request_token(self, *scopes: str, **kwargs) -> Dict:

# start an HTTP server to receive the redirect
server = None
redirect_uri: str = ""
if self._parsed_url:
try:
redirect_uri = "http://{}:{}".format(self._parsed_url.hostname, self._parsed_url.port)
server = self._server_class(self._parsed_url.hostname, self._parsed_url.port, timeout=self._timeout)
except socket.error as ex:
raise CredentialUnavailableError(message="Couldn't start an HTTP server on " + redirect_uri) from ex
else:
for port in range(8400, 9000):
try:
server = self._server_class(self._parsed_url.hostname, self._parsed_url.port, timeout=self._timeout)
except socket.error as ex:
raise CredentialUnavailableError(message="Couldn't start an HTTP server on " + redirect_uri) from ex
else:
for port in range(8400, 9000):
try:
server = self._server_class("localhost", port, timeout=self._timeout)
redirect_uri = "http://localhost:{}".format(port)
break
except socket.error:
continue # keep looking for an open port

if not server:
raise CredentialUnavailableError(message="Couldn't start an HTTP server on localhost")

flow = app.initiate_auth_code_flow(
scopes,
redirect_uri=redirect_uri,
prompt="select_account",
claims_challenge=claims,
login_hint=self._login_hint,
)
if "auth_uri" not in flow:
raise CredentialUnavailableError("Failed to begin authentication flow")
server = self._server_class("localhost", port, timeout=self._timeout)
redirect_uri = "http://localhost:{}".format(port)
break
except socket.error:
continue # keep looking for an open port

if not _open_browser(flow["auth_uri"]):
raise CredentialUnavailableError(message="Failed to open a browser")
if not server:
raise CredentialUnavailableError(message="Couldn't start an HTTP server on localhost")

# block until the server times out or receives the post-authentication redirect
response = server.wait_for_redirect()
if not response:
raise ClientAuthenticationError(
# get the url the user must visit to authenticate
scopes = list(scopes) # type: ignore
claims = kwargs.get("claims")
app = self._get_app(**kwargs)
flow = app.initiate_auth_code_flow(
scopes,
redirect_uri=redirect_uri,
prompt="select_account",
claims_challenge=claims,
login_hint=self._login_hint,
)
if "auth_uri" not in flow:
raise CredentialUnavailableError("Failed to begin authentication flow")

if not _open_browser(flow["auth_uri"]):
raise CredentialUnavailableError(message="Failed to open a browser")

# block until the server times out or receives the post-authentication redirect
response = server.wait_for_redirect()
if not response:
if within_dac.get():
raise CredentialUnavailableError(
message="Timed out after waiting {} seconds for the user to authenticate".format(self._timeout)
)

# redeem the authorization code for a token
return app.acquire_token_by_auth_code_flow(flow, response, scopes=scopes, claims_challenge=claims)

port = self._parsed_url.port if self._parsed_url else None

try:
result = app.acquire_token_interactive(
scopes=scopes,
login_hint=self._login_hint,
claims_challenge=claims,
timeout=self._timeout,
prompt="select_account",
port=port,
raise ClientAuthenticationError(
message="Timed out after waiting {} seconds for the user to authenticate".format(self._timeout)
)
except socket.error as ex:
raise CredentialUnavailableError(message="Couldn't start an HTTP server.") from ex
if "access_token" not in result and "error_description" in result:
if within_dac.get():
raise CredentialUnavailableError(message=result["error_description"])
raise ClientAuthenticationError(message=result.get("error_description"))
if "access_token" not in result:
if within_dac.get():
raise CredentialUnavailableError(message="Failed to authenticate user")
raise ClientAuthenticationError(message="Failed to authenticate user")

# base class will raise for other errors
return result
# redeem the authorization code for a token
return app.acquire_token_by_auth_code_flow(flow, response, scopes=scopes, claims_challenge=claims)


def _open_browser(url):
Expand Down

0 comments on commit 69d4812

Please sign in to comment.