Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,24 @@ $ gh-auth add --users=chrishunt --command="tmux attach"
Adding 2 key(s) to '/Users/chris/.ssh/authorized_keys'
```

Allowing someone to SSH to your machine can be a scary thing. Restricting them
to a single command goes a little way to help secure things. If you want to
keep them from forwarding ports, you can use the `--ssh-options` option to
add that to their key entry.

```bash
$ gh-auth add --users=chrishunt --ssh-options=no-port-forwarding
Adding 2 key(s) to '/Users/chris/.ssh/authorized_keys'
```

As a convenience, you may also use the `--no-forwarding` option to prevent all
forwarding (i.e. `no-port-forwarding,no-X11-forwarding,no-agent-forwarding`).

```bash
$ gh-auth add --users=chrishunt --no-forwarding
Adding 2 key(s) to '/Users/chris/.ssh/authorized_keys'
```

That was easy! When we're done working, you can revoke my access with:

```bash
Expand Down
16 changes: 15 additions & 1 deletion lib/github/auth/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class CLI < Thor

option :users, type: :array, required: true
option :command, type: :string
option :ssh_options, type: :array
option :no_forwarding, type: :boolean
desc 'add', 'Add GitHub users to authorized keys'
long_desc <<-LONGDESC
`gh-auth add` is used to add one or more GitHub user's public SSH keys
Expand All @@ -22,11 +24,23 @@ class CLI < Thor
the `--command` option.

> $ gh-auth add --users=chrishunt --command="tmux attach"

You may also provide options for the key entry, such as preventing
port forwarding. To do this, include the `--ssh-options` option.

> $ gh-auth add --users=chrishunt --ssh-options=no-port-forwarding

To disable all forwarding for their connection, use the
`--no-forwarding` option.

> $ gh-auth add --users=chrishunt --no-forwarding
LONGDESC
def add
on_keys_file :write!,
"Adding #{keys.count} key(s) to '#{keys_file.path}'",
{ command: options[:command] }
{ command: options[:command],
ssh_options: options[:ssh_options],
no_forwarding: options[:no_forwarding] }
end

option :users, type: :array, required: true
Expand Down
31 changes: 28 additions & 3 deletions lib/github/auth/keys_file.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
module Github::Auth
# Write and delete keys from the authorized_keys file
class KeysFile
attr_reader :path, :command
NO_FORWARDING_OPTIONS = %w(
no-port-forwarding
no-X11-forwarding
no-agent-forwarding
)

attr_reader :path, :command, :ssh_options

PermissionDeniedError = Class.new StandardError
FileDoesNotExistError = Class.new StandardError
Expand All @@ -10,7 +16,12 @@ class KeysFile

def initialize(options = {})
@path = File.expand_path(options[:path] || DEFAULT_PATH)
@command = options[:command]
@command = options[:command]
@ssh_options = Array(options[:ssh_options])

if options[:no_forwarding]
@ssh_options |= NO_FORWARDING_OPTIONS
end
end

def write!(keys)
Expand All @@ -20,7 +31,7 @@ def write!(keys)
unless keys_file_content.empty? || keys_file_content.end_with?("\n")
keys_file.write "\n"
end
keys_file.write "#{"command=\"#{command}\" " if command}#{key}\n"
keys_file.write key_line(key)
end
end
end
Expand Down Expand Up @@ -69,5 +80,19 @@ def keys_file_content_without(keys)
content << "\n" unless content.empty? || content.end_with?("\n")
end
end

def key_line_prefixes
prefixes = []
prefixes << ssh_options.join(',') unless ssh_options.empty?
prefixes << %Q{command="#{command}"} if command
prefixes.join(',')
end

def key_line(key)
line = []
line << key_line_prefixes unless key_line_prefixes.empty?
line << "#{key}\n"
line.join(' ')
end
end
end
25 changes: 25 additions & 0 deletions spec/acceptance/github/auth/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,31 @@ def cli(args = [])
expect(keys_file.read.strip).to be_empty
end

it 'supports ssh options' do
cli %w(add --users=chrishunt
--ssh-options=no-port-forwarding no-agent-forwarding)

expect(keys_file.read).to include 'no-port-forwarding,no-agent-forwarding'

keys_file.rewind
cli %w(remove --users=chrishunt)

expect(keys_file.read.strip).to be_empty
end

it 'supports no-forwarding option' do
comma_separated_no_forwarding_options =
Github::Auth::KeysFile::NO_FORWARDING_OPTIONS.join(',')

cli %w(add --users=chrishunt --no-forwarding)

expect(keys_file.read).to include comma_separated_no_forwarding_options

keys_file.rewind
cli %w(remove --users=chrishunt)

end

it 'prints version information' do
output = capture_stdout do
cli %w(version)
Expand Down
29 changes: 29 additions & 0 deletions spec/unit/github/auth/keys_file_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,35 @@
end
end

context 'with ssh options' do
let(:options) {{ path: path, ssh_options: ['no-way', 'no-how'] }}
let(:keys) {[ Github::Auth::Key.new('chris', 'abc123') ]}

it_should_behave_like 'a successful key addition'

it 'prefixes the key with the comma-separated ssh options' do
subject.write! keys

expect(keys_file.read).to include 'no-way,no-how'
end
end

context 'with forwarding disabled' do
let(:options) {{ path: path, no_forwarding: true }}
let(:keys) {[ Github::Auth::Key.new('chris', 'abc123') ]}

it_should_behave_like 'a successful key addition'

it 'prefixes the key with all the options to disable forwarding' do
comma_separated_no_forwarding_options =
Github::Auth::KeysFile::NO_FORWARDING_OPTIONS.join(',')

subject.write! keys

expect(keys_file.read).to include comma_separated_no_forwarding_options
end
end

context 'with existing keys in the keys file' do
let(:existing_keys) { %w(abc123 def456 ghi789) }
let(:keys) {[ Github::Auth::Key.new('chris', 'jkl012') ]}
Expand Down