Skip to content

Commit 0a62ead

Browse files
committed
Add an interactive console test script
1 parent e717407 commit 0a62ead

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed

tests/msaltest.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import getpass, logging, pprint, sys, msal
2+
3+
4+
def _input_boolean(message):
5+
return input(
6+
"{} (N/n/F/f or empty means False, otherwise it is True): ".format(message)
7+
) not in ('N', 'n', 'F', 'f', '')
8+
9+
def _input(message, default=None):
10+
return input(message.format(default=default)).strip() or default
11+
12+
def _select_options(
13+
options, header="Your options:", footer=" Your choice? ", option_renderer=str,
14+
accept_nonempty_string=False,
15+
):
16+
assert options, "options must not be empty"
17+
if header:
18+
print(header)
19+
for i, o in enumerate(options, start=1):
20+
print(" {}: {}".format(i, option_renderer(o)))
21+
if accept_nonempty_string:
22+
print(" Or you can just type in your input.")
23+
while True:
24+
raw_data = input(footer)
25+
try:
26+
choice = int(raw_data)
27+
if 1 <= choice <= len(options):
28+
return options[choice - 1]
29+
except ValueError:
30+
if raw_data and accept_nonempty_string:
31+
return raw_data
32+
33+
def _input_scopes():
34+
return _select_options([
35+
"https://graph.microsoft.com/.default",
36+
"https://management.azure.com/.default",
37+
"User.Read",
38+
"User.ReadBasic.All",
39+
],
40+
header="Select a scope (multiple scopes can only be input by manually typing them):",
41+
accept_nonempty_string=True,
42+
).split()
43+
44+
def _select_account(app):
45+
accounts = app.get_accounts()
46+
if accounts:
47+
return _select_options(
48+
accounts,
49+
option_renderer=lambda a: a["username"],
50+
header="Account(s) already signed in inside MSAL Python:",
51+
)
52+
else:
53+
print("No account available inside MSAL Python. Use other methods to acquire token first.")
54+
55+
def acquire_token_silent(app):
56+
"""acquire_token_silent() - with an account already signed into MSAL Python."""
57+
account = _select_account(app)
58+
if account:
59+
pprint.pprint(app.acquire_token_silent(
60+
_input_scopes(),
61+
account=account,
62+
force_refresh=_input_boolean("Bypass MSAL Python's token cache?"),
63+
))
64+
65+
def acquire_token_interactive(app):
66+
"""acquire_token_interactive() - User will be prompted if app opts to do select_account."""
67+
pprint.pprint(app.acquire_token_interactive(
68+
_input_scopes(),
69+
prompt="select_account" if _input_boolean("Select Account?") else None,
70+
login_hint=_input("login_hint: ") or None,
71+
))
72+
73+
def acquire_token_by_username_password(app):
74+
"""acquire_token_by_username_password() - See constraints here: https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-authentication-flows#constraints-for-ropc"""
75+
pprint.pprint(app.acquire_token_by_username_password(
76+
_input("username: "), getpass.getpass("password: "), scopes=_input_scopes()))
77+
78+
_JWK1 = """{"kty":"RSA", "n":"2tNr73xwcj6lH7bqRZrFzgSLj7OeLfbn8216uOMDHuaZ6TEUBDN8Uz0ve8jAlKsP9CQFCSVoSNovdE-fs7c15MxEGHjDcNKLWonznximj8pDGZQjVdfK-7mG6P6z-lgVcLuYu5JcWU_PeEqIKg5llOaz-qeQ4LEDS4T1D2qWRGpAra4rJX1-kmrWmX_XIamq30C9EIO0gGuT4rc2hJBWQ-4-FnE1NXmy125wfT3NdotAJGq5lMIfhjfglDbJCwhc8Oe17ORjO3FsB5CLuBRpYmP7Nzn66lRY3Fe11Xz8AEBl3anKFSJcTvlMnFtu3EpD-eiaHfTgRBU7CztGQqVbiQ", "e":"AQAB"}"""
79+
SSH_CERT_DATA = {"token_type": "ssh-cert", "key_id": "key1", "req_cnf": _JWK1}
80+
SSH_CERT_SCOPE = ["https://pas.windows.net/CheckMyAccess/Linux/.default"]
81+
82+
def acquire_ssh_cert_silently(app):
83+
"""Acquire an SSH Cert silently- This typically only works with Azure CLI"""
84+
account = _select_account(app)
85+
if account:
86+
result = app.acquire_token_silent(
87+
SSH_CERT_SCOPE,
88+
account,
89+
data=SSH_CERT_DATA,
90+
force_refresh=_input_boolean("Bypass MSAL Python's token cache?"),
91+
)
92+
pprint.pprint(result)
93+
if result and result.get("token_type") != "ssh-cert":
94+
logging.error("Unable to acquire an ssh-cert.")
95+
96+
def acquire_ssh_cert_interactive(app):
97+
"""Acquire an SSH Cert interactively - This typically only works with Azure CLI"""
98+
result = app.acquire_token_interactive(
99+
SSH_CERT_SCOPE,
100+
prompt="select_account" if _input_boolean("Select Account?") else None,
101+
login_hint=_input("login_hint: ") or None,
102+
data=SSH_CERT_DATA,
103+
)
104+
pprint.pprint(result)
105+
if result.get("token_type") != "ssh-cert":
106+
logging.error("Unable to acquire an ssh-cert")
107+
108+
def remove_account(app):
109+
"""remove_account() - Invalidate account and/or token(s) from cache, so that acquire_token_silent() would be reset"""
110+
account = _select_account(app)
111+
if account:
112+
app.remove_account(account)
113+
print('Account "{}" and/or its token(s) are signed out from MSAL Python'.format(account["username"]))
114+
115+
def exit(_):
116+
"""Exit"""
117+
print("Bye")
118+
sys.exit()
119+
120+
def main():
121+
print("Welcome to the Msal Python Console Test App")
122+
chosen_app = _select_options([
123+
{"client_id": "04b07795-8ddb-461a-bbee-02f9e1bf7b46", "name": "Azure CLI"},
124+
{"client_id": "04f0c124-f2bc-4f59-8241-bf6df9866bbd", "name": "Visual Studio (Correctly configured for MSA-PT)"},
125+
],
126+
option_renderer=lambda a: a["name"],
127+
header="Impersonate this app (or you can type in the client_id of your own app)",
128+
accept_nonempty_string=True)
129+
app = msal.PublicClientApplication(
130+
chosen_app["client_id"] if isinstance(chosen_app, dict) else chosen_app,
131+
authority=_select_options([
132+
"https://login.microsoftonline.com/common",
133+
"https://login.microsoftonline.com/organizations",
134+
"https://login.microsoftonline.com/microsoft.onmicrosoft.com",
135+
"https://login.microsoftonline.com/msidlab4.onmicrosoft.com",
136+
"https://login.microsoftonline.com/consumers",
137+
], header="Input authority", accept_nonempty_string=True),
138+
)
139+
if _input_boolean("Enable MSAL Python's DEBUG log?"):
140+
logging.basicConfig(level=logging.DEBUG)
141+
while True:
142+
func = _select_options([
143+
acquire_token_silent,
144+
acquire_token_interactive,
145+
acquire_token_by_username_password,
146+
acquire_ssh_cert_silently,
147+
acquire_ssh_cert_interactive,
148+
remove_account,
149+
exit,
150+
], option_renderer=lambda f: f.__doc__, header="MSAL Python APIs:")
151+
try:
152+
func(app)
153+
except KeyboardInterrupt: # Useful for bailing out a stuck interactive flow
154+
print("Aborted")
155+
156+
if __name__ == "__main__":
157+
main()
158+

0 commit comments

Comments
 (0)