autosign 0.1.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.rubocop.yml +12 -0
- data/.rubocop_todo.yml +659 -0
- data/.travis.yml +4 -5
- data/CHANGELOG.md +56 -0
- data/Gemfile.lock +107 -89
- data/LICENSE +201 -0
- data/README.md +37 -0
- data/Rakefile +22 -22
- data/autosign.gemspec +24 -20
- data/bin/autosign +23 -15
- data/bin/autosign-validator +14 -6
- data/lib/autosign.rb +1 -1
- data/lib/autosign/config.rb +71 -56
- data/lib/autosign/decoder.rb +7 -3
- data/lib/autosign/journal.rb +2 -2
- data/lib/autosign/token.rb +7 -7
- data/lib/autosign/validator.rb +34 -197
- data/lib/autosign/{validators → validator}/jwt.rb +41 -42
- data/lib/autosign/{validators → validator}/multiplexer.rb +24 -32
- data/lib/autosign/{validators → validator}/passwordlist.rb +16 -17
- data/lib/autosign/validator/validator_base.rb +168 -0
- data/lib/autosign/version.rb +1 -1
- metadata +78 -74
- data/features/autosign.feature +0 -93
- data/features/step_definitions/autosign_steps.rb +0 -44
- data/features/support/env.rb +0 -17
- data/features/validate.feature +0 -22
- data/fixtures/i-7672fe81.pem +0 -34
- data/spec/spec_helper.rb +0 -102
- data/spec/specs/config_spec.rb +0 -20
- data/spec/specs/decoder_spec.rb +0 -16
- data/spec/specs/journal_spec.rb +0 -41
- data/spec/specs/token_spec.rb +0 -102
- data/spec/specs/validators/jwt_spec.rb +0 -69
- data/spec/specs/validators/passwordlist_spec.rb +0 -51
data/README.md
CHANGED
@@ -81,6 +81,42 @@ password_list:
|
|
81
81
|
|
82
82
|
Note that this is a relatively insecure way to do certificate autosigning. Using one-time tokens via the `autosign generate` command is more secure. This functionality is provided to grandfather in existing use cases to ease the transition.
|
83
83
|
|
84
|
+
## Validation order
|
85
|
+
By default the validation runs the following validators in order:
|
86
|
+
|
87
|
+
1. jwt_token
|
88
|
+
2. password_list
|
89
|
+
3. multiplexer
|
90
|
+
|
91
|
+
The first validator to succeed wins and short circuits the validaiton process.
|
92
|
+
|
93
|
+
You can completely customize the list and how they are ordered via the configuration file. Or even remove some entirely.
|
94
|
+
|
95
|
+
```
|
96
|
+
---
|
97
|
+
general:
|
98
|
+
loglevel: debug
|
99
|
+
logfile: "/var/log/autosign.log"
|
100
|
+
validation_order:
|
101
|
+
- jwt_token
|
102
|
+
- multiplexer
|
103
|
+
- password_list
|
104
|
+
jwt_token:
|
105
|
+
secret: J7/WjmkC/CJp2K0/8+sktzSgCqQ=
|
106
|
+
validity: '7200'
|
107
|
+
journalfile: "/root/var/autosign/autosign.journal"
|
108
|
+
```
|
109
|
+
|
110
|
+
The validation_order config is an ordered array and since the validators will only match the first validation
|
111
|
+
to succeed the validation script should occur as fast as you want.
|
112
|
+
|
113
|
+
Additionally, if you omit any validator that validator will not be used during the validation process. This might
|
114
|
+
be important if you wanted to only use special validators or remove unwanted validator execution.
|
115
|
+
|
116
|
+
Please note, the name of the validator which is speficed by the `NAME` constant in the validator code must match
|
117
|
+
the list you specify otherwise it will not be part of the validation process.
|
118
|
+
|
119
|
+
**NOTE** To use this feature you must have deep_merge 1.2.1+ installed which is now a requirement of this gem.
|
84
120
|
|
85
121
|
### Troubleshooting
|
86
122
|
If you're having problems, try the following:
|
@@ -90,6 +126,7 @@ If you're having problems, try the following:
|
|
90
126
|
- you can manually trigger the autosigning script with something like `cat the_csr.csr | autosign-validator certname.example.com`
|
91
127
|
- If you run the puppet master foregrounded, you'll see quite a bit of autosign script output if autosign loglevel is set to debug.
|
92
128
|
|
129
|
+
Starting with the 1.0.0 release the autosign gem requires ruby 2.4. If you can't upgrade just yet you can continue to use the older 0.1.4 release.
|
93
130
|
|
94
131
|
### Further Reading
|
95
132
|
|
data/Rakefile
CHANGED
@@ -1,32 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
1
4
|
require 'rubygems'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
rescue LoadError
|
11
|
-
end
|
5
|
+
require 'bundler'
|
6
|
+
require 'bundler/gem_tasks'
|
7
|
+
require 'rake/testtask'
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
require 'cucumber'
|
10
|
+
require 'cucumber/rake/task'
|
11
|
+
require 'rdoc/task'
|
12
12
|
require 'rake/clean'
|
13
|
-
require 'rubygems/package_task'
|
14
|
-
Rake::RDocTask.new do |rd|
|
15
|
-
rd.main = "README.rdoc"
|
16
|
-
rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
|
17
|
-
rd.title = 'Your application title'
|
18
|
-
end
|
19
13
|
|
20
|
-
spec
|
14
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
15
|
+
t.rspec_opts = '--format documentation'
|
16
|
+
end
|
21
17
|
|
22
|
-
|
18
|
+
Rake::RDocTask.new do |rd|
|
19
|
+
rd.main = 'README.rdoc'
|
20
|
+
rd.rdoc_files.include('README.rdoc', 'lib/**/*.rb', 'bin/**/*')
|
21
|
+
rd.title = 'Autosign'
|
23
22
|
end
|
24
|
-
|
23
|
+
|
24
|
+
CUKE_RESULTS = 'results.html'.freeze
|
25
25
|
CLEAN << CUKE_RESULTS
|
26
26
|
desc 'Run features'
|
27
27
|
|
28
28
|
Cucumber::Rake::Task.new(:features) do |t|
|
29
|
-
t.cucumber_opts =
|
29
|
+
t.cucumber_opts = 'features --format pretty'
|
30
30
|
end
|
31
31
|
|
32
32
|
desc 'Run features tagged as work-in-progress (@wip)'
|
@@ -41,10 +41,10 @@ task 'cucumber:wip' => 'features:wip'
|
|
41
41
|
task :wip => 'features:wip'
|
42
42
|
require 'rake/testtask'
|
43
43
|
Rake::TestTask.new do |t|
|
44
|
-
t.libs <<
|
44
|
+
t.libs << 'test'
|
45
45
|
t.test_files = FileList['test/*_test.rb']
|
46
46
|
end
|
47
47
|
|
48
48
|
task :ci => [:spec, :features]
|
49
49
|
|
50
|
-
task :default => [:test
|
50
|
+
task :default => [:test, :features]
|
data/autosign.gemspec
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Ensure we require the local version and not one we might have installed already
|
2
|
-
require File.join([
|
3
|
-
spec = Gem::Specification.new do |s|
|
4
|
+
require File.join([__dir__, 'lib', 'autosign', 'version.rb'])
|
5
|
+
spec = Gem::Specification.new do |s|
|
4
6
|
s.name = 'autosign'
|
5
7
|
s.version = Autosign::VERSION
|
6
8
|
s.author = 'Daniel Dreier'
|
@@ -8,28 +10,30 @@ spec = Gem::Specification.new do |s|
|
|
8
10
|
s.homepage = 'https://github.com/danieldreier/autosign'
|
9
11
|
s.platform = Gem::Platform::RUBY
|
10
12
|
s.summary = 'Tooling to make puppet autosigning easy, secure, and extensible'
|
11
|
-
s.files
|
12
|
-
")
|
13
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|features|fixtures)/}) }
|
13
14
|
s.require_paths << 'lib'
|
14
|
-
s.
|
15
|
-
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
'CHANGELOG.md',
|
17
|
+
'LICENSE',
|
18
|
+
'README.md'
|
19
|
+
]
|
16
20
|
s.bindir = 'bin'
|
17
|
-
s.executables
|
18
|
-
s.executables << 'autosign-validator'
|
19
|
-
s.add_development_dependency('rake', '~> 10')
|
20
|
-
s.add_development_dependency('rdoc', '~> 4')
|
21
|
+
s.executables = ['autosign', 'autosign-validator']
|
21
22
|
s.add_development_dependency('aruba', '~> 0.6')
|
22
|
-
s.add_development_dependency('cucumber', '~> 2')
|
23
|
-
s.add_development_dependency('puppet', '~> 3')
|
24
|
-
s.add_development_dependency('rspec', '~> 3')
|
25
23
|
s.add_development_dependency('coveralls')
|
24
|
+
s.add_development_dependency('cucumber', '~> 2')
|
26
25
|
s.add_development_dependency('pry', '~> 0.10')
|
27
|
-
s.
|
28
|
-
s.
|
29
|
-
s.
|
26
|
+
s.add_development_dependency('puppet', '~> 6')
|
27
|
+
s.add_development_dependency('rake', '~> 13')
|
28
|
+
s.add_development_dependency('rdoc', '~> 4')
|
29
|
+
s.add_development_dependency('rspec', '~> 3')
|
30
|
+
s.add_development_dependency('rubocop', '~> 0.83.0')
|
31
|
+
s.add_development_dependency('yard', '~> 0.9.11')
|
32
|
+
s.add_development_dependency('bundler', '~> 2.0')
|
33
|
+
s.add_runtime_dependency('deep_merge', '~> 1.2')
|
34
|
+
s.add_runtime_dependency('gli', '~> 2')
|
35
|
+
s.add_runtime_dependency('iniparse', '~> 1')
|
36
|
+
s.add_runtime_dependency('jwt', '~> 1')
|
30
37
|
s.add_runtime_dependency('logging', '~> 2')
|
31
|
-
s.add_runtime_dependency('
|
32
|
-
s.add_runtime_dependency('deep_merge', '~> 1')
|
33
|
-
s.add_runtime_dependency('require_all', '~> 1')
|
34
|
-
s.add_runtime_dependency('yard', '~> 0.8')
|
38
|
+
s.add_runtime_dependency('multi_json', '>=1')
|
35
39
|
end
|
data/bin/autosign
CHANGED
@@ -52,8 +52,9 @@ command :generate do |c|
|
|
52
52
|
|
53
53
|
c.action do |global_options,options,args|
|
54
54
|
config = Autosign::Config.new({'config_file' => global_options['config']})
|
55
|
-
|
56
|
-
|
55
|
+
config_settings = config.settings
|
56
|
+
global_options['secret'] = config_settings['jwt_token']['secret'] if global_options['secret'].nil?
|
57
|
+
options['validfor'] = config_settings.to_hash['jwt_token']['validity'].to_s if options['validfor'] == '7200'
|
57
58
|
@logger.debug "validfor: " + options['validfor']
|
58
59
|
help_now!('no secret was defined via --secret or a config file') if global_options['secret'].nil?
|
59
60
|
help_now!('certname is required as argument') if args[0].nil?
|
@@ -66,9 +67,11 @@ command :generate do |c|
|
|
66
67
|
puts token.sign.to_s
|
67
68
|
else
|
68
69
|
@logger.info "generated token for: " + certname
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
unless global_options[:quiet]
|
71
|
+
puts "Autosign token for: " + token.certname + ", valid until: " + Time.at(token.validto).to_s
|
72
|
+
puts "To use the token, put the following in ${puppet_confdir}/csr_attributes.yaml prior to running puppet agent for the first time:"
|
73
|
+
puts ""
|
74
|
+
end
|
72
75
|
puts "custom_attributes:"
|
73
76
|
puts " challengePassword: \"#{token.sign.to_s}\""
|
74
77
|
end
|
@@ -85,8 +88,9 @@ command :validate do |c|
|
|
85
88
|
|
86
89
|
c.action do |global_options,options,args|
|
87
90
|
config = Autosign::Config.new({'config_file' => global_options['config']})
|
88
|
-
|
89
|
-
|
91
|
+
config_settings = config.settings
|
92
|
+
puts config_settings.to_hash['jwt_token']
|
93
|
+
global_options['secret'] = config_settings['jwt_token']['secret'] if global_options['secret'].nil?
|
90
94
|
|
91
95
|
help_now!('no secret was defined via --secret or a config file') if global_options['secret'].nil?
|
92
96
|
help_now!('certname is required') if options['certname'].nil?
|
@@ -110,7 +114,7 @@ command :config do |c|
|
|
110
114
|
c.command :setup do |setup|
|
111
115
|
setup.action do |global_options,options,args|
|
112
116
|
@logger.info "setup command ran with #{global_options} #{options} #{args}"
|
113
|
-
result = Autosign::Config.generate_default
|
117
|
+
result = Autosign::Config.generate_default({'config_file' => global_options['config']})
|
114
118
|
STDOUT.puts "generated default config file at #{result}" if result
|
115
119
|
end
|
116
120
|
end
|
@@ -120,7 +124,8 @@ command :config do |c|
|
|
120
124
|
print.action do |global_options,options,args|
|
121
125
|
@logger.debug "print command ran with #{global_options} #{options} #{args}"
|
122
126
|
config = Autosign::Config.new({'config_file' => global_options['config']})
|
123
|
-
|
127
|
+
require 'yaml'
|
128
|
+
puts config.settings.to_yaml
|
124
129
|
end
|
125
130
|
end
|
126
131
|
|
@@ -132,17 +137,20 @@ pre do |global,command,options,args|
|
|
132
137
|
# chosen command
|
133
138
|
# Use skips_pre before a command to skip this block
|
134
139
|
# on that command only
|
135
|
-
|
136
|
-
|
140
|
+
config = Autosign::Config.new
|
141
|
+
config_settings = config.settings
|
142
|
+
@logger.level = config_settings.to_hash['general']['loglevel'].to_sym unless config_settings.to_hash['general']['loglevel'].nil?
|
137
143
|
|
138
144
|
@logger.level = :error if global['quiet']
|
139
145
|
@logger.level = :info if global['verbose']
|
140
146
|
@logger.level = :debug if global['debug']
|
141
147
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
148
|
+
stdout_layout = Logging.layouts.pattern(:pattern => "%-5l -- %c : %m\n")
|
149
|
+
@logger.add_appenders Logging.appenders.stdout(:layout => stdout_layout)
|
150
|
+
|
151
|
+
unless global['logfile'].nil?
|
152
|
+
file_layout = Logging.layouts.pattern(:pattern => "%d %-5l -- %c : %m\n", :date_pattern => "%Y-%m-%dT%H:%M:%S.%s")
|
153
|
+
@logger.add_appenders Logging.appenders.file(global['logfile'], :layout => file_layout)
|
146
154
|
end
|
147
155
|
|
148
156
|
true
|
data/bin/autosign-validator
CHANGED
@@ -2,17 +2,26 @@
|
|
2
2
|
require 'autosign'
|
3
3
|
require 'logging'
|
4
4
|
|
5
|
+
### Ensure stdin is read https://tickets.puppetlabs.com/browse/SERVER-1116
|
6
|
+
raw_csr = $stdin.read
|
5
7
|
|
6
8
|
### Start logging
|
7
9
|
@logger = Logging.logger['Autosign']
|
8
|
-
@logger.level = :
|
10
|
+
@logger.level = :warn
|
9
11
|
|
10
12
|
# Start logging to stdout first so we get errors while loading the config file
|
11
13
|
@logger.add_appenders Logging.appenders.stdout
|
12
14
|
|
13
15
|
# Load config and then add logfile as a log appender
|
14
|
-
|
15
|
-
|
16
|
+
config_settings = Autosign::Config.new.settings
|
17
|
+
|
18
|
+
unless config_settings['general']['logfile'].nil?
|
19
|
+
file_layout = Logging.layouts.pattern(:pattern => "%d %-5l -- %c : %m\n", :date_pattern => "%Y-%m-%dT%H:%M:%S.%s")
|
20
|
+
@logger.add_appenders Logging.appenders.file(config_settings['general']['logfile'], :layout => file_layout)
|
21
|
+
end
|
22
|
+
|
23
|
+
@logger.level = config_settings['general']['loglevel'].to_sym unless config_settings['general']['loglevel'].nil?
|
24
|
+
|
16
25
|
### End logging initialization
|
17
26
|
|
18
27
|
### Get Inputs
|
@@ -21,11 +30,10 @@ unless ARGV.count == 1
|
|
21
30
|
exit 1
|
22
31
|
end
|
23
32
|
|
24
|
-
certname = ARGV
|
33
|
+
certname = ARGV.shift
|
25
34
|
@logger.debug "certname is " + certname
|
26
35
|
|
27
36
|
@logger.debug "reading CSR from stdin"
|
28
|
-
raw_csr = $stdin.read
|
29
37
|
csr = Autosign::Decoder.decode_csr(raw_csr)
|
30
38
|
exit 1 unless csr.is_a?(Hash)
|
31
39
|
|
@@ -33,7 +41,7 @@ exit 1 unless csr.is_a?(Hash)
|
|
33
41
|
### End Inputs
|
34
42
|
|
35
43
|
### validate token
|
36
|
-
token_validation = Autosign::Validator.any_validator(csr[:challenge_password].to_s, certname.to_s, raw_csr)
|
44
|
+
token_validation = Autosign::Validator.any_validator(csr[:challenge_password].to_s, certname.to_s, raw_csr, config_settings)
|
37
45
|
### end validation
|
38
46
|
|
39
47
|
### Exit with correct exit status
|
data/lib/autosign.rb
CHANGED
data/lib/autosign/config.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rbconfig'
|
2
4
|
require 'securerandom'
|
3
5
|
require 'deep_merge'
|
@@ -7,16 +9,16 @@ module Autosign
|
|
7
9
|
# Exceptions namespace for Autosign class
|
8
10
|
module Exceptions
|
9
11
|
# Exception representing a general failure during validation
|
10
|
-
class Validation <
|
12
|
+
class Validation < RuntimeError
|
11
13
|
end
|
12
14
|
# Exception representing a missing file during config validation
|
13
|
-
class NotFound <
|
15
|
+
class NotFound < RuntimeError
|
14
16
|
end
|
15
17
|
# Exception representing a permissions error during config validation
|
16
|
-
class Permissions <
|
18
|
+
class Permissions < RuntimeError
|
17
19
|
end
|
18
20
|
# Exception representing errors that Autosign does not know how to handle
|
19
|
-
class Error <
|
21
|
+
class Error < RuntimeError
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
@@ -36,20 +38,25 @@ module Autosign
|
|
36
38
|
# @return [Autosign::Config] instance of the Autosign::Config class
|
37
39
|
def initialize(settings_param = {})
|
38
40
|
# set up logging
|
39
|
-
@log = Logging.logger[
|
40
|
-
@log.debug "initializing
|
41
|
+
@log = Logging.logger[self.class]
|
42
|
+
@log.debug "initializing #{self.class.name}"
|
41
43
|
# validate parameter
|
42
44
|
raise 'settings is not a hash' unless settings_param.is_a?(Hash)
|
43
45
|
|
44
46
|
# look in the following places for a config file
|
45
|
-
@config_file_paths = ['/etc/autosign.conf', '/usr/local/etc/autosign.conf']
|
47
|
+
@config_file_paths = ['/etc/puppetlabs/puppetserver/autosign.conf', '/etc/autosign.conf', '/usr/local/etc/autosign.conf']
|
46
48
|
|
47
49
|
# HOME is unset when puppet runs, so we need to only use it if it's set
|
48
|
-
|
49
|
-
|
50
|
+
unless ENV['HOME'].nil?
|
51
|
+
@config_file_paths << File.join(Dir.home, '.autosign.conf')
|
52
|
+
end
|
53
|
+
|
54
|
+
unless settings_param['config_file'].nil?
|
55
|
+
@config_file_paths = [settings_param['config_file']]
|
56
|
+
end
|
50
57
|
|
51
58
|
@settings = settings_param
|
52
|
-
@log.debug
|
59
|
+
@log.debug 'Using merged settings hash: ' + @settings.to_s
|
53
60
|
end
|
54
61
|
|
55
62
|
# Return a merged settings hash of defaults, config file settings
|
@@ -57,11 +64,11 @@ module Autosign
|
|
57
64
|
#
|
58
65
|
# @return [Hash] deep merged settings hash
|
59
66
|
def settings
|
60
|
-
@log.debug
|
67
|
+
@log.debug 'merging settings'
|
61
68
|
setting_sources = [default_settings, configfile, @settings]
|
62
|
-
merged_settings = setting_sources.inject({}) { |merged, hash| merged.deep_merge(hash) }
|
63
|
-
@log.debug
|
64
|
-
|
69
|
+
merged_settings = setting_sources.inject({}) { |merged, hash| merged.deep_merge!(hash, {:overwrite_arrays => true}) }
|
70
|
+
@log.debug 'using merged settings: ' + merged_settings.to_s
|
71
|
+
merged_settings
|
65
72
|
end
|
66
73
|
|
67
74
|
private
|
@@ -78,12 +85,14 @@ module Autosign
|
|
78
85
|
def default_settings
|
79
86
|
{ 'general' =>
|
80
87
|
{
|
81
|
-
'loglevel'
|
88
|
+
'loglevel' => 'INFO',
|
89
|
+
'validation_order' => %w[
|
90
|
+
jwt_token password_list multiplexer
|
91
|
+
]
|
82
92
|
},
|
83
93
|
'jwt_token' => {
|
84
94
|
'validity' => 7200
|
85
|
-
}
|
86
|
-
}
|
95
|
+
} }
|
87
96
|
end
|
88
97
|
|
89
98
|
# Locate the configuration file, parse it from INI-format, and return
|
@@ -91,21 +100,21 @@ module Autosign
|
|
91
100
|
#
|
92
101
|
# @return [Hash] configuration settings loaded from INI file
|
93
102
|
def configfile
|
94
|
-
@log.debug
|
95
|
-
@config_file_paths.each
|
103
|
+
@log.debug 'Finding config file'
|
104
|
+
@config_file_paths.each do |file|
|
96
105
|
@log.debug "Checking if file '#{file}' exists"
|
97
106
|
if File.file?(file)
|
98
|
-
@log.debug
|
107
|
+
@log.debug 'Reading config file from: ' + file
|
99
108
|
config_file = File.read(file)
|
100
109
|
parsed_config_file = YAML.load(config_file)
|
101
|
-
#parsed_config_file = IniParse.parse(config_file).to_hash
|
102
|
-
@log.debug
|
110
|
+
# parsed_config_file = IniParse.parse(config_file).to_hash
|
111
|
+
@log.debug 'configuration read from config file: ' + parsed_config_file.to_s
|
103
112
|
return parsed_config_file if parsed_config_file.is_a?(Hash)
|
104
113
|
else
|
105
114
|
@log.debug "Configuration file '#{file}' not found"
|
106
115
|
end
|
107
|
-
|
108
|
-
|
116
|
+
end
|
117
|
+
{}
|
109
118
|
end
|
110
119
|
|
111
120
|
# Validate configuration file
|
@@ -114,14 +123,14 @@ module Autosign
|
|
114
123
|
# @param configfile [String] the absolute path of the config file to validate
|
115
124
|
# @return [String] the absolute path of the config file
|
116
125
|
def validate_config_file(configfile = location)
|
117
|
-
@log.debug
|
126
|
+
@log.debug 'validating config file'
|
118
127
|
unless File.file?(configfile)
|
119
128
|
@log.error "configuration file not found at: #{configfile}"
|
120
129
|
raise Autosign::Exceptions::NotFound
|
121
130
|
end
|
122
131
|
|
123
132
|
# check if file is world-readable
|
124
|
-
if File.world_readable?(configfile)
|
133
|
+
if File.world_readable?(configfile) || File.world_writable?(configfile)
|
125
134
|
@log.error "configuration file #{configfile} is world-readable or world-writable, which is a security risk"
|
126
135
|
raise Autosign::Exceptions::Permissions
|
127
136
|
end
|
@@ -132,25 +141,25 @@ module Autosign
|
|
132
141
|
# Generate a default configuration file
|
133
142
|
# As a convenience for the user, we can generate a default config file
|
134
143
|
# This class is currently too tightly coupled with the JWT token validator
|
135
|
-
def self.generate_default()
|
144
|
+
def self.generate_default(settings_param = {})
|
136
145
|
os_defaults = (
|
137
146
|
case RbConfig::CONFIG['host_os']
|
138
147
|
when /darwin|mac os/
|
139
148
|
{
|
140
|
-
'logpath'
|
141
|
-
'confpath'
|
149
|
+
'logpath' => File.join(Dir.home, 'autosign.log'),
|
150
|
+
'confpath' => File.join(Dir.home, '.autosign.conf'),
|
142
151
|
'journalfile' => File.join(Dir.home, '.autosign.journal')
|
143
152
|
}
|
144
153
|
when /linux/
|
145
154
|
{
|
146
|
-
'logpath'
|
147
|
-
'confpath'
|
155
|
+
'logpath' => '/var/log/autosign.log',
|
156
|
+
'confpath' => '/etc/autosign.conf',
|
148
157
|
'journalfile' => File.join(Dir.home, '/var/autosign/autosign.journal')
|
149
158
|
}
|
150
159
|
when /bsd/
|
151
160
|
{
|
152
|
-
'logpath'
|
153
|
-
'confpath'
|
161
|
+
'logpath' => '/var/log/autosign.log',
|
162
|
+
'confpath' => '/usr/local/etc/autosign.conf',
|
154
163
|
'journalfile' => File.join(Dir.home, '/var/autosign/autosign.journal')
|
155
164
|
}
|
156
165
|
else
|
@@ -161,36 +170,42 @@ module Autosign
|
|
161
170
|
config = {
|
162
171
|
'general' => {
|
163
172
|
'loglevel' => 'warn',
|
164
|
-
'logfile' =>
|
173
|
+
'logfile' => os_defaults['logpath'],
|
174
|
+
'validation_order' => %w[
|
175
|
+
jwt_token password_list multiplexer
|
176
|
+
]
|
165
177
|
},
|
166
178
|
'jwt_token' => {
|
167
|
-
'secret' =>
|
179
|
+
'secret' => SecureRandom.base64(20),
|
168
180
|
'validity' => '7200',
|
169
181
|
'journalfile' => os_defaults['journalfile']
|
170
182
|
}
|
171
183
|
}
|
172
184
|
|
173
|
-
# config = IniParse.gen do |doc|
|
174
|
-
# doc.section("general") do |general|
|
175
|
-
# general.option("loglevel", "warn")
|
176
|
-
# general.option("logfile", os_defaults['logpath'])
|
177
|
-
# end
|
178
|
-
# doc.section("jwt_token") do |jwt_token|
|
179
|
-
# jwt_token.option("secret", SecureRandom.base64(15))
|
180
|
-
# jwt_token.option("validity", 7200)
|
181
|
-
# jwt_token.option("journalfile", os_defaults['journalfile'])
|
182
|
-
# end
|
183
|
-
# doc.section("multiplexer") do |jwt_token|
|
184
|
-
# jwt_token.option(";external_policy_executable", '/usr/local/bin/some_autosign_executable')
|
185
|
-
# jwt_token.option(";external_policy_executable", '/usr/local/bin/another_autosign_executable')
|
186
|
-
# end
|
187
|
-
# doc.section("password_list") do |jwt_token|
|
188
|
-
# jwt_token.option(";password", 'static_autosign_password_here')
|
189
|
-
# jwt_token.option(";password", 'another_static_autosign_password')
|
190
|
-
# end
|
191
|
-
# end.to_ini
|
192
|
-
|
193
|
-
|
185
|
+
# config = IniParse.gen do |doc|
|
186
|
+
# doc.section("general") do |general|
|
187
|
+
# general.option("loglevel", "warn")
|
188
|
+
# general.option("logfile", os_defaults['logpath'])
|
189
|
+
# end
|
190
|
+
# doc.section("jwt_token") do |jwt_token|
|
191
|
+
# jwt_token.option("secret", SecureRandom.base64(15))
|
192
|
+
# jwt_token.option("validity", 7200)
|
193
|
+
# jwt_token.option("journalfile", os_defaults['journalfile'])
|
194
|
+
# end
|
195
|
+
# doc.section("multiplexer") do |jwt_token|
|
196
|
+
# jwt_token.option(";external_policy_executable", '/usr/local/bin/some_autosign_executable')
|
197
|
+
# jwt_token.option(";external_policy_executable", '/usr/local/bin/another_autosign_executable')
|
198
|
+
# end
|
199
|
+
# doc.section("password_list") do |jwt_token|
|
200
|
+
# jwt_token.option(";password", 'static_autosign_password_here')
|
201
|
+
# jwt_token.option(";password", 'another_static_autosign_password')
|
202
|
+
# end
|
203
|
+
# end.to_ini
|
204
|
+
config_file = settings_param['config_file'] || os_defaults['confpath']
|
205
|
+
if File.file?(config_file)
|
206
|
+
raise Autosign::Exceptions::Error, "file #{config_file} already exists, aborting"
|
207
|
+
end
|
208
|
+
return config_file if File.write(config_file, config.to_yaml)
|
194
209
|
end
|
195
210
|
end
|
196
211
|
end
|