macadmin 0.0.4
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 +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +163 -0
- data/Rakefile +23 -0
- data/ext/macadmin/password/crypto.c +89 -0
- data/ext/macadmin/password/extconf.rb +3 -0
- data/lib/macadmin.rb +22 -0
- data/lib/macadmin/common.rb +80 -0
- data/lib/macadmin/dslocal.rb +252 -0
- data/lib/macadmin/dslocal/computer.rb +22 -0
- data/lib/macadmin/dslocal/computergroup.rb +19 -0
- data/lib/macadmin/dslocal/dslocalnode.rb +281 -0
- data/lib/macadmin/dslocal/group.rb +82 -0
- data/lib/macadmin/dslocal/user.rb +113 -0
- data/lib/macadmin/mcx.rb +227 -0
- data/lib/macadmin/password.rb +72 -0
- data/lib/macadmin/shadowhash.rb +297 -0
- data/lib/macadmin/version.rb +8 -0
- data/macadmin.gemspec +35 -0
- data/spec/common_spec.rb +49 -0
- data/spec/computer_spec.rb +133 -0
- data/spec/computergroup_spec.rb +274 -0
- data/spec/dslocal_spec.rb +179 -0
- data/spec/dslocalnode_spec.rb +343 -0
- data/spec/group_spec.rb +275 -0
- data/spec/macadmin_spec.rb +13 -0
- data/spec/mcx_spec.rb +145 -0
- data/spec/password_spec.rb +40 -0
- data/spec/shadowhash_spec.rb +309 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/user_spec.rb +248 -0
- metadata +218 -0
data/spec/spec_helper.rb
ADDED
data/spec/user_spec.rb
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe MacAdmin::User do
|
5
|
+
|
6
|
+
before :all do
|
7
|
+
@sha1_string = 'AA9E81CD14C2BE42D6D85E6ED3B1A8C6176FAEF3EF4E91B7'
|
8
|
+
@sha512_string = 'a6055f17b5ddd603d284264c7363b7b211df819bc211f7e0047668e4f35ec558a3b5dee1a5cc3a287b9c3b252813782336d07f1bd0579eeaceb00f9bc99c42e349bc1f64'
|
9
|
+
|
10
|
+
# Create a dslocal sandbox
|
11
|
+
@test_dir = "/private/tmp/macadmin_user_test.#{rand(100000)}"
|
12
|
+
MacAdmin::DSLocalRecord.send(:remove_const, :DSLOCAL_ROOT)
|
13
|
+
MacAdmin::SaltedSHA1.send(:remove_const, :SHADOWHASH_STORE)
|
14
|
+
MacAdmin::SaltedSHA1::SHADOWHASH_STORE = File.expand_path @test_dir
|
15
|
+
MacAdmin::DSLocalRecord::DSLOCAL_ROOT = File.expand_path @test_dir
|
16
|
+
FileUtils.mkdir_p "#{@test_dir}/Default/groups"
|
17
|
+
FileUtils.mkdir_p "#{@test_dir}/Default/users"
|
18
|
+
|
19
|
+
# # Create a user record plist that we can load
|
20
|
+
fry = {
|
21
|
+
"uid" => ["501"],
|
22
|
+
"name" => ["fry"],
|
23
|
+
"realname" => ["Phillip J. Fry"],
|
24
|
+
"generateduid" => ["00000000-0000-0000-0000-000000000001"],
|
25
|
+
}
|
26
|
+
|
27
|
+
record = CFPropertyList::List.new
|
28
|
+
record.value = CFPropertyList.guess(fry)
|
29
|
+
record.save("#{@test_dir}/Default/users/#{fry['name'].first}.plist", CFPropertyList::List::FORMAT_BINARY)
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#new' do
|
33
|
+
name = 'bender'
|
34
|
+
subject { User.new name }
|
35
|
+
it { should be_an_instance_of User }
|
36
|
+
it 'should have a valid GeneratedUID attribute' do
|
37
|
+
value = subject[:generateduid].first
|
38
|
+
UUID.valid?(value).should be_true
|
39
|
+
end
|
40
|
+
it 'should have a UID greater or equal to MacAdmin::User::MIN_UID' do
|
41
|
+
value = subject[:uid].first
|
42
|
+
value.to_i.should >= MacAdmin::User::MIN_UID
|
43
|
+
end
|
44
|
+
its (:gid) { should eq ['20'] }
|
45
|
+
its (:name) { should eq [name] }
|
46
|
+
its (:home) { should eq ["/Users/#{name}"] }
|
47
|
+
its (:shell) { should eq ["/bin/bash"] }
|
48
|
+
its (:realname) { should eq [name] }
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#password' do
|
52
|
+
subject { User.new 'fry' }
|
53
|
+
|
54
|
+
context "when the User's password is NOT set" do
|
55
|
+
it { subject.password.should be_nil }
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when the User's password _is_ set" do
|
59
|
+
before do
|
60
|
+
subject.password = SaltedSHA512.new @sha512_string
|
61
|
+
end
|
62
|
+
it { subject.instance_variable_get(:@password).should be_a_kind_of ShadowHash }
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#password=' do
|
68
|
+
user = User.new 'fry'
|
69
|
+
modified = nil
|
70
|
+
subject { user.password = object }
|
71
|
+
|
72
|
+
context 'given a nil object' do
|
73
|
+
let(:object) do
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
it { subject.should be nil }
|
77
|
+
end
|
78
|
+
|
79
|
+
context "given a Password object" do
|
80
|
+
let(:object) do
|
81
|
+
modified = SaltedSHA512.new @sha512_string.reverse
|
82
|
+
end
|
83
|
+
it { subject.password.should eq modified.password }
|
84
|
+
end
|
85
|
+
|
86
|
+
context "given a String object" do
|
87
|
+
let(:object) do
|
88
|
+
String.new
|
89
|
+
end
|
90
|
+
it { expect { subject.password=('') }.to raise_error(ArgumentError) }
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#legacy?' do
|
96
|
+
subject { User.new :name => 'fry', :password => password }
|
97
|
+
|
98
|
+
context 'when the User record has a SHA1 password' do
|
99
|
+
let(:password) do
|
100
|
+
SaltedSHA1.new @sha1_string
|
101
|
+
end
|
102
|
+
it { subject.legacy?.should be_true }
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when the User record has a SaltedSHA512 password' do
|
106
|
+
let(:password) do
|
107
|
+
SaltedSHA512.new @sha512_string
|
108
|
+
end
|
109
|
+
it { subject.legacy?.should be_false }
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#exists?' do
|
115
|
+
|
116
|
+
context 'when the user has a Legacy password' do
|
117
|
+
|
118
|
+
guid = "00000000-0000-0000-0000-000000000001"
|
119
|
+
subject { User.new :name => 'fry', :generateduid => guid, :password => password }
|
120
|
+
|
121
|
+
context 'and the password file exists' do
|
122
|
+
let(:password) do
|
123
|
+
SaltedSHA1.new @sha1_string
|
124
|
+
end
|
125
|
+
let(:password_file) do
|
126
|
+
"#{@test_dir}/#{guid}"
|
127
|
+
end
|
128
|
+
before do
|
129
|
+
File.open(password_file, mode='w') { |f| f.write "0" * 168 + @sha1_string + "0" * 1024 }
|
130
|
+
end
|
131
|
+
it { subject.exists?.should be_true }
|
132
|
+
after do
|
133
|
+
FileUtils.rm password_file
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'and the password file does NOT exist' do
|
138
|
+
let(:password) do
|
139
|
+
SaltedSHA1.new @sha1_string
|
140
|
+
end
|
141
|
+
it { subject.exists?.should be_false }
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'when the user has a SHA512 password' do
|
147
|
+
|
148
|
+
subject { User.new :name => 'fry', :password => SaltedSHA512.new(@sha512_string) }
|
149
|
+
before { subject.create }
|
150
|
+
|
151
|
+
context 'the password matches the value in the corresponding user plist' do
|
152
|
+
it { subject.exists?.should be_true }
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'the password does NOT match the value in the corresponding user plist' do
|
156
|
+
before { subject.password = SaltedSHA512.new(@sha512_string.reverse) }
|
157
|
+
it { subject.exists?.should be_false }
|
158
|
+
end
|
159
|
+
|
160
|
+
after { subject.destroy }
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#create' do
|
166
|
+
|
167
|
+
guid = "00000000-0000-0000-0000-000000000001"
|
168
|
+
subject { User.new :name => 'fry', :generateduid => guid, :password => password }
|
169
|
+
|
170
|
+
context 'when the User record has a SHA1 password' do
|
171
|
+
let(:password) do
|
172
|
+
SaltedSHA1.new @sha1_string
|
173
|
+
end
|
174
|
+
let(:password_file) do
|
175
|
+
"#{@test_dir}/#{guid}"
|
176
|
+
end
|
177
|
+
let(:user_file) do
|
178
|
+
subject.file
|
179
|
+
end
|
180
|
+
it do
|
181
|
+
subject.create.should be_true
|
182
|
+
File.exist?(user_file).should be_true
|
183
|
+
File.exist?(password_file).should be_true
|
184
|
+
end
|
185
|
+
after { FileUtils.rm password_file }
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'when the User record has a SHA512 password' do
|
189
|
+
subject { User.new :name => 'bender', :password => password }
|
190
|
+
let(:password) do
|
191
|
+
SaltedSHA512.new @sha512_string
|
192
|
+
end
|
193
|
+
let(:user_file) do
|
194
|
+
subject.file
|
195
|
+
end
|
196
|
+
it do
|
197
|
+
subject.create.should be_true
|
198
|
+
File.exist?(user_file).should be_true
|
199
|
+
end
|
200
|
+
after { FileUtils.rm user_file }
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
describe '#destroy' do
|
206
|
+
|
207
|
+
context 'when the User record has a SHA1 password' do
|
208
|
+
guid = "00000000-0000-0000-0000-000000000001"
|
209
|
+
subject { User.new :name => 'leela', :generateduid => '331D5FCC-DBE1-4193-9DBF-BC955E997B3E', :password => password }
|
210
|
+
let(:password) do
|
211
|
+
SaltedSHA1.new @sha1_string
|
212
|
+
end
|
213
|
+
let(:password_file) do
|
214
|
+
"#{@test_dir}/#{guid}"
|
215
|
+
end
|
216
|
+
let(:user_file) do
|
217
|
+
subject.file
|
218
|
+
end
|
219
|
+
before { subject.create }
|
220
|
+
it do
|
221
|
+
subject.destroy.should be_true
|
222
|
+
File.exist?(user_file).should be_false
|
223
|
+
File.exist?(password_file).should be_false
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
context 'when the User record has a SHA512 password' do
|
228
|
+
subject { User.new :name => 'zoidberg', :password => password }
|
229
|
+
let(:password) do
|
230
|
+
SaltedSHA512.new @sha512_string
|
231
|
+
end
|
232
|
+
let(:user_file) do
|
233
|
+
subject.file
|
234
|
+
end
|
235
|
+
before { subject.create }
|
236
|
+
it do
|
237
|
+
subject.destroy.should be_true
|
238
|
+
File.exist?(user_file).should be_false
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
after :all do
|
245
|
+
FileUtils.rm_rf @test_dir
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
metadata
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: macadmin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Warsing
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2012-07-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake-compiler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: CFPropertyList
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.3'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake-compiler
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: CFPropertyList
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: Gem to assist in performing common systems administration tasks in Mac
|
140
|
+
OS X
|
141
|
+
email:
|
142
|
+
- dayglojesus@gmail.com
|
143
|
+
executables: []
|
144
|
+
extensions:
|
145
|
+
- ext/macadmin/password/extconf.rb
|
146
|
+
extra_rdoc_files: []
|
147
|
+
files:
|
148
|
+
- .gitignore
|
149
|
+
- .travis.yml
|
150
|
+
- Gemfile
|
151
|
+
- LICENSE.txt
|
152
|
+
- README.md
|
153
|
+
- Rakefile
|
154
|
+
- ext/macadmin/password/crypto.c
|
155
|
+
- ext/macadmin/password/extconf.rb
|
156
|
+
- lib/macadmin.rb
|
157
|
+
- lib/macadmin/common.rb
|
158
|
+
- lib/macadmin/dslocal.rb
|
159
|
+
- lib/macadmin/dslocal/computer.rb
|
160
|
+
- lib/macadmin/dslocal/computergroup.rb
|
161
|
+
- lib/macadmin/dslocal/dslocalnode.rb
|
162
|
+
- lib/macadmin/dslocal/group.rb
|
163
|
+
- lib/macadmin/dslocal/user.rb
|
164
|
+
- lib/macadmin/mcx.rb
|
165
|
+
- lib/macadmin/password.rb
|
166
|
+
- lib/macadmin/shadowhash.rb
|
167
|
+
- lib/macadmin/version.rb
|
168
|
+
- macadmin.gemspec
|
169
|
+
- spec/common_spec.rb
|
170
|
+
- spec/computer_spec.rb
|
171
|
+
- spec/computergroup_spec.rb
|
172
|
+
- spec/dslocal_spec.rb
|
173
|
+
- spec/dslocalnode_spec.rb
|
174
|
+
- spec/group_spec.rb
|
175
|
+
- spec/macadmin_spec.rb
|
176
|
+
- spec/mcx_spec.rb
|
177
|
+
- spec/password_spec.rb
|
178
|
+
- spec/shadowhash_spec.rb
|
179
|
+
- spec/spec_helper.rb
|
180
|
+
- spec/user_spec.rb
|
181
|
+
homepage: http://github.com/dayglojesus/macadmin
|
182
|
+
licenses:
|
183
|
+
- MIT
|
184
|
+
metadata: {}
|
185
|
+
post_install_message:
|
186
|
+
rdoc_options: []
|
187
|
+
require_paths:
|
188
|
+
- lib
|
189
|
+
- ext
|
190
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - '>='
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - '>='
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '0'
|
200
|
+
requirements: []
|
201
|
+
rubyforge_project:
|
202
|
+
rubygems_version: 2.1.10
|
203
|
+
signing_key:
|
204
|
+
specification_version: 4
|
205
|
+
summary: Ruby Mac Systems Administration Library
|
206
|
+
test_files:
|
207
|
+
- spec/common_spec.rb
|
208
|
+
- spec/computer_spec.rb
|
209
|
+
- spec/computergroup_spec.rb
|
210
|
+
- spec/dslocal_spec.rb
|
211
|
+
- spec/dslocalnode_spec.rb
|
212
|
+
- spec/group_spec.rb
|
213
|
+
- spec/macadmin_spec.rb
|
214
|
+
- spec/mcx_spec.rb
|
215
|
+
- spec/password_spec.rb
|
216
|
+
- spec/shadowhash_spec.rb
|
217
|
+
- spec/spec_helper.rb
|
218
|
+
- spec/user_spec.rb
|