Skip to content

Commit 6cb1703

Browse files
committed
Add broker._signout_silently()
1 parent 3d3c6c8 commit 6cb1703

File tree

2 files changed

+51
-20
lines changed

2 files changed

+51
-20
lines changed

msal/broker.py

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ class RedirectUriError(ValueError):
3636
class _CallbackData:
3737
def __init__(self):
3838
self.signal = Event()
39-
self.auth_result = None
39+
self.result = None
4040

41-
def complete(self, auth_result):
41+
def complete(self, result):
4242
self.signal.set()
43-
self.auth_result = auth_result
43+
self.result = result
4444

4545

4646
def _convert_error(error, client_id):
@@ -62,15 +62,16 @@ def _convert_error(error, client_id):
6262

6363

6464
def _read_account_by_id(account_id, correlation_id):
65-
"""Return the callback result which contains the account or error"""
65+
"""Return an instance of MSALRuntimeError or MSALRuntimeAccount, or None"""
6666
callback_data = _CallbackData()
6767
pymsalruntime.read_account_by_id(
6868
account_id,
6969
correlation_id,
7070
lambda result, callback_data=callback_data: callback_data.complete(result)
7171
)
7272
callback_data.signal.wait()
73-
return callback_data.auth_result
73+
return (callback_data.result.get_error() or callback_data.result.get_account()
74+
or None) # None happens when the account was not created by broker
7475

7576

7677
def _convert_result(result, client_id): # Mimic an on-the-wire response from AAD
@@ -114,7 +115,7 @@ def _signin_silently(authority, client_id, scopes, correlation_id=None, claims=N
114115
correlation_id or _get_new_correlation_id(),
115116
lambda result, callback_data=callback_data: callback_data.complete(result))
116117
callback_data.signal.wait()
117-
return _convert_result(callback_data.auth_result, client_id)
118+
return _convert_result(callback_data.result, client_id)
118119

119120

120121
def _signin_interactively(
@@ -154,17 +155,16 @@ def _signin_interactively(
154155
login_hint, # None value will be accepted since pymsalruntime 0.3+
155156
lambda result, callback_data=callback_data: callback_data.complete(result))
156157
callback_data.signal.wait()
157-
return _convert_result(callback_data.auth_result, client_id)
158+
return _convert_result(callback_data.result, client_id)
158159

159160

160161
def _acquire_token_silently(
161162
authority, client_id, account_id, scopes, claims=None, correlation_id=None):
162163
correlation_id = correlation_id or _get_new_correlation_id()
163164
account = _read_account_by_id(account_id, correlation_id)
164-
error = account.get_error()
165-
if error:
166-
return _convert_error(error, client_id)
167-
if not account.get_account(): # It happens when the account was not created by broker
165+
if isinstance(account, pymsalruntime.MSALRuntimeError):
166+
return _convert_error(account, client_id)
167+
if account is None:
168168
return
169169
params = pymsalruntime.MSALRuntimeAuthParameters(client_id, authority)
170170
params.set_requested_scopes(scopes)
@@ -174,10 +174,10 @@ def _acquire_token_silently(
174174
pymsalruntime.acquire_token_silently(
175175
params,
176176
correlation_id,
177-
account.get_account(),
177+
account,
178178
lambda result, callback_data=callback_data: callback_data.complete(result))
179179
callback_data.signal.wait()
180-
return _convert_result(callback_data.auth_result, client_id)
180+
return _convert_result(callback_data.result, client_id)
181181

182182

183183
def _acquire_token_interactively(
@@ -195,9 +195,10 @@ def _acquire_token_interactively(
195195
raise NotImplementedError("We ended up not currently using this function")
196196
correlation_id = correlation_id or _get_new_correlation_id()
197197
account = _read_account_by_id(account_id, correlation_id)
198-
error = account.get_error()
199-
if error:
200-
return _convert_error(error, client_id)
198+
if isinstance(account, pymsalruntime.MSALRuntimeError):
199+
return _convert_error(account, client_id)
200+
if account is None:
201+
return
201202
params = pymsalruntime.MSALRuntimeAuthParameters(client_id, authority)
202203
params.set_requested_scopes(scopes)
203204
params.set_redirect_uri("placeholder") # pymsalruntime 0.1 requires non-empty str,
@@ -212,8 +213,27 @@ def _acquire_token_interactively(
212213
window or pymsalruntime.get_console_window() or pymsalruntime.get_desktop_window(), # Since pymsalruntime 0.2+
213214
params,
214215
correlation_id,
215-
account.get_account(),
216+
account,
216217
lambda result, callback_data=callback_data: callback_data.complete(result))
217218
callback_data.signal.wait()
218-
return callback_data.auth_result
219+
return callback_data.result
220+
221+
222+
def _signout_silently(client_id, account_id, correlation_id=None):
223+
correlation_id = correlation_id or _get_new_correlation_id()
224+
account = _read_account_by_id(account_id, correlation_id)
225+
if isinstance(account, pymsalruntime.MSALRuntimeError):
226+
return _convert_error(account, client_id)
227+
if account is None:
228+
return
229+
callback_data = _CallbackData()
230+
pymsalruntime.signout_silently( # New in PyMsalRuntime 0.7
231+
client_id,
232+
correlation_id,
233+
account,
234+
lambda result, callback_data=callback_data: callback_data.complete(result))
235+
callback_data.signal.wait()
236+
error = callback_data.result.get_error()
237+
if error:
238+
return _convert_error(error, client_id)
219239

tests/test_broker.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
if not sys.platform.startswith("win"):
66
raise unittest.SkipTest("Currently, our broker supports Windows")
77
from msal.broker import ( # Import them after the platform check
8-
_signin_silently, _signin_interactively, _acquire_token_silently, RedirectUriError)
8+
_signin_silently, _signin_interactively, _acquire_token_silently, RedirectUriError,
9+
_signout_silently, _read_account_by_id,
10+
)
911

1012

1113
logging.basicConfig(level=logging.DEBUG)
@@ -20,15 +22,24 @@ class BrokerTestCase(unittest.TestCase):
2022
_authority = "https://login.microsoftonline.com/common"
2123
_scopes = ["https://graph.microsoft.com/.default"]
2224

23-
def test_signin_interactive_then_acquire_token_silent(self):
25+
def test_signin_interactive_then_acquire_token_silent_then_signout(self):
2426
result = _signin_interactively(self._authority, self._client_id, self._scopes)
2527
self.assertIsNotNone(result.get("access_token"), result)
2628

2729
account_id = result["_account_id"]
30+
self.assertIsNotNone(_read_account_by_id(account_id, "correlation_id"))
2831
result = _acquire_token_silently(
2932
self._authority, self._client_id, account_id, self._scopes)
3033
self.assertIsNotNone(result.get("access_token"), result)
3134

35+
signout_error = _signout_silently(self._client_id, account_id)
36+
self.assertIsNone(signout_error, msg=signout_error)
37+
account = _read_account_by_id(account_id, "correlation_id")
38+
self.assertIsNotNone(account, msg="pymsalruntime still has this account")
39+
result = _acquire_token_silently(
40+
self._authority, self._client_id, account_id, self._scopes)
41+
self.assertIn("Status_AccountUnusable", result.get("error_description", ""))
42+
3243
def test_unconfigured_app_should_raise_exception(self):
3344
app_without_needed_redirect_uri = "289a413d-284b-4303-9c79-94380abe5d22"
3445
with self.assertRaises(RedirectUriError):

0 commit comments

Comments
 (0)