More fine-grained authorizations and remove useless message GetUserByCredentials.
This commit is contained in:
		
							parent
							
								
									3e40a4ce3d
								
							
						
					
					
						commit
						cb358ef1de
					
				
					 11 changed files with 68 additions and 88 deletions
				
			
		|  | @ -11,10 +11,10 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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 "unauthorized (not admin)" unless logged_user.admin | ||||
| 
 | ||||
| 			logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin) | ||||
| 
 | ||||
| 			if authd.users_per_login.get? @login | ||||
| 				return Response::Error.new "login already used" | ||||
|  | @ -60,7 +60,7 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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? | ||||
| 
 | ||||
| 			user = authd.user? @user | ||||
|  | @ -68,7 +68,9 @@ class AuthD::Request | |||
| 
 | ||||
| 			# Only an admin can uprank someone. | ||||
| 			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 | ||||
| 
 | ||||
| 			@password.try do |s| | ||||
|  |  | |||
|  | @ -7,26 +7,22 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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? | ||||
| 
 | ||||
| 			# 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 | ||||
| 				# FIXME: This *should* require checking the new mail, with | ||||
| 				#        a new activation key and everything else. | ||||
| 				user.contact.email = email | ||||
| 				logged_user.contact.email = email | ||||
| 			end | ||||
| 
 | ||||
| 			if phone = @phone | ||||
| 				user.contact.phone = phone | ||||
| 				logged_user.contact.phone = phone | ||||
| 			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 | ||||
| 	AuthD.requests << EditContacts | ||||
|  | @ -36,15 +32,11 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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? | ||||
| 
 | ||||
| 			# 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? | ||||
| 
 | ||||
| 			_c = user.contact | ||||
| 			Response::Contacts.new user.uid, _c.email, _c.phone | ||||
| 			_c = logged_user.contact | ||||
| 			Response::Contacts.new logged_user.uid, _c.email, _c.phone | ||||
| 		end | ||||
| 	end | ||||
| 	AuthD.requests << GetContacts | ||||
|  |  | |||
|  | @ -1,23 +1,22 @@ | |||
| class AuthD::Request | ||||
| 	IPC::JSON.message Delete, 17 do | ||||
| 		# 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 | ||||
| 
 | ||||
| 		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? | ||||
| 
 | ||||
| 			# 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? | ||||
| 				return Response::Error.new "invalid credentials" if logged_user.uid != user_to_delete.uid | ||||
| 			user_to_delete = if u = @user | ||||
| 				logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin) | ||||
| 				authd.user? u | ||||
| 			else | ||||
| 				logged_user | ||||
| 			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. | ||||
| 			authd.users_per_login.delete user_to_delete.login | ||||
|  |  | |||
|  | @ -4,14 +4,11 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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? | ||||
| 
 | ||||
| 			user = authd.user? logged_user.uid | ||||
| 			return Response::Error.new "user not found" if user.nil? | ||||
| 
 | ||||
| 			# 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 | ||||
| 		end | ||||
|  |  | |||
|  | @ -10,9 +10,13 @@ class AuthD::Request | |||
| 			begin | ||||
| 				user = authd.users_per_login.get @login | ||||
| 			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" | ||||
| 			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? | ||||
| 
 | ||||
| 			if user.password_hash != authd.hash_password @password | ||||
|  |  | |||
|  | @ -6,17 +6,13 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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? | ||||
| 
 | ||||
| 			user = authd.user? logged_user.uid | ||||
| 			return Response::Error.new "user not found" if user.nil? | ||||
| 			logged_user.password_hash = authd.hash_password @new_password | ||||
| 			authd.users_per_uid.update logged_user.uid.to_s, logged_user | ||||
| 
 | ||||
| 			user.password_hash = authd.hash_password @new_password | ||||
| 
 | ||||
| 			authd.users_per_uid.update user.uid.to_s, user | ||||
| 
 | ||||
| 			Response::UserEdited.new user.uid | ||||
| 			Response::UserEdited.new logged_user.uid | ||||
| 		end | ||||
| 	end | ||||
| 	AuthD.requests << UpdatePassword | ||||
|  | @ -31,6 +27,8 @@ class AuthD::Request | |||
| 
 | ||||
| 		def handle(authd : AuthD::Service, fd : Int32) | ||||
| 			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? | ||||
| 
 | ||||
| 			if user.password_renew_key == @password_renew_key | ||||
|  | @ -56,6 +54,8 @@ class AuthD::Request | |||
| 
 | ||||
| 		def handle(authd : AuthD::Service, fd : Int32) | ||||
| 			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? | ||||
| 
 | ||||
| 			# Create a new random key for password renewal. | ||||
|  |  | |||
|  | @ -8,10 +8,9 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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 "unauthorized (not admin)" unless logged_user.admin | ||||
| 			logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin) | ||||
| 
 | ||||
| 			user = authd.user? @user | ||||
| 			return Response::Error.new "no such user" if user.nil? | ||||
|  | @ -40,10 +39,9 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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 "unauthorized (not admin)" unless logged_user.admin | ||||
| 			logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin) | ||||
| 
 | ||||
| 			user = authd.user? @user | ||||
| 			return Response::Error.new "no such user" if user.nil? | ||||
|  |  | |||
|  | @ -6,14 +6,12 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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? | ||||
| 
 | ||||
| 			user = authd.user? logged_user.uid | ||||
| 			return Response::Error.new "user not found" if user.nil? | ||||
| 
 | ||||
| 			profile = user.profile || Hash(String, JSON::Any).new | ||||
| 			profile = logged_user.profile || Hash(String, JSON::Any).new | ||||
| 
 | ||||
| 			# Skip this verification for authd administrators. | ||||
| 			unless logged_user.admin | ||||
| 				authd.configuration.read_only_profile_keys.each do |key| | ||||
| 					if @new_profile[key]? != profile[key]? | ||||
|  | @ -22,11 +20,11 @@ class AuthD::Request | |||
| 				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 | ||||
| 	AuthD.requests << ReplaceProfile | ||||
|  | @ -42,14 +40,14 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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? | ||||
| 
 | ||||
| 			user = if u = @user | ||||
| 				raise AdminAuthorizationException.new unless logged_user.admin | ||||
| 				logged_user.assert_permission("authd", "*", User::PermissionLevel::Edit) | ||||
| 				authd.user? u | ||||
| 			else | ||||
| 				authd.user? logged_user.uid | ||||
| 				logged_user | ||||
| 			end | ||||
| 			return Response::Error.new "user not found" if user.nil? | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,9 +6,9 @@ class AuthD::Request | |||
| 		end | ||||
| 
 | ||||
| 		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 "unauthorized (not admin)" unless logged_user.admin | ||||
| 			logged_user.assert_permission("authd", "*", User::PermissionLevel::Read) | ||||
| 
 | ||||
| 			pattern = Regex.new @user, Regex::Options::IGNORE_CASE | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ class AuthD::Request | |||
| 
 | ||||
| 		def handle(authd : AuthD::Service, fd : Int32) | ||||
| 			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? | ||||
| 
 | ||||
| 			if user.contact.activation_key.nil? | ||||
|  | @ -35,36 +37,16 @@ class AuthD::Request | |||
| 		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 | ||||
| 			# 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? | ||||
| 
 | ||||
| 			Response::User.new user.to_public | ||||
| 		end | ||||
| 	end | ||||
| 	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 | ||||
|  |  | |||
|  | @ -83,6 +83,14 @@ class AuthD::Service < IPC | |||
| 		@logged_users[fd]? | ||||
| 	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) | ||||
| 		if uid_or_login.is_a? Int32 | ||||
| 			@users_per_uid.get? uid_or_login.to_s | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue