Skip to content

Commit 4f0e03d

Browse files
committed
CCA can be tested by: python -m msal
1 parent bf87155 commit 4f0e03d

File tree

1 file changed

+63
-11
lines changed

1 file changed

+63
-11
lines changed

msal/__main__.py

+63-11
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,17 @@ def _select_options(
6060
if raw_data and accept_nonempty_string:
6161
return raw_data
6262

63+
enable_debug_log = _input_boolean("Enable MSAL Python's DEBUG log?")
64+
logging.basicConfig(level=logging.DEBUG if enable_debug_log else logging.INFO)
65+
try:
66+
from dotenv import load_dotenv
67+
load_dotenv()
68+
logging.info("Loaded environment variables from .env file")
69+
except ImportError:
70+
logging.warning(
71+
"python-dotenv is not installed. "
72+
"You may need to set environment variables manually.")
73+
6374
def _input_scopes():
6475
scopes = _select_options([
6576
"https://graph.microsoft.com/.default",
@@ -100,6 +111,7 @@ def _acquire_token_silent(app):
100111

101112
def _acquire_token_interactive(app, scopes=None, data=None):
102113
"""acquire_token_interactive() - User will be prompted if app opts to do select_account."""
114+
assert isinstance(app, msal.PublicClientApplication)
103115
scopes = scopes or _input_scopes() # Let user input scope param before less important prompt and login_hint
104116
prompt = _select_options([
105117
{"value": None, "description": "Unspecified. Proceed silently with a default account (if any), fallback to prompt."},
@@ -143,6 +155,7 @@ def _acquire_token_by_username_password(app):
143155

144156
def _acquire_token_by_device_flow(app):
145157
"""acquire_token_by_device_flow() - Note that this one does not go through broker"""
158+
assert isinstance(app, msal.PublicClientApplication)
146159
flow = app.initiate_device_flow(scopes=_input_scopes())
147160
print(flow["message"])
148161
sys.stdout.flush() # Some terminal needs this to ensure the message is shown
@@ -156,6 +169,7 @@ def _acquire_token_by_device_flow(app):
156169

157170
def _acquire_ssh_cert_silently(app):
158171
"""Acquire an SSH Cert silently- This typically only works with Azure CLI"""
172+
assert isinstance(app, msal.PublicClientApplication)
159173
account = _select_account(app)
160174
if account:
161175
result = app.acquire_token_silent(
@@ -170,6 +184,7 @@ def _acquire_ssh_cert_silently(app):
170184

171185
def _acquire_ssh_cert_interactive(app):
172186
"""Acquire an SSH Cert interactively - This typically only works with Azure CLI"""
187+
assert isinstance(app, msal.PublicClientApplication)
173188
result = _acquire_token_interactive(app, scopes=_SSH_CERT_SCOPE, data=_SSH_CERT_DATA)
174189
if result.get("token_type") != "ssh-cert":
175190
logging.error("Unable to acquire an ssh-cert")
@@ -185,6 +200,7 @@ def _acquire_ssh_cert_interactive(app):
185200

186201
def _acquire_pop_token_interactive(app):
187202
"""Acquire a POP token interactively - This typically only works with Azure CLI"""
203+
assert isinstance(app, msal.PublicClientApplication)
188204
POP_SCOPE = ['6256c85f-0aad-4d50-b960-e6e9b21efe35/.default'] # KAP 1P Server App Scope, obtained from https://github.com/Azure/azure-cli-extensions/pull/4468/files#diff-a47efa3186c7eb4f1176e07d0b858ead0bf4a58bfd51e448ee3607a5b4ef47f6R116
189205
result = _acquire_token_interactive(app, scopes=POP_SCOPE, data=_POP_DATA)
190206
print_json(result)
@@ -198,6 +214,16 @@ def _remove_account(app):
198214
app.remove_account(account)
199215
print('Account "{}" and/or its token(s) are signed out from MSAL Python'.format(account["username"]))
200216

217+
def _acquire_token_for_client(app):
218+
"""CCA.acquire_token_for_client() - Rerun this will get same token from cache."""
219+
assert isinstance(app, msal.ConfidentialClientApplication)
220+
print_json(app.acquire_token_for_client(scopes=_input_scopes()))
221+
222+
def _remove_tokens_for_client(app):
223+
"""CCA.remove_tokens_for_client() - Run this to evict tokens from cache."""
224+
assert isinstance(app, msal.ConfidentialClientApplication)
225+
app.remove_tokens_for_client()
226+
201227
def _exit(app):
202228
"""Exit"""
203229
bug_link = (
@@ -235,12 +261,23 @@ def _main():
235261
{"client_id": _AZURE_CLI, "name": "Azure CLI (Correctly configured for MSA-PT)"},
236262
{"client_id": _VISUAL_STUDIO, "name": "Visual Studio (Correctly configured for MSA-PT)"},
237263
{"client_id": "95de633a-083e-42f5-b444-a4295d8e9314", "name": "Whiteboard Services (Non MSA-PT app. Accepts AAD & MSA accounts.)"},
264+
{
265+
"client_id": os.getenv("CLIENT_ID"),
266+
"client_secret": os.getenv("CLIENT_SECRET"),
267+
"name": "A confidential client app (CCA) whose settings are defined "
268+
"in environment variables CLIENT_ID and CLIENT_SECRET",
269+
},
238270
],
239271
option_renderer=lambda a: a["name"],
240-
header="Impersonate this app (or you can type in the client_id of your own app)",
272+
header="Impersonate this app "
273+
"(or you can type in the client_id of your own public client app)",
241274
accept_nonempty_string=True)
242-
enable_broker = _input_boolean("Enable broker? It will error out later if your app has not registered some redirect URI")
243-
enable_debug_log = _input_boolean("Enable MSAL Python's DEBUG log?")
275+
is_cca = isinstance(chosen_app, dict) and "client_secret" in chosen_app
276+
if is_cca and not (chosen_app["client_id"] and chosen_app["client_secret"]):
277+
raise ValueError("You need to set environment variables CLIENT_ID and CLIENT_SECRET")
278+
enable_broker = (not is_cca) and _input_boolean("Enable broker? "
279+
"(It will error out later if your app has not registered some redirect URI)"
280+
)
244281
enable_pii_log = _input_boolean("Enable PII in broker's log?") if enable_broker and enable_debug_log else False
245282
authority = _select_options([
246283
"https://login.microsoftonline.com/common",
@@ -255,29 +292,44 @@ def _main():
255292
instance_discovery = _input_boolean(
256293
"You input an unusual authority which might fail the Instance Discovery. "
257294
"Now, do you want to perform Instance Discovery on your input authority?"
258-
) if not authority.startswith("https://login.microsoftonline.com") else None
295+
) if authority and not authority.startswith(
296+
"https://login.microsoftonline.com") else None
259297
app = msal.PublicClientApplication(
260298
chosen_app["client_id"] if isinstance(chosen_app, dict) else chosen_app,
261299
authority=authority,
262300
instance_discovery=instance_discovery,
263301
enable_broker_on_windows=enable_broker,
264302
enable_pii_log=enable_pii_log,
265303
token_cache=global_cache,
304+
) if not is_cca else msal.ConfidentialClientApplication(
305+
chosen_app["client_id"],
306+
client_credential=chosen_app["client_secret"],
307+
authority=authority,
308+
instance_discovery=instance_discovery,
309+
enable_pii_log=enable_pii_log,
310+
token_cache=global_cache,
266311
)
267-
if enable_debug_log:
268-
logging.basicConfig(level=logging.DEBUG)
269-
while True:
270-
func = _select_options([
312+
methods_to_be_tested = [
271313
_acquire_token_silent,
314+
] + ([
272315
_acquire_token_interactive,
273-
_acquire_token_by_username_password,
274316
_acquire_token_by_device_flow,
275317
_acquire_ssh_cert_silently,
276318
_acquire_ssh_cert_interactive,
277319
_acquire_pop_token_interactive,
320+
] if isinstance(app, msal.PublicClientApplication) else []
321+
) + [
322+
_acquire_token_by_username_password,
278323
_remove_account,
279-
_exit,
280-
], option_renderer=lambda f: f.__doc__, header="MSAL Python APIs:")
324+
] + ([
325+
_acquire_token_for_client,
326+
_remove_tokens_for_client,
327+
] if isinstance(app, msal.ConfidentialClientApplication) else []
328+
)
329+
while True:
330+
func = _select_options(
331+
methods_to_be_tested + [_exit],
332+
option_renderer=lambda f: f.__doc__, header="MSAL Python APIs:")
281333
try:
282334
func(app)
283335
except ValueError as e:

0 commit comments

Comments
 (0)