Refactoring in progress. Still a few classes to go.

master
Philippe Pittoli 2023-06-11 18:59:41 +02:00
parent 7958e7812e
commit 2786e2f7ff
10 changed files with 55 additions and 90 deletions

View File

@ -10,6 +10,9 @@ require "ipc"
require "baguette-crystal-base"
# In any message, a user can be referred by its Int32 uid or its login.
alias UserID = Int32 | String
# Allows get configuration from a provided file.
# See Baguette::Configuration::Base.get
class Baguette::Configuration

View File

@ -158,13 +158,12 @@ module AuthD
end
end
def mod_user(uid_or_login : Int32 | String, password : String? = nil, email : String? = nil, phone : String? = nil, avatar : String? = nil) : Bool | Exception
def mod_user(uid_or_login : Int32 | String, password : String? = nil, email : String? = nil, phone : String? = nil) : Bool | Exception
request = Request::ModUser.new uid_or_login
request.password = password if password
request.email = email if email
request.phone = phone if phone
request.avatar = avatar if avatar
send_now request

View File

@ -71,5 +71,22 @@ class AuthD::User
def to_public : Public
Public.new @uid, @login, @admin, @profile, @date_registration
end
end
def assert_permission(service : String, resource : String, level : User::PermissionLevel)
return if @admin # skip if admin
permissions = @permissions[service]?
unless permissions
raise AdminAuthorizationException.new "unauthorized (not admin nor in #{service} group)"
end
rights = permissions[resource]?
unless rights
raise AdminAuthorizationException.new "unauthorized (no rights on '#{service}/#{resource}')"
end
if rights < level
raise AdminAuthorizationException.new "unauthorized (insufficient rights on '#{service}/#{resource}')"
end
end
end

View File

@ -49,28 +49,24 @@ class AuthD::Request
end
AuthD.requests << AddUser
IPC::JSON.message ModUser, 5 do
property user : Int32 | String
property user : UserID
property admin : Bool = false
property password : String? = nil
property email : String? = nil
property phone : String? = nil
property avatar : String? = nil
def initialize(@user, @admin, @password, @email, @phone, @avatar)
def initialize(@user, @admin, @password, @email, @phone)
end
def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user? fd
return Response::Error.new "you must be logged" if logged_user.nil?
user = authd.user? @user
return Response::Error.new "user not found" if user.nil?
# Only an admin can create an admin.
# Only an admin can uprank someone.
if @admin
return Response::Error.new "unauthorized (not admin)" unless logged_user.admin
end

View File

@ -1,32 +1,28 @@
class AuthD::Request
IPC::JSON.message Delete, 17 do
# Deletion can be triggered by either an admin or the related user.
property user : String | Int32
property user : UserID
def initialize(@user)
end
def handle(authd : AuthD::Service, fd : Int32)
user_to_delete = authd.user? @user
return Response::Error.new "invalid user" if user_to_delete.nil?
# Get currently logged user.
logged_user = authd.get_logged_user? fd
if logged_user.nil?
return Response::Error.new "you must be logged"
end
return Response::Error.new "you must be logged" if logged_user.nil?
# Get the full AuthD::User instance, not just the public view.
user_to_delete = authd.user? logged_user.uid
return Response::Error.new "unknown user" if user_to_delete.nil?
unless logged_user.admin
# Is the logged user the target?
if logged_user.uid != user_to_delete.uid
return Response::Error.new "invalid credentials"
end
return Response::Error.new "invalid credentials" if logged_user.uid != user_to_delete.uid
end
# User or admin is now verified: let's proceed with the user deletion.
authd.users_per_login.delete user_to_delete.login
# TODO: if the current user is deleted, unlog!
# If the current user is deleted, unlog!
if logged_user.uid == user_to_delete.uid
authd.close fd
authd.logged_users.delete fd

View File

@ -1,38 +1,17 @@
class AuthD::Request
IPC::JSON.message ListUsers, 8 do
property token : String? = nil
property key : String? = nil
def initialize(@token, @key)
def initialize()
end
def handle(authd : AuthD::Service, fd : Int32)
# FIXME: Lines too long, repeatedly (>80c with 4c tabs).
@token.try do |token|
user = authd.get_user_from_token token
logged_user = authd.get_logged_user? fd
return Response::Error.new "you must be logged" if logged_user.nil?
return Response::Error.new "unauthorized (user not found from token)" unless user
user = authd.user? logged_user.uid
return Response::Error.new "user not found" if user.nil?
# Test if the user is a moderator.
if permissions = user.permissions["authd"]?
if rights = permissions["*"]?
if rights >= User::PermissionLevel::Read
else
raise AdminAuthorizationException.new "unauthorized (insufficient rights on '*')"
end
else
raise AdminAuthorizationException.new "unauthorized (no rights on '*')"
end
else
raise AdminAuthorizationException.new "unauthorized (user not in authd group)"
end
end
@key.try do |key|
return Response::Error.new "unauthorized (wrong shared key)" unless key == authd.configuration.shared_key
end
return Response::Error.new "unauthorized (no key nor token)" unless @key || @token
# Test if the user is a moderator.
user.assert_permission("authd", "*", User::PermissionLevel::Read)
Response::UsersList.new authd.users.to_h.map &.[1].to_public
end

View File

@ -13,9 +13,7 @@ class AuthD::Request
return Response::Error.new "invalid credentials"
end
if user.nil?
return Response::Error.new "invalid credentials"
end
return Response::Error.new "invalid credentials" if user.nil?
if user.password_hash != authd.hash_password @password
return Response::Error.new "invalid credentials"

View File

@ -1,22 +1,16 @@
class AuthD::Request
IPC::JSON.message UpdatePassword, 7 do
property login : String
property old_password : String
property new_password : String
def initialize(@login, @old_password, @new_password)
def initialize(@new_password)
end
def handle(authd : AuthD::Service, fd : Int32)
user = authd.users_per_login.get? @login
logged_user = authd.get_logged_user? fd
return Response::Error.new "you must be logged" if logged_user.nil?
unless user
return Response::Error.new "invalid credentials"
end
if authd.hash_password(@old_password) != user.password_hash
return Response::Error.new "invalid credentials"
end
user = authd.user? logged_user.uid
return Response::Error.new "user not found" if user.nil?
user.password_hash = authd.hash_password @new_password
@ -28,7 +22,7 @@ class AuthD::Request
AuthD.requests << UpdatePassword
IPC::JSON.message PasswordRecovery, 11 do
property user : Int32 | String
property user : UserID
property password_renew_key : String
property new_password : String
@ -36,16 +30,8 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, fd : Int32)
uid_or_login = @user
user = if uid_or_login.is_a? Int32
authd.users_per_uid.get? uid_or_login.to_s
else
authd.users_per_login.get? uid_or_login
end
if user.nil?
return Response::Error.new "user not found"
end
user = authd.user? @user
return Response::Error.new "user not found" if user.nil?
if user.password_renew_key == @password_renew_key
user.password_hash = authd.hash_password @new_password

View File

@ -1,6 +1,6 @@
class AuthD::Request
IPC::JSON.message CheckPermission, 9 do
property user : Int32 | String
property user : UserID
property service : String
property resource : String
@ -13,16 +13,8 @@ class AuthD::Request
return Response::Error.new "you must be logged" if logged_user.nil?
return Response::Error.new "unauthorized (not admin)" unless logged_user.admin
user = case u = @user
when .is_a? Int32
authd.users_per_uid.get? u.to_s
else
authd.users_per_login.get? u
end
if user.nil?
return Response::Error.new "no such user"
end
user = authd.user? @user
return Response::Error.new "no such user" if user.nil?
service = @service
service_permissions = user.permissions[service]?
@ -43,7 +35,7 @@ class AuthD::Request
AuthD.requests << CheckPermission
IPC::JSON.message SetPermission, 10 do
property user : Int32 | String
property user : UserID
property service : String
property resource : String
property permission : ::AuthD::User::PermissionLevel
@ -57,8 +49,7 @@ class AuthD::Request
return Response::Error.new "you must be logged" if logged_user.nil?
return Response::Error.new "unauthorized (not admin)" unless logged_user.admin
user = authd.users_per_uid.get? @user.to_s
user = authd.user? @user
return Response::Error.new "no such user" if user.nil?
service = @service

View File

@ -83,7 +83,7 @@ class AuthD::Service < IPC
@logged_users[fd]?
end
def user?(uid_or_login : Int32 | String)
def user?(uid_or_login : UserID)
if uid_or_login.is_a? Int32
@users_per_uid.get? uid_or_login.to_s
else