auth: Implement a generic OpenID Connect backend.

Fixes #11939.
This commit is contained in:
Mateusz Mandera
2021-05-21 16:45:43 +02:00
committed by Tim Abbott
parent 1103720f45
commit e17758f8ad
15 changed files with 316 additions and 0 deletions

View File

@@ -43,6 +43,7 @@ from social_core.backends.base import BaseAuth
from social_core.backends.github import GithubOAuth2, GithubOrganizationOAuth2, GithubTeamOAuth2
from social_core.backends.gitlab import GitLabOAuth2
from social_core.backends.google import GoogleOAuth2
from social_core.backends.open_id_connect import OpenIdConnectAuth
from social_core.backends.saml import SAMLAuth, SAMLIdentityProvider
from social_core.exceptions import (
AuthCanceled,
@@ -2263,6 +2264,54 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
return result
@external_auth_method
class GenericOpenIdConnectBackend(SocialAuthMixin, OpenIdConnectAuth):
name = "oidc"
auth_backend_name = "OpenID Connect"
sort_order = 100
# Hack: We don't yet support multiple IdPs, but we want this
# module to import if nothing has been configured yet.
settings_dict = list(settings.SOCIAL_AUTH_OIDC_ENABLED_IDPS.values() or [{}])[0]
display_icon = settings_dict.get("display_icon")
display_name = settings_dict.get("display_name", "OIDC")
# Discovery endpoint for the superclass to read all the appropriate
# configuration from.
OIDC_ENDPOINT = settings_dict.get("oidc_url")
def get_key_and_secret(self) -> Tuple[str, str]:
client_id = self.settings_dict.get("client_id", "")
secret = self.settings_dict.get("secret", "")
return client_id, secret
@classmethod
def check_config(cls) -> bool:
if len(settings.SOCIAL_AUTH_OIDC_ENABLED_IDPS.keys()) != 1:
# Only one IdP supported for now.
return False
mandatory_config_keys = ["oidc_url", "client_id", "secret"]
idp_config_dict = list(settings.SOCIAL_AUTH_OIDC_ENABLED_IDPS.values())[0]
if not all(idp_config_dict.get(key) for key in mandatory_config_keys):
return False
return True
@classmethod
def dict_representation(cls, realm: Optional[Realm] = None) -> List[ExternalAuthMethodDictT]:
return [
dict(
name=f"oidc:{cls.name}",
display_name=cls.display_name,
display_icon=cls.display_icon,
login_url=reverse("login-social", args=(cls.name,)),
signup_url=reverse("signup-social", args=(cls.name,)),
)
]
def validate_otp_params(
mobile_flow_otp: Optional[str] = None, desktop_flow_otp: Optional[str] = None
) -> None: