Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-social-auth-core for 
openSUSE:Factory checked in at 2022-06-15 00:33:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-social-auth-core (Old)
 and      /work/SRC/openSUSE:Factory/.python-social-auth-core.new.1548 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-social-auth-core"

Wed Jun 15 00:33:40 2022 rev:17 rq:982613 version:4.3.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-social-auth-core/python-social-auth-core.changes
  2022-04-20 17:03:54.335187865 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-social-auth-core.new.1548/python-social-auth-core.changes
        2022-06-15 00:34:41.162736924 +0200
@@ -1,0 +2,15 @@
+Mon Jun 13 10:44:07 UTC 2022 - Ben Greiner <c...@bnavigator.de>
+
+- Update to 4.3.0
+  * Add backend for Hashicorp Vault OIDC backend
+  * Add generic OpenID Connect backend
+  * Add Grafana OAuth2 backend
+  * Add MusicBrainz OAuth2 backend
+  * Fixed redirect state for Keycloak backend
+  * Add fallback to RSA256 in OpenID Connect when alg is not set
+  * Fixed Azure backend so it can be used with all Azure authority
+    hosts
+- Don't test extra saml for which the distro does not have the right
+  packages
+
+-------------------------------------------------------------------

Old:
----
  social-core-4.2.0.tar.gz

New:
----
  social-core-4.3.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-social-auth-core.spec ++++++
--- /var/tmp/diff_new_pack.BHrO4I/_old  2022-06-15 00:34:42.358738681 +0200
+++ /var/tmp/diff_new_pack.BHrO4I/_new  2022-06-15 00:34:42.362738687 +0200
@@ -17,42 +17,49 @@
 #
 
 
-%{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 %define modname social-core
+# saml is optional: packages in TW and Leap not compatible
+%bcond_with saml
+
 Name:           python-social-auth-core
-Version:        4.2.0
+Version:        4.3.0
 Release:        0
 Summary:        Python Social Auth Core
 License:        BSD-3-Clause
 URL:            https://github.com/python-social-auth/social-core
 Source:         
https://github.com/python-social-auth/%{modname}/archive/%{version}.tar.gz#/%{modname}-%{version}.tar.gz
 BuildRequires:  %{python_module PyJWT >= 2.0.0}
-BuildRequires:  %{python_module coverage >= 3.6}
 BuildRequires:  %{python_module cryptography >= 2.1.1}
 BuildRequires:  %{python_module defusedxml >= 0.5.0}
-BuildRequires:  %{python_module httpretty}
 BuildRequires:  %{python_module oauthlib >= 1.0.3}
-BuildRequires:  %{python_module pytest}
-BuildRequires:  %{python_module python-jose >= 3.0.0}
 BuildRequires:  %{python_module python3-openid >= 3.0.10}
-BuildRequires:  %{python_module python3-saml >= 1.2.1}
 BuildRequires:  %{python_module requests >= 2.9.1}
 BuildRequires:  %{python_module requests-oauthlib >= 0.6.1}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  ca-certificates
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
+# SECTION test requirements
+BuildRequires:  %{python_module pytest}
+BuildRequires:  %{python_module httpretty >= 0.9.6}
+#/SECTION
+# SECTION optional requirements for tests
+BuildRequires:  %{python_module python-jose >= 3.0.0}
+%if %{with saml}
+BuildRequires:  %{python_module lxml < 4.7}
+BuildRequires:  %{python_module python3-saml >= 1.2.1}
+%endif
+#/SECTION
 Requires:       python-PyJWT >= 2.0.0
 Requires:       python-cryptography >= 2.1.1
+Requires:       python-defusedxml >= 0.5.0
 Requires:       python-oauthlib >= 1.0.3
-Requires:       python-python-jose >= 3.0.0
+Requires:       python-python3-openid >= 3.0.10
 Requires:       python-requests >= 2.9.1
 Requires:       python-requests-oauthlib >= 0.6.1
+Recommends:     python-python-jose >= 3.0.0
 BuildArch:      noarch
-Requires:       python-defusedxml >= 0.5.0
-Requires:       python-python3-openid >= 3.0.10
-Recommends:     python-python3-saml >= 1.2.1
 %python_subpackages
 
 %description
@@ -75,14 +82,15 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-# python3 only: assertRaisesRegexp -> assertRaisesRegex
-# skipped tests are online based
-rm -rf _build.python2
-%pytest -k 'not (test_login or test_partial_pipeline)'
+%if !%{with saml}
+donttest+=" or test_saml"
+%endif
+%pytest -k "not (dummyprefix $donttest)"
 
 %files %{python_files}
 %doc CHANGELOG.md README.md
 %license LICENSE
-%{python_sitelib}/*
+%{python_sitelib}/social_core
+%{python_sitelib}/social_auth_core-%{version}*-info
 
 %changelog

++++++ social-core-4.2.0.tar.gz -> social-core-4.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-core-4.2.0/CHANGELOG.md 
new/social-core-4.3.0/CHANGELOG.md
--- old/social-core-4.2.0/CHANGELOG.md  2022-01-17 14:26:01.000000000 +0100
+++ new/social-core-4.3.0/CHANGELOG.md  2022-06-13 09:08:54.000000000 +0200
@@ -5,6 +5,20 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## 
[4.3.0](https://github.com/python-social-auth/social-core/releases/tag/4.3.0) - 
2022-06-13
+
+### Added
+- Add backend for Hashicorp Vault OIDC backend
+- Add generic OpenID Connect backend
+- Add Grafana OAuth2 backend
+- Add MusicBrainz OAuth2 backend
+
+### Changed
+- Fixed redirect state for Keycloak backend
+- Add fallback to RSA256 in OpenID Connect when alg is not set
+- Fixed Azure backend so it can be used with all Azure authority hosts
+
+
 ## 
[4.2.0](https://github.com/python-social-auth/social-core/releases/tag/4.2.0) - 
2022-01-17
 
 ### Added
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-core-4.2.0/social_core/__init__.py 
new/social-core-4.3.0/social_core/__init__.py
--- old/social-core-4.2.0/social_core/__init__.py       2022-01-17 
14:26:01.000000000 +0100
+++ new/social-core-4.3.0/social_core/__init__.py       2022-06-13 
09:08:54.000000000 +0200
@@ -1 +1 @@
-__version__ = '4.2.0'
+__version__ = '4.3.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-core-4.2.0/social_core/backends/azuread.py 
new/social-core-4.3.0/social_core/backends/azuread.py
--- old/social-core-4.2.0/social_core/backends/azuread.py       2022-01-17 
14:26:01.000000000 +0100
+++ new/social-core-4.3.0/social_core/backends/azuread.py       2022-06-13 
09:08:54.000000000 +0200
@@ -40,9 +40,9 @@
 class AzureADOAuth2(BaseOAuth2):
     name = 'azuread-oauth2'
     SCOPE_SEPARATOR = ' '
-    AUTHORIZATION_URL = \
-        'https://login.microsoftonline.com/common/oauth2/authorize'
-    ACCESS_TOKEN_URL = 'https://login.microsoftonline.com/common/oauth2/token'
+    BASE_URL = 'https://{authority_host}/{tenant_id}'
+    AUTHORIZATION_URL = '{base_url}/oauth2/authorize'
+    ACCESS_TOKEN_URL = '{base_url}/oauth2/token'
     ACCESS_TOKEN_METHOD = 'POST'
     REDIRECT_STATE = False
     DEFAULT_SCOPE = ['openid', 'profile', 'user_impersonation', 'email']
@@ -58,6 +58,24 @@
         ('token_type', 'token_type')
     ]
 
+    @property
+    def authority_host(self):
+        return self.setting('AUTHORITY_HOST', 'login.microsoftonline.com')
+
+    @property
+    def tenant_id(self):
+        return 'common'
+
+    @property
+    def base_url(self):
+        return self.BASE_URL.format(authority_host=self.authority_host, 
tenant_id=self.tenant_id)
+
+    def authorization_url(self):
+        return self.AUTHORIZATION_URL.format(base_url=self.base_url)
+
+    def access_token_url(self):
+        return self.ACCESS_TOKEN_URL.format(base_url=self.base_url)
+
     def get_user_id(self, details, response):
         """Use upn as unique id"""
         return response.get('upn')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-core-4.2.0/social_core/backends/azuread_b2c.py 
new/social-core-4.3.0/social_core/backends/azuread_b2c.py
--- old/social-core-4.2.0/social_core/backends/azuread_b2c.py   2022-01-17 
14:26:01.000000000 +0100
+++ new/social-core-4.3.0/social_core/backends/azuread_b2c.py   2022-06-13 
09:08:54.000000000 +0200
@@ -53,7 +53,6 @@
 class AzureADB2COAuth2(AzureADOAuth2):
     name = 'azuread-b2c-oauth2'
 
-    BASE_URL = 'https://login.microsoftonline.com/{tenant_id}'
     AUTHORIZATION_URL = '{base_url}/oauth2/v2.0/authorize'
     OPENID_CONFIGURATION_URL = 
'{base_url}/v2.0/.well-known/openid-configuration?p={policy}'
     ACCESS_TOKEN_URL = '{base_url}/oauth2/v2.0/token?p={policy}'
@@ -84,10 +83,6 @@
                                 'required and should start with `b2c_`')
         return policy
 
-    @property
-    def base_url(self):
-        return self.BASE_URL.format(tenant_id=self.tenant_id)
-
     def openid_configuration_url(self):
         return self.OPENID_CONFIGURATION_URL.format(base_url=self.base_url,
                                                     policy=self.policy)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-core-4.2.0/social_core/backends/azuread_tenant.py 
new/social-core-4.3.0/social_core/backends/azuread_tenant.py
--- old/social-core-4.2.0/social_core/backends/azuread_tenant.py        
2022-01-17 14:26:01.000000000 +0100
+++ new/social-core-4.3.0/social_core/backends/azuread_tenant.py        
2022-06-13 09:08:54.000000000 +0200
@@ -47,27 +47,18 @@
 class AzureADTenantOAuth2(AzureADOAuth2):
     name = 'azuread-tenant-oauth2'
     OPENID_CONFIGURATION_URL = \
-        
'https://login.microsoftonline.com/{tenant_id}/.well-known/openid-configuration'
-    AUTHORIZATION_URL = \
-        'https://login.microsoftonline.com/{tenant_id}/oauth2/authorize'
-    ACCESS_TOKEN_URL = 
'https://login.microsoftonline.com/{tenant_id}/oauth2/token'
-    JWKS_URL = 'https://login.microsoftonline.com/{tenant_id}/discovery/keys'
+        '{base_url}/.well-known/openid-configuration'
+    JWKS_URL = '{base_url}/discovery/keys'
 
     @property
     def tenant_id(self):
         return self.setting('TENANT_ID', 'common')
 
     def openid_configuration_url(self):
-        return self.OPENID_CONFIGURATION_URL.format(tenant_id=self.tenant_id)
-
-    def authorization_url(self):
-        return self.AUTHORIZATION_URL.format(tenant_id=self.tenant_id)
-
-    def access_token_url(self):
-        return self.ACCESS_TOKEN_URL.format(tenant_id=self.tenant_id)
+        return self.OPENID_CONFIGURATION_URL.format(base_url=self.base_url)
 
     def jwks_url(self):
-        return self.JWKS_URL.format(tenant_id=self.tenant_id)
+        return self.JWKS_URL.format(base_url=self.base_url)
 
     def get_certificate(self, kid):
         # retrieve keys from jwks_url
@@ -112,11 +103,10 @@
 
 class AzureADV2TenantOAuth2(AzureADTenantOAuth2):
     name = 'azuread-v2-tenant-oauth2'
-    OPENID_CONFIGURATION_URL = \
-        
'https://login.microsoftonline.com/{tenant_id}/v2.0/.well-known/openid-configuration'
-    AUTHORIZATION_URL = 
'https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/authorize'
-    ACCESS_TOKEN_URL = 
'https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token'
-    JWKS_URL = 
'https://login.microsoftonline.com/{tenant_id}/discovery/v2.0/keys'
+    OPENID_CONFIGURATION_URL = 
'{base_url}/v2.0/.well-known/openid-configuration'
+    AUTHORIZATION_URL = '{base_url}/oauth2/v2.0/authorize'
+    ACCESS_TOKEN_URL = '{base_url}/oauth2/v2.0/token'
+    JWKS_URL = '{base_url}/discovery/v2.0/keys'
     DEFAULT_SCOPE = ['openid', 'profile', 'offline_access']
 
     def get_user_id(self, details, response):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-core-4.2.0/social_core/backends/grafana.py 
new/social-core-4.3.0/social_core/backends/grafana.py
--- old/social-core-4.2.0/social_core/backends/grafana.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/social-core-4.3.0/social_core/backends/grafana.py       2022-06-13 
09:08:54.000000000 +0200
@@ -0,0 +1,25 @@
+from social_core.backends.oauth import BaseOAuth2
+
+
+class GrafanaOAuth2(BaseOAuth2):
+    """Grafana OAuth authentication backend"""
+    name = 'grafana'
+    AUTHORIZATION_URL = 'https://grafana.com/oauth2/authorize'
+    ACCESS_TOKEN_URL = 'https://grafana.com/api/oauth2/token'
+    ACCESS_TOKEN_METHOD = 'POST'
+    DEFAULT_SCOPE = ['profile', 'email']
+    SCOPE_SEPARATOR = ','
+    USER_DETAILS_URL = 'https://grafana.com/api/oauth2/user'
+
+    def get_user_details(self, response):
+        """Return user details from Grafana account"""
+        return {'username': response.get('login'),
+                'email': response.get('email') or '',
+                'first_name': response.get('name'),
+                'last_name': '-'}
+
+    def user_data(self, access_token, *args, **kwargs):
+        """Loads user data from service"""
+        return self.get_json(self.USER_DETAILS_URL, **{
+            'headers': {'Authorization': f'Bearer {access_token}'}
+        })
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-core-4.2.0/social_core/backends/keycloak.py 
new/social-core-4.3.0/social_core/backends/keycloak.py
--- old/social-core-4.2.0/social_core/backends/keycloak.py      2022-01-17 
14:26:01.000000000 +0100
+++ new/social-core-4.3.0/social_core/backends/keycloak.py      2022-06-13 
09:08:54.000000000 +0200
@@ -88,6 +88,7 @@
     name = 'keycloak'
     ID_KEY = 'username'
     ACCESS_TOKEN_METHOD = 'POST'
+    REDIRECT_STATE = False
 
     def authorization_url(self):
         return self.setting('AUTHORIZATION_URL')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-core-4.2.0/social_core/backends/musicbrainz.py 
new/social-core-4.3.0/social_core/backends/musicbrainz.py
--- old/social-core-4.2.0/social_core/backends/musicbrainz.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/social-core-4.3.0/social_core/backends/musicbrainz.py   2022-06-13 
09:08:54.000000000 +0200
@@ -0,0 +1,28 @@
+from social_core.backends.oauth import BaseOAuth2
+
+class MusicBrainzOAuth2(BaseOAuth2):
+    """MusicBrainz OAuth authentication backend"""
+    name = 'musicbrainz'
+    AUTHORIZATION_URL = 'https://musicbrainz.org/oauth2/authorize'
+    ACCESS_TOKEN_URL = 'https://musicbrainz.org/oauth2/token'
+    ACCESS_TOKEN_METHOD = 'POST'
+    ID_KEY = 'metabrainz_user_id'
+    DEFAULT_SCOPE = ['profile', 'email']
+    SCOPE_SEPARATOR = ' '
+    REDIRECT_STATE = False
+    EXTRA_DATA = [
+        ('metabrainz_user_id', 'id'),
+        ('expires_in', 'expires'),
+    ]
+
+    def get_user_details(self, response):
+        """Return user details from MusicBrainz account"""
+        return {'username': response.get('sub'),
+                'email': response.get('email') or '',
+                'first_name': response.get('sub')}
+
+    def user_data(self, access_token, *args, **kwargs):
+        """Loads user data from service"""
+        return self.get_json('https://musicbrainz.org/oauth2/userinfo', 
params={
+            'access_token': access_token
+        })
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-core-4.2.0/social_core/backends/oauth.py 
new/social-core-4.3.0/social_core/backends/oauth.py
--- old/social-core-4.2.0/social_core/backends/oauth.py 2022-01-17 
14:26:01.000000000 +0100
+++ new/social-core-4.3.0/social_core/backends/oauth.py 2022-06-13 
09:08:54.000000000 +0200
@@ -297,14 +297,18 @@
 class BaseOAuth2(OAuthAuth):
     """Base class for OAuth2 providers.
 
-    OAuth2 draft details at:
-        http://tools.ietf.org/html/draft-ietf-oauth-v2-10
+    OAuth2 details at:
+        https://datatracker.ietf.org/doc/html/rfc6749
     """
     REFRESH_TOKEN_URL = None
     REFRESH_TOKEN_METHOD = 'POST'
     RESPONSE_TYPE = 'code'
     REDIRECT_STATE = True
     STATE_PARAMETER = True
+    USE_BASIC_AUTH = False
+
+    def use_basic_auth(self):
+        return self.USE_BASIC_AUTH
 
     def auth_params(self, state=None):
         client_id, client_secret = self.get_key_and_secret()
@@ -332,16 +336,22 @@
         return f'{self.authorization_url()}?{params}'
 
     def auth_complete_params(self, state=None):
-        client_id, client_secret = self.get_key_and_secret()
-        return {
+        params = {
             'grant_type': 'authorization_code',  # request auth code
             'code': self.data.get('code', ''),  # server response code
-            'client_id': client_id,
-            'client_secret': client_secret,
             'redirect_uri': self.get_redirect_uri(state)
         }
+        if not self.use_basic_auth():
+            client_id, client_secret = self.get_key_and_secret()
+            params.update({
+                'client_id': client_id,
+                'client_secret': client_secret,
+            })
+        return params
 
     def auth_complete_credentials(self):
+        if self.use_basic_auth():
+            return self.get_key_and_secret()
         return None
 
     def auth_headers(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-core-4.2.0/social_core/backends/open_id_connect.py 
new/social-core-4.3.0/social_core/backends/open_id_connect.py
--- old/social-core-4.2.0/social_core/backends/open_id_connect.py       
2022-01-17 14:26:01.000000000 +0100
+++ new/social-core-4.3.0/social_core/backends/open_id_connect.py       
2022-06-13 09:08:54.000000000 +0200
@@ -26,7 +26,15 @@
     """
     Base class for Open ID Connect backends.
     Currently only the code response type is supported.
+
+    It can also be directly instantiated as a generic OIDC backend.
+    To use it you will need to set at minimum:
+
+    SOCIAL_AUTH_OIDC_OIDC_ENDPOINT = 'https://.....'  # endpoint without 
/.well-known/openid-configuration
+    SOCIAL_AUTH_OIDC_KEY = '<client_id>'
+    SOCIAL_AUTH_OIDC_SECRET = '<client_secret>'
     """
+    name = 'oidc'
     # Override OIDC_ENDPOINT in your subclass to enable autoconfig of OIDC
     OIDC_ENDPOINT = None
     ID_TOKEN_MAX_AGE = 600
@@ -37,46 +45,58 @@
     REVOKE_TOKEN_METHOD = 'GET'
     ID_KEY = 'sub'
     USERNAME_KEY = 'preferred_username'
+    JWT_ALGORITHMS = ['RS256']
+    JWT_DECODE_OPTIONS = dict()
+    # When these options are unspecified, server will choose via openid 
autoconfiguration
     ID_TOKEN_ISSUER = ''
     ACCESS_TOKEN_URL = ''
     AUTHORIZATION_URL = ''
     REVOKE_TOKEN_URL = ''
     USERINFO_URL = ''
     JWKS_URI = ''
-    JWT_ALGORITHMS = ['RS256']
-    JWT_DECODE_OPTIONS = dict()
+    TOKEN_ENDPOINT_AUTH_METHOD = ''
 
     def __init__(self, *args, **kwargs):
         self.id_token = None
         super().__init__(*args, **kwargs)
 
     def authorization_url(self):
-        return self.AUTHORIZATION_URL or \
+        return self.setting('AUTHORIZATION_URL', self.AUTHORIZATION_URL) or \
             self.oidc_config().get('authorization_endpoint')
 
     def access_token_url(self):
-        return self.ACCESS_TOKEN_URL or \
+        return self.setting('ACCESS_TOKEN_URL', self.ACCESS_TOKEN_URL) or \
             self.oidc_config().get('token_endpoint')
 
     def revoke_token_url(self, token, uid):
-        return self.REVOKE_TOKEN_URL or \
+        return self.setting('REVOKE_TOKEN_URL', self.REVOKE_TOKEN_URL) or \
             self.oidc_config().get('revocation_endpoint')
 
     def id_token_issuer(self):
-        return self.ID_TOKEN_ISSUER or \
+        return self.setting('ID_TOKEN_ISSUER', self.ID_TOKEN_ISSUER) or \
             self.oidc_config().get('issuer')
 
     def userinfo_url(self):
-        return self.USERINFO_URL or \
+        return self.setting('USERINFO_URL', self.USERINFO_URL) or \
             self.oidc_config().get('userinfo_endpoint')
 
     def jwks_uri(self):
-        return self.JWKS_URI or \
+        return self.setting('JWKS_URI', self.JWKS_URI) or \
             self.oidc_config().get('jwks_uri')
 
+    def use_basic_auth(self):
+        method = self.setting('TOKEN_ENDPOINT_AUTH_METHOD', 
self.TOKEN_ENDPOINT_AUTH_METHOD)
+        if method:
+            return method == 'client_secret_basic'
+        methods = 
self.oidc_config().get('token_endpoint_auth_methods_supported', [])
+        return not methods or 'client_secret_basic' in methods
+
+    def oidc_endpoint(self):
+        return self.setting('OIDC_ENDPOINT', self.OIDC_ENDPOINT)
+
     @cache(ttl=86400)
     def oidc_config(self):
-        return self.get_json(self.OIDC_ENDPOINT +
+        return self.get_json(self.oidc_endpoint() +
                              '/.well-known/openid-configuration')
 
     @cache(ttl=86400)
@@ -159,6 +179,8 @@
 
         for key in keys:
             if kid is None or kid == key.get('kid'):
+                if 'alg' not in key:
+                    key['alg'] = self.setting('JWT_ALGORITHMS', 
self.JWT_ALGORITHMS)[0]
                 rsakey = jwk.construct(key)
                 message, encoded_sig = id_token.rsplit('.', 1)
                 decoded_sig = base64url_decode(encoded_sig.encode('utf-8'))
@@ -184,11 +206,11 @@
             claims = jwt.decode(
                 id_token,
                 rsakey.to_pem().decode('utf-8'),
-                algorithms=self.JWT_ALGORITHMS,
+                algorithms=self.setting('JWT_ALGORITHMS', self.JWT_ALGORITHMS),
                 audience=client_id,
                 issuer=self.id_token_issuer(),
                 access_token=access_token,
-                options=self.JWT_DECODE_OPTIONS,
+                options=self.setting('JWT_DECODE_OPTIONS', 
self.JWT_DECODE_OPTIONS),
             )
         except ExpiredSignatureError:
             raise AuthTokenError(self, 'Signature has expired')
@@ -219,11 +241,12 @@
         })
 
     def get_user_details(self, response):
-        username_key = self.setting('USERNAME_KEY', default=self.USERNAME_KEY)
+        username_key = self.setting('USERNAME_KEY', self.USERNAME_KEY)
         return {
             'username': response.get(username_key),
             'email': response.get('email'),
             'fullname': response.get('name'),
             'first_name': response.get('given_name'),
             'last_name': response.get('family_name'),
+            'groups': response.get('groups'),    # not standardized but widely 
implemented
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-core-4.2.0/social_core/backends/saml.py 
new/social-core-4.3.0/social_core/backends/saml.py
--- old/social-core-4.2.0/social_core/backends/saml.py  2022-01-17 
14:26:01.000000000 +0100
+++ new/social-core-4.3.0/social_core/backends/saml.py  2022-06-13 
09:08:54.000000000 +0200
@@ -269,7 +269,6 @@
             'https': 'on' if self.strategy.request_is_secure() else 'off',
             'http_host': self.strategy.request_host(),
             'script_name': self.strategy.request_path(),
-            'server_port': self.strategy.request_port(),
             'get_data': self.strategy.request_get(),
             'post_data': self.strategy.request_post(),
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-core-4.2.0/social_core/backends/vault.py 
new/social-core-4.3.0/social_core/backends/vault.py
--- old/social-core-4.2.0/social_core/backends/vault.py 1970-01-01 
01:00:00.000000000 +0100
+++ new/social-core-4.3.0/social_core/backends/vault.py 2022-06-13 
09:08:54.000000000 +0200
@@ -0,0 +1,18 @@
+"""
+Backend for Hashicorp Vault OIDC Identity Provider in Vault 1.9+
+https://www.vaultproject.io/docs/secrets/identity/oidc-provider
+"""
+import base64
+
+from social_core.backends.open_id_connect import OpenIdConnectAuth
+from social_core.utils import cache
+
+
+
+class VaultOpenIdConnect(OpenIdConnectAuth):
+    """
+    Vault OIDC authentication backend
+
+    This is an alias for the generic OIDC backend
+    """
+    name = 'vault'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-core-4.2.0/social_core/tests/backends/test_grafana.py 
new/social-core-4.3.0/social_core/tests/backends/test_grafana.py
--- old/social-core-4.2.0/social_core/tests/backends/test_grafana.py    
1970-01-01 01:00:00.000000000 +0100
+++ new/social-core-4.3.0/social_core/tests/backends/test_grafana.py    
2022-06-13 09:08:54.000000000 +0200
@@ -0,0 +1,24 @@
+import json
+
+from .oauth import OAuth2Test
+
+
+class GrafanaOAuth2Test(OAuth2Test):
+    backend_path = 'social_core.backends.grafana.GrafanaOAuth2'
+    user_data_url = 'https://grafana.com/api/oauth2/user'
+    access_token_body = json.dumps({
+        'access_token': 'foobar',
+        'token_type': 'bearer',
+    })
+    user_data_body = json.dumps({
+        'login': 'fooboy',
+        'email': 'f...@bar.com',
+        'name': 'Foo Bar'
+    })
+    expected_username = 'fooboy'
+
+    def test_login(self):
+        self.do_login()
+
+    def test_partial_pipeline(self):
+        self.do_partial_pipeline()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-core-4.2.0/social_core/tests/backends/test_musicbrainz.py 
new/social-core-4.3.0/social_core/tests/backends/test_musicbrainz.py
--- old/social-core-4.2.0/social_core/tests/backends/test_musicbrainz.py        
1970-01-01 01:00:00.000000000 +0100
+++ new/social-core-4.3.0/social_core/tests/backends/test_musicbrainz.py        
2022-06-13 09:08:54.000000000 +0200
@@ -0,0 +1,28 @@
+import json
+
+from httpretty import HTTPretty
+
+from ...exceptions import AuthFailed
+from .oauth import OAuth2Test
+
+
+class MusicBrainzAuth2Test(OAuth2Test):
+    backend_path = 'social_core.backends.musicbrainz.MusicBrainzOAuth2'
+    user_data_url = 'https://musicbrainz.org/oauth2/userinfo'
+    expected_username = 'foobar'
+    access_token_body = json.dumps({
+      'access_token': 'GjtKfJS6G4lupbQcCOiTKo4HcLXUgI1p',
+      'expires_in': 3600,
+      'token_type': 'Bearer',
+      'refresh_token': 'GjSCBBjp4fnbE0AKo3uFu9qq9K2fFm4u'
+    })
+    user_data_body = json.dumps({
+        'sub': 'foobar',
+        'email': 'f...@bar.com',
+    })
+
+    def test_login(self):
+        self.do_login()
+
+    def test_partial_pipeline(self):
+        self.do_partial_pipeline()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-core-4.2.0/social_core/tests/backends/test_okta.py 
new/social-core-4.3.0/social_core/tests/backends/test_okta.py
--- old/social-core-4.2.0/social_core/tests/backends/test_okta.py       
2022-01-17 14:26:01.000000000 +0100
+++ new/social-core-4.3.0/social_core/tests/backends/test_okta.py       
2022-06-13 09:08:54.000000000 +0200
@@ -132,7 +132,8 @@
         self.public_key = JWK_PUBLIC_KEY.copy()
 
         HTTPretty.register_uri(HTTPretty.GET,
-                               self.backend.OIDC_ENDPOINT + 
'/.well-known/openid-configuration',
+                               # Note: okta.py strips the /oauth2 prefix using 
urljoin with absolute path
+                               
'https://dev-000000.oktapreview.com/.well-known/openid-configuration?client_id=a-key',
                                status=200,
                                body=self.openid_config_body)
         oidc_config = json.loads(self.openid_config_body)
@@ -147,3 +148,14 @@
 
         self.backend.JWKS_URI = oidc_config.get('jwks_uri')
         self.backend.ID_TOKEN_ISSUER = oidc_config.get('issuer')
+
+    def pre_complete_callback(self, start_url):
+        super().pre_complete_callback(start_url)
+        HTTPretty.register_uri('GET',
+                               uri=self.backend.userinfo_url(),
+                               status=200,
+                               body=json.dumps({'preferred_username': 
self.expected_username}),
+                               content_type='text/json')
+
+    def test_everything_works(self):
+        self.do_login()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-core-4.2.0/social_core/tests/backends/test_open_id_connect.py 
new/social-core-4.3.0/social_core/tests/backends/test_open_id_connect.py
--- old/social-core-4.2.0/social_core/tests/backends/test_open_id_connect.py    
2022-01-17 14:26:01.000000000 +0100
+++ new/social-core-4.3.0/social_core/tests/backends/test_open_id_connect.py    
2022-06-13 09:08:54.000000000 +0200
@@ -54,7 +54,11 @@
     issuer = None  # id_token issuer
     openid_config_body = None
     key = None
-    access_token_kwargs = {}
+    # Avoid sharing access_token_kwargs between different subclasses
+    def __init_subclass__(cls, **kwargs):
+        super().__init_subclass__(**kwargs)
+        cls.access_token_kwargs = getattr(cls, 'access_token_kwargs', {})
+
 
     def setUp(self):
         super().setUp()
@@ -62,7 +66,7 @@
         self.public_key = JWK_PUBLIC_KEY.copy()
 
         HTTPretty.register_uri(HTTPretty.GET,
-                               self.backend.OIDC_ENDPOINT + 
'/.well-known/openid-configuration',
+                               self.backend.oidc_endpoint() + 
'/.well-known/openid-configuration',
                                status=200,
                                body=self.openid_config_body
                                )
@@ -200,12 +204,46 @@
         self.authtoken_raised('Token error: Signature verification failed', 
kid='doesnotexist')
 
 
+class BaseOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test):
+    backend_path = \
+        'social_core.backends.open_id_connect.OpenIdConnectAuth'
+    issuer = 'https://example.com'
+    openid_config_body = json.dumps({
+        'issuer': 'https://example.com',
+        'authorization_endpoint': 'https://example.com/oidc/auth',
+        'token_endpoint': 'https://example.com/oidc/token',
+        'userinfo_endpoint': 'https://example.com/oidc/userinfo',
+        'revocation_endpoint': 'https://example.com/oidc/revoke',
+        'jwks_uri': 'https://example.com/oidc/certs',
+    })
+
+    expected_username = 'cartman'
+
+    def extra_settings(self):
+        settings = super().extra_settings()
+        settings.update({
+            f'SOCIAL_AUTH_OIDC_OIDC_ENDPOINT': 'https://example.com/oidc',
+        })
+        return settings
+
+    def pre_complete_callback(self, start_url):
+        super().pre_complete_callback(start_url)
+        HTTPretty.register_uri('GET',
+                               uri=self.backend.userinfo_url(),
+                               status=200,
+                               body=json.dumps({'preferred_username': 
self.expected_username}),
+                               content_type='text/json')
+
+    def test_everything_works(self):
+        self.do_login()
+
+
 class ExampleOpenIdConnectAuth(OpenIdConnectAuth):
     name = 'example123'
     OIDC_ENDPOINT = 'https://example.com/oidc'
 
 
-class OpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test):
+class ExampleOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test):
     backend_path = \
         
'social_core.tests.backends.test_open_id_connect.ExampleOpenIdConnectAuth'
     issuer = 'https://example.com'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-core-4.2.0/social_core/tests/backends/test_vault.py 
new/social-core-4.3.0/social_core/tests/backends/test_vault.py
--- old/social-core-4.2.0/social_core/tests/backends/test_vault.py      
1970-01-01 01:00:00.000000000 +0100
+++ new/social-core-4.3.0/social_core/tests/backends/test_vault.py      
2022-06-13 09:08:54.000000000 +0200
@@ -0,0 +1,41 @@
+import json
+
+from httpretty import HTTPretty
+
+from .oauth import OAuth2Test
+from .test_open_id_connect import OpenIdConnectTestMixin
+
+class VaultOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test):
+    backend_path = \
+        'social_core.backends.vault.VaultOpenIdConnect'
+    issuer = 'https://vault.example.net:8200/v1/identity/oidc/provider/default'
+    openid_config_body = json.dumps({
+      'issuer': 
'https://vault.example.net:8200/v1/identity/oidc/provider/default',
+      'jwks_uri': 
'https://vault.example.net:8200/v1/identity/oidc/provider/default/.well-known/keys',
+      'authorization_endpoint': 
'https://vault.example.net:8200/ui/vault/identity/oidc/provider/default/authorize',
+      'token_endpoint': 
'https://vault.example.net:8200/v1/identity/oidc/provider/default/token',
+      'userinfo_endpoint': 
'https://vault.example.net:8200/v1/identity/oidc/provider/default/userinfo',
+      'request_uri_parameter_supported': False,
+      'grant_types_supported': [ 'authorization_code' ],
+      'token_endpoint_auth_methods_supported': [ 'client_secret_basic' ],
+    })
+
+    expected_username = 'cartman'
+
+    def extra_settings(self):
+        settings = super().extra_settings()
+        settings.update({
+            f'SOCIAL_AUTH_{self.name}_OIDC_ENDPOINT': 
'https://vault.example.net:8200/v1/identity/oidc/provider/default',
+        })
+        return settings
+
+    def pre_complete_callback(self, start_url):
+        super().pre_complete_callback(start_url)
+        HTTPretty.register_uri('GET',
+                               uri=self.backend.userinfo_url(),
+                               status=200,
+                               body=json.dumps({'preferred_username': 
self.expected_username}),
+                               content_type='text/json')
+
+    def test_everything_works(self):
+        self.do_login()

Reply via email to