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

269
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 add_key(key)
@keys << key
end
def get_user(id) def add_user(user)
$id_map[id] @users << user
end user.keys.each do |key|
p key
add_key(key)
end
flush
refresh
end
def add_user(user) def remove_user(user)
$users << user @user.delete(user)
$id_map[user.id] = user flush
end refresh
end
def create_user(id) def refresh
if not system("useradd -m #{POSIX_NAME_PREFIX}#{id}") then @users = File.open("#{@path}/.ssh/users","r") do |f|
raise "User creation failed" 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 end
user = User.new end
user.id = id
user.path = "/home/#{POSIX_NAME_PREFIX}#{id}"
user.posixname = "#{POSIX_NAME_PREFIX}#{id}"
$users << user
$id_map[id] = user
FileUtils.mkdir "#{user.path}/.ssh" def get_project(id)
FileUtils.touch "#{user.path}/.ssh/authorized_keys" $project_id_map[id]
FileUtils.chown_R user.id, user.id, "#{user.path}/.ssh" end
def add_project(project)
$projects << project
$project_id_map[project.id] = project
end
def create_project(id)
if not system("useradd -m #{POSIX_NAME_PREFIX}#{id}") then
raise "Project creation failed"
end
user 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 end
def remove_user(user) def remove_project(project)
system("userdel -r #{user.posixname}") system("userdel -r #{project.posixname}")
$users.remove(user) $projects.remove(project)
$id_map[id] = nil $project_id_map[id] = nil
end end
def user_by_posix_name(posix_name) def project_by_posix_name(posix_name)
user = User.new project = Project.new
user.id = posix_name[POSIX_NAME_PREFIX.length..-1] project.id = posix_name[POSIX_NAME_PREFIX.length..-1]
user.path = "/home/#{posix_name}" project.path = "/home/#{posix_name}"
user.posixname = posix_name project.posixname = posix_name
user 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,51 +1,92 @@
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
when :remove user.add_key_from_string(key)
keys = get_ssh_pubkeys(user)#.map{|k| puts k.pretty} rescue InvalidSSHPubKey => e
key = $prompt.select("Select the key to delete", keys) puts e.message.colorize(:red)
unless $prompt.no?("Are you sure you want to delete this key?") keys_user(user)
remove_ssh_pubkey(user,key) rescue DuplicateSSHPubKey => e
puts e.message.colorize(:red)
keys_user(user)
end end
when :reset when :remove
unless $prompt.no?("Are you sure you want to reset the keys for this user?") choices = user.keys.map { |k| [k.pretty, k] }.to_h
unless $prompt.no?("Really sure?") key = $prompt.select("Select the key to remove", choices)
reset_pubkeys(user) unless $prompt.no?("Are you sure you want to remove this key?")
end user.remove_key(key)
end 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
counter += 1
end
users = $prompt.multi_select("Select users", choices, default: defaults)
project.users = users
project.flush
project.refresh
end
end
while true while true
init init
end end