More fine-grained authorizations and remove useless message GetUserByCredentials.
This commit is contained in:
parent
3e40a4ce3d
commit
cb358ef1de
@ -11,10 +11,10 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
|
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
return Response::Error.new "unauthorized (not admin)" unless logged_user.admin
|
|
||||||
|
logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin)
|
||||||
|
|
||||||
if authd.users_per_login.get? @login
|
if authd.users_per_login.get? @login
|
||||||
return Response::Error.new "login already used"
|
return Response::Error.new "login already used"
|
||||||
@ -60,7 +60,7 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
|
|
||||||
user = authd.user? @user
|
user = authd.user? @user
|
||||||
@ -68,7 +68,9 @@ class AuthD::Request
|
|||||||
|
|
||||||
# Only an admin can uprank someone.
|
# Only an admin can uprank someone.
|
||||||
if @admin
|
if @admin
|
||||||
return Response::Error.new "unauthorized (not admin)" unless logged_user.admin
|
logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin)
|
||||||
|
else
|
||||||
|
logged_user.assert_permission("authd", "*", User::PermissionLevel::Edit)
|
||||||
end
|
end
|
||||||
|
|
||||||
@password.try do |s|
|
@password.try do |s|
|
||||||
|
@ -7,26 +7,22 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
|
|
||||||
# Get the full AuthD::User instance, not just the public view.
|
|
||||||
user = authd.user? logged_user.uid
|
|
||||||
return Response::Error.new "unknown user" if user.nil?
|
|
||||||
|
|
||||||
if email = @email
|
if email = @email
|
||||||
# FIXME: This *should* require checking the new mail, with
|
# FIXME: This *should* require checking the new mail, with
|
||||||
# a new activation key and everything else.
|
# a new activation key and everything else.
|
||||||
user.contact.email = email
|
logged_user.contact.email = email
|
||||||
end
|
end
|
||||||
|
|
||||||
if phone = @phone
|
if phone = @phone
|
||||||
user.contact.phone = phone
|
logged_user.contact.phone = phone
|
||||||
end
|
end
|
||||||
|
|
||||||
authd.users_per_uid.update user
|
authd.users_per_uid.update logged_user
|
||||||
|
|
||||||
Response::UserEdited.new user.uid
|
Response::UserEdited.new logged_user.uid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
AuthD.requests << EditContacts
|
AuthD.requests << EditContacts
|
||||||
@ -36,15 +32,11 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
|
|
||||||
# Get the full AuthD::User instance, not just the public view.
|
_c = logged_user.contact
|
||||||
user = authd.user? logged_user.uid
|
Response::Contacts.new logged_user.uid, _c.email, _c.phone
|
||||||
return Response::Error.new "unknown user" if user.nil?
|
|
||||||
|
|
||||||
_c = user.contact
|
|
||||||
Response::Contacts.new user.uid, _c.email, _c.phone
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
AuthD.requests << GetContacts
|
AuthD.requests << GetContacts
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
class AuthD::Request
|
class AuthD::Request
|
||||||
IPC::JSON.message Delete, 17 do
|
IPC::JSON.message Delete, 17 do
|
||||||
# Deletion can be triggered by either an admin or the related user.
|
# Deletion can be triggered by either an admin or the related user.
|
||||||
property user : UserID
|
property user : UserID | Nil = nil
|
||||||
|
|
||||||
def initialize(@user)
|
def initialize(@user = nil)
|
||||||
end
|
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_full? fd
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
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 = if u = @user
|
||||||
user_to_delete = authd.user? logged_user.uid
|
logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin)
|
||||||
return Response::Error.new "unknown user" if user_to_delete.nil?
|
authd.user? u
|
||||||
|
else
|
||||||
unless logged_user.admin
|
logged_user
|
||||||
# Is the logged user the target?
|
|
||||||
return Response::Error.new "invalid credentials" if logged_user.uid != user_to_delete.uid
|
|
||||||
end
|
end
|
||||||
|
return Response::Error.new "unknown user" if user_to_delete.nil?
|
||||||
|
|
||||||
# User or admin is now verified: let's proceed with the user deletion.
|
# User or admin is now verified: let's proceed with the user deletion.
|
||||||
authd.users_per_login.delete user_to_delete.login
|
authd.users_per_login.delete user_to_delete.login
|
||||||
|
@ -4,14 +4,11 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
|
|
||||||
user = authd.user? logged_user.uid
|
|
||||||
return Response::Error.new "user not found" if user.nil?
|
|
||||||
|
|
||||||
# Test if the user is a moderator.
|
# Test if the user is a moderator.
|
||||||
user.assert_permission("authd", "*", User::PermissionLevel::Read)
|
logged_user.assert_permission("authd", "*", User::PermissionLevel::Read)
|
||||||
|
|
||||||
Response::UsersList.new authd.users.to_h.map &.[1].to_public
|
Response::UsersList.new authd.users.to_h.map &.[1].to_public
|
||||||
end
|
end
|
||||||
|
@ -10,9 +10,13 @@ class AuthD::Request
|
|||||||
begin
|
begin
|
||||||
user = authd.users_per_login.get @login
|
user = authd.users_per_login.get @login
|
||||||
rescue e : DODB::MissingEntry
|
rescue e : DODB::MissingEntry
|
||||||
|
# This lack of proper error message is intentional.
|
||||||
|
# Let attackers try to authenticate themselves with a wrong login.
|
||||||
return Response::Error.new "invalid credentials"
|
return Response::Error.new "invalid credentials"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This line is basically just to please the Crystal's type system.
|
||||||
|
# No user means DODB::MissingEntry, so it's already covered.
|
||||||
return Response::Error.new "invalid credentials" if user.nil?
|
return Response::Error.new "invalid credentials" if user.nil?
|
||||||
|
|
||||||
if user.password_hash != authd.hash_password @password
|
if user.password_hash != authd.hash_password @password
|
||||||
|
@ -6,17 +6,13 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
|
|
||||||
user = authd.user? logged_user.uid
|
logged_user.password_hash = authd.hash_password @new_password
|
||||||
return Response::Error.new "user not found" if user.nil?
|
authd.users_per_uid.update logged_user.uid.to_s, logged_user
|
||||||
|
|
||||||
user.password_hash = authd.hash_password @new_password
|
Response::UserEdited.new logged_user.uid
|
||||||
|
|
||||||
authd.users_per_uid.update user.uid.to_s, user
|
|
||||||
|
|
||||||
Response::UserEdited.new user.uid
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
AuthD.requests << UpdatePassword
|
AuthD.requests << UpdatePassword
|
||||||
@ -31,6 +27,8 @@ class AuthD::Request
|
|||||||
|
|
||||||
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.
|
||||||
|
# Not sure I care enough to fix this.
|
||||||
return Response::Error.new "user not found" if user.nil?
|
return Response::Error.new "user not found" if user.nil?
|
||||||
|
|
||||||
if user.password_renew_key == @password_renew_key
|
if user.password_renew_key == @password_renew_key
|
||||||
@ -56,6 +54,8 @@ class AuthD::Request
|
|||||||
|
|
||||||
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.
|
||||||
|
# Not sure I care enough to fix this.
|
||||||
return Response::Error.new "user not found" if user.nil?
|
return Response::Error.new "user not found" if user.nil?
|
||||||
|
|
||||||
# Create a new random key for password renewal.
|
# Create a new random key for password renewal.
|
||||||
|
@ -8,10 +8,9 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
|
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
return Response::Error.new "unauthorized (not admin)" unless logged_user.admin
|
logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin)
|
||||||
|
|
||||||
user = authd.user? @user
|
user = authd.user? @user
|
||||||
return Response::Error.new "no such user" if user.nil?
|
return Response::Error.new "no such user" if user.nil?
|
||||||
@ -40,10 +39,9 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
|
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
return Response::Error.new "unauthorized (not admin)" unless logged_user.admin
|
logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin)
|
||||||
|
|
||||||
user = authd.user? @user
|
user = authd.user? @user
|
||||||
return Response::Error.new "no such user" if user.nil?
|
return Response::Error.new "no such user" if user.nil?
|
||||||
|
@ -6,14 +6,12 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
|
|
||||||
user = authd.user? logged_user.uid
|
profile = logged_user.profile || Hash(String, JSON::Any).new
|
||||||
return Response::Error.new "user not found" if user.nil?
|
|
||||||
|
|
||||||
profile = user.profile || Hash(String, JSON::Any).new
|
|
||||||
|
|
||||||
|
# Skip this verification for authd administrators.
|
||||||
unless logged_user.admin
|
unless logged_user.admin
|
||||||
authd.configuration.read_only_profile_keys.each do |key|
|
authd.configuration.read_only_profile_keys.each do |key|
|
||||||
if @new_profile[key]? != profile[key]?
|
if @new_profile[key]? != profile[key]?
|
||||||
@ -22,11 +20,11 @@ class AuthD::Request
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
user.profile = @new_profile
|
logged_user.profile = @new_profile
|
||||||
|
|
||||||
authd.users_per_uid.update user.uid.to_s, user
|
authd.users_per_uid.update logged_user.uid.to_s, logged_user
|
||||||
|
|
||||||
Response::User.new user.to_public
|
Response::User.new logged_user.to_public
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
AuthD.requests << ReplaceProfile
|
AuthD.requests << ReplaceProfile
|
||||||
@ -42,14 +40,14 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
|
|
||||||
user = if u = @user
|
user = if u = @user
|
||||||
raise AdminAuthorizationException.new unless logged_user.admin
|
logged_user.assert_permission("authd", "*", User::PermissionLevel::Edit)
|
||||||
authd.user? u
|
authd.user? u
|
||||||
else
|
else
|
||||||
authd.user? logged_user.uid
|
logged_user
|
||||||
end
|
end
|
||||||
return Response::Error.new "user not found" if user.nil?
|
return Response::Error.new "user not found" if user.nil?
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ class AuthD::Request
|
|||||||
end
|
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_full? fd
|
||||||
return Response::Error.new "you must be logged" if logged_user.nil?
|
return Response::Error.new "you must be logged" if logged_user.nil?
|
||||||
return Response::Error.new "unauthorized (not admin)" unless logged_user.admin
|
logged_user.assert_permission("authd", "*", User::PermissionLevel::Read)
|
||||||
|
|
||||||
pattern = Regex.new @user, Regex::Options::IGNORE_CASE
|
pattern = Regex.new @user, Regex::Options::IGNORE_CASE
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ class AuthD::Request
|
|||||||
|
|
||||||
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.
|
||||||
|
# Not sure I care enough to fix this.
|
||||||
return Response::Error.new "user not found" if user.nil?
|
return Response::Error.new "user not found" if user.nil?
|
||||||
|
|
||||||
if user.contact.activation_key.nil?
|
if user.contact.activation_key.nil?
|
||||||
@ -35,36 +37,16 @@ class AuthD::Request
|
|||||||
end
|
end
|
||||||
|
|
||||||
def handle(authd : AuthD::Service, fd : Int32)
|
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
|
user = authd.user? @user
|
||||||
|
# This is a way for an attacker to know what are the valid logins.
|
||||||
|
# Not sure I care enough to fix this.
|
||||||
return Response::Error.new "user not found" if user.nil?
|
return Response::Error.new "user not found" if user.nil?
|
||||||
|
|
||||||
Response::User.new user.to_public
|
Response::User.new user.to_public
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
AuthD.requests << GetUser
|
AuthD.requests << GetUser
|
||||||
|
|
||||||
IPC::JSON.message GetUserByCredentials, 4 do
|
|
||||||
property login : String
|
|
||||||
property password : String
|
|
||||||
|
|
||||||
def initialize(@login, @password)
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle(authd : AuthD::Service, fd : Int32)
|
|
||||||
user = authd.users_per_login.get? @login
|
|
||||||
return Response::Error.new "invalid credentials" unless user
|
|
||||||
|
|
||||||
if authd.hash_password(@password) != user.password_hash
|
|
||||||
return Response::Error.new "invalid credentials"
|
|
||||||
end
|
|
||||||
|
|
||||||
user.date_last_connection = Time.local
|
|
||||||
|
|
||||||
# Change the date of the last connection.
|
|
||||||
authd.users_per_uid.update user.uid.to_s, user
|
|
||||||
|
|
||||||
Response::User.new user.to_public
|
|
||||||
end
|
|
||||||
end
|
|
||||||
AuthD.requests << GetUserByCredentials
|
|
||||||
end
|
end
|
||||||
|
@ -83,6 +83,14 @@ class AuthD::Service < IPC
|
|||||||
@logged_users[fd]?
|
@logged_users[fd]?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Instead of just getting the public view of a logged user,
|
||||||
|
# get the actual User instance.
|
||||||
|
def get_logged_user_full?(fd : Int32)
|
||||||
|
if u = @logged_users[fd]?
|
||||||
|
user? u.uid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def user?(uid_or_login : UserID)
|
def user?(uid_or_login : UserID)
|
||||||
if uid_or_login.is_a? Int32
|
if uid_or_login.is_a? Int32
|
||||||
@users_per_uid.get? uid_or_login.to_s
|
@users_per_uid.get? uid_or_login.to_s
|
||||||
|
Loading…
Reference in New Issue
Block a user