def _check_token(): token = request.headers.get('AUTHORIZATION') from keycloak import KeycloakOpenID keycloak_openid = KeycloakOpenID( server_url=app.config.get("SERVER_URL"), client_id=app.config.get("CLIENT_ID"), realm_name=app.config.get("REALM_NAME"), client_secret_key=app.config.get("CLIENT_SECRET_KEY")) token_info = keycloak_openid.introspect(token) return True
class AuthEndpoint: def __init__(self, app): self.app = app self.url = self.app.config['KEYCLOAK_URL'] self.client_id = self.app.config['CLIENT_ID'] self.client_secret = self.app.config['CLIENT_SECRET'] self.keycloak_openid = KeycloakOpenID( server_url=self.url, client_id=self.client_id, realm_name='apartments', client_secret_key=self.client_secret, verify=False) def require_token(self, roles=None): def decorator(f): @wraps(f) def decorated_function(*args, **kwargs): auth_header = request.headers.get('Authorization') if not auth_header: return 'Authorization required', 401 if 'Bearer ' not in auth_header: return 'Bearer token required', 401 token = auth_header.replace('Bearer ', '') try: user = self.keycloak_openid.introspect(token) missing_roles = set(roles) - set( user['resource_access']['api-gateway']['roles']) if missing_roles: return F'Unauthorized, missing roles. {missing_roles}', 401 except Exception: return 'Unauthorized', 401 return f(*args, **kwargs) return decorated_function return decorator
class _Keycloak(AuthProvider): f""" Redis key-value pair database implementation of KeyValueStore Defines methods for getting, deleting and putting key value pairs :param host, port, db (see also `https://github.com/andymccurdy/redis-py)` Example: ``` db = KeyValueDatabase.instance(provider='redis', host='localhost', port=6379, db=0) ``` """ def __init__(self, domain: Optional[str] = None, audience: Optional[str] = None): super().__init__() self._domain = domain or os.getenv('KEYCLOAK_DOMAIN') self._client_secret_key = os.getenv('KEYCLOAK_CLIENT_SECRET_KEY') self._client_secret_id = os.getenv('KEYCLOAK_CLIENT_SECRET_ID') self._realm = os.getenv('KEYCLOAK_REALM') self._audience = audience or os.getenv('XCUBE_HUB_OAUTH_AUD') self._algorithms = ["RS256"] if self._domain is None: raise Unauthorized(description="Keycloak error: Domain not set") if self._audience is None: raise Unauthorized(description="Keycloak error: Audience not set") self._keycloak_openid = KeycloakOpenID( server_url=f"https://{self._domain}/auth/", client_id=self._client_secret_id, realm_name=self._realm, client_secret_key=self._client_secret_key, verify=True) def get_email(self, claims): if 'email' not in claims: return "no email" return claims['email'] def verify_token(self, token: str) -> Dict: """ Get a key value :param token: :return: """ try: self._keycloak_openid.introspect(token) except KeycloakGetError as e: raise Unauthorized(description="invalid token: " + str(e)) certs = self._keycloak_openid.certs() rsa_key = {} for key in certs["keys"]: rsa_key = { "kty": key["kty"], "kid": key["kid"], "use": key["use"], "n": key["n"], "e": key["e"] } try: self._claims = self._keycloak_openid.decode_token(token=token, key=rsa_key) except Exception as e: raise Unauthorized(description=str(e)) return self._claims
class KeycloakClient: """Wrapper for Keycloak OpenID and admin clients.""" def __init__(self, server, resource, realm, secret, admin_user, admin_pass): self.openid = KeycloakOpenID( server_url=server, client_id=resource, realm_name=realm, client_secret_key=secret, ) self.admin = _KeycloakAdmin( server_url=server, client_id=resource, realm_name=realm, client_secret_key=secret, username=admin_user, password=admin_pass, auto_refresh_token=['get', 'put', 'post', 'delete'], ) def login(self, username, password): return self.openid.token(username, password, totp=None) def token_refresh(self, refresh_token): return self.openid.refresh_token(refresh_token) def token_info(self, token): return self.openid.introspect(token) def user_list(self, query=None): return self.admin.get_users(query) def user_get(self, user_id): return self.admin.get_user(user_id) def user_create(self, data): data = data.copy() data.setdefault('enabled', True) if 'password' in data: data['credentials'] = [ { 'type': 'password', 'value': data['password'] }, ] del data['password'] return self.admin.create_user(data) def user_update(self, user_id, data): data = data.copy() if 'password' in data: data['credentials'] = [ { 'type': 'password', 'value': data['password'] }, ] del data['password'] self.admin.update_user(user_id, data) def user_delete(self, user_id): self.admin.delete_user(user_id) def user_group_list(self, user_id): """Get list of groups user belongs to.""" return self.admin.get_user_groups(user_id) def user_role_list(self, user_id): """ Get set of all user roles (**role names**), directly assigned and also inherited from a group. """ roles = set() # directly assigned roles roles = { i['name'] for i in self.admin.get_realm_roles_of_user(user_id) } # iherited roles from group for group in self.user_group_list(user_id): roles |= { i['name'] for i in self.admin.get_group_realm_roles(group['id']) } return roles def user_check_group(self, user_id, group_id): """Check if user belongs to the given group.""" return self.user_check_group_any(user_id, [group_id]) def user_check_group_any(self, user_id, group_id_list): """Check if user belongs to any of the given groups.""" return any(group['id'] in group_id_list for group in self.user_group_list(user_id)) def user_check_role(self, user_id, role_name): """Check if user has role.""" return role_name in self.user_role_list(user_id) def group_list(self): return self.admin.get_groups() def group_get(self, group_id): return self.admin.get_group(group_id) def group_create(self, data): # `create_group` always returns b'' self.admin.create_group(data) for group in self.group_list(): if group['name'] == data['name']: return group['id'] def group_update(self, group_id, data): self.admin.update_group(group_id, data) def group_delete(self, group_id): self.admin.delete_group(group_id) def group_user_list(self, group_id): """Get list of users in group.""" return self.admin.get_group_members(group_id) def group_user_add(self, user_id, group_id): """Add user to group.""" self.admin.group_user_add(user_id, group_id) def group_user_remove(self, user_id, group_id): """Remove user from group.""" self.admin.group_user_remove(user_id, group_id) def group_role_list(self, group_id): return self.admin.get_group_realm_roles(group_id) def group_role_add(self, role_name, group_id): """Add role to group. **Role NAME, not ID.**""" role = self.role_get(role_name) self.admin.assign_group_realm_roles(group_id, [role]) def group_role_remove(self, role_name, group_id): """Remove role from group. **Role NAME, not ID.**""" role = self.role_get(role_name) self.admin.delete_group_realm_roles(group_id, [role]) def role_list(self): return self.admin.get_realm_roles() def role_get(self, role_name): """Get role by name. **NAME, not ID.**""" return self.admin.get_realm_role(role_name) def role_create(self, data): # `create_role` always returns b'' self.admin.create_realm_role(data) for role in self.role_list(): if role['name'] == data['name']: return role['name'] def role_update(self, role_id, data): self.admin.update_realm_role(role_id, data) def role_delete(self, role_id): self.admin.delete_realm_role(role_id)
# Refresh token token = keycloak_openid.refresh_token(token['refresh_token']) # Logout keycloak_openid.logout(token['refresh_token']) # Get Certs certs = keycloak_openid.certs() # Get RPT (Entitlement) token = keycloak_openid.token("user", "password") rpt = keycloak_openid.entitlement(token['access_token'], "resource_id") # Instropect RPT token_rpt_info = keycloak_openid.introspect(keycloak_openid.introspect(token['access_token'], rpt=rpt['rpt'], token_type_hint="requesting_party_token")) # Introspect Token token_info = keycloak_openid.introspect(token['access_token'])) # Decode Token KEYCLOAK_PUBLIC_KEY = keycloak_openid.public_key() options = {"verify_signature": True, "verify_aud": True, "exp": True} token_info = keycloak_openid.decode_token(token['access_token'], key=KEYCLOAK_PUBLIC_KEY, options=options) # Get permissions by token token = keycloak_openid.token("user", "password") keycloak_openid.load_authorization_config("example-authz-config.json") policies = keycloak_openid.get_policies(token['access_token'], method_token_info='decode', key=KEYCLOAK_PUBLIC_KEY) permissions = keycloak_openid.get_permissions(token['access_token'], method_token_info='introspect')