Authd now handles authorization as well.

This commit is contained in:
Philippe Pittoli 2024-03-31 11:51:42 +02:00
parent 407cfc874a
commit a6272b3873
5 changed files with 40 additions and 16 deletions

View File

@ -21,6 +21,12 @@ module DNSManager
def initialize(@domain, @rr) def initialize(@domain, @rr)
end end
end end
class CannotCheckPermissionsException < ::Exception
property uid : UserDataID
property resource : String
def initialize(@uid, @resource)
end
end
class AuthorizationException < ::Exception class AuthorizationException < ::Exception
end end
class NoOwnershipException < ::Exception class NoOwnershipException < ::Exception
@ -31,8 +37,6 @@ module DNSManager
end end
class TokenNotFoundException < ::Exception class TokenNotFoundException < ::Exception
end end
class AdminAuthorizationException < ::Exception
end
end end
@ -79,6 +83,24 @@ class DNSManager::Service < IPC
@authd.decode_token token @authd.decode_token token
end 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) def handle_request(event : IPC::Event)
request_start = Time.utc request_start = Time.utc
@ -101,15 +123,15 @@ class DNSManager::Service < IPC
rescue e : DomainNotFoundException rescue e : DomainNotFoundException
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} domain not found" Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} domain not found"
Response::DomainNotFound.new 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 rescue e : UnknownUserException
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} unknown user" Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} unknown user"
Response::UnknownUser.new Response::UnknownUser.new
rescue e : NoOwnershipException rescue e : NoOwnershipException
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} no ownership error" Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} no ownership error"
Response::NoOwnership.new 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 rescue e : NotLoggedException
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} user not logged" Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} user not logged"
Response::Error.new "user not logged" Response::Error.new "user not logged"

View File

@ -7,7 +7,7 @@ class DNSManager::Request
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
user = dnsmanagerd.get_logged_user event user = dnsmanagerd.get_logged_user event
return Response::ErrorUserNotLogged.new unless user 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
end end
DNSManager.requests << GetOrphanDomains DNSManager.requests << GetOrphanDomains

View File

@ -19,7 +19,8 @@ class DNSManager::Request
accepted_domains = dnsmanagerd.configuration.accepted_domains.not_nil! accepted_domains = dnsmanagerd.configuration.accepted_domains.not_nil!
user_domains = user_data.domains 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 else
Response::ErrorInvalidToken.new Response::ErrorInvalidToken.new
end end
@ -41,7 +42,7 @@ class DNSManager::Request
user = dnsmanagerd.get_logged_user event user = dnsmanagerd.get_logged_user event
return Response::ErrorUserNotLogged.new unless user 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
end end
DNSManager.requests << DeleteUser DNSManager.requests << DeleteUser

View File

@ -50,9 +50,10 @@ class DNSManager::Response
DNSManager.responses << AcceptedDomains DNSManager.responses << AcceptedDomains
IPC::JSON.message Logged, 16 do IPC::JSON.message Logged, 16 do
property admin : Bool
property accepted_domains : Array(String) property accepted_domains : Array(String)
property my_domains : Array(String) property my_domains : Array(String)
def initialize(@accepted_domains, @my_domains) def initialize(@admin, @accepted_domains, @my_domains)
end end
end end
DNSManager.responses << Logged DNSManager.responses << Logged

View File

@ -261,14 +261,14 @@ class DNSManager::Storage
end end
# Get all removed users from `authd`, list all their domains and remove their data from `dnsmanagerd`. # 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 def get_orphan_domains(dnsmanagerd : DNSManager::Service, user_id : UserDataID) : IPC::JSON
user_must_be_admin! user_id user_must_be_admin! dnsmanagerd, user_id
Baguette::Log.debug "list all orphan domains (long computation)" Baguette::Log.debug "list all orphan domains (long computation)"
orphans = [] of String orphans = [] of String
user_data.each do |user| user_data.each do |user|
begin begin
authd.get_user? user.uid dnsmanagerd.authd.get_user? user.uid
rescue e rescue e
Baguette::Log.warning "no authd info on user #{user.uid}: #{e} (removing this user)" 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" 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 user_data_by_uid.delete user_data.uid.to_s
end 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 = user_must_exist! user_id
user_data_to_delete = if u = user_to_delete 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}." Baguette::Log.info "Admin #{user_id} removes data of user #{u}."
user_must_exist! u user_must_exist! u
else else
@ -331,9 +331,9 @@ class DNSManager::Storage
user_data user_data
end 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 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 user_data
end end