Skip to content

Commit bee7af0

Browse files
authored
Merge pull request #121 from AzureAD/release-0.9.0
MSAL Python 0.9.0
2 parents ae7f794 + a5d74ec commit bee7af0

8 files changed

+88
-37
lines changed

msal/application.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919

2020
# The __init__.py will import this. Not the other way around.
21-
__version__ = "0.8.0"
21+
__version__ = "0.9.0"
2222

2323
logger = logging.getLogger(__name__)
2424

@@ -195,6 +195,7 @@ def get_authorization_request_url(
195195
state=None, # Recommended by OAuth2 for CSRF protection
196196
redirect_uri=None,
197197
response_type="code", # Can be "token" if you use Implicit Grant
198+
prompt=None,
198199
**kwargs):
199200
"""Constructs a URL for you to start a Authorization Code Grant.
200201
@@ -208,6 +209,11 @@ def get_authorization_request_url(
208209
:param str response_type:
209210
Default value is "code" for an OAuth2 Authorization Code grant.
210211
You can use other content such as "id_token".
212+
:param str prompt:
213+
By default, no prompt value will be sent, not even "none".
214+
You will have to specify a value explicitly.
215+
Its valid values are defined in Open ID Connect specs
216+
https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
211217
:return: The authorization url as a string.
212218
"""
213219
""" # TBD: this would only be meaningful in a new acquire_token_interactive()
@@ -235,6 +241,7 @@ def get_authorization_request_url(
235241
return client.build_auth_request_uri(
236242
response_type=response_type,
237243
redirect_uri=redirect_uri, state=state, login_hint=login_hint,
244+
prompt=prompt,
238245
scope=decorate_scope(scopes, self.client_id),
239246
)
240247

@@ -413,7 +420,7 @@ def acquire_token_silent(
413420
# verify=self.verify, proxies=self.proxies, timeout=self.timeout,
414421
# ) if authority else self.authority
415422
result = self._acquire_token_silent_from_cache_and_possibly_refresh_it(
416-
scopes, account, self.authority, **kwargs)
423+
scopes, account, self.authority, force_refresh=force_refresh, **kwargs)
417424
if result:
418425
return result
419426
for alias in self._get_authority_aliases(self.authority.instance):

msal/authority.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ def __init__(self, authority_url, validate_authority=True,
4848
self.proxies = proxies
4949
self.timeout = timeout
5050
authority, self.instance, tenant = canonicalize(authority_url)
51-
is_b2c = any(self.instance.endswith("." + d) for d in WELL_KNOWN_B2C_HOSTS)
51+
parts = authority.path.split('/')
52+
is_b2c = any(self.instance.endswith("." + d) for d in WELL_KNOWN_B2C_HOSTS) or (
53+
len(parts) == 3 and parts[2].lower().startswith("b2c_"))
5254
if (tenant != "adfs" and (not is_b2c) and validate_authority
5355
and self.instance not in WELL_KNOWN_AUTHORITY_HOSTS):
5456
payload = instance_discovery(

msal/token_cache.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def wipe(dictionary, sensitive_fields): # Masks sensitive info
108108
if sensitive in dictionary:
109109
dictionary[sensitive] = "********"
110110
wipe(event.get("data", {}),
111-
("password", "client_secret", "refresh_token", "assertion"))
111+
("password", "client_secret", "refresh_token", "assertion", "username"))
112112
try:
113113
return self.__add(event, now=now)
114114
finally:

sample/confidential_client_certificate_sample.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@
22
The configuration file would look like this (sans those // comments):
33
44
{
5-
"authority": "https://login.microsoftonline.com/organizations",
5+
"authority": "https://login.microsoftonline.com/Enter_the_Tenant_Name_Here",
66
"client_id": "your_client_id",
77
"scope": ["https://graph.microsoft.com/.default"],
8-
// For more information about scopes for an app, refer:
9-
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate"
8+
// Specific to Client Credentials Grant i.e. acquire_token_for_client(),
9+
// you don't specify, in the code, the individual scopes you want to access.
10+
// Instead, you statically declared them when registering your application.
11+
// Therefore the only possible scope is "resource/.default"
12+
// (here "https://graph.microsoft.com/.default")
13+
// which means "the static permissions defined in the application".
1014
1115
"thumbprint": "790E... The thumbprint generated by AAD when you upload your public cert",
12-
"private_key_file": "filename.pem"
16+
"private_key_file": "filename.pem",
1317
// For information about generating thumbprint and private key file, refer:
1418
// https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Client-Credentials#client-credentials-with-certificate
19+
20+
"endpoint": "https://graph.microsoft.com/v1.0/users"
21+
// For this resource to work, you need to visit Application Permissions
22+
// page in portal, declare scope User.Read.All, which needs admin consent
23+
// https://github.com/Azure-Samples/ms-identity-python-daemon/blob/master/2-Call-MsGraph-WithCertificate/README.md
1524
}
1625
1726
You can then run this sample with a JSON configuration file:
@@ -23,11 +32,13 @@
2332
import json
2433
import logging
2534

35+
import requests
2636
import msal
2737

2838

2939
# Optional logging
30-
# logging.basicConfig(level=logging.DEBUG)
40+
# logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
41+
# logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs
3142

3243
config = json.load(open(sys.argv[1]))
3344

@@ -53,10 +64,11 @@
5364
result = app.acquire_token_for_client(scopes=config["scope"])
5465

5566
if "access_token" in result:
56-
print(result["access_token"])
57-
print(result["token_type"])
58-
print(result["expires_in"]) # You don't normally need to care about this.
59-
# It will be good for at least 5 minutes.
67+
# Calling graph using the access token
68+
graph_data = requests.get( # Use token to call downstream service
69+
config["endpoint"],
70+
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
71+
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))
6072
else:
6173
print(result.get("error"))
6274
print(result.get("error_description"))

sample/confidential_client_secret_sample.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,24 @@
22
The configuration file would look like this (sans those // comments):
33
44
{
5-
"authority": "https://login.microsoftonline.com/organizations",
5+
"authority": "https://login.microsoftonline.com/Enter_the_Tenant_Name_Here",
66
"client_id": "your_client_id",
77
"scope": ["https://graph.microsoft.com/.default"],
8-
// For more information about scopes for an app, refer:
9-
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate"
10-
11-
"secret": "The secret generated by AAD during your confidential app registration"
8+
// Specific to Client Credentials Grant i.e. acquire_token_for_client(),
9+
// you don't specify, in the code, the individual scopes you want to access.
10+
// Instead, you statically declared them when registering your application.
11+
// Therefore the only possible scope is "resource/.default"
12+
// (here "https://graph.microsoft.com/.default")
13+
// which means "the static permissions defined in the application".
14+
15+
"secret": "The secret generated by AAD during your confidential app registration",
1216
// For information about generating client secret, refer:
1317
// https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Client-Credentials#registering-client-secrets-using-the-application-registration-portal
1418
19+
"endpoint": "https://graph.microsoft.com/v1.0/users"
20+
// For this resource to work, you need to visit Application Permissions
21+
// page in portal, declare scope User.Read.All, which needs admin consent
22+
// https://github.com/Azure-Samples/ms-identity-python-daemon/blob/master/1-Call-MsGraph-WithSecret/README.md
1523
}
1624
1725
You can then run this sample with a JSON configuration file:
@@ -23,11 +31,13 @@
2331
import json
2432
import logging
2533

34+
import requests
2635
import msal
2736

2837

2938
# Optional logging
30-
# logging.basicConfig(level=logging.DEBUG)
39+
# logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
40+
# logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs
3141

3242
config = json.load(open(sys.argv[1]))
3343

@@ -53,10 +63,12 @@
5363
result = app.acquire_token_for_client(scopes=config["scope"])
5464

5565
if "access_token" in result:
56-
print(result["access_token"])
57-
print(result["token_type"])
58-
print(result["expires_in"]) # You don't normally need to care about this.
59-
# It will be good for at least 5 minutes.
66+
# Calling graph using the access token
67+
graph_data = requests.get( # Use token to call downstream service
68+
config["endpoint"],
69+
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
70+
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))
71+
6072
else:
6173
print(result.get("error"))
6274
print(result.get("error_description"))

sample/device_flow_sample.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
{
55
"authority": "https://login.microsoftonline.com/common",
66
"client_id": "your_client_id",
7-
"scope": ["User.Read"]
7+
"scope": ["User.ReadBasic.All"],
8+
// You can find the other permission names from this document
9+
// https://docs.microsoft.com/en-us/graph/permissions-reference
10+
"endpoint": "https://graph.microsoft.com/v1.0/users"
11+
// You can find more Microsoft Graph API endpoints from Graph Explorer
12+
// https://developer.microsoft.com/en-us/graph/graph-explorer
813
}
914
1015
You can then run this sample with a JSON configuration file:
@@ -16,11 +21,13 @@
1621
import json
1722
import logging
1823

24+
import requests
1925
import msal
2026

2127

2228
# Optional logging
23-
# logging.basicConfig(level=logging.DEBUG)
29+
# logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
30+
# logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs
2431

2532
config = json.load(open(sys.argv[1]))
2633

@@ -70,12 +77,12 @@
7077
# and then keep calling acquire_token_by_device_flow(flow) in your own customized loop.
7178

7279
if "access_token" in result:
73-
print(result["access_token"])
74-
print(result["token_type"])
75-
print(result["expires_in"]) # You don't normally need to care about this.
76-
# It will be good for at least 5 minutes.
80+
# Calling graph using the access token
81+
graph_data = requests.get( # Use token to call downstream service
82+
config["endpoint"],
83+
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
84+
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))
7785
else:
7886
print(result.get("error"))
7987
print(result.get("error_description"))
8088
print(result.get("correlation_id")) # You may need this when reporting a bug
81-

sample/username_password_sample.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@
55
"authority": "https://login.microsoftonline.com/organizations",
66
"client_id": "your_client_id",
77
"username": "your_username@your_tenant.com",
8-
"scope": ["User.Read"],
9-
"password": "This is a sample only. You better NOT persist your password."
8+
"password": "This is a sample only. You better NOT persist your password.",
9+
"scope": ["User.ReadBasic.All"],
10+
// You can find the other permission names from this document
11+
// https://docs.microsoft.com/en-us/graph/permissions-reference
12+
"endpoint": "https://graph.microsoft.com/v1.0/users"
13+
// You can find more Microsoft Graph API endpoints from Graph Explorer
14+
// https://developer.microsoft.com/en-us/graph/graph-explorer
1015
}
1116
1217
You can then run this sample with a JSON configuration file:
@@ -18,11 +23,13 @@
1823
import json
1924
import logging
2025

26+
import requests
2127
import msal
2228

2329

2430
# Optional logging
25-
# logging.basicConfig(level=logging.DEBUG)
31+
# logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
32+
# logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs
2633

2734
config = json.load(open(sys.argv[1]))
2835

@@ -51,10 +58,11 @@
5158
config["username"], config["password"], scopes=config["scope"])
5259

5360
if "access_token" in result:
54-
print(result["access_token"])
55-
print(result["token_type"])
56-
print(result["expires_in"]) # You don't normally need to care about this.
57-
# It will be good for at least 5 minutes.
61+
# Calling graph using the access token
62+
graph_data = requests.get( # Use token to call downstream service
63+
config["endpoint"],
64+
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
65+
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))
5866
else:
5967
print(result.get("error"))
6068
print(result.get("error_description"))

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[bdist_wheel]
2+
universal=1
3+

0 commit comments

Comments
 (0)