File: test_user_password.rb

package info (click to toggle)
ruby-activeldap 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 1,588 kB
  • sloc: ruby: 18,143; sh: 12; makefile: 5
file content (194 lines) | stat: -rw-r--r-- 6,536 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
require 'al-test-utils'

class TestUserPassword < Test::Unit::TestCase
  priority :must

  priority :normal
  def test_valid?
    {
      "{CRYPT}.yNLaKqtwQbnY" => 'wibble', #CRYPT
      "{MD5}DRB9CfW75Ayt495ccenptw==" => 'letmein', #MD5
      "{SMD5}8L2iXJuazftLVHrAf7ptPFQIDaw=" => 'letmein', #SMD5 as generated by slappasswd (4 bytes of salt)
      "{SMD5}kXibTNG+O98gaQtkugYcmSTiE+M2Z5TA" => 'letmein', #SMD5 as generated by Apache Directory Studio (8 bytes of salt)
      "{SMD5}4PkkYH5qI6ydk/9pwvZD3DYwYzVlMzVlLTBkZDEtNGJhMi05NjI5LWRlODgyMDhiMWZmYQ==" => 'letmein', #SMD5 generated with 36 bytes of salt
      "{SHA}t6h1/B6iKLkGEEG3zsS9PFKrPOM=" => 'letmein', #SHA
      "{SSHA}YA87hc9/L/cCGR1HValcJb7a8AYxZXY4" => 'wibble', # SSHA as generated by slappasswd (4 bytes of salt)
      "{SSHA}6J6Ios3l1panY9sm0+g9l3/jFz2kwOPrVA4+OA==" => 'letmein', # SSHA as generated by Apache Directory Studio (8 bytes of salt)
      "{SSHA}f/j1unqoJg1C1zjw8tvxSp4xpow2MGM1ZTM1ZS0wZGQxLTRiYTItOTYyOS1kZTg4MjA4YjFmZmE=" => 'letmein', #SSHA generated with 36 bytes of salt
      "letmein" => 'letmein', #Cleartext password
    }.each do |hash, plain|
      assert_send([ActiveLdap::UserPassword, :valid?,
                   plain, hash])
      assert_not_send([ActiveLdap::UserPassword, :valid?,
                   "not#{plain}", hash])
    end
  end

  sub_test_case("crypt") do
    def test_encrypt
      salt = ".WoUoU9f3IlUx9Hh7D/8y.xA6ziklGib"
      assert_equal("{CRYPT}.W57FZhV52w0s",
                   ActiveLdap::UserPassword.crypt("password", salt))

      password = "PASSWORD"
      hashed_password = ActiveLdap::UserPassword.crypt(password)
      salt = hashed_password.sub(/^\{CRYPT\}/, '')
      assert_equal(hashed_password,
                   ActiveLdap::UserPassword.crypt(password, salt))
    end

    sub_test_case("extract_salt") do
      sub_test_case("base format") do
        def test_less
          message = "salt size must be 2: <a>"
          assert_raise(ArgumentError.new(message)) do
            extract_salt(:crypt, "a")
          end
        end

        def test_exact
          assert_extract_salt(:crypt, "ab", "ab")
        end

        def test_more
          assert_extract_salt(:crypt, "ab", "abc")
        end
      end

      sub_test_case("glibc2 format") do
        sub_test_case("ID") do
          def test_md5
            assert_extract_salt(:crypt, "$1$abcdefgh$", "$1$abcdefgh$")
          end

          def test_blowfish
            assert_extract_salt(:crypt, "$2a$abcdefgh$", "$2a$abcdefgh$")
          end

          def test_sha256
            assert_extract_salt(:crypt, "$5$abcdefgh$", "$5$abcdefgh$")
          end

          def test_sha512
            assert_extract_salt(:crypt, "$6$abcdefgh$", "$6$abcdefgh$")
          end
        end

        sub_test_case("salt") do
          def test_not_teminated
            message = "salt character must be [a-zA-Z0-9./]: <$1>"
            assert_raise(ArgumentError.new(message)) do
              extract_salt(:crypt, "$1$")
            end
          end

          def test_empty
            assert_extract_salt(:crypt, "$1$$", "$1$$")
          end

          def test_lower_case
            assert_extract_salt(:crypt, "$1$abc$", "$1$abc$")
          end

          def test_upper_case
            assert_extract_salt(:crypt, "$1$ABC$", "$1$ABC$")
          end

          def test_digit
            assert_extract_salt(:crypt, "$1$012$", "$1$012$")
          end

          def test_dot
            assert_extract_salt(:crypt, "$1$...$", "$1$...$")
          end

          def test_slash
            assert_extract_salt(:crypt, "$1$///$", "$1$///$")
          end

          def test_mix
            assert_extract_salt(:crypt, "$1$aA0./$", "$1$aA0./$")
          end

          def test_max
            assert_extract_salt(:crypt,
                                "$1$0123456789abcdef$",
                                "$1$0123456789abcdef$")
          end

          def test_over
            message = "salt character must be [a-zA-Z0-9./]: <$1>"
            assert_raise(ArgumentError.new(message)) do
              extract_salt(:crypt, "$1$0123456789abcdefg$")
            end
          end
        end
      end
    end
  end

  def test_md5
    assert_equal("{MD5}X03MO1qnZdYdgyfeuILPmQ==",
                 ActiveLdap::UserPassword.md5("password"))
  end

  def test_smd5
    assert_equal("{SMD5}gjz+SUSfZaux99Xsji/No200cGI=",
                 ActiveLdap::UserPassword.smd5("password", "m4pb"))

    password = "PASSWORD"
    hashed_password = ActiveLdap::UserPassword.smd5(password)
    salt = decode64(hashed_password.sub(/^\{SMD5\}/, ''))[-4, 4]
    assert_equal(hashed_password,
                 ActiveLdap::UserPassword.smd5(password, salt))
  end

  def test_extract_salt_for_smd5
    assert_extract_salt(:smd5, 'this', encode64("1234567890123456this"))
    assert_extract_salt(:smd5, 'this is the salt', encode64("1234567890123456this is the salt"))
    assert_extract_salt(:smd5, nil, encode64("123456789"))
    assert_extract_salt(:smd5, nil, encode64("123456789012345"))
    assert_extract_salt(:smd5, nil, encode64("1234567890123456"))
  end

  def test_sha
    assert_equal("{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=",
                 ActiveLdap::UserPassword.sha("password"))
  end

  def test_ssha
    assert_equal("{SSHA}ipnlCLA1HaK3mm3hyneJIp+Px2h1RGk3",
                 ActiveLdap::UserPassword.ssha("password", "uDi7"))

    password = "PASSWORD"
    hashed_password = ActiveLdap::UserPassword.ssha(password)
    salt = decode64(hashed_password.sub(/^\{SSHA\}/, ''))[-4, 4]
    assert_equal(hashed_password,
                 ActiveLdap::UserPassword.ssha(password, salt))
  end

  def test_extract_salt_for_ssha
    assert_extract_salt(:ssha, 'this', encode64("12345678901234567890this"))
    assert_extract_salt(:ssha, 'this is the salt', encode64("12345678901234567890this is the salt"))
    assert_extract_salt(:ssha, nil, encode64("12345678901234"))
    assert_extract_salt(:ssha, nil, encode64("1234567890123456789"))
    assert_extract_salt(:ssha, nil, encode64("12345678901234567890"))
  end

  private
  def extract_salt(type, hashed_password)
    ActiveLdap::UserPassword.send("extract_salt_for_#{type}",
                                  hashed_password)
  end
  def assert_extract_salt(type, expected, hashed_password)
    assert_equal(expected, extract_salt(type, hashed_password))
  end

  def encode64(string)
    [string].pack('m').chomp
  end

  def decode64(string)
    string.unpack('m')[0]
  end
end