Compiles.

rewrite
Karchnu 2020-11-20 11:53:10 +01:00
parent 6a6ccfe37f
commit 3879e7915d
4 changed files with 107 additions and 97 deletions

View File

@ -13,8 +13,11 @@ class Baguette::Configuration
property login : String? = nil
property pass : String? = nil
property shared_key : String = "nico-nico-nii" # Default authd key, as per the specs. :eyes:
property shared_key : String = "nico-nico-nii" # Default authd key, as per the specs. :eyes:
property shared_key_file : String? = nil
def initialize
end
end
end
@ -22,6 +25,12 @@ module AuthD
class Exception < ::Exception
end
class UserNotFound < ::Exception
end
class AuthenticationInfoLacking < ::Exception
end
# Not used for now.
class NotLoggedException < ::Exception
end

View File

@ -31,7 +31,8 @@ end
require "./network"
class AuthD::Service
# Provides a JWT-based authentication scheme for service-specific users.
class AuthD::Service < IPC::Server
property configuration : Baguette::Configuration::Auth
# DB and its indexes.
@ -52,6 +53,8 @@ class AuthD::Service
if @configuration.recreate_indexes
@users.reindex_everything!
end
super "authd"
end
def hash_password(password : String) : String
@ -88,6 +91,9 @@ class AuthD::Service
response = begin
request.handle self, event
rescue e : UserNotFound
Baguette::Log.error "#{request_name} user not found"
AuthD::Response::Error.new "authorization error"
rescue e : AuthorizationException
Baguette::Log.error "#{request_name} authorization error"
AuthD::Response::Error.new "authorization error"
@ -126,13 +132,12 @@ class AuthD::Service
end
def run
##
# Provides a JWT-based authentication scheme for service-specific users.
server = IPC::Server.new "auth"
server.base_timer = @configuration.ipc_timer
server.timer = @configuration.ipc_timer
Baguette::Log.title "Starting authd"
server.loop do |event|
@base_timer = @configuration.ipc_timer
@timer = @configuration.ipc_timer
self.loop do |event|
case event
when IPC::Event::Timer
Baguette::Log.debug "Timer" if @configuration.print_ipc_timer

View File

@ -3,7 +3,7 @@ require "json"
require "ipc/json"
class IPC::JSON
def handle(service : IPC::Server, event : IPC::Event::Events)
def handle(service : AuthD::Service, event : IPC::Event::Events)
raise "unimplemented"
end
end

View File

@ -8,7 +8,7 @@ class AuthD::Request
def handle(authd : AuthD::Service, event : IPC::Event::Events)
begin
user = authd.users_per_login.get request.login
user = authd.users_per_login.get @login
rescue e : DODB::MissingEntry
return Response::Error.new "invalid credentials"
end
@ -17,7 +17,7 @@ class AuthD::Request
return Response::Error.new "invalid credentials"
end
if user.password_hash != authd.hash_password request.password
if user.password_hash != authd.hash_password @password
return Response::Error.new "invalid credentials"
end
@ -49,27 +49,27 @@ class AuthD::Request
def handle(authd : AuthD::Service, event : IPC::Event::Events)
# No verification of the users' informations when an admin adds it.
# No mail address verification.
if request.shared_key != authd.configuration.shared_key
if @shared_key != authd.configuration.shared_key
return Response::Error.new "invalid authentication key"
end
if authd.users_per_login.get? request.login
if authd.users_per_login.get? @login
return Response::Error.new "login already used"
end
if authd.configuration.require_email && request.email.nil?
if authd.configuration.require_email && @email.nil?
return Response::Error.new "email required"
end
password_hash = authd.hash_password request.password
password_hash = authd.hash_password @password
uid = authd.new_uid
user = User.new uid, request.login, password_hash
user.contact.email = request.email unless request.email.nil?
user.contact.phone = request.phone unless request.phone.nil?
user = User.new uid, @login, password_hash
user.contact.email = @email unless @email.nil?
user.contact.phone = @phone unless @phone.nil?
request.profile.try do |profile|
@profile.try do |profile|
user.profile = profile
end
@ -91,7 +91,7 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
user = authd.users_per_login.get? request.login
user = authd.users_per_login.get? @login
if user.nil?
return Response::Error.new "user not found"
@ -102,7 +102,7 @@ class AuthD::Request
end
# remove the user contact activation key: the email is validated
if user.contact.activation_key == request.activation_key
if user.contact.activation_key == @activation_key
user.contact.activation_key = nil
else
return Response::Error.new "wrong activation key"
@ -122,7 +122,7 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
uid_or_login = request.user
uid_or_login = @user
user = if uid_or_login.is_a? Int32
authd.users_per_uid.get? uid_or_login.to_s
else
@ -146,13 +146,13 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
user = authd.users_per_login.get? request.login
user = authd.users_per_login.get? @login
unless user
return Response::Error.new "invalid credentials"
end
if authd.hash_password(request.password) != user.password_hash
if authd.hash_password(@password) != user.password_hash
return Response::Error.new "invalid credentials"
end
@ -179,11 +179,11 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
if request.shared_key != authd.configuration.shared_key
if @shared_key != authd.configuration.shared_key
return Response::Error.new "invalid authentication key"
end
uid_or_login = request.user
uid_or_login = @user
user = if uid_or_login.is_a? Int32
authd.users_per_uid.get? uid_or_login.to_s
else
@ -194,15 +194,15 @@ class AuthD::Request
return Response::Error.new "user not found"
end
request.password.try do |s|
@password.try do |s|
user.password_hash = authd.hash_password s
end
request.email.try do |email|
@email.try do |email|
user.contact.email = email
end
request.phone.try do |phone|
@phone.try do |phone|
user.contact.phone = phone
end
@ -228,11 +228,11 @@ class AuthD::Request
return Response::Error.new "registrations not allowed"
end
if authd.users_per_login.get? request.login
if authd.users_per_login.get? @login
return Response::Error.new "login already used"
end
if authd.configuration.require_email && request.email.nil?
if authd.configuration.require_email && @email.nil?
return Response::Error.new "email required"
end
@ -242,10 +242,10 @@ class AuthD::Request
return Response::Error.new "No activation URL were entered. Cannot send activation mails."
end
if ! request.email.nil?
if ! @email.nil?
# Test on the email address format.
grok = Grok.new [ "%{EMAILADDRESS:email}" ]
result = grok.parse request.email.not_nil!
result = grok.parse @email.not_nil!
email = result["email"]?
if email.nil?
@ -254,18 +254,18 @@ class AuthD::Request
end
# In this case we should not accept its registration.
if request.password.size < 4
if @password.size < 4
return Response::Error.new "password too short"
end
uid = authd.new_uid
password = authd.hash_password request.password
password = authd.hash_password @password
user = User.new uid, request.login, password
user.contact.email = request.email unless request.email.nil?
user.contact.phone = request.phone unless request.phone.nil?
user = User.new uid, @login, password
user.contact.email = @email unless @email.nil?
user.contact.phone = @phone unless @phone.nil?
request.profile.try do |profile|
@profile.try do |profile|
user.profile = profile
end
@ -313,17 +313,17 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
user = authd.users_per_login.get? request.login
user = authd.users_per_login.get? @login
unless user
return Response::Error.new "invalid credentials"
end
if authd.hash_password(request.old_password) != user.password_hash
if authd.hash_password(@old_password) != user.password_hash
return Response::Error.new "invalid credentials"
end
user.password_hash = authd.hash_password request.new_password
user.password_hash = authd.hash_password @new_password
authd.users_per_uid.update user.uid.to_s, user
@ -341,7 +341,7 @@ class AuthD::Request
def handle(authd : AuthD::Service, event : IPC::Event::Events)
# FIXME: Lines too long, repeatedly (>80c with 4c tabs).
request.token.try do |token|
@token.try do |token|
user = authd.get_user_from_token token
return Response::Error.new "unauthorized (user not found from token)"
@ -349,11 +349,11 @@ class AuthD::Request
return Response::Error.new "unauthorized (user not in authd group)" unless user.permissions["authd"]?.try(&.["*"].>=(User::PermissionLevel::Read))
end
request.key.try do |key|
@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 request.key || request.token
return Response::Error.new "unauthorized (no key nor token)" unless @key || @token
Response::UsersList.new authd.users.to_h.map &.[1].to_public
end
@ -374,7 +374,7 @@ class AuthD::Request
def handle(authd : AuthD::Service, event : IPC::Event::Events)
authorized = false
if key = request.shared_key
if key = @shared_key
if key == authd.configuration.shared_key
authorized = true
else
@ -382,14 +382,14 @@ class AuthD::Request
end
end
if token = request.token
if token = @token
user = authd.get_user_from_token token
if user.nil?
return Response::Error.new "token does not match user"
end
if user.login != request.user && user.uid != request.user
if user.login != @user && user.uid != @user
return Response::Error.new "token does not match user"
end
@ -400,7 +400,7 @@ class AuthD::Request
return Response::Error.new "unauthorized"
end
user = case u = request.user
user = case u = @user
when .is_a? Int32
authd.users_per_uid.get? u.to_s
else
@ -411,20 +411,20 @@ class AuthD::Request
return Response::Error.new "no such user"
end
service = request.service
service = @service
service_permissions = user.permissions[service]?
if service_permissions.nil?
return Response::PermissionCheck.new service, request.resource, user.uid, User::PermissionLevel::None
return Response::PermissionCheck.new service, @resource, user.uid, User::PermissionLevel::None
end
resource_permissions = service_permissions[request.resource]?
resource_permissions = service_permissions[@resource]?
if resource_permissions.nil?
return Response::PermissionCheck.new service, request.resource, user.uid, User::PermissionLevel::None
return Response::PermissionCheck.new service, @resource, user.uid, User::PermissionLevel::None
end
return Response::PermissionCheck.new service, request.resource, user.uid, resource_permissions
return Response::PermissionCheck.new service, @resource, user.uid, resource_permissions
end
end
AuthD.requests << CheckPermission
@ -441,17 +441,17 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
unless request.shared_key == authd.configuration.shared_key
unless @shared_key == authd.configuration.shared_key
return Response::Error.new "unauthorized"
end
user = authd.users_per_uid.get? request.user.to_s
user = authd.users_per_uid.get? @user.to_s
if user.nil?
return Response::Error.new "no such user"
end
service = request.service
service = @service
service_permissions = user.permissions[service]?
if service_permissions.nil?
@ -459,15 +459,15 @@ class AuthD::Request
user.permissions[service] = service_permissions
end
if request.permission.none?
service_permissions.delete request.resource
if @permission.none?
service_permissions.delete @resource
else
service_permissions[request.resource] = request.permission
service_permissions[@resource] = @permission
end
authd.users_per_uid.update user.uid.to_s, user
Response::PermissionSet.new user.uid, service, request.resource, request.permission
Response::PermissionSet.new user.uid, service, @resource, @permission
end
end
AuthD.requests << SetPermission
@ -481,7 +481,7 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
uid_or_login = request.user
uid_or_login = @user
user = if uid_or_login.is_a? Int32
authd.users_per_uid.get? uid_or_login.to_s
else
@ -492,8 +492,8 @@ class AuthD::Request
return Response::Error.new "user not found"
end
if user.password_renew_key == request.password_renew_key
user.password_hash = authd.hash_password request.new_password
if user.password_renew_key == @password_renew_key
user.password_hash = authd.hash_password @new_password
else
return Response::Error.new "renew key not valid"
end
@ -515,7 +515,7 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
uid_or_login = request.user
uid_or_login = @user
user = if uid_or_login.is_a? Int32
authd.users_per_uid.get? uid_or_login.to_s
else
@ -526,7 +526,7 @@ class AuthD::Request
return Response::Error.new "no such user"
end
if user.contact.email != request.email
if user.contact.email != @email
# Same error as when users are not found.
return Response::Error.new "no such user"
end
@ -575,7 +575,7 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
pattern = Regex.new request.user, Regex::Options::IGNORE_CASE
pattern = Regex.new @user, Regex::Options::IGNORE_CASE
matching_users = Array(AuthD::User::Public).new
@ -609,11 +609,11 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
user = authd.get_user_from_token request.token
user = authd.get_user_from_token @token
return Response::Error.new "invalid user" unless user
new_profile = request.new_profile
new_profile = @new_profile
profile = user.profile || Hash(String, JSON::Any).new
@ -648,43 +648,39 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
user = if token = request.token
user = authd.get_user_from_token token
user = if token = @token
u = authd.get_user_from_token token
raise UserNotFound.new unless u
u
elsif shared_key = @shared_key
raise AdminAuthorizationException.new if shared_key != authd.configuration.shared_key
return Response::Error.new "invalid user" unless user
u = @user
raise UserNotFound.new unless u
user
elsif shared_key = request.shared_key
return Response::Error.new "invalid shared key" if shared_key != authd.configuration.shared_key
user = request.user
return Response::Error.new "invalid user" unless user
user = if user.is_a? Int32
authd.users_per_uid.get? user.to_s
u = if u.is_a? Int32
authd.users_per_uid.get? u.to_s
else
authd.users_per_login.get? user
authd.users_per_login.get? u
end
raise UserNotFound.new unless u
return Response::Error.new "invalid user" unless user
user
u
else
return Response::Error.new "no token or shared_key/user pair"
raise AuthenticationInfoLacking.new
end
new_profile = user.profile || Hash(String, JSON::Any).new
unless request.shared_key
unless @shared_key
authd.configuration.read_only_profile_keys.each do |key|
if request.new_profile.has_key? key
if @new_profile.has_key? key
return Response::Error.new "tried to edit read only key"
end
end
end
request.new_profile.each do |key, value|
@new_profile.each do |key, value|
new_profile[key] = value
end
@ -707,11 +703,11 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
user = authd.get_user_from_token request.token
user = authd.get_user_from_token @token
return Response::Error.new "invalid user" unless user
if email = request.email
if email = @email
# FIXME: This *should* require checking the new mail, with
# a new activation key and everything else.
user.contact.email = email
@ -739,7 +735,7 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
uid_or_login = request.user
uid_or_login = @user
user_to_delete = if uid_or_login.is_a? Int32
authd.users_per_uid.get? uid_or_login.to_s
else
@ -752,11 +748,11 @@ class AuthD::Request
# Either the request comes from an admin or the user.
# Shared key == admin, check the key.
if key = request.shared_key
if key = @shared_key
return Response::Error.new "unauthorized (wrong shared key)" unless key == authd.configuration.shared_key
else
login = request.login
pass = request.password
login = @login
pass = @password
if login.nil? || pass.nil?
return Response::Error.new "authentication failed (no shared key, no login)"
end
@ -798,7 +794,7 @@ class AuthD::Request
end
def handle(authd : AuthD::Service, event : IPC::Event::Events)
user = authd.get_user_from_token request.token
user = authd.get_user_from_token @token
return Response::Error.new "invalid user" unless user