improved stuff, can't remember except better user handling

This commit is contained in:
Christoffer Müller Madsen 2017-06-03 01:32:23 +02:00
parent 0ab9081564
commit 291aeb98ed
2 changed files with 271 additions and 77 deletions

273
collab.rb
View File

@ -1,62 +1,189 @@
require 'fileutils' require 'fileutils'
POSIX_NAME_PREFIX = "emacs" POSIX_NAME_PREFIX = "emacs"
USER_LOCATION = "./users/"
$projects = []
$users = [] $users = []
$id_map = {} $project_id_map = {}
$user_id_map = {}
##################### #####################
# User manipulation # # User manipulation #
##################### #####################
class User class User
attr_accessor :id, :path, :posixname attr_accessor :id, :keypath
attr_reader :keys
def to_s
"#{@id}"
end
def initialize(id)
@id = id
@keypath = "#{USER_LOCATION}#{id}"
refresh_keys
end
def add_key_from_string(keystring)
unless valid_pubkey? keystring
raise InvalidSSHPubKey, "Public key not valid"
end
ks = keystring.split(" ");
key = SSHKey.new(ks[0][4..6], ks[1], ks[2])
unless @keys.include? key
@keys << key
else
raise DuplicateSSHPubKey, "Public key is already added to user"
end
flush
refresh_keys
flush_projects_with_user(self)
end
def remove_key(key)
@keys.delete(key)
flush
refresh_keys
flush_projects_with_user(self)
end
def refresh_keys
File.open(@keypath,"r") do |f|
@keys = f.read.split("\n").select{ |line| line[0..2] == "ssh" }.map{ |ks| k = ks.split(" "); SSHKey.new(k[0][4..6], k[1], k[2]) }
end
end
def flush
File.open(@keypath,"w+") do |key_file|
@keys.each do |key|
key_file << "#{key.to_s}\n"
end
end
end
end
def add_user(id)
user = User.new(id)
$users << user
$user_id_map[id] = user
end
def get_user_by_id(id)
$user_id_map[id]
end
def validate_password
end
########################
# Project manipulation #
########################
class Project
attr_accessor :id, :path, :posixname, :users
attr_reader :keys
def initialize
@users = []
end
def to_s def to_s
"#{@id}, #{@path}" "#{@id}, #{@path}"
end end
end
def get_user(id) def add_key(key)
$id_map[id] @keys << key
end
def add_user(user)
$users << user
$id_map[user.id] = user
end
def create_user(id)
if not system("useradd -m #{POSIX_NAME_PREFIX}#{id}") then
raise "User creation failed"
end end
user = User.new def add_user(user)
user.id = id @users << user
user.path = "/home/#{POSIX_NAME_PREFIX}#{id}" user.keys.each do |key|
user.posixname = "#{POSIX_NAME_PREFIX}#{id}" p key
$users << user add_key(key)
$id_map[id] = user end
flush
refresh
end
FileUtils.mkdir "#{user.path}/.ssh" def remove_user(user)
FileUtils.touch "#{user.path}/.ssh/authorized_keys" @user.delete(user)
FileUtils.chown_R user.id, user.id, "#{user.path}/.ssh" flush
refresh
end
def refresh
@users = File.open("#{@path}/.ssh/users","r") do |f|
f.read.split("\n").map{|id| p id; puts $user_id_map; get_user_by_id(id)}
end
p @users
@keys = extract_ssh_pubkeys("#{@path}/.ssh/authorized_keys")
end
def flush
File.open("#{@path}/.ssh/users","w+") do |user_file|
@users.each do |u|
user_file << "#{u.id}\n"
end
end
get_ssh_keyfile(self,"w+") do |key_file|
@users.each do |user|
user.keys.each do |key|
key_file << "#{key.to_s}\n"
end
end
end
end
user
end end
def remove_user(user) def get_project(id)
system("userdel -r #{user.posixname}") $project_id_map[id]
$users.remove(user)
$id_map[id] = nil
end end
def user_by_posix_name(posix_name) def add_project(project)
user = User.new $projects << project
user.id = posix_name[POSIX_NAME_PREFIX.length..-1] $project_id_map[project.id] = project
user.path = "/home/#{posix_name}" end
user.posixname = posix_name
user def create_project(id)
if not system("useradd -m #{POSIX_NAME_PREFIX}#{id}") then
raise "Project creation failed"
end
project = Project.new
project.id = id
project.path = "/home/#{POSIX_NAME_PREFIX}#{id}"
project.posixname = "#{POSIX_NAME_PREFIX}#{id}"
$projects << project
$project_id_map[id] = project
FileUtils.mkdir "#{project.path}/.ssh"
FileUtils.touch "#{project.path}/.ssh/authorized_keys"
FileUtils.touch "#{project.path}/.ssh/users"
FileUtils.chown_R project.id, project.id, "#{project.path}/.ssh"
project
end
def remove_project(project)
system("userdel -r #{project.posixname}")
$projects.remove(project)
$project_id_map[id] = nil
end
def project_by_posix_name(posix_name)
project = Project.new
project.id = posix_name[POSIX_NAME_PREFIX.length..-1]
project.path = "/home/#{posix_name}"
project.posixname = posix_name
project
end end
#################### ####################
@ -89,35 +216,44 @@ class SSHKey
end end
end end
def get_ssh_keyfile(user,mode,&block) class InvalidSSHPubKey < StandardError
file = File.open("#{user.path}/.ssh/authorized_keys",mode) end
class DuplicateSSHPubKey < StandardError
end
def get_ssh_keyfile(project,mode,&block)
file = File.open("#{project.path}/.ssh/authorized_keys",mode)
return file unless block_given? return file unless block_given?
yield(file) yield(file)
ensure ensure
file.close file.close
end end
def get_ssh_pubkeys(user) def get_ssh_pubkeys(project)
extract_ssh_pubkeys("#{user.path}/.ssh/authorized_keys") extract_ssh_pubkeys("#{project.path}/.ssh/authorized_keys")
end end
def add_ssh_pubkey(user,key) # Deprecate
if not valid_pubkey? key then raise "Public key not valid" end def add_ssh_pubkey(project,key)
get_ssh_keyfile(user,"a") do |key_file| unless valid_pubkey? key
raise InvalidSSHPubKey, "Public key not valid"
end
get_ssh_keyfile(project,"a") do |key_file|
key_file << "#{key.to_s}\n" key_file << "#{key.to_s}\n"
end end
end end
def reset_pubkeys(user) def reset_pubkeys(project)
FileUtils.rm "#{user.path}/.ssh/authorized_keys" FileUtils.rm "#{project.path}/.ssh/authorized_keys"
FileUtils.touch "#{user.path}/.ssh/authorized_keys" FileUtils.touch "#{project.path}/.ssh/authorized_keys"
FileUtils.chown_R user.id, user.id, "#{user.path}/.ssh" FileUtils.chown_R project.id, project.id, "#{project.path}/.ssh"
end end
def remove_ssh_pubkey(user,key) def remove_ssh_pubkey(project,key)
keys = get_ssh_pubkeys(user) keys = get_ssh_pubkeys(project)
reset_pubkeys(user) reset_pubkeys(project)
keys.each{ |k| unless k == key then add_ssh_pubkey(user,k) end} keys.each{ |k| unless k == key then add_ssh_pubkey(project,k) end}
end end
def remove_ssh_pubkey_by_key def remove_ssh_pubkey_by_key
@ -149,23 +285,40 @@ end
########### ###########
# User DB # # Project DB #
########### ###########
def reload_users_from_passwd def reload_projects_from_passwd
$users = [] $projects = []
`cut -d: -f1 /etc/passwd`.split("\n"). `cut -d: -f1 /etc/passwd`.split("\n").
select{|u| u.start_with? POSIX_NAME_PREFIX}. select{|u| u.start_with? POSIX_NAME_PREFIX}.
map{|u| user_by_posix_name(u)}. map{|u| project_by_posix_name(u)}.
each{|u| add_user(u)} each{|u| add_project(u)}
$projects.each{|p| p.refresh}
end end
def reload_users_from_dir
`ls -1 #{USER_LOCATION}`.split("\n").
map{|u| User.new(u)}.
each{|u| add_user(u.id)}
end
def flush_all_to_disk
$users.each {|u| u.flush}
$projects.each {|p| p.flush}
end
def flush_projects_with_user(user)
$projects.select{|p| p.users.include? user}.each do |p|
p.flush
end
end
################################################ ################################################
reload_users_from_passwd reload_users_from_dir
reload_projects_from_passwd
#remove_project 5
#remove_user 5 #create_project 3
#create_user 3 #add_ssh_pubkey(get_project(3), "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7ZKN2fKcUQUaQqDjNCQQBSdqBVGX7lprNCJmceDBfybhbnuZJ8KvzJJIJIIbzqheW5BVCfkWJY6OgkpAumLWSRCS5n2+AnDHwQgpKDS93OeV+9/kattVtsVUBZaghymyJ2UfA0r918dkxcT9SZbNSl9raiDUUmj3JY8UM219BQP7BRqoZ6e/YZz9lO7ORy6yQT6fIMaVOaZcoDPr6oyNJfadm9POvS/Wl63onoRI9dzpHQG9RuHCcUhHJhkGtzY7GeRWc85WqA9Q4vYo0SK5Je9BG1cvAAVTfV+eYEJEiSDMwWj60roH0C3/ipmzxD/kWqg6YBJWL+XAyQkDnmbuD christoffermadsen@strawberry.thedevcave.net")
#add_ssh_pubkey(get_user(3), "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7ZKN2fKcUQUaQqDjNCQQBSdqBVGX7lprNCJmceDBfybhbnuZJ8KvzJJIJIIbzqheW5BVCfkWJY6OgkpAumLWSRCS5n2+AnDHwQgpKDS93OeV+9/kattVtsVUBZaghymyJ2UfA0r918dkxcT9SZbNSl9raiDUUmj3JY8UM219BQP7BRqoZ6e/YZz9lO7ORy6yQT6fIMaVOaZcoDPr6oyNJfadm9POvS/Wl63onoRI9dzpHQG9RuHCcUhHJhkGtzY7GeRWc85WqA9Q4vYo0SK5Je9BG1cvAAVTfV+eYEJEiSDMwWj60roH0C3/ipmzxD/kWqg6YBJWL+XAyQkDnmbuD christoffermadsen@strawberry.thedevcave.net")

View File

@ -1,49 +1,90 @@
require_relative 'collab' require_relative 'collab'
require 'tty-prompt' require 'tty-prompt'
require 'colorize'
$prompt = TTY::Prompt.new $prompt = TTY::Prompt.new
$login = "root"
def init def init
choices = %w(Keys Users Quit) puts "Logged in as " + $login.colorize(:cyan) + "\n"
choices = %w(Users Projects Quit)
case $prompt.select("What do you want to do?", choices) case $prompt.select("What do you want to do?", choices)
when "Projects"
projects
when "Users" when "Users"
users users
when "Keys"
keys
when "Quit" when "Quit"
exit exit
end end
end end
def keys def users
choices = $users choices = $users
user = $prompt.select("Pick a user", choices) user = $prompt.select("Pick a user", choices)
keys_user(user) keys_user(user)
end end
def keys_user(user) def keys_user(user)
choices = {'List keys' => :list ,'Add key' => :add, 'Remove key' => :remove, 'Reset authorized_keys' => :reset} choices = {'List keys' => :list ,'Add key' => :add, 'Remove key' => :remove}
case $prompt.select("What do you want to do for user #{user}?", choices) case $prompt.select("What do you want to do?", choices)
when :list when :list
get_ssh_pubkeys(user).each{|k| puts k.pretty} user.keys.each{|k| puts k.pretty}
keys_user user keys_user user
when :add when :add
key = $prompt.ask("Please enter a valid public SSH key", echo: false) key = $prompt.ask("Please enter a valid public SSH key", echo: false)
add_ssh_pubkey(user,key) begin
user.add_key_from_string(key)
rescue InvalidSSHPubKey => e
puts e.message.colorize(:red)
keys_user(user)
rescue DuplicateSSHPubKey => e
puts e.message.colorize(:red)
keys_user(user)
end
when :remove when :remove
keys = get_ssh_pubkeys(user)#.map{|k| puts k.pretty} choices = user.keys.map { |k| [k.pretty, k] }.to_h
key = $prompt.select("Select the key to delete", keys) key = $prompt.select("Select the key to remove", choices)
unless $prompt.no?("Are you sure you want to delete this key?") unless $prompt.no?("Are you sure you want to remove this key?")
remove_ssh_pubkey(user,key) user.remove_key(key)
end
when :reset
unless $prompt.no?("Are you sure you want to reset the keys for this user?")
unless $prompt.no?("Really sure?")
reset_pubkeys(user)
end end
end end
end
def projects
choices = $projects
project = $prompt.select("Pick a project", choices)
keys_project(project)
end
def keys_project(project)
choices = {'List users' => :list,
'Add user' => :add,
'Select users with access' => :select}
case $prompt.select("What do you want to do?", choices)
when :list
project.users.each {|u| puts u.id}
when :add
choices = $users
user = $prompt.select("Pick a user", choices)
project.add_user(user)
puts "Added user #{user} to #{project}".colorize(:green)
when :select
choices = $users
# Mark already added users as "default"
counter = 1
defaults = []
choices.each do |u|
if project.users.include? u then
defaults << counter
end end
counter += 1
end
users = $prompt.multi_select("Select users", choices, default: defaults)
project.users = users
project.flush
project.refresh
end
end end
while true while true