from __future__ import annotations from urllib.parse import urljoin from django.conf import settings from oauth2_provider.oauth2_validators import OAuth2Validator def _preferred_username(user) -> str: username = (getattr(user, "username", "") or "").strip() return username or f"employee-{user.pk}" def _is_active_employee(user) -> bool: if not user or not getattr(user, "is_authenticated", False): return False if not getattr(user, "is_active", False): return False if not getattr(user, "email_verified", False): return False return bool(getattr(user, "is_actually_active", True)) def _employee_groups(user) -> list[str]: groups = {"portal-users"} groups.update(user.groups.values_list("name", flat=True)) if getattr(user, "is_staff", False): groups.add("portal-staff") if getattr(user, "is_superuser", False): groups.add("portal-admins") return sorted(groups) def _picture_url(user) -> str | None: avatar = getattr(user, "avatar", None) if not avatar: return None try: return urljoin(f"{settings.SITE_URL}/", avatar.url.lstrip("/")) except (ValueError, AttributeError): return None class CorporateOAuth2Validator(OAuth2Validator): """Expose only verified corporate identity claims to OIDC clients.""" oidc_claim_scope = { **OAuth2Validator.oidc_claim_scope, "groups": "groups", } def validate_code(self, client_id, code, client, request, *args, **kwargs): valid = super().validate_code( client_id, code, client, request, *args, **kwargs ) return bool(valid and _is_active_employee(getattr(request, "user", None))) def validate_bearer_token(self, token, scopes, request): valid = super().validate_bearer_token(token, scopes, request) return bool(valid and _is_active_employee(getattr(request, "user", None))) def validate_refresh_token( self, refresh_token, client, request, *args, **kwargs ): valid = super().validate_refresh_token( refresh_token, client, request, *args, **kwargs ) return bool(valid and _is_active_employee(getattr(request, "user", None))) def get_additional_claims(self, request): user = request.user full_name = user.get_full_name().strip() updated_at = getattr(user, "updated_at", None) claims = { "name": full_name or str(user), "given_name": user.first_name, "family_name": user.last_name, "preferred_username": _preferred_username(user), "nickname": _preferred_username(user), "email": user.email, "email_verified": bool(user.email_verified), "locale": "ru-RU", "zoneinfo": settings.TIME_ZONE, "groups": _employee_groups(user), } picture = _picture_url(user) if picture: claims["picture"] = picture if updated_at: claims["updated_at"] = int(updated_at.timestamp()) return claims