Browse Source

UMA: convenient resource and scope assembly

pull/297/head
Merle Nerger 3 years ago
parent
commit
a190a8753c
  1. 4
      keycloak/exceptions.py
  2. 8
      keycloak/keycloak_openid.py
  3. 88
      keycloak/uma_permissions.py

4
keycloak/exceptions.py

@ -81,6 +81,10 @@ class KeycloakPermissionFormatError(KeycloakOperationError):
pass
class PermissionDefinitionError(Exception):
pass
def raise_error_from_response(response, error, expected_codes=None, skip_exists=False):
if expected_codes is None:
expected_codes = [200, 201, 204]

8
keycloak/keycloak_openid.py

@ -25,6 +25,7 @@ import json
from jose import jwt
from .uma_permissions import UMA_Permission
from .authorization import Authorization
from .connection import ConnectionManager
from .exceptions import KeycloakPermissionFormatError, raise_error_from_response, KeycloakGetError, \
@ -297,7 +298,6 @@ class KeycloakOpenID:
data_raw = self.connection.raw_get(URL_REALM.format(**params_path))
return raise_error_from_response(data_raw, KeycloakGetError)['public_key']
def entitlement(self, token, resource_server_id):
"""
Client applications can use a specific endpoint to obtain a special security token
@ -523,7 +523,7 @@ def build_permission_param(permissions):
"""
if permissions is None or permissions == "":
return set()
if isinstance(permissions, str):
if isinstance(permissions, (str, UMA_Permission)):
return set((permissions,))
try: # treat as dictionary of permissions
@ -531,11 +531,11 @@ def build_permission_param(permissions):
for resource, scopes in permissions.items():
if scopes is None:
result.add(resource)
elif isinstance(scopes, str):
elif isinstance(scopes, (str, UMA_Permission)):
result.add("{}#{}".format(resource, scopes))
else:
for scope in scopes:
if not isinstance(scope, str):
if not isinstance(scope, (str, UMA_Permission)):
raise KeycloakPermissionFormatError(
'misbuilt permission {}'.format(permissions))
result.add("{}#{}".format(resource, scope))

88
keycloak/uma_permissions.py

@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
#
# The MIT License (MIT)
#
# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from keycloak.exceptions import PermissionDefinitionError
class UMA_Permission():
"""A class to conveniently assembly permissions.
The class itself is callable, and will return the assembled permission.
Usage example:
>>> r = Resource("Users")
>>> s = Scope("delete")
>>> permission = r(s)
>>> print(permission)
'Users#delete'
"""
def __init__(self, *, resource="", scope=""):
self.resource = resource
self.scope = scope
def __str__(self):
scope = self.scope
if scope:
scope = "#"+scope
return "{}{}".format(self.resource, scope)
def __eq__(self, __o: object) -> bool:
return str(self) == str(__o)
def __repr__(self) -> str:
return self.__str__()
def __hash__(self) -> int:
return hash(str(self))
def __call__(self, *args, resource="", scope="") -> object:
result_resource = self.resource
result_scope = self.scope
for arg in args:
if not isinstance(arg, UMA_Permission):
raise PermissionDefinitionError(
"can't determine if '{}' is a resource or scope".format(arg))
if arg.resource:
result_resource = str(arg.resource)
if arg.scope:
result_scope = str(arg.scope)
if resource:
result_resource = str(resource)
if scope:
result_scope = str(scope)
return UMA_Permission(resource=result_resource, scope=result_scope)
class Resource(UMA_Permission):
def __init__(self, resource):
super().__init__(resource=resource)
class Scope(UMA_Permission):
def __init__(self, scope):
super().__init__(scope=scope)
Loading…
Cancel
Save