Hello community, here is the log from the commit of package python-msal for openSUSE:Factory checked in at 2020-11-13 18:59:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-msal (Old) and /work/SRC/openSUSE:Factory/.python-msal.new.24930 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-msal" Fri Nov 13 18:59:14 2020 rev:4 rq:848336 version:1.6.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-msal/python-msal.changes 2020-10-02 17:28:11.990412164 +0200 +++ /work/SRC/openSUSE:Factory/.python-msal.new.24930/python-msal.changes 2020-11-13 18:59:16.366128013 +0100 @@ -1,0 +2,16 @@ +Fri Nov 13 12:14:27 UTC 2020 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- Update to version 1.6.0 + + New Feature: ```ConfidentialClientApplication``` accepts private + key encrypted by a passphrase. (#232, #270) + + Enhancement: Provides different exception and messages while + encountering transient error during tenant discovery (#263, #269) +- from version 1.5.1 + + Bugfix: We now cache tokens by specified environment, not by OIDC Discovery. + This won't matter most of the time, but it can be needed when your tenant is + in transitional state while migrating to a different cloud. (#247) + + Bugfix: We now make sure one app's sign-out operation would be successful even + when another app is acquiring token from cache at the same time. (#258, #262) +- Update Requires from setup.py + +------------------------------------------------------------------- Old: ---- msal-1.5.0.tar.gz New: ---- msal-1.6.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-msal.spec ++++++ --- /var/tmp/diff_new_pack.mbA9dy/_old 2020-11-13 18:59:16.858128553 +0100 +++ /var/tmp/diff_new_pack.mbA9dy/_new 2020-11-13 18:59:16.862128557 +0100 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-msal -Version: 1.5.0 +Version: 1.6.0 Release: 0 Summary: Microsoft Authentication Library (MSAL) for Python License: MIT @@ -30,6 +30,7 @@ BuildRequires: fdupes BuildRequires: python-rpm-macros Requires: python-PyJWT >= 1.0.0 +Requires: python-cryptography >= 0.6 Requires: python-requests >= 2.0.0 BuildArch: noarch # SECTION test requirements ++++++ msal-1.5.0.tar.gz -> msal-1.6.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-1.5.0/PKG-INFO new/msal-1.6.0/PKG-INFO --- old/msal-1.5.0/PKG-INFO 2020-09-03 23:50:40.000000000 +0200 +++ new/msal-1.6.0/PKG-INFO 2020-11-02 07:35:08.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: msal -Version: 1.5.0 +Version: 1.6.0 Summary: The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect. Home-page: https://github.com/AzureAD/microsoft-authentication-library-for-python Author: Microsoft Corporation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-1.5.0/msal/application.py new/msal-1.6.0/msal/application.py --- old/msal-1.5.0/msal/application.py 2020-09-03 23:50:17.000000000 +0200 +++ new/msal-1.6.0/msal/application.py 2020-11-02 07:34:49.000000000 +0100 @@ -21,7 +21,7 @@ # The __init__.py will import this. Not the other way around. -__version__ = "1.5.0" +__version__ = "1.6.0" logger = logging.getLogger(__name__) @@ -90,6 +90,14 @@ return json.dumps(claims_dict) +def _str2bytes(raw): + # A conversion based on duck-typing rather than six.text_type + try: + return raw.encode(encoding="utf-8") + except: + return raw + + class ClientApplication(object): ACQUIRE_TOKEN_SILENT_ID = "84" @@ -123,7 +131,8 @@ { "private_key": "...-----BEGIN PRIVATE KEY-----...", "thumbprint": "A1B2C3D4E5F6...", - "public_certificate": "...-----BEGIN CERTIFICATE-----..." (Optional. See below.) + "public_certificate": "...-----BEGIN CERTIFICATE-----... (Optional. See below.)", + "passphrase": "Passphrase if the private_key is encrypted (Optional. Added in version 1.6.0)", } *Added in version 0.5.0*: @@ -193,6 +202,18 @@ Default value is None, means it will not be passed to Microsoft. :param list[str] client_capabilities: (optional) Allows configuration of one or more client capabilities, e.g. ["CP1"]. + + Client capability is meant to inform the Microsoft identity platform + (STS) what this client is capable for, + so STS can decide to turn on certain features. + For example, if client is capable to handle *claims challenge*, + STS can then issue CAE access tokens to resources + knowing when the resource emits *claims challenge* + the client will be capable to handle. + + Implementation details: + Client capability is implemented using "claims" parameter on the wire, + for now. MSAL will combine them into `claims parameter <https://openid.net/specs/openid-connect-core-1_0-final.html#ClaimsParameter`_ which you will later provide via one of the acquire-token request. @@ -240,8 +261,18 @@ headers = {} if 'public_certificate' in client_credential: headers["x5c"] = extract_certs(client_credential['public_certificate']) + if not client_credential.get("passphrase"): + unencrypted_private_key = client_credential['private_key'] + else: + from cryptography.hazmat.primitives import serialization + from cryptography.hazmat.backends import default_backend + unencrypted_private_key = serialization.load_pem_private_key( + _str2bytes(client_credential["private_key"]), + _str2bytes(client_credential["passphrase"]), + backend=default_backend(), # It was a required param until 2020 + ) assertion = JwtAssertionCreator( - client_credential["private_key"], algorithm="RS256", + unencrypted_private_key, algorithm="RS256", sha1_thumbprint=client_credential.get("thumbprint"), headers=headers) client_assertion = assertion.create_regenerative_assertion( audience=authority.token_endpoint, issuer=self.client_id, @@ -264,7 +295,8 @@ default_body=default_body, client_assertion=client_assertion, client_assertion_type=client_assertion_type, - on_obtaining_tokens=self.token_cache.add, + on_obtaining_tokens=lambda event: self.token_cache.add(dict( + event, environment=authority.instance)), on_removing_rt=self.token_cache.remove_rt, on_updating_rt=self.token_cache.update_rt) @@ -275,7 +307,7 @@ login_hint=None, # type: Optional[str] state=None, # Recommended by OAuth2 for CSRF protection redirect_uri=None, - response_type="code", # Can be "token" if you use Implicit Grant + response_type="code", # Could be "token" if you use Implicit Grant prompt=None, nonce=None, domain_hint=None, # type: Optional[str] @@ -292,7 +324,11 @@ Address to return to upon receiving a response from the authority. :param str response_type: Default value is "code" for an OAuth2 Authorization Code grant. - You can use other content such as "id_token". + + You could use other content such as "id_token" or "token", + which would trigger an Implicit Grant, but that is + `not recommended <https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-implicit-grant-flow#is-the-implicit-grant-suitable-for-my-app>`_. + :param str prompt: By default, no prompt value will be sent, not even "none". You will have to specify a value explicitly. @@ -735,6 +771,11 @@ response = client.obtain_token_by_refresh_token( entry, rt_getter=lambda token_item: token_item["secret"], on_removing_rt=rt_remover or self.token_cache.remove_rt, + on_obtaining_tokens=lambda event: self.token_cache.add(dict( + event, + environment=authority.instance, + skip_account_creation=True, # To honor a concurrent remove_account() + )), scope=scopes, headers={ CLIENT_REQUEST_ID: correlation_id or _get_new_correlation_id(), @@ -936,7 +977,8 @@ "https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Username-Password-Authentication") logger.debug("wstrust_endpoint = %s", wstrust_endpoint) wstrust_result = wst_send_request( - username, password, user_realm_result.get("cloud_audience_urn"), + username, password, + user_realm_result.get("cloud_audience_urn", "urn:federation:MicrosoftOnline"), wstrust_endpoint.get("address", # Fallback to an AAD supplied endpoint user_realm_result.get("federation_active_auth_url")), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-1.5.0/msal/authority.py new/msal-1.6.0/msal/authority.py --- old/msal-1.5.0/msal/authority.py 2020-09-03 23:50:17.000000000 +0200 +++ new/msal-1.6.0/msal/authority.py 2020-11-02 07:34:49.000000000 +0100 @@ -83,7 +83,7 @@ openid_config = tenant_discovery( tenant_discovery_endpoint, self.http_client) - except ValueError: # json.decoder.JSONDecodeError in Py3 subclasses this + except ValueError: raise ValueError( "Unable to get authority configuration for {}. " "Authority would typically be in a format of " @@ -140,8 +140,17 @@ def tenant_discovery(tenant_discovery_endpoint, http_client, **kwargs): # Returns Openid Configuration resp = http_client.get(tenant_discovery_endpoint, **kwargs) - payload = json.loads(resp.text) - if 'authorization_endpoint' in payload and 'token_endpoint' in payload: - return payload - raise MsalServiceError(status_code=resp.status_code, **payload) + if resp.status_code == 200: + payload = json.loads(resp.text) # It could raise ValueError + if 'authorization_endpoint' in payload and 'token_endpoint' in payload: + return payload # Happy path + raise ValueError("OIDC Discovery does not provide enough information") + if 400 <= resp.status_code < 500: + # Nonexist tenant would hit this path + # e.g. https://login.microsoftonline.com/nonexist_tenant/v2.0/.well-known/openid-configuration + raise ValueError("OIDC Discovery endpoint rejects our request") + # Transient network error would hit this path + resp.raise_for_status() + raise RuntimeError( # A fallback here, in case resp.raise_for_status() is no-op + "Unable to complete OIDC Discovery: %d, %s" % (resp.status_code, resp.text)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-1.5.0/msal/oauth2cli/oauth2.py new/msal-1.6.0/msal/oauth2cli/oauth2.py --- old/msal-1.5.0/msal/oauth2cli/oauth2.py 2020-09-03 23:50:17.000000000 +0200 +++ new/msal-1.6.0/msal/oauth2cli/oauth2.py 2020-11-02 07:34:49.000000000 +0100 @@ -462,6 +462,7 @@ def _obtain_token( self, grant_type, params=None, data=None, also_save_rt=False, + on_obtaining_tokens=None, *args, **kwargs): _data = data.copy() # to prevent side effect resp = super(Client, self)._obtain_token( @@ -481,7 +482,7 @@ # but our obtain_token_by_authorization_code(...) encourages # app developer to still explicitly provide a scope here. scope = _data.get("scope") - self.on_obtaining_tokens({ + (on_obtaining_tokens or self.on_obtaining_tokens)({ "client_id": self.client_id, "scope": scope, "token_endpoint": self.configuration["token_endpoint"], @@ -495,6 +496,7 @@ rt_getter=lambda token_item: token_item["refresh_token"], on_removing_rt=None, on_updating_rt=None, + on_obtaining_tokens=None, **kwargs): # type: (Union[str, dict], Union[str, list, set, tuple], Callable) -> dict """This is an overload which will trigger token storage callbacks. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-1.5.0/msal/token_cache.py new/msal-1.6.0/msal/token_cache.py --- old/msal-1.5.0/msal/token_cache.py 2020-09-03 23:50:17.000000000 +0200 +++ new/msal-1.6.0/msal/token_cache.py 2020-11-02 07:34:49.000000000 +0100 @@ -126,6 +126,8 @@ environment = realm = None if "token_endpoint" in event: _, environment, realm = canonicalize(event["token_endpoint"]) + if "environment" in event: # Always available unless in legacy test cases + environment = event["environment"] # Set by application.py response = event.get("response", {}) data = event.get("data", {}) access_token = response.get("access_token") @@ -170,7 +172,7 @@ at["key_id"] = data.get("key_id") self.modify(self.CredentialType.ACCESS_TOKEN, at, at) - if client_info: + if client_info and not event.get("skip_account_creation"): account = { "home_account_id": home_account_id, "environment": environment, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-1.5.0/msal.egg-info/PKG-INFO new/msal-1.6.0/msal.egg-info/PKG-INFO --- old/msal-1.5.0/msal.egg-info/PKG-INFO 2020-09-03 23:50:40.000000000 +0200 +++ new/msal-1.6.0/msal.egg-info/PKG-INFO 2020-11-02 07:35:08.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: msal -Version: 1.5.0 +Version: 1.6.0 Summary: The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect. Home-page: https://github.com/AzureAD/microsoft-authentication-library-for-python Author: Microsoft Corporation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-1.5.0/msal.egg-info/requires.txt new/msal-1.6.0/msal.egg-info/requires.txt --- old/msal-1.5.0/msal.egg-info/requires.txt 2020-09-03 23:50:40.000000000 +0200 +++ new/msal-1.6.0/msal.egg-info/requires.txt 2020-11-02 07:35:08.000000000 +0100 @@ -1,2 +1,3 @@ requests<3,>=2.0.0 PyJWT[crypto]<2,>=1.0.0 +cryptography<4,>=0.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-1.5.0/setup.py new/msal-1.6.0/setup.py --- old/msal-1.5.0/setup.py 2020-09-03 23:50:17.000000000 +0200 +++ new/msal-1.6.0/setup.py 2020-11-02 07:34:49.000000000 +0100 @@ -74,6 +74,16 @@ install_requires=[ 'requests>=2.0.0,<3', 'PyJWT[crypto]>=1.0.0,<2', + + 'cryptography>=0.6,<4', + # load_pem_private_key() is available since 0.6 + # https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst#06---2014-09-29 + # + # Not sure what should be used as an upper bound here + # https://github.com/pyca/cryptography/issues/5532 + # We will go with "<4" for now, which is also what our another dependency, + # pyjwt, currently use. + ] ) _______________________________________________ openSUSE Commits mailing list -- commit@lists.opensuse.org To unsubscribe, email commit-le...@lists.opensuse.org List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette List Archives: https://lists.opensuse.org/archives/list/commit@lists.opensuse.org