ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: Plane OIDC и план платформы
This commit is contained in:
@@ -81,7 +81,12 @@ class NodeDCOIDCCallbackEndpoint(View):
|
||||
if not has_required_group(groups):
|
||||
return oidc_error_redirect(base_url, next_path, "oidc_access_denied")
|
||||
|
||||
user = resolve_linked_user(claims=claims, groups=groups, auto_link=config["auto_link_email"])
|
||||
user = resolve_linked_user(
|
||||
claims=claims,
|
||||
groups=groups,
|
||||
auto_link=config["auto_link_email"],
|
||||
sync_profile=config["sync_profile"],
|
||||
)
|
||||
|
||||
if user is None or not user.is_active:
|
||||
return oidc_error_redirect(base_url, next_path, "oidc_user_not_linked")
|
||||
@@ -109,6 +114,7 @@ def get_oidc_config():
|
||||
"redirect_uri": redirect_uri,
|
||||
"scope": os.environ.get("PLANE_OIDC_SCOPE", "openid email profile groups"),
|
||||
"auto_link_email": os.environ.get("PLANE_OIDC_AUTO_LINK_EMAIL", "0") == "1",
|
||||
"sync_profile": os.environ.get("PLANE_OIDC_SYNC_PROFILE", "1") == "1",
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +179,7 @@ def has_required_group(groups):
|
||||
return bool(required_groups.intersection(set(groups)))
|
||||
|
||||
|
||||
def resolve_linked_user(claims, groups, auto_link):
|
||||
def resolve_linked_user(claims, groups, auto_link, sync_profile):
|
||||
subject = str(claims.get("sub") or "")
|
||||
email = str(claims.get("email") or "").strip().lower()
|
||||
|
||||
@@ -206,9 +212,53 @@ def resolve_linked_user(claims, groups, auto_link):
|
||||
user = link.user
|
||||
user.last_login_medium = OIDC_PROVIDER
|
||||
user.last_login_time = timezone.now()
|
||||
user.save(update_fields=["last_login_medium", "last_login_time", "updated_at"])
|
||||
update_fields = ["last_login_medium", "last_login_time", "updated_at"]
|
||||
|
||||
if sync_profile:
|
||||
update_fields.extend(sync_user_profile_from_claims(user, claims))
|
||||
|
||||
user.save(update_fields=list(dict.fromkeys(update_fields)))
|
||||
return user
|
||||
|
||||
|
||||
def sync_user_profile_from_claims(user, claims):
|
||||
updated_fields = []
|
||||
display_name = first_string_claim(claims, "name", "preferred_username")
|
||||
given_name = first_string_claim(claims, "given_name")
|
||||
family_name = first_string_claim(claims, "family_name")
|
||||
avatar_url = first_string_claim(claims, "picture", "avatar_url", "avatar")
|
||||
|
||||
if display_name and user.display_name != display_name:
|
||||
user.display_name = display_name
|
||||
updated_fields.append("display_name")
|
||||
|
||||
if not given_name and display_name:
|
||||
name_parts = display_name.split(" ", 1)
|
||||
given_name = name_parts[0]
|
||||
family_name = family_name or (name_parts[1] if len(name_parts) > 1 else "")
|
||||
|
||||
if given_name and user.first_name != given_name:
|
||||
user.first_name = given_name
|
||||
updated_fields.append("first_name")
|
||||
|
||||
if family_name is not None and user.last_name != family_name:
|
||||
user.last_name = family_name
|
||||
updated_fields.append("last_name")
|
||||
|
||||
if avatar_url and user.avatar != avatar_url:
|
||||
user.avatar = avatar_url
|
||||
updated_fields.append("avatar")
|
||||
|
||||
return updated_fields
|
||||
|
||||
|
||||
def first_string_claim(claims, *keys):
|
||||
for key in keys:
|
||||
value = claims.get(key)
|
||||
if isinstance(value, str) and value:
|
||||
return value
|
||||
return None
|
||||
|
||||
|
||||
def oidc_error_redirect(base_url, next_path, error_code):
|
||||
return HttpResponseRedirect(get_safe_redirect_url(base_url=base_url, next_path=next_path, params={"error": error_code}))
|
||||
|
||||
Reference in New Issue
Block a user