Skip to content

Commit

Permalink
Merge pull request #121 from AzureAD/release-0.9.0
Browse files Browse the repository at this point in the history
MSAL Python 0.9.0
  • Loading branch information
rayluo authored Oct 31, 2019
2 parents ae7f794 + a5d74ec commit bee7af0
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 37 deletions.
11 changes: 9 additions & 2 deletions msal/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@


# The __init__.py will import this. Not the other way around.
__version__ = "0.8.0"
__version__ = "0.9.0"

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -195,6 +195,7 @@ def get_authorization_request_url(
state=None, # Recommended by OAuth2 for CSRF protection
redirect_uri=None,
response_type="code", # Can be "token" if you use Implicit Grant
prompt=None,
**kwargs):
"""Constructs a URL for you to start a Authorization Code Grant.
Expand All @@ -208,6 +209,11 @@ def get_authorization_request_url(
:param str response_type:
Default value is "code" for an OAuth2 Authorization Code grant.
You can use other content such as "id_token".
:param str prompt:
By default, no prompt value will be sent, not even "none".
You will have to specify a value explicitly.
Its valid values are defined in Open ID Connect specs
https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
:return: The authorization url as a string.
"""
""" # TBD: this would only be meaningful in a new acquire_token_interactive()
Expand Down Expand Up @@ -235,6 +241,7 @@ def get_authorization_request_url(
return client.build_auth_request_uri(
response_type=response_type,
redirect_uri=redirect_uri, state=state, login_hint=login_hint,
prompt=prompt,
scope=decorate_scope(scopes, self.client_id),
)

Expand Down Expand Up @@ -413,7 +420,7 @@ def acquire_token_silent(
# verify=self.verify, proxies=self.proxies, timeout=self.timeout,
# ) if authority else self.authority
result = self._acquire_token_silent_from_cache_and_possibly_refresh_it(
scopes, account, self.authority, **kwargs)
scopes, account, self.authority, force_refresh=force_refresh, **kwargs)
if result:
return result
for alias in self._get_authority_aliases(self.authority.instance):
Expand Down
4 changes: 3 additions & 1 deletion msal/authority.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ def __init__(self, authority_url, validate_authority=True,
self.proxies = proxies
self.timeout = timeout
authority, self.instance, tenant = canonicalize(authority_url)
is_b2c = any(self.instance.endswith("." + d) for d in WELL_KNOWN_B2C_HOSTS)
parts = authority.path.split('/')
is_b2c = any(self.instance.endswith("." + d) for d in WELL_KNOWN_B2C_HOSTS) or (
len(parts) == 3 and parts[2].lower().startswith("b2c_"))
if (tenant != "adfs" and (not is_b2c) and validate_authority
and self.instance not in WELL_KNOWN_AUTHORITY_HOSTS):
payload = instance_discovery(
Expand Down
2 changes: 1 addition & 1 deletion msal/token_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def wipe(dictionary, sensitive_fields): # Masks sensitive info
if sensitive in dictionary:
dictionary[sensitive] = "********"
wipe(event.get("data", {}),
("password", "client_secret", "refresh_token", "assertion"))
("password", "client_secret", "refresh_token", "assertion", "username"))
try:
return self.__add(event, now=now)
finally:
Expand Down
30 changes: 21 additions & 9 deletions sample/confidential_client_certificate_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@
The configuration file would look like this (sans those // comments):
{
"authority": "https://login.microsoftonline.com/organizations",
"authority": "https://login.microsoftonline.com/Enter_the_Tenant_Name_Here",
"client_id": "your_client_id",
"scope": ["https://graph.microsoft.com/.default"],
// For more information about scopes for an app, refer:
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate"
// Specific to Client Credentials Grant i.e. acquire_token_for_client(),
// you don't specify, in the code, the individual scopes you want to access.
// Instead, you statically declared them when registering your application.
// Therefore the only possible scope is "resource/.default"
// (here "https://graph.microsoft.com/.default")
// which means "the static permissions defined in the application".
"thumbprint": "790E... The thumbprint generated by AAD when you upload your public cert",
"private_key_file": "filename.pem"
"private_key_file": "filename.pem",
// For information about generating thumbprint and private key file, refer:
// https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Client-Credentials#client-credentials-with-certificate
"endpoint": "https://graph.microsoft.com/v1.0/users"
// For this resource to work, you need to visit Application Permissions
// page in portal, declare scope User.Read.All, which needs admin consent
// https://github.com/Azure-Samples/ms-identity-python-daemon/blob/master/2-Call-MsGraph-WithCertificate/README.md
}
You can then run this sample with a JSON configuration file:
Expand All @@ -23,11 +32,13 @@
import json
import logging

import requests
import msal


# Optional logging
# logging.basicConfig(level=logging.DEBUG)
# logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
# logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs

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

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

if "access_token" in result:
print(result["access_token"])
print(result["token_type"])
print(result["expires_in"]) # You don't normally need to care about this.
# It will be good for at least 5 minutes.
# Calling graph using the access token
graph_data = requests.get( # Use token to call downstream service
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))
else:
print(result.get("error"))
print(result.get("error_description"))
Expand Down
32 changes: 22 additions & 10 deletions sample/confidential_client_secret_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@
The configuration file would look like this (sans those // comments):
{
"authority": "https://login.microsoftonline.com/organizations",
"authority": "https://login.microsoftonline.com/Enter_the_Tenant_Name_Here",
"client_id": "your_client_id",
"scope": ["https://graph.microsoft.com/.default"],
// For more information about scopes for an app, refer:
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate"
"secret": "The secret generated by AAD during your confidential app registration"
// Specific to Client Credentials Grant i.e. acquire_token_for_client(),
// you don't specify, in the code, the individual scopes you want to access.
// Instead, you statically declared them when registering your application.
// Therefore the only possible scope is "resource/.default"
// (here "https://graph.microsoft.com/.default")
// which means "the static permissions defined in the application".
"secret": "The secret generated by AAD during your confidential app registration",
// For information about generating client secret, refer:
// https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Client-Credentials#registering-client-secrets-using-the-application-registration-portal
"endpoint": "https://graph.microsoft.com/v1.0/users"
// For this resource to work, you need to visit Application Permissions
// page in portal, declare scope User.Read.All, which needs admin consent
// https://github.com/Azure-Samples/ms-identity-python-daemon/blob/master/1-Call-MsGraph-WithSecret/README.md
}
You can then run this sample with a JSON configuration file:
Expand All @@ -23,11 +31,13 @@
import json
import logging

import requests
import msal


# Optional logging
# logging.basicConfig(level=logging.DEBUG)
# logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
# logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs

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

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

if "access_token" in result:
print(result["access_token"])
print(result["token_type"])
print(result["expires_in"]) # You don't normally need to care about this.
# It will be good for at least 5 minutes.
# Calling graph using the access token
graph_data = requests.get( # Use token to call downstream service
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))

else:
print(result.get("error"))
print(result.get("error_description"))
Expand Down
21 changes: 14 additions & 7 deletions sample/device_flow_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
{
"authority": "https://login.microsoftonline.com/common",
"client_id": "your_client_id",
"scope": ["User.Read"]
"scope": ["User.ReadBasic.All"],
// You can find the other permission names from this document
// https://docs.microsoft.com/en-us/graph/permissions-reference
"endpoint": "https://graph.microsoft.com/v1.0/users"
// You can find more Microsoft Graph API endpoints from Graph Explorer
// https://developer.microsoft.com/en-us/graph/graph-explorer
}
You can then run this sample with a JSON configuration file:
Expand All @@ -16,11 +21,13 @@
import json
import logging

import requests
import msal


# Optional logging
# logging.basicConfig(level=logging.DEBUG)
# logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
# logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs

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

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

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

22 changes: 15 additions & 7 deletions sample/username_password_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
"authority": "https://login.microsoftonline.com/organizations",
"client_id": "your_client_id",
"username": "your_username@your_tenant.com",
"scope": ["User.Read"],
"password": "This is a sample only. You better NOT persist your password."
"password": "This is a sample only. You better NOT persist your password.",
"scope": ["User.ReadBasic.All"],
// You can find the other permission names from this document
// https://docs.microsoft.com/en-us/graph/permissions-reference
"endpoint": "https://graph.microsoft.com/v1.0/users"
// You can find more Microsoft Graph API endpoints from Graph Explorer
// https://developer.microsoft.com/en-us/graph/graph-explorer
}
You can then run this sample with a JSON configuration file:
Expand All @@ -18,11 +23,13 @@
import json
import logging

import requests
import msal


# Optional logging
# logging.basicConfig(level=logging.DEBUG)
# logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
# logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs

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

Expand Down Expand Up @@ -51,10 +58,11 @@
config["username"], config["password"], scopes=config["scope"])

if "access_token" in result:
print(result["access_token"])
print(result["token_type"])
print(result["expires_in"]) # You don't normally need to care about this.
# It will be good for at least 5 minutes.
# Calling graph using the access token
graph_data = requests.get( # Use token to call downstream service
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))
else:
print(result.get("error"))
print(result.get("error_description"))
Expand Down
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[bdist_wheel]
universal=1

0 comments on commit bee7af0

Please sign in to comment.