Compare commits

...

10 commits

28 changed files with 389 additions and 67 deletions

15
apparmor.d/boilerplate Normal file
View file

@ -0,0 +1,15 @@
# This file is related to the `Baguette` project (authd, dnsmanagerd…).
# It is a way to avoid the long and complex default configuration files provided
# by the system. Allowed operations can be known in a matter of seconds.
# Accept basically all available libraries.
@{BASE_LIBS}=/{,usr/,usr/local/}lib{,32,64}/*.so* /usr/lib/x86_64*/*.so* /etc/ld*
# Enable reading files from different places required by the libraries I use,
# which may be the Crystal standard library itself.
@{BASE_RO}=/dev/{,u}random /dev/pts/* /proc/** /etc/localtime /usr/share/zoneinfo/**
@{BASE_RW}=/dev/{null,zero,full}
# Found in other profiles:
# Recent glibc uses /dev/full in preference to /dev/null for programs
# that don't have open fds at exec().

27
apparmor.d/dnsmanager Normal file
View file

@ -0,0 +1,27 @@
# Main configuration directory.
@{MAIN_CONF_DIR}=@{HOME}/.config/baguette
# Main configuration files.
@{AUTHD_CONFIG}=@{MAIN_CONF_DIR}/auth.yml
@{DNSMANAGERD_CONFIG}=@{MAIN_CONF_DIR}/dnsmanager.yml
# Databases.
@{AUTHD_DB_PATH}=@{HOME}/tmp/db-authd
@{DNSMANAGERD_DB_PATH}=@{HOME}/tmp/db-dnsmanagerd
# Key to encrypt passwords.
@{AUTHD_DB_KEY}=@{MAIN_CONF_DIR}/authd-db-key
# DNS templates (read-only entries).
@{DNSMANAGERD_TEMPLATES}=@{MAIN_CONF_DIR}/templates/*.json
# Logs.
@{LOGS_DIR}=@{HOME}/tmp/logs
@{AUTHD_LOGS}=@{LOGS_DIR}/auth
@{DNSMANAGERD_LOGS}=@{LOGS_DIR}/dnsmanager
# Mailer for authd.
@{MAILER}=/{usr,usr/local}/bin/mailer
# IPC-related directory (see libipc(7)).
@{LIBIPC_DIR}=/tmp/.libipc-run/

View file

@ -0,0 +1,33 @@
abi <abi/3.0>,
include <tunables/global>
include <dnsmanager>
include <boilerplate>
/usr/local/bin/authd flags=(enforce) {
# See the file `boilerplate`.
@{BASE_LIBS} mr,
@{BASE_RO} r,
@{BASE_RW} rw,
# Allow IPC-related unix sockets.
owner @{LIBIPC_DIR}/* rwk,
# Enable all unix socket operations. TODO: restrict this even further?
unix,
# Deny networking (udp and tcp).
deny network tcp,
deny network udp,
# Enable to read the configuration (and the database key).
owner @{AUTHD_CONFIG} r,
owner @{AUTHD_DB_KEY} r,
# Database and logs.
owner @{AUTHD_DB_PATH}/** rwkl,
owner @{AUTHD_LOGS} w,
# Enable authd to send mails.
@{MAILER} ux,
}

View file

@ -4,6 +4,9 @@
login: admin login: admin
pass: secret pass: secret
# Path to the log file. By default, everything is just printed on screen.
log_file: /var/log/baguette/auth.log
# In case you have a special `mailer` application. # In case you have a special `mailer` application.
# Read the manual to understand how it is invoked. # Read the manual to understand how it is invoked.
mailer_exe: /usr/local/bin/my-special-mailer mailer_exe: /usr/local/bin/my-special-mailer
@ -40,16 +43,10 @@ recovery_template: netlibre-email-recovery
#verbosity: 4 #verbosity: 4
# By default, print everything except KEEPALIVE messages.
#messages_to_mask: [KEEPALIVE]
#print_password_recovery_parameters: false #print_password_recovery_parameters: false
# IPC-related variables. By default, only print errors and exceptions. # IPC-related messages. By default, only print errors and exceptions.
#print_ipc_timer: false #ipc_messages_to_show: [ERROR, EXCEPTION]
#print_ipc_connection: false
#print_ipc_disconnection: false
#print_ipc_extra_socket: false
#print_ipc_message_received: false
#print_ipc_message_sent: false
#print_ipc_switch: false
#print_ipc_error: true
#print_ipc_exception: true
#print_keepalive: false

View file

@ -33,6 +33,8 @@ can be:
.Bl -tag -width " print functions" -compact .Bl -tag -width " print functions" -compact
.It Li bootstrap .It Li bootstrap
Add the first user (an admin). Add the first user (an admin).
.It Li exit
Kill the service.
.It Li migration-script .It Li migration-script
Adding a batch of users from old code base. Adding a batch of users from old code base.
.It Li user .It Li user
@ -113,7 +115,13 @@ Add the first user (will automatically be an admin).
.br .br
.Nm authctl .Nm authctl
.Ar migration-script No .Ar migration-script No
.br
Kill the service.
.br
.Nm authctl
.Ar exit No
.br
Operations on users. Operations on users.
.br .br
@ -259,13 +267,13 @@ to handle users (authentication, authorization, preferences and profile)
.It .It
.Xr mailer 1 .Xr mailer 1
a simple executable to send mails based on templates a simple executable to send mails based on templates
.
.It
.Xr dodb 7
a document database library used in
.Xr authd .
.El .El
The Document-oriented DataBase (DoDB) library used in
.Xr authd .
.br
.Lk https://git.baguette.netlib.re/Baguette/dodb.cr dodb
.Sh Limitations .Sh Limitations
WARNING: WARNING:
.Xr authctl .Xr authctl

View file

@ -58,8 +58,8 @@ to encrypt users's password is read from the file
.Pa /var/authd/secret-password . .Pa /var/authd/secret-password .
.br .br
Finally, indexes are recreated, which is related to the Finally, indexes are recreated, which is related to the
.Xr dodb 7 .Xr DoDB
document database, see the related manual page to learn more. document database, see the related documentation to learn more.
.Sh Configuration file variables .Sh Configuration file variables
The following presents the complete list of configuration file variables. The following presents the complete list of configuration file variables.
@ -70,50 +70,72 @@ related variables:
. .
.Bl -tag -width " print functions" -compact .Bl -tag -width " print functions" -compact
.It Li ipc_timer .It Li ipc_timer
Int32, 30_000 (30 seconds) Int32, 30_000
. .br
The IPC timer wakes the process by default every 30 seconds.
There is no much point changing this value since nothing is executed periodically anyway, at least for now.
.It Li verbosity .It Li verbosity
Int32, 4 ([0-4], Int32, 4
.br
[0-4],
.Dq 0 .Dq 0
being quiet and being quiet and
.Dq 4 .Dq 4
meaning printing debug values) meaning printing debug values.
.
.It Li print functions
Print functions enable to select messages to print, for example by printing a message each time a message is received while ignoring keepalive messages.
.Bl -tag -width " print_ipc_message_received" -compact .It Li ipc_messages_to_show
.It Li print_ipc_timer Array of
Bool, false .Vt Baguette::Configuration::IPC::MESSAGE ,
.It Li print_ipc_connection [ERROR, EXCEPTION]
Bool, false
.It Li print_ipc_disconnection Types of IPC messages to print, for example all connections.
Bool, false This is mainly for debug since it is very low-level.
.It Li print_ipc_extra_socket High-level messages are more relevant to log.
Bool, false By default, errors and exceptions are logged.
.It Li print_ipc_message_received
Bool, false See
.It Li print_ipc_message_sent .Xr Baguette-crystal-base ,
Bool, false which includes the
.It Li print_ipc_switch .Vt Baguette::Configuration::IPC::MESSAGE
Bool, false definition.
.It Li print_ipc_error This type has an alias in
Bool, true .Xr authd :
.It Li print_ipc_exception .Vt IPCMESSAGE .
Bool, true
.It Li print_keepalive .It Li service_name
Bool, false String,
.Dq auth
.br
.Xr libipc 7
unix socket name.
.El .El
.
.El .El
Specific Specific
.Xr authd .Xr authd
variables: variables:
.Bl -tag -width " print_password_recovery_parameters" -compact .Bl -tag -width " print_password_recovery" -compact
.It Li service_name .It Li log_file
String, String?,
.Dq auth .Em none
.br
Path to the log file.
.It Li messages_to_mask
Array of
.Vt AuthD::MESSAGE ,
.Em [ KEEPALIVE ]
.br
List of high-level
.Em authd
messages to mask in the logs.
.br
The type
.Vt AuthD::MESSAGE
has an alias:
.Vt AUTHMESSAGE .
.It Li recreate_indexes .It Li recreate_indexes
Bool, false Bool, false
.It Li storage_directory .It Li storage_directory
@ -250,13 +272,27 @@ to handle users (authentication, authorization, preferences and profile)
.It .It
.Xr mailer 1 .Xr mailer 1
a simple executable to send mails based on templates a simple executable to send mails based on templates
.
.It
.Xr dodb 7
a document database library used in
.Xr authd .
.El .El
The Document-oriented DataBase (DoDB) library used in
.Xr authd .
.br
.Lk https://git.baguette.netlib.re/Baguette/dodb.cr dodb
The online service
.Dq netlib.re
is the first one to use the
.Xr authd
daemon.
.br
.Lk https://www.netlib.re netlib.re
The logging and configuration library for the whole
.Dq baguette
project.
.br
.Lk https://git.baguette.netlib.re/Baguette/baguette-crystal-base baguette-crystal-base
.Sh Limitations .Sh Limitations
WARNING: WARNING:
.Xr authd .Xr authd

View file

@ -99,6 +99,10 @@ module AuthD
], read ], read
end end
def exit
send_now Request::Exit.new
end
def validate_user(login : String, activation_key : String) def validate_user(login : String, activation_key : String)
send_now Request::ValidateUser.new login, activation_key send_now Request::ValidateUser.new login, activation_key
parse_message [ parse_message [

View file

@ -79,6 +79,15 @@ parser = OptionParser.new do |parser|
unrecognized_args_to_context_args.call parser, 2 unrecognized_args_to_context_args.call parser, 2
end end
parser.on "exit", "Kill the service." do
parser.banner = "Usage: exit"
Baguette::Log.info "Kill the service."
Context.command = "exit"
opt_authd_login.call parser
opt_help.call parser
unrecognized_args_to_context_args.call parser, 0
end
parser.on "migration-script", "Add a batch of users from old code base." do parser.on "migration-script", "Add a batch of users from old code base." do
parser.banner = "usage: migration-script user-db.txt" parser.banner = "usage: migration-script user-db.txt"
Baguette::Log.info "Add a batch of users." Baguette::Log.info "Add a batch of users."

View file

@ -66,6 +66,7 @@ class Actions
@the_call["user-migrate"] = ->user_migrate @the_call["user-migrate"] = ->user_migrate
@the_call["migration-script"] = ->migration_script @the_call["migration-script"] = ->migration_script
@the_call["user-mod"] = ->user_mod @the_call["user-mod"] = ->user_mod
@the_call["exit"] = ->kill_service
@the_call["permission-set"] = ->permission_set @the_call["permission-set"] = ->permission_set
@the_call["permission-check"] = ->permission_check @the_call["permission-check"] = ->permission_check
@ -192,6 +193,14 @@ class Actions
puts "error: #{e.message}" puts "error: #{e.message}"
end end
def kill_service
puts "Kill the service."
authd.exit
rescue e : AuthD::Exception
puts "error: #{e.message}"
end
def user_change_password def user_change_password
args = Context.args.not_nil! args = Context.args.not_nil!
login = args[0] login = args[0]

View file

@ -7,6 +7,10 @@ class IPC::JSON
def handle(service : AuthD::Service, fd : Int32) def handle(service : AuthD::Service, fd : Int32)
raise "unimplemented" raise "unimplemented"
end end
def to_s(io : IO)
io << self.class.name.sub /[^:]+::[^:]+::/, ""
end
end end
module AuthD module AuthD

View file

@ -9,6 +9,11 @@ class AuthD::Request
def initialize(@login, @password, @admin, @email, @profile) def initialize(@login, @password, @admin, @email, @profile)
end end
def to_s(io : IO)
super io
io << " (login: #{@login}, email: #{@email})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user_full? fd logged_user = authd.get_logged_user_full? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil? return Response::ErrorMustBeAuthenticated.new if logged_user.nil?
@ -56,6 +61,11 @@ class AuthD::Request
def initialize(@login, @password, @email, @profile = nil) def initialize(@login, @password, @email, @profile = nil)
end end
def to_s(io : IO)
super io
io << " (login: #{@login}, email: #{email})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
# Check if there already is a registered user. # Check if there already is a registered user.
if authd.users.to_a.size > 0 if authd.users.to_a.size > 0
@ -90,6 +100,11 @@ class AuthD::Request
def initialize(@token) def initialize(@token)
end end
def to_s(io : IO)
super io
io << " (token size: #{@token.size})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user_full? fd logged_user = authd.get_logged_user_full? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil? return Response::ErrorMustBeAuthenticated.new if logged_user.nil?
@ -105,4 +120,23 @@ class AuthD::Request
end end
end end
AuthD.requests << DecodeToken AuthD.requests << DecodeToken
IPC::JSON.message Exit, 248 do
def initialize
end
def to_s(io : IO)
super io
end
def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user_full? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil?
logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin)
Baguette::Log.warning "exit requested, bye"
exit 0
end
end
AuthD.requests << Exit
end end

View file

@ -6,6 +6,11 @@ class AuthD::Request
def initialize(@user = nil) def initialize(@user = nil)
end end
def to_s(io : IO)
super io
io << " (user: #{@user})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user_full? fd logged_user = authd.get_logged_user_full? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil? return Response::ErrorMustBeAuthenticated.new if logged_user.nil?

View file

@ -22,6 +22,11 @@ class AuthD::Request
def initialize(@login, @password) def initialize(@login, @password)
end end
def to_s(io : IO)
super io
io << " (login: #{@login})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
begin begin
user = authd.users_per_login.get @login user = authd.users_per_login.get @login

View file

@ -10,6 +10,11 @@ class AuthD::Request
def initialize(@login, @password_hash_brkn, @admin = false, @email = nil, @profile = nil) def initialize(@login, @password_hash_brkn, @admin = false, @email = nil, @profile = nil)
end end
def to_s(io : IO)
super io
io << " (login: #{@login}, admin: #{@admin})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user_full? fd logged_user = authd.get_logged_user_full? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil? return Response::ErrorMustBeAuthenticated.new if logged_user.nil?

View file

@ -8,6 +8,11 @@ class AuthD::Request
def initialize(@user, @admin, @password, @email) def initialize(@user, @admin, @password, @email)
end end
def to_s(io : IO)
super io
io << " (user: #{@user}, admin: #{@admin})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user_full? fd logged_user = authd.get_logged_user_full? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil? return Response::ErrorMustBeAuthenticated.new if logged_user.nil?

View file

@ -6,6 +6,11 @@ class AuthD::Request
def initialize(@login = nil, @email = nil) def initialize(@login = nil, @email = nil)
end end
def to_s(io : IO)
super io
io << " (login: #{@login})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
if @login.nil? && @email.nil? if @login.nil? && @email.nil?
return Response::ErrorUserNotFound.new return Response::ErrorUserNotFound.new
@ -54,6 +59,11 @@ class AuthD::Request
def initialize(@user, @password_renew_key, @new_password) def initialize(@user, @password_renew_key, @new_password)
end end
def to_s(io : IO)
super io
io << " (user: #{@user}, password_renew_key: #{@password_renew_key})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
user = authd.user? @user user = authd.user? @user
# This is a way for an attacker to know what are the valid logins. # This is a way for an attacker to know what are the valid logins.

View file

@ -7,6 +7,11 @@ class AuthD::Request
def initialize(@user, @service, @resource) def initialize(@user, @service, @resource)
end end
def to_s(io : IO)
super io
io << " (user: #{@user}, service: #{@service}, resource: #{@resource})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user_full? fd logged_user = authd.get_logged_user_full? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil? return Response::ErrorMustBeAuthenticated.new if logged_user.nil?
@ -42,6 +47,11 @@ class AuthD::Request
def initialize(@user, @service, @resource, @permission) def initialize(@user, @service, @resource, @permission)
end end
def to_s(io : IO)
super io
io << " (user: #{@user}, service: #{@service}, resource: #{@resource}, permission: #{@permission})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user_full? fd logged_user = authd.get_logged_user_full? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil? return Response::ErrorMustBeAuthenticated.new if logged_user.nil?

View file

@ -8,6 +8,11 @@ class AuthD::Request
def initialize(@new_profile_entries, @user = nil) def initialize(@new_profile_entries, @user = nil)
end end
def to_s(io : IO)
super io
io << " (user: #{@user})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user_full? fd logged_user = authd.get_logged_user_full? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil? return Response::ErrorMustBeAuthenticated.new if logged_user.nil?

View file

@ -8,6 +8,11 @@ class AuthD::Request
def initialize(@login, @password, @email, @profile) def initialize(@login, @password, @email, @profile)
end end
def to_s(io : IO)
super io
io << " (login: #{@login})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
unless authd.configuration.registrations unless authd.configuration.registrations
return Response::ErrorRegistrationsClosed.new return Response::ErrorRegistrationsClosed.new

View file

@ -9,6 +9,11 @@ class AuthD::Request
def initialize(@regex = nil, @offset = 0) def initialize(@regex = nil, @offset = 0)
end end
def to_s(io : IO)
super io
io << " (regex: #{@regex}, offset: #{@offset})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user_full? fd logged_user = authd.get_logged_user_full? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil? return Response::ErrorMustBeAuthenticated.new if logged_user.nil?

View file

@ -6,6 +6,11 @@ class AuthD::Request
def initialize(@user, @activation_key) def initialize(@user, @activation_key)
end end
def to_s(io : IO)
super io
io << " (user: #{@user}, activation_key: #{@activation_key})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
user = authd.user? @user user = authd.user? @user
# This is a way for an attacker to know what are the valid logins. # This is a way for an attacker to know what are the valid logins.
@ -40,6 +45,11 @@ class AuthD::Request
def initialize(@user) def initialize(@user)
end end
def to_s(io : IO)
super io
io << " (user: #{@user})"
end
def handle(authd : AuthD::Service, fd : Int32) def handle(authd : AuthD::Service, fd : Int32)
logged_user = authd.get_logged_user? fd logged_user = authd.get_logged_user? fd
return Response::ErrorMustBeAuthenticated.new if logged_user.nil? return Response::ErrorMustBeAuthenticated.new if logged_user.nil?

View file

@ -4,6 +4,12 @@ class AuthD::Response
property email : String? = nil property email : String? = nil
def initialize(@user, @email) def initialize(@user, @email)
end end
def to_s(io : IO)
super io
io << " (user: #{@user}, email: #{@email})"
end
end end
AuthD.responses << Contacts AuthD.responses << Contacts
end end

View file

@ -9,6 +9,11 @@ class AuthD::Response
property email : String property email : String
def initialize(@email) def initialize(@email)
end end
def to_s(io : IO)
super io
io << " (email: #{@email})"
end
end end
AuthD.responses << NewEmailAddressValidated AuthD.responses << NewEmailAddressValidated
end end

View file

@ -3,6 +3,11 @@ class AuthD::Response
property reason : String? = nil property reason : String? = nil
def initialize(@reason) def initialize(@reason)
end end
def to_s(io : IO)
super io
io << " (reason: #{@reason})"
end
end end
AuthD.responses << Error AuthD.responses << Error
@ -70,6 +75,11 @@ class AuthD::Response
property read_only_keys : Array(String) property read_only_keys : Array(String)
def initialize(@read_only_keys) def initialize(@read_only_keys)
end end
def to_s(io : IO)
super io
io << " (read_only_keys: #{@read_only_keys.join(",")})"
end
end end
AuthD.responses << ErrorReadOnlyProfileKeys AuthD.responses << ErrorReadOnlyProfileKeys

View file

@ -6,6 +6,11 @@ class AuthD::Response
property pending_email : String? = nil property pending_email : String? = nil
def initialize(@token, @uid, @current_email, @pending_email) def initialize(@token, @uid, @current_email, @pending_email)
end end
def to_s(io : IO)
super io
io << " (uid: #{@uid})"
end
end end
AuthD.responses << Login AuthD.responses << Login
end end

View file

@ -6,6 +6,11 @@ class AuthD::Response
property permission : ::AuthD::User::PermissionLevel property permission : ::AuthD::User::PermissionLevel
def initialize(@service, @resource, @user, @permission) def initialize(@service, @resource, @user, @permission)
end end
def to_s(io : IO)
super io
io << " (user: #{@user}, service: #{@service}, resource: #{@resource}, permission: #{@permission})"
end
end end
AuthD.responses << PermissionCheck AuthD.responses << PermissionCheck
@ -16,6 +21,11 @@ class AuthD::Response
property permission : ::AuthD::User::PermissionLevel property permission : ::AuthD::User::PermissionLevel
def initialize(@user, @service, @resource, @permission) def initialize(@user, @service, @resource, @permission)
end end
def to_s(io : IO)
super io
io << " (user: #{@user}, service: #{@service}, resource: #{@resource}, permission: #{@permission})"
end
end end
AuthD.responses << PermissionSet AuthD.responses << PermissionSet
end end

View file

@ -3,6 +3,11 @@ class AuthD::Response
property user : ::AuthD::User::Public property user : ::AuthD::User::Public
def initialize(@user) def initialize(@user)
end end
def to_s(io : IO)
super io
io << " (user public data: #{@user})"
end
end end
AuthD.responses << User AuthD.responses << User
@ -10,6 +15,11 @@ class AuthD::Response
property user : ::AuthD::User::Public property user : ::AuthD::User::Public
def initialize(@user) def initialize(@user)
end end
def to_s(io : IO)
super io
io << " (user public data: #{@user})"
end
end end
AuthD.responses << UserAdded AuthD.responses << UserAdded
@ -17,6 +27,11 @@ class AuthD::Response
property uid : UInt32 property uid : UInt32
def initialize(@uid) def initialize(@uid)
end end
def to_s(io : IO)
super io
io << " (uid: #{@uid})"
end
end end
AuthD.responses << UserEdited AuthD.responses << UserEdited
@ -24,6 +39,11 @@ class AuthD::Response
property user : ::AuthD::User::Public property user : ::AuthD::User::Public
def initialize(@user) def initialize(@user)
end end
def to_s(io : IO)
super io
io << " (user public data: #{@user})"
end
end end
AuthD.responses << UserValidated AuthD.responses << UserValidated
@ -31,6 +51,11 @@ class AuthD::Response
property users : Array(::AuthD::User::Public) property users : Array(::AuthD::User::Public)
def initialize(@users) def initialize(@users)
end end
def to_s(io : IO)
super io
io << " (users public data: #{(@users.map &.uid).join ","})"
end
end end
AuthD.responses << UsersList AuthD.responses << UsersList
@ -38,6 +63,11 @@ class AuthD::Response
property users : Array(::AuthD::User::Public) property users : Array(::AuthD::User::Public)
def initialize(@users) def initialize(@users)
end end
def to_s(io : IO)
super io
io << " (users public data: #{(@users.map &.uid).join ","})"
end
end end
AuthD.responses << MatchingUsers AuthD.responses << MatchingUsers
@ -45,6 +75,11 @@ class AuthD::Response
property uid : UInt32 property uid : UInt32
def initialize(@uid) def initialize(@uid)
end end
def to_s(io : IO)
super io
io << " (uid: #{@uid})"
end
end end
AuthD.responses << UserDeleted AuthD.responses << UserDeleted
end end

View file

@ -29,7 +29,7 @@ class AuthD::Service < IPC
property configuration : Baguette::Configuration::Auth property configuration : Baguette::Configuration::Auth
# DB and its indexes. # DB and its indexes.
property users : DODB::Storage::Cached(User) property users : DODB::Storage::Common(User)
property users_per_uid : DODB::Trigger::IndexCached(User) property users_per_uid : DODB::Trigger::IndexCached(User)
property users_per_login : DODB::Trigger::IndexCached(User) property users_per_login : DODB::Trigger::IndexCached(User)
property users_per_email : DODB::Trigger::IndexCached(User) property users_per_email : DODB::Trigger::IndexCached(User)
@ -42,7 +42,7 @@ class AuthD::Service < IPC
def initialize(@configuration) def initialize(@configuration)
super() super()
@users = DODB::Storage::Cached(User).new @configuration.storage_directory @users = DODB::Storage::Common(User).new @configuration.storage_directory, 5000
@users_per_uid = @users.new_index "uid", &.uid.to_s @users_per_uid = @users.new_index "uid", &.uid.to_s
@users_per_login = @users.new_index "login", &.login @users_per_login = @users.new_index "login", &.login
@users_per_email = @users.new_index "email" do |user| @users_per_email = @users.new_index "email" do |user|
@ -111,7 +111,7 @@ class AuthD::Service < IPC
File.write @last_uid_file, uid.to_s File.write @last_uid_file, uid.to_s
end end
def get_logged_user?(fd : Int32) def get_logged_user?(fd : Int32) : AuthD::User::Public?
@logged_users[fd]? @logged_users[fd]?
end end
@ -123,6 +123,17 @@ class AuthD::Service < IPC
end end
end end
# `log_user_info` provides a string composed from either the user
# id in case the user was authenticated or the file descriptor of
# the connection.
def log_user_info(fd : Int32) : String
if user = get_logged_user? fd
"userid #{user.uid}"
else
"fd #{"%4d" % fd}"
end
end
def user?(uid_or_login : UserID) def user?(uid_or_login : UserID)
if uid_or_login.is_a? UInt32 if uid_or_login.is_a? UInt32
@users_per_uid.get? uid_or_login.to_s @users_per_uid.get? uid_or_login.to_s
@ -144,20 +155,21 @@ class AuthD::Service < IPC
end end
request_name = request.class.name.sub /^AuthD::Request::/, "" request_name = request.class.name.sub /^AuthD::Request::/, ""
connection_info_str = log_user_info event.fd
response = begin response = begin
request.handle self, event.fd request.handle self, event.fd
rescue e : UserNotFound rescue e : UserNotFound
Baguette::Log.error "(fd #{ "%4d" % event.fd}) #{request_name} user not found" Baguette::Log.error "(#{connection_info_str}) #{request} user not found"
AuthD::Response::Error.new "authorization error" AuthD::Response::Error.new "authorization error"
rescue e : AuthenticationInfoLacking rescue e : AuthenticationInfoLacking
Baguette::Log.error "(fd #{ "%4d" % event.fd}) #{request_name} lacking authentication info" Baguette::Log.error "(#{connection_info_str}) #{request} lacking authentication info"
AuthD::Response::Error.new "authorization error" AuthD::Response::Error.new "authorization error"
rescue e : AdminAuthorizationException rescue e : AdminAuthorizationException
Baguette::Log.error "(fd #{ "%4d" % event.fd}) #{request_name} admin authentication failed" Baguette::Log.error "(#{connection_info_str}) #{request} admin authentication failed"
AuthD::Response::Error.new "authorization error" AuthD::Response::Error.new "authorization error"
rescue e rescue e
Baguette::Log.error "(fd #{ "%4d" % event.fd}) #{request_name} generic error #{e}" Baguette::Log.error "(#{connection_info_str}) #{request} generic error #{e}"
AuthD::Response::Error.new "unknown error" AuthD::Response::Error.new "unknown error"
end end
@ -169,13 +181,11 @@ class AuthD::Service < IPC
duration = Time.utc - request_start duration = Time.utc - request_start
response_name = response.class.name.sub /^AuthD::Response::/, ""
if response.is_a? AuthD::Response::Error if response.is_a? AuthD::Response::Error
Baguette::Log.warning "fd #{ "%4d" % event.fd} (#{duration}) #{request_name} >> #{response_name} (#{response.reason})" Baguette::Log.warning "(#{connection_info_str}) (#{duration}) #{request} >> #{response}"
else else
if request_name != "KeepAlive" || should_display? AUTHMESSAGE::KEEPALIVE if request_name != "KeepAlive" || should_display? AUTHMESSAGE::KEEPALIVE
Baguette::Log.debug "fd #{ "%4d" % event.fd} (#{duration}) #{request_name} >> #{response_name}" Baguette::Log.debug "(#{connection_info_str}) (#{duration}) #{request} >> #{response}"
end end
end end
end end