htauth 1.2.0 → 2.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.
@@ -0,0 +1,206 @@
1
+ require 'spec_helper'
2
+ require 'htauth/cli/passwd'
3
+ require 'tempfile'
4
+
5
+ describe HTAuth::CLI::Passwd do
6
+
7
+ before(:each) do
8
+
9
+ # existing
10
+ @tf = Tempfile.new("rpasswrd-passwd-test")
11
+ @tf.write(IO.read(PASSWD_ORIGINAL_TEST_FILE))
12
+ @tf.close
13
+ @htauth = HTAuth::CLI::Passwd.new
14
+
15
+ # new file
16
+ @new_file = File.join(File.dirname(@tf.path), "new-testfile")
17
+
18
+ # rework stdout and stderr
19
+ @stdout = ConsoleIO.new
20
+ @old_stdout = $stdout
21
+ $stdout = @stdout
22
+
23
+ @stderr = ConsoleIO.new
24
+ @old_stderr = $stderr
25
+ $stderr = @stderr
26
+
27
+ @stdin = ConsoleIO.new
28
+ @old_stdin = $stdin
29
+ $stdin = @stdin
30
+ end
31
+
32
+ after(:each) do
33
+ @tf.close(true)
34
+ $stderr = @old_stderr
35
+ $stdout = @old_stdout
36
+ $stdin = @old_stdin
37
+ File.unlink(@new_file) if File.exist?(@new_file)
38
+ end
39
+
40
+ it "displays help appropriately" do
41
+ begin
42
+ @htauth.run([ "-h" ])
43
+ rescue SystemExit => se
44
+ se.status.must_equal 1
45
+ @stdout.string.must_match( /passwordfile username/m )
46
+ end
47
+ end
48
+
49
+ it "displays the version appropriately" do
50
+ begin
51
+ @htauth.run([ "--version" ])
52
+ rescue SystemExit => se
53
+ se.status.must_equal 1
54
+ @stdout.string.must_match( /version #{HTAuth::VERSION}/)
55
+ end
56
+ end
57
+
58
+ it "creates a new file with one md5 entry" do
59
+ begin
60
+ @stdin.puts "a secret"
61
+ @stdin.puts "a secret"
62
+ @stdin.rewind
63
+ @htauth.run([ "-m", "-c", @new_file, "alice" ])
64
+ rescue SystemExit => se
65
+ se.status.must_equal 0
66
+ l = IO.readlines(@new_file)
67
+ fields = l.first.split(':')
68
+ fields.first.must_equal "alice"
69
+ fields.last.must_match( /^\$apr1\$/ )
70
+ end
71
+ end
72
+
73
+ it "truncates an exiting file if told to create a new file" do
74
+ before_lines = IO.readlines(@tf.path)
75
+ begin
76
+ @stdin.puts "b secret"
77
+ @stdin.puts "b secret"
78
+ @stdin.rewind
79
+ @htauth.run([ "-c", @tf.path, "bob"])
80
+ rescue SystemExit => se
81
+ se.status.must_equal 0
82
+ after_lines = IO.readlines(@tf.path)
83
+ after_lines.size.must_equal 1
84
+ before_lines.size.must_equal 2
85
+ end
86
+ end
87
+
88
+ it "adds an entry to an existing file and force SHA" do
89
+ begin
90
+ @stdin.puts "c secret"
91
+ @stdin.puts "c secret"
92
+ @stdin.rewind
93
+ @htauth.run([ "-s", @tf.path, "charlie" ])
94
+ rescue SystemExit => se
95
+ se.status.must_equal 0
96
+ after_lines = IO.readlines(@tf.path)
97
+ after_lines.size.must_equal 3
98
+ al = after_lines.last.split(':')
99
+ al.first.must_equal "charlie"
100
+ al.last.must_match( /\{SHA\}/ )
101
+ end
102
+ end
103
+
104
+ it "can create a plaintext encrypted file" do
105
+ begin
106
+ @stdin.puts "a bad password"
107
+ @stdin.puts "a bad password"
108
+ @stdin.rewind
109
+ @htauth.run(["-c", "-p", @tf.path, "bradley"])
110
+ rescue SystemExit => se
111
+ se.status.must_equal 0
112
+ IO.read(@tf.path).strip.must_equal "bradley:a bad password"
113
+ end
114
+ end
115
+
116
+ it "has a batch mode for command line passwords" do
117
+ begin
118
+ @htauth.run(["-c", "-p", "-b", @tf.path, "bradley", "a bad password"])
119
+ rescue SystemExit => se
120
+ se.status.must_equal 0
121
+ IO.read(@tf.path).strip.must_equal "bradley:a bad password"
122
+ end
123
+ end
124
+
125
+ it "updates an entry in an existing file and force crypt" do
126
+ before_lines = IO.readlines(@tf.path)
127
+ begin
128
+ @stdin.puts "a new secret"
129
+ @stdin.puts "a new secret"
130
+ @stdin.rewind
131
+ @htauth.run([ "-d", @tf.path, "alice" ])
132
+ rescue SystemExit => se
133
+ @stderr.string.must_equal ""
134
+ se.status.must_equal 0
135
+ after_lines = IO.readlines(@tf.path)
136
+ after_lines.size.must_equal before_lines.size
137
+
138
+ a_b = before_lines.first.split(":")
139
+ a_a = after_lines.first.split(":")
140
+
141
+ a_b.first.must_equal a_a.first
142
+ a_b.last.wont_equal a_a.last
143
+ end
144
+ end
145
+
146
+ it "deletes an entry in an existing file" do
147
+ begin
148
+ @htauth.run([ "-D", @tf.path, "bob" ])
149
+ rescue SystemExit => se
150
+ @stderr.string.must_equal ""
151
+ se.status.must_equal 0
152
+ IO.read(@tf.path).must_equal IO.read(PASSWD_DELETE_TEST_FILE)
153
+ end
154
+ end
155
+
156
+ it "sends to STDOUT when the -n option is used" do
157
+ begin
158
+ @htauth.run(["-n", "-p", "-b", "bradley", "a bad password"])
159
+ rescue SystemExit => se
160
+ se.status.must_equal 0
161
+ @stdout.string.strip.must_equal "bradley:a bad password"
162
+ end
163
+ end
164
+
165
+ it "has an error if it does not have permissions on the file" do
166
+ begin
167
+ @stdin.puts "a secret"
168
+ @stdin.puts "a secret"
169
+ @stdin.rewind
170
+ @htauth.run([ "-c", "/etc/you-cannot-create-me", "alice"])
171
+ rescue SystemExit => se
172
+ @stderr.string.must_match( %r{Password file failure \(/etc/you-cannot-create-me\)}m )
173
+ se.status.must_equal 1
174
+ end
175
+ end
176
+
177
+ it "has an error if the input passwords do not match" do
178
+ begin
179
+ @stdin.puts "a secret"
180
+ @stdin.puts "a bad secret"
181
+ @stdin.rewind
182
+ @htauth.run([ @tf.path, "alice"])
183
+ rescue SystemExit => se
184
+ @stderr.string.must_match( /They don't match, sorry./m )
185
+ se.status.must_equal 1
186
+ end
187
+ end
188
+
189
+ it "has an error if the options are incorrect" do
190
+ begin
191
+ @htauth.run(["--blah"])
192
+ rescue SystemExit => se
193
+ @stderr.string.must_match( /ERROR:/m )
194
+ se.status.must_equal 1
195
+ end
196
+ end
197
+
198
+ it "errors if send to stdout and create a new file options are both used" do
199
+ begin
200
+ @htauth.run(["-c", "-n"])
201
+ rescue SystemExit => se
202
+ @stderr.string.must_match( /ERROR:/m )
203
+ se.status.must_equal 1
204
+ end
205
+ end
206
+ end
@@ -2,59 +2,59 @@ require 'spec_helper'
2
2
  require 'htauth/digest_entry'
3
3
 
4
4
  describe HTAuth::DigestEntry do
5
- before(:each) do
6
- @alice = HTAuth::DigestEntry.new("alice", "htauth")
7
- @bob = HTAuth::DigestEntry.new("bob", "htauth", "b secret")
8
- end
9
-
10
- it "initializes with a user and realm" do
11
- @alice.user.must_equal "alice"
12
- @alice.realm.must_equal "htauth"
13
- end
14
-
15
- it "has the correct digest for a password" do
16
- @alice.password = "digit"
17
- @alice.digest.must_equal "4ed9e5744c6747af8f292d28afd6372e"
18
- end
19
-
20
- it "returns username:realm for a key" do
21
- @alice.key.must_equal "alice:htauth"
22
- end
23
-
24
- it "checks the password correctly" do
25
- @bob.authenticated?("b secret").must_equal true
26
- end
27
-
28
- it "formats correctly when put to a string" do
29
- @bob.to_s.must_equal "bob:htauth:fcbeab6821d2ab3b00934c958db0fd1e"
30
- end
31
-
32
- it "parses an input line" do
33
- @bob_new = HTAuth::DigestEntry.from_line("bob:htauth:fcbeab6821d2ab3b00934c958db0fd1e")
34
- @bob.user.must_equal @bob_new.user
35
- @bob.digest.must_equal @bob_new.digest
36
- @bob.realm.must_equal @bob_new.realm
37
- end
38
-
39
- it "knows if an input line is a possible entry and raises an exception" do
40
- lambda { HTAuth::DigestEntry.is_entry!("#stuff") }.must_raise(HTAuth::InvalidDigestEntry)
41
- lambda { HTAuth::DigestEntry.is_entry!("this:that:other:stuff") }.must_raise(HTAuth::InvalidDigestEntry)
42
- lambda { HTAuth::DigestEntry.is_entry!("this:that:other") }.must_raise(HTAuth::InvalidDigestEntry)
43
- lambda { HTAuth::DigestEntry.is_entry!("this:that:0a90549e8ffb2dd62f98252a95d88xyz") }.must_raise(HTAuth::InvalidDigestEntry)
44
- end
45
-
46
- it "knows if an input line is a possible entry and returns false" do
47
- HTAuth::DigestEntry.is_entry?("#stuff").must_equal false
48
- HTAuth::DigestEntry.is_entry?("this:that:other:stuff").must_equal false
49
- HTAuth::DigestEntry.is_entry?("this:that:other").must_equal false
50
- HTAuth::DigestEntry.is_entry?("this:that:0a90549e8ffb2dd62f98252a95d88xyz").must_equal false
51
- end
52
-
53
- it "knows if an input line is a possible entry and returns true" do
54
- HTAuth::DigestEntry.is_entry?("bob:htauth:0a90549e8ffb2dd62f98252a95d88697").must_equal true
55
- end
56
-
57
- it "duplicates itself" do
58
- @alice.dup.to_s.must_equal @alice.to_s
59
- end
5
+ before(:each) do
6
+ @alice = HTAuth::DigestEntry.new("alice", "htauth")
7
+ @bob = HTAuth::DigestEntry.new("bob", "htauth", "b secret")
8
+ end
9
+
10
+ it "initializes with a user and realm" do
11
+ @alice.user.must_equal "alice"
12
+ @alice.realm.must_equal "htauth"
13
+ end
14
+
15
+ it "has the correct digest for a password" do
16
+ @alice.password = "digit"
17
+ @alice.digest.must_equal "4ed9e5744c6747af8f292d28afd6372e"
18
+ end
19
+
20
+ it "returns username:realm for a key" do
21
+ @alice.key.must_equal "alice:htauth"
22
+ end
23
+
24
+ it "checks the password correctly" do
25
+ @bob.authenticated?("b secret").must_equal true
26
+ end
27
+
28
+ it "formats correctly when put to a string" do
29
+ @bob.to_s.must_equal "bob:htauth:fcbeab6821d2ab3b00934c958db0fd1e"
30
+ end
31
+
32
+ it "parses an input line" do
33
+ @bob_new = HTAuth::DigestEntry.from_line("bob:htauth:fcbeab6821d2ab3b00934c958db0fd1e")
34
+ @bob.user.must_equal @bob_new.user
35
+ @bob.digest.must_equal @bob_new.digest
36
+ @bob.realm.must_equal @bob_new.realm
37
+ end
38
+
39
+ it "knows if an input line is a possible entry and raises an exception" do
40
+ lambda { HTAuth::DigestEntry.is_entry!("#stuff") }.must_raise(HTAuth::InvalidDigestEntry)
41
+ lambda { HTAuth::DigestEntry.is_entry!("this:that:other:stuff") }.must_raise(HTAuth::InvalidDigestEntry)
42
+ lambda { HTAuth::DigestEntry.is_entry!("this:that:other") }.must_raise(HTAuth::InvalidDigestEntry)
43
+ lambda { HTAuth::DigestEntry.is_entry!("this:that:0a90549e8ffb2dd62f98252a95d88xyz") }.must_raise(HTAuth::InvalidDigestEntry)
44
+ end
45
+
46
+ it "knows if an input line is a possible entry and returns false" do
47
+ HTAuth::DigestEntry.is_entry?("#stuff").must_equal false
48
+ HTAuth::DigestEntry.is_entry?("this:that:other:stuff").must_equal false
49
+ HTAuth::DigestEntry.is_entry?("this:that:other").must_equal false
50
+ HTAuth::DigestEntry.is_entry?("this:that:0a90549e8ffb2dd62f98252a95d88xyz").must_equal false
51
+ end
52
+
53
+ it "knows if an input line is a possible entry and returns true" do
54
+ HTAuth::DigestEntry.is_entry?("bob:htauth:0a90549e8ffb2dd62f98252a95d88697").must_equal true
55
+ end
56
+
57
+ it "duplicates itself" do
58
+ @alice.dup.to_s.must_equal @alice.to_s
59
+ end
60
60
  end
@@ -4,62 +4,62 @@ require 'tempfile'
4
4
 
5
5
  describe HTAuth::DigestFile do
6
6
 
7
- before(:each) do
8
- @tf = Tempfile.new("rpasswrd-digest")
9
- @tf.write(IO.read(DIGEST_ORIGINAL_TEST_FILE))
10
- @tf.close
11
- @digest_file = HTAuth::DigestFile.new(@tf.path)
12
-
13
- @tf2 = Tempfile.new("rpasswrd-digest-empty")
14
- @tf2.close
15
- @empty_digest_file = HTAuth::DigestFile.new(@tf2.path)
16
- end
7
+ before(:each) do
8
+ @tf = Tempfile.new("rpasswrd-digest")
9
+ @tf.write(IO.read(DIGEST_ORIGINAL_TEST_FILE))
10
+ @tf.close
11
+ @digest_file = HTAuth::DigestFile.new(@tf.path)
17
12
 
18
- after(:each) do
19
- @tf2.close(true)
20
- @tf.close(true)
21
- end
13
+ @tf2 = Tempfile.new("rpasswrd-digest-empty")
14
+ @tf2.close
15
+ @empty_digest_file = HTAuth::DigestFile.new(@tf2.path)
16
+ end
22
17
 
23
- it "can add a new entry to an already existing digest file" do
24
- @digest_file.add_or_update("charlie", "htauth-new", "c secret")
25
- @digest_file.contents.must_equal IO.read(DIGEST_ADD_TEST_FILE)
26
- end
18
+ after(:each) do
19
+ @tf2.close(true)
20
+ @tf.close(true)
21
+ end
27
22
 
28
- it "can tell if an entry already exists in the digest file" do
29
- @digest_file.has_entry?("alice", "htauth").must_equal true
30
- @digest_file.has_entry?("alice", "some other realm").must_equal false
31
- end
32
-
33
- it "can update an entry in an already existing digest file" do
34
- @digest_file.add_or_update("alice", "htauth", "a new secret")
35
- @digest_file.contents.must_equal IO.read(DIGEST_UPDATE_TEST_FILE)
36
- end
23
+ it "can add a new entry to an already existing digest file" do
24
+ @digest_file.add_or_update("charlie", "htauth-new", "c secret")
25
+ @digest_file.contents.must_equal IO.read(DIGEST_ADD_TEST_FILE)
26
+ end
37
27
 
38
- it "fetches a copy of an entry" do
39
- @digest_file.fetch("alice", "htauth").to_s.must_equal "alice:htauth:2f361db93147d84831eb34f19d05bfbb"
40
- end
28
+ it "can tell if an entry already exists in the digest file" do
29
+ @digest_file.has_entry?("alice", "htauth").must_equal true
30
+ @digest_file.has_entry?("alice", "some other realm").must_equal false
31
+ end
41
32
 
42
- it "raises an error if an attempt is made to alter a non-existenet file" do
43
- lambda { HTAuth::DigestFile.new("some-file") }.must_raise(HTAuth::FileAccessError)
44
- end
33
+ it "can update an entry in an already existing digest file" do
34
+ @digest_file.add_or_update("alice", "htauth", "a new secret")
35
+ @digest_file.contents.must_equal IO.read(DIGEST_UPDATE_TEST_FILE)
36
+ end
45
37
 
46
- # this test will only work on systems that have /etc/ssh_host_rsa_key
47
- it "raises an error if an attempt is made to open a file where no permissions are granted" do
48
- lambda { HTAuth::DigestFile.new("/etc/ssh_host_rsa_key") }.must_raise(HTAuth::FileAccessError)
49
- end
38
+ it "fetches a copy of an entry" do
39
+ @digest_file.fetch("alice", "htauth").to_s.must_equal "alice:htauth:2f361db93147d84831eb34f19d05bfbb"
40
+ end
50
41
 
51
- it "deletes an entry" do
52
- @digest_file.delete("alice", "htauth")
53
- @digest_file.contents.must_equal IO.read(DIGEST_DELETE_TEST_FILE)
54
- end
55
-
56
- it "is usable in a ruby manner and yeilds itself when opened" do
57
- HTAuth::DigestFile.open(@tf.path) do |pf|
58
- pf.add_or_update("alice", "htauth", "a secret")
59
- pf.delete('bob', 'htauth')
60
- end
61
- lines = IO.readlines(@tf.path)
62
- lines.size.must_equal 1
63
- lines.first.strip.must_equal "alice:htauth:2f361db93147d84831eb34f19d05bfbb"
42
+ it "raises an error if an attempt is made to alter a non-existenet file" do
43
+ lambda { HTAuth::DigestFile.new("some-file") }.must_raise(HTAuth::FileAccessError)
44
+ end
45
+
46
+ # this test will only work on systems that have /etc/ssh_host_rsa_key
47
+ it "raises an error if an attempt is made to open a file where no permissions are granted" do
48
+ lambda { HTAuth::DigestFile.new("/etc/ssh_host_rsa_key") }.must_raise(HTAuth::FileAccessError)
49
+ end
50
+
51
+ it "deletes an entry" do
52
+ @digest_file.delete("alice", "htauth")
53
+ @digest_file.contents.must_equal IO.read(DIGEST_DELETE_TEST_FILE)
54
+ end
55
+
56
+ it "is usable in a ruby manner and yeilds itself when opened" do
57
+ HTAuth::DigestFile.open(@tf.path) do |pf|
58
+ pf.add_or_update("alice", "htauth", "a secret")
59
+ pf.delete('bob', 'htauth')
64
60
  end
61
+ lines = IO.readlines(@tf.path)
62
+ lines.size.must_equal 1
63
+ lines.first.strip.must_equal "alice:htauth:2f361db93147d84831eb34f19d05bfbb"
64
+ end
65
65
  end
@@ -3,15 +3,15 @@ require File.join(File.dirname(__FILE__),"spec_helper.rb")
3
3
  require 'htauth/md5'
4
4
 
5
5
  describe HTAuth::Md5 do
6
- it "has a prefix" do
7
- HTAuth::Md5.new.prefix.must_equal "$apr1$"
8
- end
6
+ it "has a prefix" do
7
+ HTAuth::Md5.new.prefix.must_equal "$apr1$"
8
+ end
9
9
 
10
- it "encrypts the same way that apache does" do
11
- apache_salt = "L0LDd/.."
12
- apache_result = "$apr1$L0LDd/..$yhUzDjpxam5F1kWdtwMco1"
13
- md5 = HTAuth::Md5.new({ 'salt' => apache_salt })
14
- md5.encode("a secret").must_equal apache_result
15
- end
10
+ it "encrypts the same way that apache does" do
11
+ apache_salt = "L0LDd/.."
12
+ apache_result = "$apr1$L0LDd/..$yhUzDjpxam5F1kWdtwMco1"
13
+ md5 = HTAuth::Md5.new({ 'salt' => apache_salt })
14
+ md5.encode("a secret").must_equal apache_result
15
+ end
16
16
  end
17
17