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 <[email protected]>
+
+- 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': '[email protected]',
+ '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': '[email protected]',
+ })
+
+ 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()