Merge pull request #987 from warpc/953-ssh_keys
[refs #953] Support git over ssh: access, add/remove keys.
This commit is contained in:
commit
6d449de465
|
@ -10,4 +10,8 @@ class Users::BaseController < ApplicationController
|
||||||
@user = User.opened.find_by_insensitive_uname! user_id
|
@user = User.opened.find_by_insensitive_uname! user_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_current_user
|
||||||
|
@user = current_user
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ class Users::SettingsController < Users::BaseController
|
||||||
if @user.update_without_password(params[:user])
|
if @user.update_without_password(params[:user])
|
||||||
update_avatar(@user, params)
|
update_avatar(@user, params)
|
||||||
if send_confirmation
|
if send_confirmation
|
||||||
@user.confirmed_at, @user.confirmation_sent_at = nil
|
@user.confirmed_at = @user.confirmation_sent_at = nil
|
||||||
@user.send_confirmation_instructions
|
@user.send_confirmation_instructions
|
||||||
end
|
end
|
||||||
flash[:notice] = t('flash.user.saved')
|
flash[:notice] = t('flash.user.saved')
|
||||||
|
@ -44,10 +44,4 @@ class Users::SettingsController < Users::BaseController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def set_current_user
|
|
||||||
@user = current_user
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- encoding : utf-8 -*-
|
||||||
|
class Users::SshKeysController < Users::BaseController
|
||||||
|
skip_before_filter :find_user
|
||||||
|
|
||||||
|
def index
|
||||||
|
@ssh_keys = current_user.ssh_keys
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@ssh_key = current_user.ssh_keys.new params[:ssh_key]
|
||||||
|
|
||||||
|
if @ssh_key.save
|
||||||
|
flash[:notice] = t 'flash.ssh_keys.saved'
|
||||||
|
else
|
||||||
|
flash[:error] = t 'flash.ssh_keys.save_error'
|
||||||
|
flash[:warning] = @ssh_key.errors.full_messages.join('. ') unless @ssh_key.errors.blank?
|
||||||
|
end
|
||||||
|
redirect_to ssh_keys_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@ssh_key = current_user.ssh_keys.find params[:id]
|
||||||
|
if @ssh_key.destroy
|
||||||
|
flash[:notice] = t 'flash.ssh_keys.destroyed'
|
||||||
|
else
|
||||||
|
flash[:error] = t 'flash.ssh_keys.destroy_error'
|
||||||
|
end
|
||||||
|
redirect_to ssh_keys_path
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,17 @@
|
||||||
|
# -*- encoding : utf-8 -*-
|
||||||
|
class Users::UsersController < Users::BaseController
|
||||||
|
skip_before_filter :authenticate_user!, :only => :allowed
|
||||||
|
|
||||||
|
def allowed
|
||||||
|
key = SshKey.find(params[:key_id])
|
||||||
|
owner_name, project_name = params[:project].split '/'
|
||||||
|
project = Project.find_by_owner_and_name!(owner_name, project_name ? project_name : '!')
|
||||||
|
action = case params[:action_type]
|
||||||
|
when 'git-upload-pack'
|
||||||
|
then :read
|
||||||
|
when 'git-receive-pack'
|
||||||
|
then :write
|
||||||
|
end
|
||||||
|
render :inline => (!key.user.access_locked? && Ability.new(key.user).can?(action, project)) ? 'true' : 'false'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,63 @@
|
||||||
|
# This class is based on
|
||||||
|
# https://github.com/gitlabhq/gitlabhq/blob/15c0e58a49d623a0f8747e1d7e74364324eeb79f/app/models/key.rb
|
||||||
|
|
||||||
|
class SshKey < ActiveRecord::Base
|
||||||
|
SHELL_KEY_COMMAND = "sudo ~#{APP_CONFIG['shell_user']}/gitlab-shell/bin/gitlab-keys"
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
attr_accessible :key, :name
|
||||||
|
|
||||||
|
before_validation lambda { self.key = key.strip if key.present? }
|
||||||
|
before_validation :set_fingerprint
|
||||||
|
|
||||||
|
validates :name, :length => {:maximum => 255}
|
||||||
|
validates :key, :length => {:maximum => 5000}, format: { :with => /ssh-.{3} / } # Public key?
|
||||||
|
validates :fingerprint, uniqueness: true, :presence => { :message => I18n.t('activerecord.errors.ssh_key.wrong_key') }
|
||||||
|
|
||||||
|
after_create :add_key
|
||||||
|
before_destroy :remove_key
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def set_fingerprint
|
||||||
|
return false unless key
|
||||||
|
|
||||||
|
file = Tempfile.new('key_file', "#{APP_CONFIG['root_path']}/tmp")
|
||||||
|
begin
|
||||||
|
file.puts key
|
||||||
|
file.rewind
|
||||||
|
fingerprint_output = `ssh-keygen -lf #{file.path} 2>&1` # Catch stderr.
|
||||||
|
exitstatus = $?.exitstatus
|
||||||
|
ensure
|
||||||
|
file.close
|
||||||
|
file.unlink # deletes the temp file
|
||||||
|
end
|
||||||
|
if exitstatus != 0
|
||||||
|
self.fingerprint = nil
|
||||||
|
else
|
||||||
|
self.fingerprint = fingerprint_output.split.try :[], 1
|
||||||
|
if name.blank?
|
||||||
|
s = fingerprint_output.split.try :[], 2
|
||||||
|
if File.exist? s # no identificator
|
||||||
|
start = key =~ /ssh-.{3} /
|
||||||
|
self.name = key[start..start+26] # taken first 26 characters
|
||||||
|
else
|
||||||
|
self.name = s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def key_id
|
||||||
|
"key-#{id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_key
|
||||||
|
system "#{SHELL_KEY_COMMAND} add-key #{key_id} \"#{key}\"" # Safety?
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_key
|
||||||
|
system "#{SHELL_KEY_COMMAND} rm-key #{key_id}"# \"#{key}\""
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -29,6 +29,7 @@ class User < Avatar
|
||||||
has_many :own_platforms, :as => :owner, :class_name => 'Platform', :dependent => :destroy
|
has_many :own_platforms, :as => :owner, :class_name => 'Platform', :dependent => :destroy
|
||||||
|
|
||||||
has_many :key_pairs
|
has_many :key_pairs
|
||||||
|
has_many :ssh_keys, :dependent => :destroy
|
||||||
|
|
||||||
validates :uname, :presence => true, :uniqueness => {:case_sensitive => false}, :format => {:with => /\A[a-z0-9_]+\z/}, :reserved_name => true
|
validates :uname, :presence => true, :uniqueness => {:case_sensitive => false}, :format => {:with => /\A[a-z0-9_]+\z/}, :reserved_name => true
|
||||||
validate { errors.add(:uname, :taken) if Group.by_uname(uname).present? }
|
validate { errors.add(:uname, :taken) if Group.by_uname(uname).present? }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
%aside
|
%aside
|
||||||
.admin-preferences
|
.admin-preferences
|
||||||
%ul
|
%ul
|
||||||
%li{:class => action_name == 'profile' ? 'active' : nil}= link_to t("layout.users.profile"), profile_settings_path
|
%li{:class => action_name == 'profile' ? 'active' : nil}= link_to t('layout.users.profile'), profile_settings_path
|
||||||
%li{:class => action_name == 'private' ? 'active' : nil}= link_to t("layout.users.user_private_settings"), private_settings_path
|
%li{:class => action_name == 'private' ? 'active' : nil}= link_to t('layout.users.user_private_settings'), private_settings_path
|
||||||
%li{:class => action_name == 'notifiers' ? 'active' : nil}= link_to t("layout.users.settings_notifier"), notifiers_settings_path
|
%li{:class => action_name == 'notifiers' ? 'active' : nil}= link_to t('layout.users.settings_notifier'), notifiers_settings_path
|
||||||
|
%li{:class => controller_name == 'ssh_keys' ? 'active' : nil}= link_to t('ssh_keys'), ssh_keys_path
|
|
@ -0,0 +1,26 @@
|
||||||
|
= form_tag ssh_keys_path, :id => 'ssh_keys_form' do
|
||||||
|
= hidden_field_tag "_method", "post"
|
||||||
|
%table.tablesorter{:cellpadding => "0", :cellspacing => "0"}
|
||||||
|
%thead
|
||||||
|
%tr
|
||||||
|
%th= title t('ssh_keys')
|
||||||
|
%th{:colspan => "2"}= t 'layout.delete'
|
||||||
|
%tbody
|
||||||
|
- @ssh_keys.each do |key|
|
||||||
|
%tr
|
||||||
|
%td="#{key.name} (#{key.fingerprint})"
|
||||||
|
%td= link_to image_tag('x.png'), ssh_key_path(key), :method => :delete, :confirm => t('layout.confirm')
|
||||||
|
.both
|
||||||
|
|
||||||
|
%h3.fix.bpadding10= t 'add_key'
|
||||||
|
|
||||||
|
= form_for SshKey.new, :url => ssh_keys_path, :html => {:class => :form} do |f|
|
||||||
|
.leftlist= f.label :name, t('activerecord.attributes.ssh_key.name')
|
||||||
|
.rightlist= f.text_field :name
|
||||||
|
.both
|
||||||
|
.leftlist= f.label :key, t('activerecord.attributes.ssh_key.key')
|
||||||
|
.rightlist= f.text_area :key
|
||||||
|
%br
|
||||||
|
= f.submit t('layout.add')#, :class => 'button'
|
||||||
|
|
||||||
|
- content_for :sidebar, render('sidebar')
|
|
@ -0,0 +1,24 @@
|
||||||
|
en:
|
||||||
|
ssh_keys: SSH Keys
|
||||||
|
add_key: Add key
|
||||||
|
activerecord:
|
||||||
|
errors:
|
||||||
|
ssh_key:
|
||||||
|
wrong_key: '^Wrong public key'
|
||||||
|
models:
|
||||||
|
ssh_key: SSH Key
|
||||||
|
attributes:
|
||||||
|
ssh_key:
|
||||||
|
id: Id
|
||||||
|
name: Name
|
||||||
|
fingerprint: Key
|
||||||
|
created_at: Created
|
||||||
|
updated_at: Updated
|
||||||
|
user_id: User
|
||||||
|
key: Key
|
||||||
|
flash:
|
||||||
|
ssh_keys:
|
||||||
|
saved: SSH key successfully saved
|
||||||
|
save_error: SSH key save error
|
||||||
|
destroyed: SSH key succefully destroyed
|
||||||
|
destroy_error: SSH key destroy error
|
|
@ -0,0 +1,24 @@
|
||||||
|
ru:
|
||||||
|
ssh_keys: SSH ключи
|
||||||
|
add_key: Добавить ключ
|
||||||
|
activerecord:
|
||||||
|
errors:
|
||||||
|
ssh_key:
|
||||||
|
wrong_key: '^Неправильный публичный ключ'
|
||||||
|
models:
|
||||||
|
ssh_key: SSH ключ
|
||||||
|
attributes:
|
||||||
|
ssh_key:
|
||||||
|
id: Id
|
||||||
|
name: Имя
|
||||||
|
fingerprint: Ключ
|
||||||
|
created_at: Создано
|
||||||
|
updated_at: Обновлено
|
||||||
|
user_id: Пользователь
|
||||||
|
key: Ключ
|
||||||
|
flash:
|
||||||
|
ssh_keys:
|
||||||
|
saved: SSH ключ успешно сохранен
|
||||||
|
save_error: Ошибка создания SSH ключа
|
||||||
|
destroyed: SSH ключ успешно удален
|
||||||
|
destroy_error: Ошибка удаления SSH ключа
|
|
@ -81,6 +81,7 @@ Rosa::Application.routes.draw do
|
||||||
resources :product_build_lists, :only => [:index, :show, :destroy, :create] do
|
resources :product_build_lists, :only => [:index, :show, :destroy, :create] do
|
||||||
put :cancel, :on => :member
|
put :cancel, :on => :member
|
||||||
end
|
end
|
||||||
|
resources :ssh_keys, :only => [:index, :create, :destroy]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -194,8 +195,9 @@ Rosa::Application.routes.draw do
|
||||||
put :notifiers
|
put :notifiers
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :register_requests, :only => [:new, :create], :format => /ru|en/ #view support only two languages
|
resources :register_requests, :only => [:new, :create], :format => /ru|en/ #view support only two languages
|
||||||
|
resources :ssh_keys, :only => [:index, :create, :destroy]
|
||||||
|
get '/allowed' => 'users#allowed'
|
||||||
end
|
end
|
||||||
|
|
||||||
scope :module => 'groups' do
|
scope :module => 'groups' do
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
class CreateSshKeys < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :ssh_keys do |t|
|
||||||
|
t.string :name
|
||||||
|
t.text :key, :null => false
|
||||||
|
t.string :fingerprint, :null => false
|
||||||
|
t.integer :user_id, :null => false
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :ssh_keys, :fingerprint, :unique => true
|
||||||
|
add_index :ssh_keys, :user_id
|
||||||
|
end
|
||||||
|
end
|
14
db/schema.rb
14
db/schema.rb
|
@ -11,7 +11,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended to check this file into your version control system.
|
# It's strongly recommended to check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(:version => 20130222112415) do
|
ActiveRecord::Schema.define(:version => 20130227102900) do
|
||||||
|
|
||||||
create_table "activity_feeds", :force => true do |t|
|
create_table "activity_feeds", :force => true do |t|
|
||||||
t.integer "user_id", :null => false
|
t.integer "user_id", :null => false
|
||||||
|
@ -453,6 +453,18 @@ ActiveRecord::Schema.define(:version => 20130222112415) do
|
||||||
t.boolean "new_associated_build", :default => true
|
t.boolean "new_associated_build", :default => true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "ssh_keys", :force => true do |t|
|
||||||
|
t.string "name"
|
||||||
|
t.text "key", :null => false
|
||||||
|
t.string "fingerprint", :null => false
|
||||||
|
t.integer "user_id", :null => false
|
||||||
|
t.datetime "created_at", :null => false
|
||||||
|
t.datetime "updated_at", :null => false
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index "ssh_keys", ["fingerprint"], :name => "index_ssh_keys_on_fingerprint", :unique => true
|
||||||
|
add_index "ssh_keys", ["user_id"], :name => "index_ssh_keys_on_user_id"
|
||||||
|
|
||||||
create_table "subscribes", :force => true do |t|
|
create_table "subscribes", :force => true do |t|
|
||||||
t.string "subscribeable_type"
|
t.string "subscribeable_type"
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe SshKey do
|
||||||
|
pending "add some examples to (or delete) #{__FILE__}"
|
||||||
|
end
|
Loading…
Reference in New Issue