GitHub user cboettcher edited a comment on the discussion: Keycloak auth 
manager causes long loading times for the webserver

Some additional context from what I've already looked into and thought about:

[Here](https://github.com/apache/airflow/blob/b7ea2a6fa5418862b93fcb11c75c02bef0f85c95/providers/keycloak/src/airflow/providers/keycloak/auth_manager/keycloak_auth_manager.py#L273)
 Is the function that is called for every singel-resource authentication 
request, and it creates a request to keycloak every time. The [batch 
function](https://github.com/apache/airflow/blob/b7ea2a6fa5418862b93fcb11c75c02bef0f85c95/providers/keycloak/src/airflow/providers/keycloak/auth_manager/keycloak_auth_manager.py#L309)
 does not seem to be used much.


---
I tried something like this, which seemed to solve the loading time issue, but 
it kinda ignores the `context attributes` and has no proper caching.

```
class KeycloakAuthManagerPermissions():
    """A set of permissions."""

    def __init__(self, permissions: dict[str, list[str]]) -> None:
        self.permissions = permissions

    def get_permissions(self) -> dict[str, list[str]]:
        return self.permissions
    
    def get_resource_permissions(self, resource_name: str) -> list[str]:
        return self.permissions.get(resource_name, [])
    
    @staticmethod
    def get_permissions_from_keycloak_string(keycloak_permissions: 
list[dict[str, str | list[str]]]) -> KeycloakAuthManagerPermissions:
        formatted_permissions: dict[str, list[str]] = {}

        for single_permission in keycloak_permissions:
            resource_name = single_permission.get("rsname")
            allowed_method_list = single_permission.get("scopes", [])
            if resource_name and isinstance(resource_name, str) and 
isinstance(allowed_method_list, list):
                formatted_permissions[resource_name] = allowed_method_list

        return KeycloakAuthManagerPermissions(formatted_permissions)
```
```
    def _get_user_perms(
            self,
            *,
            user: KeycloakAuthManagerUser
    ) -> KeycloakAuthManagerPermissions:
        #TODO store and cache permissions token properly instead of this dict

        if self._cached_perms.get(user.get_id()):
            log.debug(f"Using cached permissions for user {user.get_name()}")
        else:
            kc_client = self.get_keycloak_client()
            permissions = kc_client.uma_permissions(token=user.access_token)
            log.debug(f"Retrieved fresh permissions of user {user.get_id()}.")
            
            self._cached_perms[user.get_id()] = 
KeycloakAuthManagerPermissions.get_permissions_from_keycloak_string(permissions)
        

        return self._cached_perms[user.get_id()]
```
```
def _is_authorized(
        self,
        *,
        method: ResourceMethod | str,
        resource_type: KeycloakResource,
        user: KeycloakAuthManagerUser,
        resource_id: str | None = None,
        attributes: dict[str, str | None] | None = None,
    ) -> bool:
        permissions = self._get_user_perms(user=user)

        context_attributes = prune_dict(attributes or {})
        if resource_id:
            context_attributes[RESOURCE_ID_ATTRIBUTE_NAME] = resource_id
        elif method == "GET":
            method = "LIST"

        log.debug(f"Trying to get access to {resource_type.value}-{method} for 
user {user.get_name()}")

        return method in 
permissions.get_resource_permissions(resource_type.value)
```

GitHub link: 
https://github.com/apache/airflow/discussions/56502#discussioncomment-14643893

----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to: [email protected]

Reply via email to