Skip to content

Commit 4a612cc

Browse files
committed
Merge branch 'hotfix/option_lists'
2 parents ebdf5c2 + 0d326f8 commit 4a612cc

File tree

6 files changed

+34
-43
lines changed

6 files changed

+34
-43
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# CHANGELOG for ssh
2+
## 0.10.12
3+
* Updated authorized_keys to allow for commas, quotes, and spaces inside the options.
4+
* fixed a bug that was adding a single space to the end of entries.
5+
26
## 0.10.10
37
* Fixed default key type for authorized keys
48
* Added some basic validation to ssh keys in authorized_keys provider

libraries/ssh_config_helpers.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def default?(path)
1212
File.expand_path(path).eql? File.expand_path(node['ssh']['config_path'])
1313
end
1414

15-
def parse_file(path)
15+
def parse_file(path) # rubocop:disable Style/CyclomaticComplexity
1616
entries = {}
1717
return entries unless ::File.exist?(path)
1818
name = nil

metadata.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
license 'Apache 2.0'
55
description 'LWRPs for managing SSH known_hosts and config files'
66
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
7-
version '0.10.10'
7+
version '0.10.12'
88

99
supports 'ubuntu'
1010
supports 'rhel'

providers/authorized_keys.rb

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,14 @@ def update_file
5252

5353
def format_lines
5454
@lines.collect do |line|
55-
joined = ''
56-
if line[:options]
57-
joined << line[:options].collect do |key, value|
58-
if value.nil? || value.empty?
59-
key.to_s
60-
elsif value.include?(' ') && !value.include?('"')
61-
"#{key}=\"#{value}\""
62-
else
63-
"#{key}=#{value}"
64-
end
55+
if line[:options].nil?
56+
joined = ''
57+
else
58+
joined = line[:options].collect do |key, value|
59+
(value.nil? || value.empty?) ? key.to_s : "#{key}=\"#{value}\""
6560
end.join(',')
66-
joined << ' '
6761
end
62+
joined << ' ' unless joined.empty?
6863
joined << line[:type] << ' ' << line[:key]
6964
line[:comment] && (joined << ' ' << line[:comment])
7065
joined
@@ -92,45 +87,31 @@ def load_current_resource
9287
def parse(current)
9388
current.reduce([]) do |memo, row|
9489
line = {}
95-
fields = extract_fields(row)
90+
# split on whitespace that is not inside of quotes
91+
fields = row.split(/(?!\B"[^"]*)\s(?![^"]*"\B)/)
9692
line[:options] = parse_options(fields.shift) unless types.include? fields[0]
9793
validate_type(fields[0], @path)
9894
line[:type] = fields[0]
9995
line[:key] = fields[1]
100-
line[:comment] = fields[2..-1].join(' ') if row[2]
96+
line[:comment] = fields[2..-1].join(' ') if fields[2]
10197
memo << line
10298
end
10399
end
104100

105-
def extract_fields(row)
106-
return :comment => row if row.empty? || row[0] == '#'
107-
108-
quotes = 0
109-
fields = []
110-
row.scan(/\S+/) do |match|
111-
if quotes.even? || quotes == 0
112-
fields << match
113-
else
114-
fields[-1] << " #{match}"
115-
end
116-
quotes += match.count('"')
117-
end
118-
fields
119-
end
120-
121101
def parse_options(text)
122102
options = {}
123-
split = text.split(',')
103+
# split on commas that are not inside quotes
104+
split = text.split(/(?!\B"[^"]*),(?![^"]*"\B)/)
124105
split.each do |group|
125106
validate_options(group, @path)
126107
group = group.split('=')
127-
options[group[0]] = group[1]
108+
options[group[0]] = group[1].nil? ? nil : group[1].gsub(/\A"|"\Z/, '')
128109
end
129110
options
130111
end
131112

132113
def types
133-
%w(ssh-rsa ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 ssh-dss)
114+
@types ||= %w(ssh-rsa ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 ssh-dss)
134115
end
135116

136117
def validate_type(type, source)
@@ -142,16 +123,22 @@ def validate_options(option, source)
142123
if option.is_a? Hash
143124
option.each { |o| validate_options o, source }
144125
return
145-
elsif option.is_a? String
146-
option = option.split('=')
147126
end
148-
149-
binary_options = %w(cert-authority no-agent-forwarding no-port-forwarding no-pty no-user-rc no-X11-forwarding)
150-
other_options = %w(command environment from permitopen principals tunnel)
127+
option = option.split('=') if option.is_a? String
151128

152129
if option[1].nil? || option[1].empty?
153-
fail "Invalid Option in #{source}: #{option}" unless binary_options.include? option[0].to_s
130+
validate_binary_option option[0]
154131
else
155-
fail "Invalid Option in #{source}: #{option}" unless other_options.include? option[0].to_s
132+
validate_valued_option option[0]
156133
end
157134
end
135+
136+
def validate_binary_option(option)
137+
@binary_options ||= %w(cert-authority no-agent-forwarding no-port-forwarding no-pty no-user-rc no-X11-forwarding)
138+
fail "Invalid Option in #{source}: #{option}" unless @binary_options.include? option.to_s
139+
end
140+
141+
def validate_valued_option(option)
142+
@other_options ||= %w(command environment from permitopen principals tunnel)
143+
fail "Invalid Option in #{source}: #{option}" unless @other_options.include? option.to_s
144+
end

test/cookbooks/ssh_test/recipes/authorized_keys.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
ssh_authorized_keys 'first' do
99
user 'test-user'
1010
type 'ssh-rsa'
11-
options 'no-agent-forwarding' => nil, 'no-pty' => nil, :command => 'ls /root'
11+
options 'no-agent-forwarding' => nil, 'no-pty' => nil, :command => 'ls /root', :from => '10.10.1.2,10.4.2.1'
1212
comment 'I left a comment'
1313
key 'AAAAB3NzaC1yc2EAAAADAQABAAACAQCeCRfSzGWGNsisAZpuFIS0GmHJfgms3g8okwL9h9AvoQPwgyhyri/Wlcz3eyZMvuR4/vwh9FgWpRwLxot7QSGry58GYR9tHkDT9o3m0Hlx28E+K2gbNK5SyFROx5lSfOZkCSyPjBEBmTAadpVYZBJj789oeAT3dDvsxMAqokCIjV5Ey9xBIWKapbsDiTdOHmtDhlrFZfBc75I6tTnW9WGVG6gCQtzyC/tJ2DmWJhtEz9UjxhAOUzazHM2CJ2IlF3SHm+nz7xjTWmGVRzpiellmN+2StmibuFkoZP8L//9v06gDKqp2lNSsi2SJujAsEiKAGtQu6Aa4hdxRFt87m6WSN9lusAazZvnX5s93lAmUAG+wWPnAsujkRSDwv2Ju+GdQFW3ncML7aXFOhIMViG6B98X2h9f3W6XdwQseh10QfvFZ3fAmcAvWvlEM0pGXdfKeFY0LfD7UFxTvzEfqPKnbV6SKlAIMAQ3CX+Q1sZ4nfqopZVJwHDHSL/KQeVKePdyFbZcFVE4L/zruS/fLDqiDMq9yZqMu3WkP5bp4crzguaVwHmrTG4k1XOH5jkMrUj7javMLQHWu56bj0heynhXw7gzXnC/DSgY58/1BPEy7ejsGr0RX2LBRulh84UkV0cjLs8MZyBrhS4dYwyBmtcYlh+OVVVwFimg4ayR7UlkVMw==' # rubocop:disable all
1414
end

test/integration/authorized_keys/serverspec/authorized_keys_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
describe user('test-user') do
44
it { should exist }
55
# rubocop:disable all
6-
it { should have_authorized_key 'no-agent-forwarding,no-pty,command="ls /root" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCeCRfSzGWGNsisAZpuFIS0GmHJfgms3g8okwL9h9AvoQPwgyhyri/Wlcz3eyZMvuR4/vwh9FgWpRwLxot7QSGry58GYR9tHkDT9o3m0Hlx28E+K2gbNK5SyFROx5lSfOZkCSyPjBEBmTAadpVYZBJj789oeAT3dDvsxMAqokCIjV5Ey9xBIWKapbsDiTdOHmtDhlrFZfBc75I6tTnW9WGVG6gCQtzyC/tJ2DmWJhtEz9UjxhAOUzazHM2CJ2IlF3SHm+nz7xjTWmGVRzpiellmN+2StmibuFkoZP8L//9v06gDKqp2lNSsi2SJujAsEiKAGtQu6Aa4hdxRFt87m6WSN9lusAazZvnX5s93lAmUAG+wWPnAsujkRSDwv2Ju+GdQFW3ncML7aXFOhIMViG6B98X2h9f3W6XdwQseh10QfvFZ3fAmcAvWvlEM0pGXdfKeFY0LfD7UFxTvzEfqPKnbV6SKlAIMAQ3CX+Q1sZ4nfqopZVJwHDHSL/KQeVKePdyFbZcFVE4L/zruS/fLDqiDMq9yZqMu3WkP5bp4crzguaVwHmrTG4k1XOH5jkMrUj7javMLQHWu56bj0heynhXw7gzXnC/DSgY58/1BPEy7ejsGr0RX2LBRulh84UkV0cjLs8MZyBrhS4dYwyBmtcYlh+OVVVwFimg4ayR7UlkVMw== I left a comment' }
6+
it { should have_authorized_key 'no-agent-forwarding,no-pty,command="ls /root",from="10.10.1.2,10.4.2.1" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCeCRfSzGWGNsisAZpuFIS0GmHJfgms3g8okwL9h9AvoQPwgyhyri/Wlcz3eyZMvuR4/vwh9FgWpRwLxot7QSGry58GYR9tHkDT9o3m0Hlx28E+K2gbNK5SyFROx5lSfOZkCSyPjBEBmTAadpVYZBJj789oeAT3dDvsxMAqokCIjV5Ey9xBIWKapbsDiTdOHmtDhlrFZfBc75I6tTnW9WGVG6gCQtzyC/tJ2DmWJhtEz9UjxhAOUzazHM2CJ2IlF3SHm+nz7xjTWmGVRzpiellmN+2StmibuFkoZP8L//9v06gDKqp2lNSsi2SJujAsEiKAGtQu6Aa4hdxRFt87m6WSN9lusAazZvnX5s93lAmUAG+wWPnAsujkRSDwv2Ju+GdQFW3ncML7aXFOhIMViG6B98X2h9f3W6XdwQseh10QfvFZ3fAmcAvWvlEM0pGXdfKeFY0LfD7UFxTvzEfqPKnbV6SKlAIMAQ3CX+Q1sZ4nfqopZVJwHDHSL/KQeVKePdyFbZcFVE4L/zruS/fLDqiDMq9yZqMu3WkP5bp4crzguaVwHmrTG4k1XOH5jkMrUj7javMLQHWu56bj0heynhXw7gzXnC/DSgY58/1BPEy7ejsGr0RX2LBRulh84UkV0cjLs8MZyBrhS4dYwyBmtcYlh+OVVVwFimg4ayR7UlkVMw== I left a comment' }
77
it { should have_authorized_key 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDzB76TOkrDRaevO3I1qzosRXliAuYdjcMejHwwL5v2hRqTrBePlMW6nqz8/JgLTzHn/KxzkrKLb0GlpPDrJ1KByWGYZsfydUfv7n1+5ogoA7UW7dUc4DoQtGPuy4Xe0enr88VfALlT11aWKAw8K/I39zWiPvJNX3Mks0f3/3smjLaQEnDWWWiawp5YgzJmyzsqZFZrrFCUgv7AP1EjZofWUcRvYEEjMhKsK+G2H2VCN7MpH0cJ97E0bKNQjHBrwGyMLQZUOndGakCuOuTLpikOXSpUUz5LwqCiRIj6iUtWevwk+AYLZwxPYQpCxFceVFDhPDaJQ85vweSq+HEg7hRujq9jO7vM9LIgjqg7fwQ2Ql6zO9NjXv2UalzBi0H2AbKT1V/PpNufPgolyb/dK7Jqpqu7Ytggctl2fGyLe8yVaC9gD+/BBeCl82LZI142kdXmf4WYcZgOgcRgGJrbSZjeMzX6zZpiD1AG3T7xyEn2twmC/TqptmQEAG2BBzGum+S6pU0rnOt2UJngRnviK2vptAWtRlSlsopySOXv+VbqUXhRjHRT/+2nq5Q4BWcjsZaaoo1uWh2glATRnGK995A1zJ3gWrBA+IaC6stKzjSG0KPwLjzHfPKbWjDX76D/qdo0qBN5hBiHDRfmiNqpNYS9NHACDZNVPBS5N1d5BUkyKw==' }
88
it { should have_authorized_key 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC5ulpHLJfGxi/sMjqOSWVKbW4yeNzWF2VAZYM/QYqH/9LUuEwBAgxFB96dxDn+AY9UxM2lmiYajsHHF6qqnRPuK2SVHKZ8SSR/yEWL6AtkeX5z0QgzCqXLAgMUbzRy6TRb/SM8tqQ+ybVGiVaSK+UGT5saFY3WLmhq2wJva5TzRhxtL+vnQMNUDaFylTZDqw9Y0GFHkqEvcU2L0bcLlhEr0NVUFwz0M2yW0mx+Y8wwwUxxFhbTsjxV2c6Fa/bmqSN1I6z5K0hYQRyPlNpjEKlKT57TTHrlSCsf+Id2DOC1EbEVcCtIT6tIlahys9qayYM/36nbD0ru0NgDY2NliWlTk+F7L9gBncPdCib9euz3JqyftnNGT9OzpK8A9U4nKDVdaQKVN6Eat4ViEmwBnO8CeaT2XDKVLOJcRnaZu6pYFvbZcyBC0DPThksvl1pTlnBr7aypW/15lkXY1vNPa6mvyfFjO5SHDCBvMRSaCB4NqGreaVaomvnvMv+wwn+PCNmvTSv2PfZzjWHbp5wip7x9bNmF8s1w2knOR3appjEDnJm6YR4KuXMRxr4zsAxVvC5uOhs4JVh91Ujtec/aVKXBQuggT8tX00M6rSamMbvNkmlA6WIVrwmYvCRIo8GqKKxU8lJJcdt/y/qa4jIdd5Z6mWQmhy8Jw8La7J2GWvX3Ow==' }
99
# rubocop:enable all

0 commit comments

Comments
 (0)