From a6272b3873ed22891d489962d50cc85ee2d638d8 Mon Sep 17 00:00:00 2001 From: Philippe Pittoli Date: Sun, 31 Mar 2024 11:51:42 +0200 Subject: [PATCH] Authd now handles authorization as well. --- src/main.cr | 32 +++++++++++++++++++++++++++----- src/requests/admin.cr | 2 +- src/requests/user.cr | 5 +++-- src/responses/zone.cr | 3 ++- src/storage.cr | 14 +++++++------- 5 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/main.cr b/src/main.cr index 7dd364f..26abe52 100644 --- a/src/main.cr +++ b/src/main.cr @@ -21,6 +21,12 @@ module DNSManager def initialize(@domain, @rr) end end + class CannotCheckPermissionsException < ::Exception + property uid : UserDataID + property resource : String + def initialize(@uid, @resource) + end + end class AuthorizationException < ::Exception end class NoOwnershipException < ::Exception @@ -31,8 +37,6 @@ module DNSManager end class TokenNotFoundException < ::Exception end - class AdminAuthorizationException < ::Exception - end end @@ -79,6 +83,24 @@ class DNSManager::Service < IPC @authd.decode_token token end + def check_permissions(uid : UInt32, resource : String) : AuthD::User::PermissionLevel + response = @authd.check_permission uid, "dnsmanager", resource + case response + when AuthD::Response::PermissionCheck + return response.permission + end + raise CannotCheckPermissionsException.new uid, resource + rescue e + Baguette::Log.error "error while checking permissions: #{e}" + raise CannotCheckPermissionsException.new uid, resource + end + + def assert_permissions!(uid : UInt32, resource : String, perms : AuthD::User::PermissionLevel) + if check_permissions(uid, resource) < perms + raise AuthorizationException.new + end + end + def handle_request(event : IPC::Event) request_start = Time.utc @@ -101,15 +123,15 @@ class DNSManager::Service < IPC rescue e : DomainNotFoundException Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} domain not found" Response::DomainNotFound.new + rescue e : CannotCheckPermissionsException + Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} cannot check permissions of user '#{e.uid}' on resource '#{e.resource}'" + Response::InsufficientRights.new rescue e : UnknownUserException Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} unknown user" Response::UnknownUser.new rescue e : NoOwnershipException Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} no ownership error" Response::NoOwnership.new - rescue e : AdminAuthorizationException - Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} no admin authorization" - Response::Error.new "admin authorization error" rescue e : NotLoggedException Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} user not logged" Response::Error.new "user not logged" diff --git a/src/requests/admin.cr b/src/requests/admin.cr index f1ddebe..afc26f9 100644 --- a/src/requests/admin.cr +++ b/src/requests/admin.cr @@ -7,7 +7,7 @@ class DNSManager::Request def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON user = dnsmanagerd.get_logged_user event return Response::ErrorUserNotLogged.new unless user - dnsmanagerd.storage.get_orphan_domains dnsmanagerd.authd, user.uid + dnsmanagerd.storage.get_orphan_domains dnsmanagerd, user.uid end end DNSManager.requests << GetOrphanDomains diff --git a/src/requests/user.cr b/src/requests/user.cr index 33e961d..5ce4041 100644 --- a/src/requests/user.cr +++ b/src/requests/user.cr @@ -19,7 +19,8 @@ class DNSManager::Request accepted_domains = dnsmanagerd.configuration.accepted_domains.not_nil! user_domains = user_data.domains - Response::Logged.new accepted_domains, user_domains + perms = dnsmanagerd.check_permissions response.user.uid, "*" + Response::Logged.new (perms == AuthD::User::PermissionLevel::Admin), accepted_domains, user_domains else Response::ErrorInvalidToken.new end @@ -41,7 +42,7 @@ class DNSManager::Request user = dnsmanagerd.get_logged_user event return Response::ErrorUserNotLogged.new unless user - dnsmanagerd.storage.delete_user_data user.uid, user_id + dnsmanagerd.storage.delete_user_data dnsmanagerd, user.uid, user_id end end DNSManager.requests << DeleteUser diff --git a/src/responses/zone.cr b/src/responses/zone.cr index 8016546..02b2d19 100644 --- a/src/responses/zone.cr +++ b/src/responses/zone.cr @@ -50,9 +50,10 @@ class DNSManager::Response DNSManager.responses << AcceptedDomains IPC::JSON.message Logged, 16 do + property admin : Bool property accepted_domains : Array(String) property my_domains : Array(String) - def initialize(@accepted_domains, @my_domains) + def initialize(@admin, @accepted_domains, @my_domains) end end DNSManager.responses << Logged diff --git a/src/storage.cr b/src/storage.cr index 8f401f9..c1356fa 100644 --- a/src/storage.cr +++ b/src/storage.cr @@ -261,14 +261,14 @@ class DNSManager::Storage end # Get all removed users from `authd`, list all their domains and remove their data from `dnsmanagerd`. - def get_orphan_domains(authd : AuthD::Client, user_id : UserDataID) : IPC::JSON - user_must_be_admin! user_id + def get_orphan_domains(dnsmanagerd : DNSManager::Service, user_id : UserDataID) : IPC::JSON + user_must_be_admin! dnsmanagerd, user_id Baguette::Log.debug "list all orphan domains (long computation)" orphans = [] of String user_data.each do |user| begin - authd.get_user? user.uid + dnsmanagerd.authd.get_user? user.uid rescue e Baguette::Log.warning "no authd info on user #{user.uid}: #{e} (removing this user)" Baguette::Log.debug "user #{user.uid} had #{user.domains.size} domains" @@ -304,10 +304,10 @@ class DNSManager::Storage user_data_by_uid.delete user_data.uid.to_s end - def delete_user_data(user_id : UserDataID, user_to_delete : UserDataID?) : IPC::JSON + def delete_user_data(dnsmanagerd : DNSManager::Service, user_id : UserDataID, user_to_delete : UserDataID?) : IPC::JSON user_data = user_must_exist! user_id user_data_to_delete = if u = user_to_delete - user_must_be_admin! user_id + user_must_be_admin! dnsmanagerd, user_id Baguette::Log.info "Admin #{user_id} removes data of user #{u}." user_must_exist! u else @@ -331,9 +331,9 @@ class DNSManager::Storage user_data end - def user_must_be_admin!(user_id : UserDataID) : UserData + def user_must_be_admin!(dnsmanagerd : DNSManager::Service, user_id : UserDataID) : UserData user_data = user_must_exist! user_id - raise AdminAuthorizationException.new unless user_data.admin + dnsmanagerd.assert_permissions! user_id, "*", AuthD::User::PermissionLevel::Admin user_data end