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.
@@ -1,132 +0,0 @@
1
- require 'htauth/version'
2
- require 'htauth/errors'
3
- require 'htauth/digest_file'
4
-
5
- require 'ostruct'
6
- require 'optparse'
7
-
8
- require 'highline'
9
-
10
- module HTAuth
11
- class Digest
12
-
13
- MAX_PASSWD_LENGTH = 255
14
-
15
- attr_accessor :digest_file
16
-
17
- def initialize
18
- @digest_file = nil
19
- @option_parser = nil
20
- @options = nil
21
- end
22
-
23
- def options
24
- if @options.nil? then
25
- @options = ::OpenStruct.new
26
- @options.show_version = false
27
- @options.show_help = false
28
- @options.file_mode = DigestFile::ALTER
29
- @options.passwdfile = nil
30
- @options.realm = nil
31
- @options.username = nil
32
- @options.delete_entry = false
33
- end
34
- @options
35
- end
36
-
37
- def option_parser
38
- if not @option_parser then
39
- @option_parser = OptionParser.new do |op|
40
- op.banner = "Usage: #{op.program_name} [options] passwordfile realm username"
41
- op.on("-c", "--create", "Create a new digest password file; this overwrites an existing file.") do |c|
42
- options.file_mode = DigestFile::CREATE
43
- end
44
-
45
- op.on("-D", "--delete", "Delete the specified user.") do |d|
46
- options.delete_entry = d
47
- end
48
-
49
- op.on("-h", "--help", "Display this help.") do |h|
50
- options.show_help = h
51
- end
52
-
53
- op.on("-v", "--version", "Show version info.") do |v|
54
- options.show_version = v
55
- end
56
- end
57
- end
58
- @option_parser
59
- end
60
-
61
- def show_help
62
- $stdout.puts option_parser
63
- exit 1
64
- end
65
-
66
- def show_version
67
- $stdout.puts "#{option_parser.program_name}: version #{HTAuth::VERSION}"
68
- exit 1
69
- end
70
-
71
- def parse_options(argv)
72
- begin
73
- option_parser.parse!(argv)
74
- show_version if options.show_version
75
- show_help if options.show_help or argv.size < 3
76
-
77
- options.passwdfile = argv.shift
78
- options.realm = argv.shift
79
- options.username = argv.shift
80
- rescue ::OptionParser::ParseError => pe
81
- $stderr.puts "ERROR: #{option_parser.program_name} - #{pe}"
82
- $stderr.puts "Try `#{option_parser.program_name} --help` for more information"
83
- exit 1
84
- end
85
- end
86
-
87
- def run(argv, env = ENV)
88
- begin
89
- parse_options(argv)
90
- digest_file = DigestFile.new(options.passwdfile, options.file_mode)
91
-
92
- if options.delete_entry then
93
- digest_file.delete(options.username, options.realm)
94
- else
95
- # initialize here so that if $stdin is overwritten it gets picked up
96
- hl = ::HighLine.new
97
-
98
- action = digest_file.has_entry?(options.username, options.realm) ? "Changing" : "Adding"
99
-
100
- $stdout.puts "#{action} password for #{options.username} in realm #{options.realm}."
101
-
102
- pw_in = hl.ask(" New password: ") { |q| q.echo = '*' }
103
- raise PasswordError, "password '#{pw_in}' too long" if pw_in.length >= MAX_PASSWD_LENGTH
104
-
105
- pw_validate = hl.ask("Re-type new password: ") { |q| q.echo = '*' }
106
- raise PasswordError, "They don't match, sorry." unless pw_in == pw_validate
107
-
108
- digest_file.add_or_update(options.username, options.realm, pw_in)
109
- end
110
-
111
- digest_file.save!
112
-
113
- rescue HTAuth::FileAccessError => fae
114
- msg = "Could not open password file #{options.passwdfile} "
115
- $stderr.puts "#{msg}: #{fae.message}"
116
- $stderr.puts fae.backtrace.join("\n")
117
- exit 1
118
- rescue HTAuth::PasswordError => pe
119
- $stderr.puts "#{pe.message}"
120
- exit 1
121
- rescue HTAuth::DigestFileError => fe
122
- $stderr.puts "#{fe.message}"
123
- exit 1
124
- rescue SignalException => se
125
- $stderr.puts
126
- $stderr.puts "Interrupted #{se}"
127
- exit 1
128
- end
129
- exit 0
130
- end
131
- end
132
- end
@@ -1,10 +0,0 @@
1
- #--
2
- # Copyrigth (c) 2008 Jeremy Hinegardner
3
- # All rights reserved. See LICENSE and/or COPYING for details
4
- #++
5
-
6
- module HTAuth
7
- class FileAccessError < StandardError ; end
8
- class TempFileError < StandardError ; end
9
- class PasswordError < StandardError ; end
10
- end
@@ -1,181 +0,0 @@
1
- require 'htauth/errors'
2
- require 'htauth/passwd_file'
3
-
4
- require 'ostruct'
5
- require 'optparse'
6
-
7
- require 'highline'
8
-
9
- module HTAuth
10
- class Passwd
11
-
12
- MAX_PASSWD_LENGTH = 255
13
-
14
- attr_accessor :passwd_file
15
-
16
- def initialize
17
- @passwd_file = nil
18
- @option_parser = nil
19
- @options = nil
20
- end
21
-
22
- def options
23
- if @options.nil? then
24
- @options = ::OpenStruct.new
25
- @options.batch_mode = false
26
- @options.file_mode = File::ALTER
27
- @options.passwdfile = nil
28
- @options.algorithm = Algorithm::EXISTING
29
- @options.send_to_stdout = false
30
- @options.show_version = false
31
- @options.show_help = false
32
- @options.username = nil
33
- @options.delete_entry = false
34
- @options.password = ""
35
- end
36
- @options
37
- end
38
-
39
- def option_parser
40
- if not @option_parser then
41
- @option_parser = OptionParser.new do |op|
42
- op.banner = <<EOB
43
- Usage:
44
- #{op.program_name} [-cmdpsD] passwordfile username
45
- #{op.program_name} -b[cmdpsD] passwordfile username password
46
-
47
- #{op.program_name} -n[mdps] username
48
- #{op.program_name} -nb[mdps] username password
49
- EOB
50
-
51
- op.separator ""
52
-
53
- op.on("-b", "--batch", "Batch mode, get the password from the command line, rather than prompt") do |b|
54
- options.batch_mode = b
55
- end
56
-
57
- op.on("-c", "--create", "Create a new file; this overwrites an existing file.") do |c|
58
- options.file_mode = HTAuth::File::CREATE
59
- end
60
-
61
- op.on("-d", "--crypt", "Force CRYPT encryption of the password.") do |c|
62
- options.algorithm = "crypt"
63
- end
64
-
65
- op.on("-D", "--delete", "Delete the specified user.") do |d|
66
- options.delete_entry = d
67
- end
68
-
69
- op.on("-h", "--help", "Display this help.") do |h|
70
- options.show_help = h
71
- end
72
-
73
- op.on("-m", "--md5", "Force MD5 encryption of the password (default).") do |m|
74
- options.algorithm = "md5"
75
- end
76
-
77
- op.on("-n", "--stdout", "Do not update the file; Display the results on stdout instead.") do |n|
78
- options.send_to_stdout = true
79
- options.passwdfile = HTAuth::File::STDOUT_FLAG
80
- end
81
-
82
- op.on("-p", "--plaintext", "Do not encrypt the password (plaintext).") do |p|
83
- options.algorithm = "plaintext"
84
- end
85
-
86
- op.on("-s", "--sha1", "Force SHA encryption of the password.") do |s|
87
- options.algorithm = "sha1"
88
- end
89
-
90
- op.on("-v", "--version", "Show version info.") do |v|
91
- options.show_version = v
92
- end
93
-
94
- op.separator ""
95
-
96
- op.separator "The SHA algorihtm does not use a salt and is less secure than the MD5 algorithm"
97
- end
98
- end
99
- @option_parser
100
- end
101
-
102
- def show_help
103
- $stdout.puts option_parser
104
- exit 1
105
- end
106
-
107
- def show_version
108
- $stdout.puts "#{option_parser.program_name}: version #{HTAuth::VERSION}"
109
- exit 1
110
- end
111
-
112
- def parse_options(argv)
113
- begin
114
- option_parser.parse!(argv)
115
- show_version if options.show_version
116
- show_help if options.show_help
117
-
118
- raise ::OptionParser::ParseError, "Unable to send to stdout AND create a new file" if options.send_to_stdout and (options.file_mode == File::CREATE)
119
- raise ::OptionParser::ParseError, "a username is needed" if options.send_to_stdout and argv.size < 1
120
- raise ::OptionParser::ParseError, "a username and password are needed" if options.send_to_stdout and options.batch_mode and ( argv.size < 2 )
121
- raise ::OptionParser::ParseError, "a passwordfile, username and password are needed " if not options.send_to_stdout and options.batch_mode and ( argv.size < 3 )
122
- raise ::OptionParser::ParseError, "a passwordfile and username are needed" if argv.size < 2
123
-
124
- options.passwdfile = argv.shift unless options.send_to_stdout
125
- options.username = argv.shift
126
- options.password = argv.shift if options.batch_mode
127
-
128
- rescue ::OptionParser::ParseError => pe
129
- $stderr.puts "ERROR: #{option_parser.program_name} - #{pe}"
130
- show_help
131
- exit 1
132
- end
133
- end
134
-
135
- def run(argv, env = ENV)
136
- begin
137
- parse_options(argv)
138
- passwd_file = PasswdFile.new(options.passwdfile, options.file_mode)
139
-
140
- if options.delete_entry then
141
- passwd_file.delete(options.username)
142
- else
143
- unless options.batch_mode
144
- # initialize here so that if $stdin is overwritten it gets picked up
145
- hl = ::HighLine.new
146
-
147
- action = passwd_file.has_entry?(options.username) ? "Changing" : "Adding"
148
-
149
- $stdout.puts "#{action} password for #{options.username}."
150
-
151
- pw_in = hl.ask(" New password: ") { |q| q.echo = '*' }
152
- raise PasswordError, "password '#{pw_in}' too long" if pw_in.length >= MAX_PASSWD_LENGTH
153
-
154
- pw_validate = hl.ask("Re-type new password: ") { |q| q.echo = '*' }
155
- raise PasswordError, "They don't match, sorry." unless pw_in == pw_validate
156
- options.password = pw_in
157
- end
158
- passwd_file.add_or_update(options.username, options.password, options.algorithm)
159
- end
160
-
161
- passwd_file.save!
162
-
163
- rescue HTAuth::FileAccessError => fae
164
- msg = "Password file failure (#{options.passwdfile}) "
165
- $stderr.puts "#{msg}: #{fae.message}"
166
- exit 1
167
- rescue HTAuth::PasswordError => pe
168
- $stderr.puts "#{pe.message}"
169
- exit 1
170
- rescue HTAuth::PasswdFileError => fe
171
- $stderr.puts "#{fe.message}"
172
- exit 1
173
- rescue SignalException => se
174
- $stderr.puts
175
- $stderr.puts "Interrupted #{se}"
176
- exit 1
177
- end
178
- exit 0
179
- end
180
- end
181
- end
@@ -1,150 +0,0 @@
1
- require 'spec_helper'
2
- require 'htauth/digest'
3
- require 'tempfile'
4
-
5
- describe HTAuth::Digest do
6
-
7
- before(:each) do
8
-
9
- # existing
10
- @tf = Tempfile.new("rpasswrd-digest-test")
11
- @tf.write(IO.read(DIGEST_ORIGINAL_TEST_FILE))
12
- @tf.close
13
- @rdigest = HTAuth::Digest.new
14
-
15
- # new file
16
- @new_file = File.join(File.dirname(@tf.path), "new-testfile")
17
-
18
- # rework stdout and stderr
19
- @stdout = StringIO.new
20
- @old_stdout = $stdout
21
- $stdout = @stdout
22
-
23
- @stderr = StringIO.new
24
- @old_stderr = $stderr
25
- $stderr = @stderr
26
-
27
- @stdin = StringIO.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
- @rdigest.run([ "-h" ])
43
- rescue SystemExit => se
44
- se.status.must_equal 1
45
- @stdout.string.must_match( /passwordfile realm username/m )
46
- end
47
- end
48
-
49
- it "displays the version appropriately" do
50
- begin
51
- @rdigest.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 entries" do
59
- begin
60
- @stdin.puts "b secret"
61
- @stdin.puts "b secret"
62
- @stdin.rewind
63
- @rdigest.run([ "-c", @new_file, "htauth", "bob" ])
64
- rescue SystemExit => se
65
- se.status.must_equal 0
66
- IO.read(@new_file).must_equal IO.readlines(DIGEST_ORIGINAL_TEST_FILE).first
67
- end
68
- end
69
-
70
- it "truncates an exiting file if told to create a new file" do
71
- begin
72
- @stdin.puts "b secret"
73
- @stdin.puts "b secret"
74
- @stdin.rewind
75
- @rdigest.run([ "-c", @tf.path, "htauth", "bob"])
76
- rescue SystemExit => se
77
- se.status.must_equal 0
78
- IO.read(@tf.path).must_equal IO.read(DIGEST_DELETE_TEST_FILE)
79
- end
80
- end
81
-
82
- it "adds an entry to an existing file" do
83
- begin
84
- @stdin.puts "c secret"
85
- @stdin.puts "c secret"
86
- @stdin.rewind
87
- @rdigest.run([ @tf.path, "htauth-new", "charlie" ])
88
- rescue SystemExit => se
89
- se.status.must_equal 0
90
- IO.read(@tf.path).must_equal IO.read(DIGEST_ADD_TEST_FILE)
91
- end
92
- end
93
-
94
- it "updates an entry in an existing file" do
95
- begin
96
- @stdin.puts "a new secret"
97
- @stdin.puts "a new secret"
98
- @stdin.rewind
99
- @rdigest.run([ @tf.path, "htauth", "alice" ])
100
- rescue SystemExit => se
101
- @stderr.string.must_equal ""
102
- se.status.must_equal 0
103
- IO.read(@tf.path).must_equal IO.read(DIGEST_UPDATE_TEST_FILE)
104
- end
105
- end
106
-
107
- it "deletes an entry in an existing file" do
108
- begin
109
- @rdigest.run([ "-d", @tf.path, "htauth", "alice" ])
110
- rescue SystemExit => se
111
- @stderr.string.must_equal ""
112
- se.status.must_equal 0
113
- IO.read(@tf.path).must_equal IO.read(DIGEST_DELETE_TEST_FILE)
114
- end
115
- end
116
-
117
- it "has an error if it does not have permissions on the file" do
118
- begin
119
- @stdin.puts "a secret"
120
- @stdin.puts "a secret"
121
- @stdin.rewind
122
- @rdigest.run([ "-c", "/etc/you-cannot-create-me", "htauth", "alice"])
123
- rescue SystemExit => se
124
- @stderr.string.must_match( %r{Could not open password file /etc/you-cannot-create-me}m )
125
- se.status.must_equal 1
126
- end
127
- end
128
-
129
- it "has an error if the input passwords do not match" do
130
- begin
131
- @stdin.puts "a secret"
132
- @stdin.puts "a bad secret"
133
- @stdin.rewind
134
- @rdigest.run([ @tf.path, "htauth", "alice"])
135
- rescue SystemExit => se
136
- @stderr.string.must_match( /They don't match, sorry./m )
137
- se.status.must_equal 1
138
- end
139
- end
140
-
141
- it "has an error if the options are incorrect" do
142
- begin
143
- @rdigest.run(["--blah"])
144
- rescue SystemExit => se
145
- @stderr.string.must_match( /ERROR:/m )
146
- se.status.must_equal 1
147
- end
148
- end
149
-
150
- end