Skip to content

Commit edb6c0b

Browse files
authored
Merge pull request #592 from AzureAD/release-1.24.0
MSAL Python 1.24.0
2 parents 1318025 + 66fc6eb commit edb6c0b

16 files changed

+504
-198
lines changed

.github/workflows/python-package.yml

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,40 +32,69 @@ jobs:
3232
- uses: actions/checkout@v2
3333
- name: Set up Python ${{ matrix.python-version }}
3434
uses: actions/setup-python@v2
35+
# It automatically takes care of pip cache, according to
36+
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#about-caching-workflow-dependencies
3537
with:
3638
python-version: ${{ matrix.python-version }}
3739

38-
# Derived from https://github.com/actions/cache/blob/main/examples.md#using-pip-to-get-cache-location
39-
# However, a before-and-after test shows no improvement in this repo,
40-
# possibly because the bottlenect was not in downloading those small python deps.
41-
- name: Get pip cache dir from pip 20.1+
42-
id: pip-cache
43-
run: |
44-
echo "::set-output name=dir::$(pip cache dir)"
45-
- name: pip cache
46-
uses: actions/cache@v2
47-
with:
48-
path: ${{ steps.pip-cache.outputs.dir }}
49-
key: ${{ runner.os }}-py${{ matrix.python-version }}-pip-${{ hashFiles('**/setup.py', '**/requirements.txt') }}
50-
5140
- name: Install dependencies
5241
run: |
5342
python -m pip install --upgrade pip
5443
python -m pip install flake8 pytest
5544
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
45+
- name: Test with pytest
46+
run: pytest --benchmark-skip
5647
- name: Lint with flake8
5748
run: |
5849
# stop the build if there are Python syntax errors or undefined names
5950
#flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
6051
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
6152
#flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
62-
- name: Test with pytest
53+
54+
cb:
55+
# Benchmark only after the correctness has been tested by CI,
56+
# and then run benchmark only once (sampling with only one Python version).
57+
needs: ci
58+
runs-on: ubuntu-latest
59+
steps:
60+
- uses: actions/checkout@v2
61+
- name: Set up Python 3.9
62+
uses: actions/setup-python@v2
63+
with:
64+
python-version: 3.9
65+
- name: Install dependencies
6366
run: |
64-
pytest
67+
python -m pip install --upgrade pip
68+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
69+
- name: Setup an updatable cache for Performance Baselines
70+
uses: actions/cache@v3
71+
with:
72+
path: .perf.baseline
73+
key: ${{ runner.os }}-performance-${{ hashFiles('tests/test_benchmark.py') }}
74+
restore-keys: ${{ runner.os }}-performance-
75+
- name: Run benchmark
76+
run: pytest --benchmark-only --benchmark-json benchmark.json --log-cli-level INFO tests/test_benchmark.py
77+
- name: Render benchmark result
78+
uses: benchmark-action/github-action-benchmark@v1
79+
with:
80+
tool: 'pytest'
81+
output-file-path: benchmark.json
82+
fail-on-alert: true
83+
- name: Publish Gibhub Pages
84+
run: git push origin gh-pages
6585

6686
cd:
6787
needs: ci
68-
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags') || github.ref == 'refs/heads/main')
88+
# Note: github.event.pull_request.draft == false WON'T WORK in "if" statement,
89+
# because the triggered event is a push, not a pull_request.
90+
# This means each commit will trigger a release on TestPyPI.
91+
# Those releases will only succeed when each push has a new version number: a1, a2, a3, etc.
92+
if: |
93+
github.event_name == 'push' &&
94+
(
95+
startsWith(github.ref, 'refs/tags') ||
96+
startsWith(github.ref, 'refs/heads/release-')
97+
)
6998
runs-on: ubuntu-latest
7099
steps:
71100
- uses: actions/checkout@v2
@@ -77,14 +106,16 @@ jobs:
77106
run: |
78107
python -m pip install build --user
79108
python -m build --sdist --wheel --outdir dist/ .
80-
- name: Publish to TestPyPI
109+
- name: |
110+
Publish to TestPyPI when pushing to release-* branch.
111+
You better test with a1, a2, b1, b2 releases first.
81112
uses: pypa/[email protected]
82-
if: github.ref == 'refs/heads/main'
113+
if: startsWith(github.ref, 'refs/heads/release-')
83114
with:
84115
user: __token__
85116
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
86117
repository_url: https://test.pypi.org/legacy/
87-
- name: Publish to PyPI
118+
- name: Publish to PyPI when tagged
88119
if: startsWith(github.ref, 'refs/tags')
89120
uses: pypa/[email protected]
90121
with:

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,5 @@ docs/_build/
5858
tests/config.json
5959

6060

61-
.env
61+
.env
62+
.perf.baseline

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Microsoft Authentication Library (MSAL) for Python
22

3-
| `dev` branch | Reference Docs | # of Downloads per different platforms | # of Downloads per recent MSAL versions |
4-
|---------------|---------------|----------------------------------------|-----------------------------------------|
5-
[![Build status](https://github.com/AzureAD/microsoft-authentication-library-for-python/actions/workflows/python-package.yml/badge.svg?branch=dev)](https://github.com/AzureAD/microsoft-authentication-library-for-python/actions) | [![Documentation Status](https://readthedocs.org/projects/msal-python/badge/?version=latest)](https://msal-python.readthedocs.io/en/latest/?badge=latest) | [![Downloads](https://pepy.tech/badge/msal)](https://pypistats.org/packages/msal) | [![Download monthly](https://pepy.tech/badge/msal/month)](https://pepy.tech/project/msal)
3+
| `dev` branch | Reference Docs | # of Downloads per different platforms | # of Downloads per recent MSAL versions | Benchmark Diagram |
4+
|:------------:|:--------------:|:--------------------------------------:|:---------------------------------------:|:-----------------:|
5+
[![Build status](https://github.com/AzureAD/microsoft-authentication-library-for-python/actions/workflows/python-package.yml/badge.svg?branch=dev)](https://github.com/AzureAD/microsoft-authentication-library-for-python/actions) | [![Documentation Status](https://readthedocs.org/projects/msal-python/badge/?version=latest)](https://msal-python.readthedocs.io/en/latest/?badge=latest) | [![Downloads](https://static.pepy.tech/badge/msal)](https://pypistats.org/packages/msal) | [![Download monthly](https://static.pepy.tech/badge/msal/month)](https://pepy.tech/project/msal) | [📉](https://azuread.github.io/microsoft-authentication-library-for-python/dev/bench/)
66

77
The Microsoft Authentication Library for Python enables applications to integrate with the [Microsoft identity platform](https://aka.ms/aaddevv2). It allows you to sign in users or apps with Microsoft identities ([Azure AD](https://azure.microsoft.com/services/active-directory/), [Microsoft Accounts](https://account.microsoft.com) and [Azure AD B2C](https://azure.microsoft.com/services/active-directory-b2c/) accounts) and obtain tokens to call Microsoft APIs such as [Microsoft Graph](https://graph.microsoft.io/) or your own APIs registered with the Microsoft identity platform. It is built using industry standard OAuth2 and OpenID Connect protocols
88

msal/application.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626

2727
# The __init__.py will import this. Not the other way around.
28-
__version__ = "1.23.0" # When releasing, also check and bump our dependencies's versions if needed
28+
__version__ = "1.24.0" # When releasing, also check and bump our dependencies's versions if needed
2929

3030
logger = logging.getLogger(__name__)
3131
_AUTHORITY_TYPE_CLOUDSHELL = "CLOUDSHELL"
@@ -73,6 +73,11 @@ def _pii_less_home_account_id(home_account_id):
7373

7474
def _clean_up(result):
7575
if isinstance(result, dict):
76+
if "_msalruntime_telemetry" in result or "_msal_python_telemetry" in result:
77+
result["msal_telemetry"] = json.dumps({ # Telemetry as an opaque string
78+
"msalruntime_telemetry": result.get("_msalruntime_telemetry"),
79+
"msal_python_telemetry": result.get("_msal_python_telemetry"),
80+
}, separators=(",", ":"))
7681
return {
7782
k: result[k] for k in result
7883
if k != "refresh_in" # MSAL handled refresh_in, customers need not
@@ -188,6 +193,7 @@ def __init__(
188193
http_cache=None,
189194
instance_discovery=None,
190195
allow_broker=None,
196+
enable_pii_log=None,
191197
):
192198
"""Create an instance of application.
193199
@@ -200,12 +206,19 @@ def __init__(
200206
or an X509 certificate container in this form::
201207
202208
{
203-
"private_key": "...-----BEGIN PRIVATE KEY-----...",
209+
"private_key": "...-----BEGIN PRIVATE KEY-----... in PEM format",
204210
"thumbprint": "A1B2C3D4E5F6...",
205211
"public_certificate": "...-----BEGIN CERTIFICATE-----... (Optional. See below.)",
206212
"passphrase": "Passphrase if the private_key is encrypted (Optional. Added in version 1.6.0)",
207213
}
208214
215+
MSAL Python requires a "private_key" in PEM format.
216+
If your cert is in a PKCS12 (.pfx) format, you can also
217+
`convert it to PEM and get the thumbprint <https://github.com/Azure/azure-sdk-for-python/blob/07d10639d7e47f4852eaeb74aef5d569db499d6e/sdk/identity/azure-identity/azure/identity/_credentials/certificate.py#L101-L123>`_.
218+
219+
The thumbprint is available in your app's registration in Azure Portal.
220+
Alternatively, you can `calculate the thumbprint <https://github.com/Azure/azure-sdk-for-python/blob/07d10639d7e47f4852eaeb74aef5d569db499d6e/sdk/identity/azure-identity/azure/identity/_credentials/certificate.py#L94-L97>`_.
221+
209222
*Added in version 0.5.0*:
210223
public_certificate (optional) is public key certificate
211224
which will be sent through 'x5c' JWT header only for
@@ -495,6 +508,13 @@ def __init__(
495508
* AAD and MSA accounts (i.e. Non-ADFS, non-B2C)
496509
497510
New in version 1.20.0.
511+
512+
:param boolean enable_pii_log:
513+
When enabled, logs may include PII (Personal Identifiable Information).
514+
This can be useful in troubleshooting broker behaviors.
515+
The default behavior is False.
516+
517+
New in version 1.24.0.
498518
"""
499519
self.client_id = client_id
500520
self.client_credential = client_credential
@@ -571,6 +591,8 @@ def __init__(
571591
try:
572592
from . import broker # Trigger Broker's initialization
573593
self._enable_broker = True
594+
if enable_pii_log:
595+
broker._enable_pii_log()
574596
except RuntimeError:
575597
logger.exception(
576598
"Broker is unavailable on this platform. "
@@ -966,7 +988,7 @@ def authorize(): # A controller in a web app
966988
self._validate_ssh_cert_input_data(kwargs.get("data", {}))
967989
telemetry_context = self._build_telemetry_context(
968990
self.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE_ID)
969-
response =_clean_up(self.client.obtain_token_by_auth_code_flow(
991+
response = _clean_up(self.client.obtain_token_by_auth_code_flow(
970992
auth_code_flow,
971993
auth_response,
972994
scope=self._decorate_scope(scopes) if scopes else None,

msal/authority.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,9 @@ def canonicalize(authority_or_auth_endpoint):
163163
raise ValueError(
164164
"Your given address (%s) should consist of "
165165
"an https url with a minimum of one segment in a path: e.g. "
166-
"https://login.microsoftonline.com/<tenant> "
167-
"or https://<tenant_name>.ciamlogin.com/<tenant> "
168-
"or https://<tenant_name>.b2clogin.com/<tenant_name>.onmicrosoft.com/policy"
166+
"https://login.microsoftonline.com/{tenant} "
167+
"or https://{tenant_name}.ciamlogin.com/{tenant} "
168+
"or https://{tenant_name}.b2clogin.com/{tenant_name}.onmicrosoft.com/policy"
169169
% authority_or_auth_endpoint)
170170

171171
def _instance_discovery(url, http_client, instance_discovery_endpoint, **kwargs):

msal/broker.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@
2323
except (ImportError, AttributeError): # AttributeError happens when a prior pymsalruntime uninstallation somehow leaved an empty folder behind
2424
# PyMsalRuntime currently supports these Windows versions, listed in this MSFT internal link
2525
# https://github.com/AzureAD/microsoft-authentication-library-for-cpp/pull/2406/files
26-
raise ImportError( # TODO: Remove or adjust this line right before merging this PR
27-
'You need to install dependency by: pip install "msal[broker]>=1.20,<2"')
26+
raise ImportError('You need to install dependency by: pip install "msal[broker]>=1.20,<2"')
2827
# It could throw RuntimeError when running on ancient versions of Windows
2928

3029

@@ -84,9 +83,11 @@ def _read_account_by_id(account_id, correlation_id):
8483

8584

8685
def _convert_result(result, client_id, expected_token_type=None): # Mimic an on-the-wire response from AAD
86+
telemetry = result.get_telemetry_data()
87+
telemetry.pop("wam_telemetry", None) # In pymsalruntime 0.13, it contains PII "account_id"
8788
error = result.get_error()
8889
if error:
89-
return _convert_error(error, client_id)
90+
return dict(_convert_error(error, client_id), _msalruntime_telemetry=telemetry)
9091
id_token_claims = json.loads(result.get_id_token()) if result.get_id_token() else {}
9192
account = result.get_account()
9293
assert account, "Account is expected to be always available"
@@ -107,7 +108,7 @@ def _convert_result(result, client_id, expected_token_type=None): # Mimic an on
107108
granted_scopes = result.get_granted_scopes() # New in pymsalruntime 0.3.x
108109
if granted_scopes:
109110
return_value["scope"] = " ".join(granted_scopes) # Mimic the on-the-wire data format
110-
return return_value
111+
return dict(return_value, _msalruntime_telemetry=telemetry)
111112

112113

113114
def _get_new_correlation_id():
@@ -235,3 +236,6 @@ def _signout_silently(client_id, account_id, correlation_id=None):
235236
if error:
236237
return _convert_error(error, client_id)
237238

239+
def _enable_pii_log():
240+
pymsalruntime.set_is_pii_enabled(1) # New in PyMsalRuntime 0.13.0
241+

requirements.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
1-
.
2-
python-dotenv
1+
-e .
2+
3+
# python-dotenv 1.0+ no longer supports Python 3.7
4+
python-dotenv>=0.21,<2
5+
6+
pytest-benchmark>=4,<5
7+
perf_baseline>=0.1,<0.2
8+

setup.cfg

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,76 @@
1+
# Format https://setuptools.pypa.io/en/latest/userguide/declarative_config.html
2+
13
[bdist_wheel]
24
universal=1
35

46
[metadata]
7+
name = msal
8+
version = attr: msal.__version__
9+
description =
10+
The Microsoft Authentication Library (MSAL) for Python library
11+
enables your app to access the Microsoft Cloud
12+
by supporting authentication of users with
13+
Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA)
14+
using industry standard OAuth2 and OpenID Connect.
15+
long_description = file: README.md
16+
long_description_content_type = text/markdown
17+
license = MIT
18+
author = Microsoft Corporation
19+
author_email = [email protected]
20+
url = https://github.com/AzureAD/microsoft-authentication-library-for-python
21+
classifiers =
22+
Development Status :: 5 - Production/Stable
23+
Programming Language :: Python
24+
Programming Language :: Python :: 2
25+
Programming Language :: Python :: 2.7
26+
Programming Language :: Python :: 3
27+
Programming Language :: Python :: 3.5
28+
Programming Language :: Python :: 3.6
29+
Programming Language :: Python :: 3.7
30+
Programming Language :: Python :: 3.8
31+
Programming Language :: Python :: 3.9
32+
Programming Language :: Python :: 3.10
33+
Programming Language :: Python :: 3.11
34+
License :: OSI Approved :: MIT License
35+
Operating System :: OS Independent
36+
537
project_urls =
638
Changelog = https://github.com/AzureAD/microsoft-authentication-library-for-python/releases
739
Documentation = https://msal-python.readthedocs.io/
840
Questions = https://stackoverflow.com/questions/tagged/azure-ad-msal+python
941
Feature/Bug Tracker = https://github.com/AzureAD/microsoft-authentication-library-for-python/issues
42+
43+
44+
[options]
45+
include_package_data = False # We used to ship LICENSE, but our __init__.py already mentions MIT
46+
packages = find:
47+
python_requires = >=2.7
48+
install_requires =
49+
requests>=2.0.0,<3
50+
51+
# MSAL does not use jwt.decode(),
52+
# therefore is insusceptible to CVE-2022-29217 so no need to bump to PyJWT 2.4+
53+
PyJWT[crypto]>=1.0.0,<3
54+
55+
# load_pem_private_key() is available since 0.6
56+
# https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst#06---2014-09-29
57+
#
58+
# And we will use the cryptography (X+3).0.0 as the upper bound,
59+
# based on their latest deprecation policy
60+
# https://cryptography.io/en/latest/api-stability/#deprecation
61+
cryptography>=0.6,<44
62+
63+
mock; python_version<'3.3'
64+
65+
[options.extras_require]
66+
broker =
67+
# The broker is defined as optional dependency,
68+
# so that downstream apps can opt in. The opt-in is needed, partially because
69+
# most existing MSAL Python apps do not have the redirect_uri needed by broker.
70+
# MSAL Python uses a subset of API from PyMsalRuntime 0.13.0+,
71+
# but we still bump the lower bound to 0.13.2+ for its important bugfix (https://github.com/AzureAD/microsoft-authentication-library-for-cpp/pull/3244)
72+
pymsalruntime>=0.13.2,<0.14; python_version>='3.6' and platform_system=='Windows'
73+
74+
[options.packages.find]
75+
exclude =
76+
tests

0 commit comments

Comments
 (0)