mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 09:12:11 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			96 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
 | 
						|
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
						|
 | 
						|
from oauth2_provider.oauth2_validators import OAuth2Validator
 | 
						|
from oauth2_provider.scopes import BaseScopes
 | 
						|
from member.models import Club
 | 
						|
from note.models import Alias
 | 
						|
from note_kfet.middlewares import get_current_request
 | 
						|
 | 
						|
from .backends import PermissionBackend
 | 
						|
from .models import Permission
 | 
						|
 | 
						|
 | 
						|
class PermissionScopes(BaseScopes):
 | 
						|
    """
 | 
						|
    An OAuth2 scope is defined by a permission object and a club.
 | 
						|
    A token will have a subset of permissions from the owner of the application,
 | 
						|
    and can be useful to make queries through the API with limited privileges.
 | 
						|
    """
 | 
						|
 | 
						|
    def get_all_scopes(self, **kwargs):
 | 
						|
        scopes = {}
 | 
						|
        if 'scopes' in kwargs:
 | 
						|
            for scope in kwargs['scopes']:
 | 
						|
                if scope == 'openid':
 | 
						|
                    scopes['openid'] = "OpenID Connect"
 | 
						|
                else:
 | 
						|
                    p = Permission.objects.get(id=scope.split('_')[0])
 | 
						|
                    club = Club.objects.get(id=scope.split('_')[1])
 | 
						|
                    scopes[scope] = f"{p.description} (club {club.name})"
 | 
						|
            return scopes
 | 
						|
 | 
						|
        scopes = {f"{p.id}_{club.id}": f"{p.description} (club {club.name})"
 | 
						|
                  for p in Permission.objects.all() for club in Club.objects.all()}
 | 
						|
        scopes['openid'] = "OpenID Connect"
 | 
						|
        return scopes
 | 
						|
 | 
						|
    def get_available_scopes(self, application=None, request=None, *args, **kwargs):
 | 
						|
        if not application:
 | 
						|
            return []
 | 
						|
        scopes = [f"{p.id}_{p.membership.club.id}"
 | 
						|
                  for t in Permission.PERMISSION_TYPES
 | 
						|
                  for p in PermissionBackend.get_raw_permissions(get_current_request(), t[0])]
 | 
						|
        scopes.append('openid')
 | 
						|
        return scopes
 | 
						|
 | 
						|
    def get_default_scopes(self, application=None, request=None, *args, **kwargs):
 | 
						|
        if not application:
 | 
						|
            return []
 | 
						|
        scopes = [f"{p.id}_{p.membership.club.id}"
 | 
						|
                  for p in PermissionBackend.get_raw_permissions(get_current_request(), 'view')]
 | 
						|
        scopes.append('openid')
 | 
						|
        return scopes
 | 
						|
 | 
						|
 | 
						|
class PermissionOAuth2Validator(OAuth2Validator):
 | 
						|
    oidc_claim_scope = OAuth2Validator.oidc_claim_scope
 | 
						|
    oidc_claim_scope.update({"name": 'openid',
 | 
						|
                             "normalized_name": 'openid',
 | 
						|
                             "email": 'openid',
 | 
						|
                             })
 | 
						|
 | 
						|
    def get_additional_claims(self, request):
 | 
						|
        return {
 | 
						|
            "name": request.user.username,
 | 
						|
            "normalized_name": Alias.normalize(request.user.username),
 | 
						|
            "email": request.user.email,
 | 
						|
        }
 | 
						|
 | 
						|
    def get_discovery_claims(self, request):
 | 
						|
        claims = super().get_discovery_claims(self)
 | 
						|
        return claims + ["name", "normalized_name", "email"]
 | 
						|
 | 
						|
    def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs):
 | 
						|
        """
 | 
						|
        User can request as many scope as he wants, including invalid scopes,
 | 
						|
        but it will have only the permissions he has.
 | 
						|
 | 
						|
        This allows clients to request more permission to get finally a
 | 
						|
        subset of permissions.
 | 
						|
        """
 | 
						|
 | 
						|
        valid_scopes = set()
 | 
						|
 | 
						|
        for t in Permission.PERMISSION_TYPES:
 | 
						|
            for p in PermissionBackend.get_raw_permissions(get_current_request(), t[0]):
 | 
						|
                scope = f"{p.id}_{p.membership.club.id}"
 | 
						|
                if scope in scopes:
 | 
						|
                    valid_scopes.add(scope)
 | 
						|
 | 
						|
        if 'openid' in scopes:
 | 
						|
            valid_scopes.add('openid')
 | 
						|
 | 
						|
        request.scopes = valid_scopes
 | 
						|
        return valid_scopes
 |