inspec 1.0.0.beta3 → 1.0.0
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 +4 -4
- data/CHANGELOG.md +34 -2
- data/README.md +1 -1
- data/docs/inspec_and_friends.md +4 -1
- data/docs/profiles.md +14 -0
- data/lib/bundles/inspec-compliance/target.rb +15 -2
- data/lib/inspec/base_cli.rb +10 -0
- data/lib/inspec/cli.rb +16 -0
- data/lib/inspec/dependencies/lockfile.rb +5 -13
- data/lib/inspec/dsl.rb +7 -4
- data/lib/inspec/errors.rb +1 -0
- data/lib/inspec/profile.rb +1 -0
- data/lib/inspec/profile_context.rb +7 -0
- data/lib/inspec/runner.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/resources/parse_config.rb +18 -1
- data/lib/resources/security_policy.rb +54 -0
- data/lib/resources/sys_info.rb +1 -1
- data/lib/resources/users.rb +78 -62
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c1825c5508e4853cf4bc1446a5b2bd679d9d1be
|
4
|
+
data.tar.gz: 6ffbe626a987b38ea03561d8bd18681803d89aaf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bb3e9f9c6295dcb29e500b134e5b264ac239f8270cb695dd6c28aeefa7fc9b65604e93b9c144f2754536988a8c1220dc31df12add23729fcaea9eabecbd6b11
|
7
|
+
data.tar.gz: 5916f874af8a593d5b08e7456bacf42b5ed7c6dadf73b243c4e0d6d675af470f7aa2928abb603da4a32d97c76ded9e1354e6ab05eac61ffd85d4d0030e7fe60f
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,39 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [1.0.0
|
4
|
-
[Full Changelog](https://github.com/chef/inspec/compare/v1.0.0.
|
3
|
+
## [1.0.0](https://github.com/chef/inspec/tree/1.0.0) (2016-09-26)
|
4
|
+
[Full Changelog](https://github.com/chef/inspec/compare/v1.0.0.beta3...1.0.0)
|
5
|
+
|
6
|
+
**Implemented enhancements:**
|
7
|
+
|
8
|
+
- InSpec OS package [\#646](https://github.com/chef/inspec/issues/646)
|
9
|
+
- replace wmi win32\_useraccount with adsi users [\#1149](https://github.com/chef/inspec/pull/1149) ([chris-rock](https://github.com/chris-rock))
|
10
|
+
|
11
|
+
**Fixed bugs:**
|
12
|
+
|
13
|
+
- README.md has broken link to non-existent file [\#1136](https://github.com/chef/inspec/issues/1136)
|
14
|
+
|
15
|
+
**Merged pull requests:**
|
16
|
+
|
17
|
+
- update omnibus images [\#1164](https://github.com/chef/inspec/pull/1164) ([chris-rock](https://github.com/chris-rock))
|
18
|
+
- website / tutorial interaction [\#1163](https://github.com/chef/inspec/pull/1163) ([chris-rock](https://github.com/chris-rock))
|
19
|
+
- fix buttons on community page [\#1162](https://github.com/chef/inspec/pull/1162) ([arlimus](https://github.com/arlimus))
|
20
|
+
- fix alignment of community buttons [\#1161](https://github.com/chef/inspec/pull/1161) ([arlimus](https://github.com/arlimus))
|
21
|
+
- Fix require\_controls DSL method [\#1160](https://github.com/chef/inspec/pull/1160) ([stevendanna](https://github.com/stevendanna))
|
22
|
+
- Document the require\_resource function [\#1158](https://github.com/chef/inspec/pull/1158) ([stevendanna](https://github.com/stevendanna))
|
23
|
+
- fix css in docs search [\#1157](https://github.com/chef/inspec/pull/1157) ([arlimus](https://github.com/arlimus))
|
24
|
+
- update www readme for releasing the site [\#1156](https://github.com/chef/inspec/pull/1156) ([arlimus](https://github.com/arlimus))
|
25
|
+
- Fix minor typo in sys\_info documentation [\#1155](https://github.com/chef/inspec/pull/1155) ([stevendanna](https://github.com/stevendanna))
|
26
|
+
- fix outdated link in readme [\#1154](https://github.com/chef/inspec/pull/1154) ([arlimus](https://github.com/arlimus))
|
27
|
+
- fix minor website bugs [\#1153](https://github.com/chef/inspec/pull/1153) ([arlimus](https://github.com/arlimus))
|
28
|
+
- clean www before releasing [\#1152](https://github.com/chef/inspec/pull/1152) ([arlimus](https://github.com/arlimus))
|
29
|
+
- add docs to the website [\#1151](https://github.com/chef/inspec/pull/1151) ([arlimus](https://github.com/arlimus))
|
30
|
+
- return empty array for known privileges [\#1150](https://github.com/chef/inspec/pull/1150) ([chris-rock](https://github.com/chris-rock))
|
31
|
+
- Extend example for parse\_config.rb [\#1148](https://github.com/chef/inspec/pull/1148) ([nvtkaszpir](https://github.com/nvtkaszpir))
|
32
|
+
- Bump lockfile version to 1.0 [\#1141](https://github.com/chef/inspec/pull/1141) ([stevendanna](https://github.com/stevendanna))
|
33
|
+
- Improve error messages from compliance fetcher [\#1126](https://github.com/chef/inspec/pull/1126) ([stevendanna](https://github.com/stevendanna))
|
34
|
+
|
35
|
+
## [v1.0.0.beta3](https://github.com/chef/inspec/tree/v1.0.0.beta3) (2016-09-25)
|
36
|
+
[Full Changelog](https://github.com/chef/inspec/compare/v1.0.0.beta2...v1.0.0.beta3)
|
5
37
|
|
6
38
|
**Implemented enhancements:**
|
7
39
|
|
data/README.md
CHANGED
@@ -18,7 +18,7 @@ describe inetd_conf do
|
|
18
18
|
end
|
19
19
|
```
|
20
20
|
|
21
|
-
InSpec makes it easy to run your tests wherever you need. More options
|
21
|
+
InSpec makes it easy to run your tests wherever you need. More options are found in our [CLI docs](http://inspec.io/docs/reference/cli/).
|
22
22
|
|
23
23
|
```bash
|
24
24
|
# run test locally
|
data/docs/inspec_and_friends.md
CHANGED
@@ -4,6 +4,9 @@ title: InSpec and friends
|
|
4
4
|
|
5
5
|
# InSpec and friends
|
6
6
|
|
7
|
+
This page looks at projects that are similar to InSpec to explain how they
|
8
|
+
relate to each other.
|
9
|
+
|
7
10
|
## RSpec
|
8
11
|
|
9
12
|
RSpec is an awesome framework that is widely used to test Ruby code. It
|
@@ -37,7 +40,7 @@ control "sshd-11" do
|
|
37
40
|
end
|
38
41
|
```
|
39
42
|
|
40
|
-
|
43
|
+
## Serverspec
|
41
44
|
|
42
45
|
Serverspec can be credited as the first extension of RSpec that enabled
|
43
46
|
users to run RSpec tests on servers to verify deployed artifacts. It was
|
data/docs/profiles.md
CHANGED
@@ -242,6 +242,20 @@ For example, to require that controls `cis-fs-2.1` and `cis-fs-2.2` be loaded fr
|
|
242
242
|
|
243
243
|
end
|
244
244
|
|
245
|
+
|
246
|
+
## require_resource
|
247
|
+
|
248
|
+
By default, all of the resources from a listed dependency are available
|
249
|
+
for use in your profile. If two of your dependencies provide a resource with
|
250
|
+
the same name, you can use the `require_resource` DSL function to
|
251
|
+
disambiguate the two:
|
252
|
+
|
253
|
+
require_resource(profile: 'my_dep', resource: 'my_res',
|
254
|
+
as: 'my_res2')
|
255
|
+
|
256
|
+
This will allow you to reference the resource `my_res` from the
|
257
|
+
profile `my_dep` using the name `my_res2`.
|
258
|
+
|
245
259
|
# Profile Attributes
|
246
260
|
|
247
261
|
Attributes may be used in profiles to define secrets, such as user names and passwords, that should not otherwise be stored in plain-text in a cookbook. First specify a variable in the control for each secret, then add the secret to a Yaml file located on the local machine, and then run `inspec exec` and specify the path to that Yaml file using the `--attrs` attribute.
|
@@ -4,6 +4,7 @@
|
|
4
4
|
|
5
5
|
require 'uri'
|
6
6
|
require 'inspec/fetcher'
|
7
|
+
require 'inspec/errors'
|
7
8
|
|
8
9
|
# InSpec Target Helper for Chef Compliance
|
9
10
|
# reuses UrlHelper, but it knows the target server and the access token already
|
@@ -24,11 +25,23 @@ module Compliance
|
|
24
25
|
|
25
26
|
# check if we have a compliance token
|
26
27
|
config = Compliance::Configuration.new
|
27
|
-
|
28
|
+
if config['token'].nil?
|
29
|
+
fail Inspec::FetcherFailure, <<EOF
|
30
|
+
|
31
|
+
Cannot fetch #{uri} because your compliance token has not been
|
32
|
+
configured.
|
33
|
+
|
34
|
+
Please login using
|
35
|
+
|
36
|
+
inspec compliance login https://your_compliance_server --user admin --insecure --token 'PASTE TOKEN HERE'
|
37
|
+
EOF
|
38
|
+
end
|
28
39
|
|
29
40
|
# verifies that the target e.g base/ssh exists
|
30
41
|
profile = uri.host + uri.path
|
31
|
-
Compliance::API.exist?(config, profile)
|
42
|
+
if !Compliance::API.exist?(config, profile)
|
43
|
+
fail Inpsec::FetcherFailure, "The compliance profile #{profile} was not found on the configured compliance server"
|
44
|
+
end
|
32
45
|
new(target_url(profile, config), config)
|
33
46
|
rescue URI::Error => _e
|
34
47
|
nil
|
data/lib/inspec/base_cli.rb
CHANGED
@@ -132,6 +132,16 @@ module Inspec
|
|
132
132
|
Logger.const_get(l.upcase)
|
133
133
|
end
|
134
134
|
|
135
|
+
def pretty_handle_exception(exception)
|
136
|
+
case exception
|
137
|
+
when Inspec::Error
|
138
|
+
$stderr.puts exception.message
|
139
|
+
exit(1)
|
140
|
+
else
|
141
|
+
raise exception # rubocop:disable Style/SignalException
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
135
145
|
def configure_logger(o)
|
136
146
|
#
|
137
147
|
# TODO(ssd): This is a big gross, but this configures the
|
data/lib/inspec/cli.rb
CHANGED
@@ -48,6 +48,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
48
48
|
fdst = File.expand_path(dst)
|
49
49
|
File.write(fdst, JSON.dump(profile.info))
|
50
50
|
end
|
51
|
+
rescue StandardError => e
|
52
|
+
pretty_handle_exception(e)
|
51
53
|
end
|
52
54
|
|
53
55
|
desc 'check PATH', 'verify all tests at the specified PATH'
|
@@ -97,6 +99,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
97
99
|
end
|
98
100
|
end
|
99
101
|
exit 1 unless result[:summary][:valid]
|
102
|
+
rescue StandardError => e
|
103
|
+
pretty_handle_exception(e)
|
100
104
|
end
|
101
105
|
|
102
106
|
desc 'vendor', 'Download all dependencies and generate a lockfile'
|
@@ -105,6 +109,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
105
109
|
profile = Inspec::Profile.for_target('./', opts.merge(cache: Inspec::Cache.new(path)))
|
106
110
|
lockfile = profile.generate_lockfile
|
107
111
|
File.write('inspec.lock', lockfile.to_yaml)
|
112
|
+
rescue StandardError => e
|
113
|
+
pretty_handle_exception(e)
|
108
114
|
end
|
109
115
|
|
110
116
|
desc 'archive PATH', 'archive a profile to tar.gz (default) or zip'
|
@@ -136,6 +142,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
136
142
|
|
137
143
|
# generate archive
|
138
144
|
exit 1 unless profile.archive(opts)
|
145
|
+
rescue StandardError => e
|
146
|
+
pretty_handle_exception(e)
|
139
147
|
end
|
140
148
|
|
141
149
|
desc 'exec PATHS', 'run all test files at the specified PATH.'
|
@@ -147,6 +155,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
147
155
|
|
148
156
|
# run tests
|
149
157
|
run_tests(targets, o)
|
158
|
+
rescue StandardError => e
|
159
|
+
pretty_handle_exception(e)
|
150
160
|
end
|
151
161
|
|
152
162
|
desc 'detect', 'detect the target OS'
|
@@ -165,6 +175,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
165
175
|
mark_text(res[item.to_sym]))
|
166
176
|
}
|
167
177
|
end
|
178
|
+
rescue StandardError => e
|
179
|
+
pretty_handle_exception(e)
|
168
180
|
end
|
169
181
|
|
170
182
|
desc 'shell', 'open an interactive debugging shell'
|
@@ -196,12 +208,16 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
196
208
|
exit 0
|
197
209
|
rescue RuntimeError, Train::UserError => e
|
198
210
|
$stderr.puts e.message
|
211
|
+
rescue StandardError => e
|
212
|
+
pretty_handle_exception(e)
|
199
213
|
end
|
200
214
|
|
201
215
|
desc 'env', 'Output shell-appropriate completion configuration'
|
202
216
|
def env(shell = nil)
|
203
217
|
p = Inspec::EnvPrinter.new(self.class, shell)
|
204
218
|
p.print_and_exit!
|
219
|
+
rescue StandardError => e
|
220
|
+
pretty_handle_exception(e)
|
205
221
|
end
|
206
222
|
|
207
223
|
desc 'version', 'prints the version of this tool'
|
@@ -4,8 +4,8 @@ require 'yaml'
|
|
4
4
|
module Inspec
|
5
5
|
class Lockfile
|
6
6
|
# When we finalize this feature, we should set these to 1
|
7
|
-
MINIMUM_SUPPORTED_VERSION =
|
8
|
-
CURRENT_LOCKFILE_VERSION =
|
7
|
+
MINIMUM_SUPPORTED_VERSION = 1
|
8
|
+
CURRENT_LOCKFILE_VERSION = 1
|
9
9
|
|
10
10
|
def self.from_dependency_set(dep_set)
|
11
11
|
lockfile_content = {
|
@@ -32,14 +32,6 @@ lower than the minimum supported version #{MINIMUM_SUPPORTED_VERSION}.
|
|
32
32
|
Please create a new lockfile for this project by running:
|
33
33
|
|
34
34
|
inspec vendor
|
35
|
-
EOF
|
36
|
-
elsif version == 0
|
37
|
-
# Remove this case once this feature stablizes
|
38
|
-
$stderr.puts <<EOF
|
39
|
-
WARNING: This is a version 0 lockfile. Thank you for trying the
|
40
|
-
experimental dependency management feature. Please be aware you may
|
41
|
-
need to regenerate this lockfile in future versions as the feature is
|
42
|
-
currently in development.
|
43
35
|
EOF
|
44
36
|
elsif version > CURRENT_LOCKFILE_VERSION
|
45
37
|
fail <<EOF
|
@@ -78,8 +70,8 @@ EOF
|
|
78
70
|
# different entry points of the API.
|
79
71
|
def parse_content_hash(lockfile_content_hash)
|
80
72
|
case version
|
81
|
-
when
|
82
|
-
|
73
|
+
when 1
|
74
|
+
parse_content_hash_1(lockfile_content_hash)
|
83
75
|
else
|
84
76
|
# If we've gotten here, there is likely a mistake in the
|
85
77
|
# lockfile version validation in the constructor.
|
@@ -87,7 +79,7 @@ EOF
|
|
87
79
|
end
|
88
80
|
end
|
89
81
|
|
90
|
-
def
|
82
|
+
def parse_content_hash_1(lockfile_content_hash)
|
91
83
|
@deps = if lockfile_content_hash['depends']
|
92
84
|
lockfile_content_hash['depends'].map { |i| symbolize_keys(i) }
|
93
85
|
end
|
data/lib/inspec/dsl.rb
CHANGED
@@ -53,12 +53,15 @@ EOF
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def self.filter_included_controls(context, profile, &block)
|
56
|
-
|
56
|
+
mock = Inspec::Backend.create({ backend: 'mock' })
|
57
|
+
include_ctx = Inspec::ProfileContext.for_profile(profile, mock, {})
|
57
58
|
include_ctx.load(block) if block_given?
|
58
59
|
# remove all rules that were not registered
|
59
|
-
context.
|
60
|
-
|
61
|
-
|
60
|
+
context.all_rules.each do |r|
|
61
|
+
id = Inspec::Rule.rule_id(r)
|
62
|
+
fid = Inspec::Rule.profile_id(r) + '/' + id
|
63
|
+
unless include_ctx.rules[id] || include_ctx.rules[fid]
|
64
|
+
context.remove_rule(fid)
|
62
65
|
end
|
63
66
|
end
|
64
67
|
end
|
data/lib/inspec/errors.rb
CHANGED
data/lib/inspec/profile.rb
CHANGED
@@ -67,6 +67,13 @@ module Inspec
|
|
67
67
|
@conf['profile'].supports_os?
|
68
68
|
end
|
69
69
|
|
70
|
+
def remove_rule(id)
|
71
|
+
@rules[id] = nil if @rules.key?(id)
|
72
|
+
@control_subcontexts.each do |c|
|
73
|
+
c.remove_rule(id)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
70
77
|
def all_controls
|
71
78
|
ret = @rules.values
|
72
79
|
ret += @control_subcontexts.map(&:all_rules).flatten
|
data/lib/inspec/runner.rb
CHANGED
data/lib/inspec/version.rb
CHANGED
@@ -19,10 +19,27 @@ module Inspec::Resources
|
|
19
19
|
desc 'Use the parse_config InSpec audit resource to test arbitrary configuration files.'
|
20
20
|
example "
|
21
21
|
output = command('some-command').stdout
|
22
|
-
|
23
22
|
describe parse_config(output, { data_config_option: value } ) do
|
24
23
|
its('setting') { should eq 1 }
|
25
24
|
end
|
25
|
+
|
26
|
+
output2 = command('curl http://127.0.0.1/php_status').stdout
|
27
|
+
# php status is in format 'key : value', and we do not allow for multiple values
|
28
|
+
options2 = {
|
29
|
+
assignment_re: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
|
30
|
+
multiple_values: false
|
31
|
+
}
|
32
|
+
|
33
|
+
describe parse_config(output2, options2) do
|
34
|
+
its('pool') { should eq 'www'}
|
35
|
+
its('process manager') { should eq process_manager }
|
36
|
+
end
|
37
|
+
|
38
|
+
# getting specific key from the output above, convert it to integer and then compare
|
39
|
+
# make sure 'listen queue' is below 100
|
40
|
+
describe parse_config(output2, options2 ).params['listen queue'].to_i do
|
41
|
+
it { should be < 100 }
|
42
|
+
end
|
26
43
|
"
|
27
44
|
|
28
45
|
attr_reader :content
|
@@ -16,6 +16,57 @@
|
|
16
16
|
require 'hashie'
|
17
17
|
|
18
18
|
module Inspec::Resources
|
19
|
+
# known and supported MS privilege rights
|
20
|
+
# @see https://technet.microsoft.com/en-us/library/dd277311.aspx
|
21
|
+
# @see https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx
|
22
|
+
MS_PRIVILEGES_RIGHTS = [
|
23
|
+
'SeNetworkLogonRight',
|
24
|
+
'SeBackupPrivilege',
|
25
|
+
'SeChangeNotifyPrivilege',
|
26
|
+
'SeSystemtimePrivilege',
|
27
|
+
'SeCreatePagefilePrivilege',
|
28
|
+
'SeDebugPrivilege',
|
29
|
+
'SeRemoteShutdownPrivilege',
|
30
|
+
'SeAuditPrivilege',
|
31
|
+
'SeIncreaseQuotaPrivilege',
|
32
|
+
'SeIncreaseBasePriorityPrivilege',
|
33
|
+
'SeLoadDriverPrivilege',
|
34
|
+
'SeBatchLogonRight',
|
35
|
+
'SeServiceLogonRight',
|
36
|
+
'SeInteractiveLogonRight',
|
37
|
+
'SeSecurityPrivilege',
|
38
|
+
'SeSystemEnvironmentPrivilege',
|
39
|
+
'SeProfileSingleProcessPrivilege',
|
40
|
+
'SeSystemProfilePrivilege',
|
41
|
+
'SeAssignPrimaryTokenPrivilege',
|
42
|
+
'SeRestorePrivilege',
|
43
|
+
'SeShutdownPrivilege',
|
44
|
+
'SeTakeOwnershipPrivilege',
|
45
|
+
'SeUndockPrivilege',
|
46
|
+
'SeManageVolumePrivilege',
|
47
|
+
'SeRemoteInteractiveLogonRight',
|
48
|
+
'SeImpersonatePrivilege',
|
49
|
+
'SeCreateGlobalPrivilege',
|
50
|
+
'SeIncreaseWorking',
|
51
|
+
'SeTimeZonePrivilege',
|
52
|
+
'SeCreateSymbolicLinkPrivilege',
|
53
|
+
'SeDenyNetworkLogonRight', # Deny access to this computer from the network
|
54
|
+
'SeDenyInteractiveLogonRight', # Deny logon locally
|
55
|
+
'SeDenyBatchLogonRight', # Deny logon as a batch job
|
56
|
+
'SeDenyServiceLogonRight', # Deny logon as a service
|
57
|
+
'SeTcbPrivilege',
|
58
|
+
'SeMachineAccountPrivilege',
|
59
|
+
'SeCreateTokenPrivilege',
|
60
|
+
'SeCreatePermanentPrivilege',
|
61
|
+
'SeEnableDelegationPrivilege',
|
62
|
+
'SeLockMemoryPrivilege',
|
63
|
+
'SeSyncAgentPrivilege',
|
64
|
+
'SeUnsolicitedInputPrivilege',
|
65
|
+
'SeTrustedCredManAccessPrivilege',
|
66
|
+
'SeRelabelPrivilege', # the privilege to change a Windows integrity label (new to Windows Vista)
|
67
|
+
'SeDenyRemoteInteractiveLogonRight', # Deny logon through Terminal Services
|
68
|
+
].freeze
|
69
|
+
|
19
70
|
class SecurityPolicy < Inspec.resource(1)
|
20
71
|
name 'security_policy'
|
21
72
|
desc 'Use the security_policy InSpec audit resource to test security policies on the Microsoft Windows platform.'
|
@@ -42,6 +93,9 @@ module Inspec::Resources
|
|
42
93
|
# deep search for hash key
|
43
94
|
params.extend Hashie::Extensions::DeepFind
|
44
95
|
res = params.deep_find(name.to_s)
|
96
|
+
|
97
|
+
# return an empty array if configuration does not include rights configuration
|
98
|
+
return [] if res.nil? && MS_PRIVILEGES_RIGHTS.include?(name.to_s)
|
45
99
|
res
|
46
100
|
end
|
47
101
|
|
data/lib/resources/sys_info.rb
CHANGED
data/lib/resources/users.rb
CHANGED
@@ -547,21 +547,12 @@ module Inspec::Resources
|
|
547
547
|
end
|
548
548
|
end
|
549
549
|
|
550
|
-
#
|
550
|
+
# This optimization was inspired by
|
551
|
+
# @see https://mcpmag.com/articles/2015/04/15/reporting-on-local-accounts.aspx
|
552
|
+
# Alternative solutions are WMI Win32_UserAccount
|
551
553
|
# @see https://msdn.microsoft.com/en-us/library/aa394507(v=vs.85).aspx
|
552
554
|
# @see https://msdn.microsoft.com/en-us/library/aa394153(v=vs.85).aspx
|
553
|
-
#
|
554
|
-
# using Get-AdUser would be the best command for domain machines, but it will not be installed
|
555
|
-
# on client machines by default
|
556
|
-
# @see https://technet.microsoft.com/en-us/library/ee617241.aspx
|
557
|
-
# @see https://technet.microsoft.com/en-us/library/hh509016(v=WS.10).aspx
|
558
|
-
# @see http://woshub.com/get-aduser-getting-active-directory-users-data-via-powershell/
|
559
|
-
# @see http://stackoverflow.com/questions/17548523/the-term-get-aduser-is-not-recognized-as-the-name-of-a-cmdlet
|
560
|
-
#
|
561
|
-
# Just for reference, we could also use ADSI (Active Directory Service Interfaces)
|
562
|
-
# @see https://mcpmag.com/articles/2015/04/15/reporting-on-local-accounts.aspx
|
563
555
|
class WindowsUser < UserInfo
|
564
|
-
# parse windows account name
|
565
556
|
def parse_windows_account(username)
|
566
557
|
account = username.split('\\')
|
567
558
|
name = account.pop
|
@@ -570,67 +561,92 @@ module Inspec::Resources
|
|
570
561
|
end
|
571
562
|
|
572
563
|
def identity(username)
|
573
|
-
#
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
if
|
578
|
-
|
579
|
-
else
|
580
|
-
filter = "Name = '#{account}' and LocalAccount = true"
|
581
|
-
end
|
564
|
+
# TODO: we look for local users only at this point
|
565
|
+
name, _domain = parse_windows_account(username)
|
566
|
+
return if collect_user_details.nil?
|
567
|
+
res = collect_user_details.select { |user| user[:username] == name }
|
568
|
+
res[0] if res.length > 0
|
569
|
+
end
|
582
570
|
|
571
|
+
def list_users
|
572
|
+
collect_user_details.map { |user| user[:username] }
|
573
|
+
end
|
574
|
+
|
575
|
+
# https://msdn.microsoft.com/en-us/library/aa746340(v=vs.85).aspx
|
576
|
+
def collect_user_details # rubocop:disable Metrics/MethodLength
|
577
|
+
return @users_cache if defined?(@users_cache)
|
583
578
|
script = <<-EOH
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
579
|
+
Function ConvertTo-SID { Param([byte[]]$BinarySID)
|
580
|
+
(New-Object System.Security.Principal.SecurityIdentifier($BinarySID,0)).Value
|
581
|
+
}
|
582
|
+
|
583
|
+
Function Convert-UserFlag { Param ($UserFlag)
|
584
|
+
$List = @()
|
585
|
+
Switch ($UserFlag) {
|
586
|
+
($UserFlag -BOR 0x0001) { $List += 'SCRIPT' }
|
587
|
+
($UserFlag -BOR 0x0002) { $List += 'ACCOUNTDISABLE' }
|
588
|
+
($UserFlag -BOR 0x0008) { $List += 'HOMEDIR_REQUIRED' }
|
589
|
+
($UserFlag -BOR 0x0010) { $List += 'LOCKOUT' }
|
590
|
+
($UserFlag -BOR 0x0020) { $List += 'PASSWD_NOTREQD' }
|
591
|
+
($UserFlag -BOR 0x0040) { $List += 'PASSWD_CANT_CHANGE' }
|
592
|
+
($UserFlag -BOR 0x0080) { $List += 'ENCRYPTED_TEXT_PWD_ALLOWED' }
|
593
|
+
($UserFlag -BOR 0x0100) { $List += 'TEMP_DUPLICATE_ACCOUNT' }
|
594
|
+
($UserFlag -BOR 0x0200) { $List += 'NORMAL_ACCOUNT' }
|
595
|
+
($UserFlag -BOR 0x0800) { $List += 'INTERDOMAIN_TRUST_ACCOUNT' }
|
596
|
+
($UserFlag -BOR 0x1000) { $List += 'WORKSTATION_TRUST_ACCOUNT' }
|
597
|
+
($UserFlag -BOR 0x2000) { $List += 'SERVER_TRUST_ACCOUNT' }
|
598
|
+
($UserFlag -BOR 0x10000) { $List += 'DONT_EXPIRE_PASSWORD' }
|
599
|
+
($UserFlag -BOR 0x20000) { $List += 'MNS_LOGON_ACCOUNT' }
|
600
|
+
($UserFlag -BOR 0x40000) { $List += 'SMARTCARD_REQUIRED' }
|
601
|
+
($UserFlag -BOR 0x80000) { $List += 'TRUSTED_FOR_DELEGATION' }
|
602
|
+
($UserFlag -BOR 0x100000) { $List += 'NOT_DELEGATED' }
|
603
|
+
($UserFlag -BOR 0x200000) { $List += 'USE_DES_KEY_ONLY' }
|
604
|
+
($UserFlag -BOR 0x400000) { $List += 'DONT_REQ_PREAUTH' }
|
605
|
+
($UserFlag -BOR 0x800000) { $List += 'PASSWORD_EXPIRED' }
|
606
|
+
($UserFlag -BOR 0x1000000) { $List += 'TRUSTED_TO_AUTH_FOR_DELEGATION' }
|
607
|
+
($UserFlag -BOR 0x04000000) { $List += 'PARTIAL_SECRETS_ACCOUNT' }
|
608
|
+
}
|
609
|
+
$List
|
610
|
+
}
|
611
|
+
|
612
|
+
$Computername = $Env:Computername
|
613
|
+
$adsi = [ADSI]"WinNT://$Computername"
|
614
|
+
$adsi.Children | where {$_.SchemaClassName -eq 'user'} | ForEach {
|
615
|
+
New-Object PSObject -property @{
|
616
|
+
uid = ConvertTo-SID -BinarySID $_.ObjectSID[0]
|
617
|
+
username = $_.Name[0]
|
618
|
+
description = $_.Description[0]
|
619
|
+
disabled = $_.AccountDisabled[0]
|
620
|
+
userflags = Convert-UserFlag -UserFlag $_.UserFlags[0]
|
621
|
+
passwordage = [math]::Round($_.PasswordAge[0]/86400)
|
622
|
+
minpasswordlength = $_.MinPasswordLength[0]
|
623
|
+
mindays = [math]::Round($_.MinPasswordAge[0]/86400)
|
624
|
+
maxdays = [math]::Round($_.MaxPasswordAge[0]/86400)
|
625
|
+
warndays = $null
|
626
|
+
badpasswordattempts = $_.BadPasswordAttempts[0]
|
627
|
+
maxbadpasswords = $_.MaxBadPasswordsAllowed[0]
|
628
|
+
gid = $null
|
629
|
+
group = $null
|
630
|
+
groups = $null
|
631
|
+
home = $_.HomeDirectory[0]
|
632
|
+
shell = $null
|
633
|
+
domain = $Computername
|
634
|
+
}
|
635
|
+
} | ConvertTo-Json
|
595
636
|
EOH
|
596
|
-
|
597
637
|
cmd = inspec.powershell(script)
|
598
|
-
|
599
638
|
# cannot rely on exit code for now, successful command returns exit code 1
|
600
639
|
# return nil if cmd.exit_status != 0, try to parse json
|
601
640
|
begin
|
602
|
-
|
641
|
+
users = JSON.parse(cmd.stdout)
|
603
642
|
rescue JSON::ParserError => _e
|
604
643
|
return nil
|
605
644
|
end
|
606
645
|
|
607
|
-
|
608
|
-
|
609
|
-
#
|
610
|
-
|
611
|
-
group_names = group_hashes.map { |grp| grp['Caption'] }
|
612
|
-
{
|
613
|
-
uid: user_hash['SID'],
|
614
|
-
username: user_hash['Caption'],
|
615
|
-
gid: nil,
|
616
|
-
group: nil,
|
617
|
-
groups: group_names,
|
618
|
-
disabled: user_hash['Disabled'],
|
619
|
-
}
|
620
|
-
end
|
621
|
-
|
622
|
-
# not implemented yet
|
623
|
-
def meta_info(_username)
|
624
|
-
{
|
625
|
-
home: nil,
|
626
|
-
shell: nil,
|
627
|
-
}
|
628
|
-
end
|
629
|
-
|
630
|
-
def list_users
|
631
|
-
script = 'Get-WmiObject Win32_UserAccount | Select-Object -ExpandProperty Caption'
|
632
|
-
cmd = inspec.powershell(script)
|
633
|
-
cmd.stdout.chomp.lines
|
646
|
+
# ensure we have an array of groups
|
647
|
+
users = [users] if !users.is_a?(Array)
|
648
|
+
# convert keys to symbols
|
649
|
+
@users_cache = users.map { |user| user.each_with_object({}) { |(k, v), h| h[k.to_sym] = v } }
|
634
650
|
end
|
635
651
|
end
|
636
652
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dominik Richter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-09-
|
11
|
+
date: 2016-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: train
|
@@ -525,9 +525,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
525
525
|
version: '0'
|
526
526
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
527
527
|
requirements:
|
528
|
-
- - "
|
528
|
+
- - ">="
|
529
529
|
- !ruby/object:Gem::Version
|
530
|
-
version:
|
530
|
+
version: '0'
|
531
531
|
requirements: []
|
532
532
|
rubyforge_project:
|
533
533
|
rubygems_version: 2.4.6
|
@@ -535,3 +535,4 @@ signing_key:
|
|
535
535
|
specification_version: 4
|
536
536
|
summary: Infrastructure and compliance testing.
|
537
537
|
test_files: []
|
538
|
+
has_rdoc:
|