• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yast / yast-users / 5453098972

pending completion
5453098972

Pull #383

github

web-flow
Merge 54d62cefa into f91b954c3
Pull Request #383: User creation page got messed when going back after importing user(s) from existing installation

16 of 16 new or added lines in 1 file covered. (100.0%)

3319 of 5513 relevant lines covered (60.2%)

35.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

5.2
/src/include/users/ldap_dialogs.rb
1
# encoding: utf-8
2

3
# ------------------------------------------------------------------------------
4
# Copyright (c) 2006-2012 Novell, Inc. All Rights Reserved.
5
#
6
#
7
# This program is free software; you can redistribute it and/or modify it under
8
# the terms of version 2 of the GNU General Public License as published by the
9
# Free Software Foundation.
10
#
11
# This program is distributed in the hope that it will be useful, but WITHOUT
12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License along with
16
# this program; if not, contact Novell, Inc.
17
#
18
# To contact Novell about this file by physical or electronic mail, you may find
19
# current contact information at www.novell.com.
20
# ------------------------------------------------------------------------------
21

22
# File:        include/users/widgets.ycp
23
# Package:        Configuration of users and groups
24
# Summary:        Widgets definitions and helper functions
25
# Authors:        Jiri Suchomel <jsuchome@suse.cz>
26
#
27
# $Id$
28
module Yast
1✔
29
  module UsersLdapDialogsInclude
1✔
30
    def initialize_users_ldap_dialogs(include_target)
1✔
31
      Yast.import "UI"
18✔
32

33
      Yast.import "Label"
18✔
34
      Yast.import "Ldap"
18✔
35
      Yast.import "LdapPopup"
18✔
36
      Yast.import "Popup"
18✔
37
      Yast.import "Users"
18✔
38
      Yast.import "Wizard"
18✔
39

40
      textdomain "users"
18✔
41
    end
42

43
    # dialog for Password Policy configuration object
44
    # @param [Hash] ppolicy data with Password Policy object to be edited (as obtained from LDAP search)
45
    # @return [Hash] with modifications of ppolicy object, nil in case of `cancel
46
    def PasswordPolicyDialog(ppolicy)
1✔
47
      ppolicy = deep_copy(ppolicy)
×
48
      # reduce the list values to single ones
49
      ppolicy = Builtins.mapmap(
×
50
        Convert.convert(ppolicy, :from => "map", :to => "map <string, any>")
51
      ) do |a, val|
52
        if Ops.is_list?(val) &&
×
53
            (Ldap.SingleValued(a) || Builtins.size(Convert.to_list(val)) == 1)
54
          val = Ops.get(Convert.to_list(val), 0)
×
55
        end
56
        val = val == "TRUE" if val == "TRUE" || val == "FALSE"
×
57
        { a => val }
×
58
      end
59
      ppolicy_orig = deep_copy(ppolicy)
×
60

61
      # help text for Password Policy Dialog
62
      help_text = _(
×
63
        "<p>Select the <b>Password Change Policies</b>, <b>Password Aging Policies</b>, and <b>Lockout Policies</b> tabs to choose LDAP password policy groups of attributes to configure.</p>"
64
      )
65

66

67
      # tab-specific help texts
68
      tabs_help_text = {
69
        # help text for pwdInHistory attribute
70
        :pwchange => _(
×
71
          "<p>Specify the <b>Maximum Number of Passwords Stored in History</b> to set how many previously used passwords should be saved. Saved passwords may not be used.</p>"
72
        ) +
73
          # help text for pwdMustChange attribute
74
          _(
75
            "<p>Check <b>User Must Change Password after Reset</b> to force users to change their passwords after the the password is reset or changed by an administrator.</p>"
76
          ) +
77
          # help text for pwdAllowUserChange attribute
78
          _(
79
            "<p>Check <b>User Can Change Password</b> to allow users to change their passwords.</p>"
80
          ) +
81
          # help text for pwdSafeModify attribute
82
          _(
83
            "<p>If the existing password must be provided along with the new password, check <b>Old Password Required for Password Change</b>.</p>"
84
          ) +
85
          # help text for pwdCheckQuality attribute
86
          _(
87
            "<p>Select whether the password quality should be verified while passwords are modified or added. Select <b>No Checking</b> if passwords should not be checked at all. With <b>Accept Uncheckable Passwords</b>, passwords are accepted even if the check cannot be performed, for example, if the user has provided an encrypted password. With <b>Only Accept Checked Passwords</b> passwords are refused if the quality test fails or the password cannot be checked.</p>"
88
          ) +
89
          # help text for pwdMinLength attribute
90
          _(
91
            "Set the minimum number of characters that must be used in a password in <b>Minimum Password Length</b>.</p>"
92
          ),
93
        # help text for pwdMinAge attribute
94
        :aging    => _(
95
          "<p><b>Minimum Password Age</b> sets how much time must pass between modifications to the password.</p>"
96
        ) +
97
          # help text for pwdMaxAge attribute
98
          _(
99
            "<p><b>Maximum Password Age</b> sets how long after modification a password expires.</p>"
100
          ) +
101
          # help text for pwdExpireWarning attribute
102
          _(
103
            "<p>In <b>Time before Password Expiration to Issue Warning</b> set how long before a password is due to expire that an expiration warning messages should be given to an authenticating user.</p>"
104
          ) +
105
          # help text for pwdGraceAuthNLimit attribute
106
          _(
107
            "<p>Set the number of times an expired password can be used to authenticate in <b>Allowed Uses of an Expired Password</b>.</p>"
108
          ),
109
        # help text for pwdLockout attribute
110
        :lockout  => _(
111
          "<p>Check <b>Enable Password Locking</b> to forbid use of a password after a specified number of consecutive failed bind attempts.</p>"
112
        ) +
113
          # help text for pwdMaxFailure attribute
114
          _(
115
            "<p>Set the number of consecutive failed bind  attempts after which the password may not be used to authenticate in <b>Bind Failures to Lock the Password</b>.</p>"
116
          ) +
117
          # help text for pwdLockoutDuration attribute
118
          _(
119
            "<p>Set how long the password cannot be used in <b>Password Lock Duration</b>.</p>"
120
          ) +
121
          # help text for pwdFailureCountInterval attribute
122
          _(
123
            "<p><b>Bind Failures Cache Duration</b> sets how long before password failures are purged from the failure counter even though no successful authentication has occurred.</p>"
124
          )
125
      }
126

127
      # map of attribute names for each tab
128
      attributes = {
129
        :pwchange => [
×
130
          "pwdInHistory",
131
          "pwdMustChange",
132
          "pwdAllowUserChange",
133
          "pwdSafeModify",
134
          "pwdCheckQuality",
135
          "pwdMinLength"
136
        ],
137
        :aging    => [
138
          "pwdMinAge",
139
          "pwdMaxAge",
140
          "pwdExpireWarning",
141
          "pwdGraceAuthNLimit"
142
        ],
143
        :lockout  => [
144
          "pwdLockout",
145
          "pwdLockoutDuration",
146
          "pwdMaxFailure",
147
          "pwdFailureCountInterval"
148
        ]
149
      }
150

151
      time_attributes = [
152
        "pwdMinAge",
×
153
        "pwdMaxAge",
154
        "pwdExpireWarning",
155
        "pwdLockoutDuration",
156
        "pwdFailureCountInterval"
157
      ]
158

159
      default_values = {
×
160
        "pwdMustChange"      => false,
161
        "pwdAllowUserChange" => true,
162
        "pwdSafeModify"      => false,
163
        "pwdLockout"         => false
164
      }
165

166
      # maximal value of IntFields
167
      max = 99999
×
168

169
      tabs = [
170
        # tab label
171
        Item(Id(:pwchange), _("&Password Change Policies"), true),
×
172
        # tab label
173
        Item(Id(:aging), _("Pa&ssword Aging Policies")),
174
        # tab label
175
        Item(Id(:lockout), _("&Lockout Policies"))
176
      ]
177
      tabs_term = VBox(
×
178
        DumbTab(Id(:tabs), tabs, ReplacePoint(Id(:tabContents), VBox(Empty())))
179
      )
180
      has_tabs = true
×
181
      if !UI.HasSpecialWidget(:DumbTab)
×
182
        has_tabs = false
×
183
        tabbar = HBox()
×
184
        Builtins.foreach(tabs) do |it|
×
185
          label = Ops.get_string(it, 1, "")
×
186
          tabbar = Builtins.add(tabbar, PushButton(Ops.get_term(it, 0) do
×
187
            Id(label)
×
188
          end, label))
189
        end
190
        tabs_term = VBox(
×
191
          Left(tabbar),
192
          Frame("", ReplacePoint(Id(:tabContents), Empty()))
193
        )
194
      end
195

196
      contents = deep_copy(tabs_term)
×
197

198
      # generate the term of password policy tab and update the help text
199
      set_password_policies_term = lambda do
×
200
        pwdcheckquality = Builtins.tointeger(
×
201
          Ops.get_string(ppolicy, "pwdCheckQuality", "0")
202
        )
203
        tab_cont = Top(
×
204
          HBox(
205
            HSpacing(0.5),
206
            VBox(
207
              VSpacing(0.8),
208
              IntField(
209
                Id("pwdInHistory"),
210
                # IntField label
211
                _("Ma&ximum Number of Passwords Stored in History"),
212
                0,
213
                max,
214
                Builtins.tointeger(Ops.get_string(ppolicy, "pwdInHistory", "0"))
215
              ),
216
              VSpacing(0.4),
217
              Left(
218
                CheckBox(
219
                  Id("pwdMustChange"),
220
                  # checkbox label
221
                  _("U&ser Must Change Password after Reset"),
222
                  Ops.get_boolean(ppolicy, "pwdMustChange", true)
223
                )
224
              ),
225
              VSpacing(0.2),
226
              Left(
227
                CheckBox(
228
                  Id("pwdAllowUserChange"),
229
                  # checkbox label
230
                  _("&User Can Change Password"),
231
                  Ops.get_boolean(ppolicy, "pwdAllowUserChange", true)
232
                )
233
              ),
234
              VSpacing(0.2),
235
              Left(
236
                CheckBox(
237
                  Id("pwdSafeModify"),
238
                  # checkbox label
239
                  _("&Old Password Required for Password Change"),
240
                  Ops.get_boolean(ppolicy, "pwdSafeModify", false)
241
                )
242
              ),
243
              VSpacing(0.4),
244
              # frame label
245
              HBox(
246
                HSpacing(2),
247
                Frame(
248
                  _("Password Quality Checking"),
249
                  VBox(
250
                    VSpacing(0.5),
251
                    RadioButtonGroup(
252
                      Id("pwdCheckQuality"),
253
                      VBox(
254
                        Left(
255
                          RadioButton(
256
                            Id(0),
257
                            Opt(:notify),
258
                            _("&No Checking"),
259
                            pwdcheckquality == 0
260
                          )
261
                        ),
262
                        Left(
263
                          RadioButton(
264
                            Id(1),
265
                            Opt(:notify),
266
                            _("Acc&ept Uncheckable Passwords"),
267
                            pwdcheckquality == 1
268
                          )
269
                        ),
270
                        Left(
271
                          RadioButton(
272
                            Id(2),
273
                            Opt(:notify),
274
                            _("&Only Accept Checked Passwords"),
275
                            pwdcheckquality == 2
276
                          )
277
                        )
278
                      )
279
                    ),
280
                    VSpacing(0.4),
281
                    # IntField label
282
                    IntField(
283
                      Id("pwdMinLength"),
284
                      _("&Minimum Password Length"),
285
                      0,
286
                      max,
287
                      Builtins.tointeger(
288
                        Ops.get_string(ppolicy, "pwdMinLength", "0")
289
                      )
290
                    )
291
                  )
292
                )
293
              )
294
            ),
295
            HSpacing(0.5)
296
          )
297
        )
298

299
        UI.ReplaceWidget(:tabContents, tab_cont)
×
300
        UI.ChangeWidget(
×
301
          Id("pwdMinLength"),
302
          :Enabled,
303
          Ops.greater_than(pwdcheckquality, 0)
304
        )
305
        nil
×
306
      end
307

308
      time_dialog = lambda do |id, label|
×
309
        value = Builtins.tointeger(Ops.get_string(ppolicy, id, "0"))
×
310
        days = Ops.divide(value, 24 * 60 * 60)
×
311
        if Ops.greater_than(days, 0)
×
312
          value = Ops.subtract(
×
313
            value,
314
            Ops.multiply(Ops.multiply(Ops.multiply(days, 24), 60), 60)
315
          )
316
        end
317
        hours = Ops.divide(value, 60 * 60)
×
318
        if Ops.greater_than(hours, 0)
×
319
          value = Ops.subtract(value, Ops.multiply(Ops.multiply(hours, 60), 60))
×
320
        end
321
        minutes = Ops.divide(value, 60)
×
322
        if Ops.greater_than(minutes, 0)
×
323
          value = Ops.subtract(value, Ops.multiply(minutes, 60))
×
324
        end
325
        HBox(
×
326
          HSpacing(0.3),
327
          Frame(
328
            label,
329
            HBox(
330
              IntField(Id(Ops.add(id, "d")), _("Days"), 0, max, days),
331
              IntField(Id(Ops.add(id, "h")), _("Hours"), 0, 23, hours),
332
              IntField(Id(Ops.add(id, "m")), _("Minutes"), 0, 59, minutes),
333
              IntField(Id(Ops.add(id, "s")), _("Seconds"), 0, 59, value)
334
            )
335
          ),
336
          HSpacing(0.3)
337
        )
338
      end
339

340
      get_seconds_value = lambda do |attr|
×
341
        days = Convert.to_integer(
×
342
          UI.QueryWidget(Id(Ops.add(attr, "d")), :Value)
343
        )
344
        hours = Convert.to_integer(
×
345
          UI.QueryWidget(Id(Ops.add(attr, "h")), :Value)
346
        )
347
        minutes = Convert.to_integer(
×
348
          UI.QueryWidget(Id(Ops.add(attr, "m")), :Value)
349
        )
350
        seconds = Convert.to_integer(
×
351
          UI.QueryWidget(Id(Ops.add(attr, "s")), :Value)
352
        )
353
        Ops.add(
×
354
          Ops.add(
355
            Ops.add(
356
              Ops.multiply(Ops.multiply(Ops.multiply(days, 24), 60), 60),
357
              Ops.multiply(Ops.multiply(hours, 60), 60)
358
            ),
359
            Ops.multiply(minutes, 60)
360
          ),
361
          seconds
362
        )
363
      end
364

365
      # generate the term of password aging tab
366
      set_aging_policies_term = lambda do
×
367
        tab_cont = Top(
×
368
          HBox(
369
            HSpacing(0.5),
370
            VBox(
371
              VSpacing(0.7),
372
              # frame label
373
              time_dialog.call("pwdMinAge", _("Minimum Password Age")),
374
              VSpacing(0.4),
375
              # frame label
376
              time_dialog.call("pwdMaxAge", _("Maximum Password Age")),
377
              VSpacing(0.4),
378
              time_dialog.call(
379
                "pwdExpireWarning",
380
                # frame label
381
                _("Time before Password Expiration to Issue Warning")
382
              ),
383
              VSpacing(0.2),
384
              IntField(
385
                Id("pwdGraceAuthNLimit"),
386
                # IntField label
387
                _("Allowed Uses of an Expired Password"),
388
                0,
389
                max,
390
                Builtins.tointeger(
391
                  Ops.get_string(ppolicy, "pwdGraceAuthNLimit", "0")
392
                )
393
              )
394
            ),
395
            HSpacing(0.5)
396
          )
397
        )
398
        UI.ReplaceWidget(:tabContents, tab_cont)
×
399
        nil
×
400
      end
401

402
      # generate the term of lockout aging tab
403
      set_lockout_policies_term = lambda do
×
404
        pwdlockout = Ops.get_boolean(ppolicy, "pwdLockout", false)
×
405

406
        tab_cont = Top(
×
407
          HBox(
408
            HSpacing(0.5),
409
            VBox(
410
              VSpacing(0.8),
411
              Left(
412
                CheckBox(
413
                  Id("pwdLockout"),
414
                  Opt(:notify),
415
                  # check box label
416
                  _("Enable Password Locking"),
417
                  pwdlockout
418
                )
419
              ),
420
              VSpacing(0.4),
421
              IntField(
422
                Id("pwdMaxFailure"),
423
                # intField label
424
                _("Bind Failures to Lock the Password"),
425
                0,
426
                max,
427
                Builtins.tointeger(
428
                  Ops.get_string(ppolicy, "pwdMaxFailure", "0")
429
                )
430
              ),
431
              # frame label
432
              time_dialog.call(
433
                "pwdLockoutDuration",
434
                _("Password Lock Duration")
435
              ),
436
              VSpacing(0.4),
437
              time_dialog.call(
438
                "pwdFailureCountInterval",
439
                # frame label
440
                _("Bind Failures Cache Duration")
441
              )
442
            ),
443
            HSpacing(0.5)
444
          )
445
        )
446

447
        UI.ReplaceWidget(:tabContents, tab_cont)
×
448
        UI.ChangeWidget(Id("pwdMaxFailure"), :Enabled, pwdlockout)
×
449
        Builtins.foreach(["d", "h", "m", "s"]) do |suffix|
×
450
          UI.ChangeWidget(
×
451
            Id(Ops.add("pwdLockoutDuration", suffix)),
452
            :Enabled,
453
            pwdlockout
454
          )
455
          UI.ChangeWidget(
×
456
            Id(Ops.add("pwdFailureCountInterval", suffix)),
457
            :Enabled,
458
            pwdlockout
459
          )
460
        end
461
        nil
×
462
      end
463

464
      current_tab = :pwchange
×
465
      result = nil
×
466

467
      Wizard.OpenNextBackDialog
×
468

469
      # dialog label
470
      Wizard.SetContentsButtons(
×
471
        _("Password Policy Configuration"),
472
        contents,
473
        Ops.add(help_text, Ops.get_string(tabs_help_text, current_tab, "")),
474
        Label.CancelButton,
475
        Label.OKButton
476
      )
477
      Wizard.HideAbortButton
×
478

479
      set_password_policies_term.call
×
480

481
      while true
×
482
        result = UI.UserInput
×
483

484
        if Ops.is_symbol?(result) &&
×
485
            Builtins.contains(
486
              [:back, :cancel, :abort],
487
              Convert.to_symbol(result)
488
            )
489
          break
×
490
        end
491

492
        # save the values from UI
493
        Builtins.foreach(Ops.get_list(attributes, current_tab, [])) do |attr|
×
494
          if Builtins.contains(time_attributes, attr)
×
495
            Ops.set(
×
496
              ppolicy,
497
              attr,
498
              Builtins.sformat("%1", get_seconds_value.call(attr))
499
            )
500
            next
×
501
          end
502
          val = UI.QueryWidget(Id(attr), :Value)
×
503
          val = Builtins.sformat("%1", val) if Ops.is_integer?(val)
×
504
          Ops.set(ppolicy, attr, val)
×
505
        end
506

507
        if (result == :pwchange || result == :aging || result == :lockout) &&
×
508
            result != current_tab
509
          if result == :pwchange
×
510
            set_password_policies_term.call
×
511
          elsif result == :aging
×
512
            set_aging_policies_term.call
×
513
          elsif result == :lockout
×
514
            set_lockout_policies_term.call
×
515
          end
516
          current_tab = Convert.to_symbol(result)
×
517
          UI.ChangeWidget(Id(:tabs), :CurrentItem, current_tab) if has_tabs
×
518
          Wizard.SetHelpText(
×
519
            Ops.add(help_text, Ops.get_string(tabs_help_text, current_tab, ""))
520
          )
521
          next
×
522
        end
523
        if result == :next
×
524
          cont = false
×
525

526
          # check the template required attributes...
527
          Builtins.foreach(Ops.get_list(ppolicy, "objectClass", [])) do |oc|
×
528
            next if cont
×
529
            Builtins.foreach(Ldap.GetRequiredAttributes(oc)) do |attr|
×
530
              val = Ops.get(ppolicy, attr)
×
531
              if !cont && val == nil || val == [] || val == ""
×
532
                #error popup, %1 is attribute name
533
                Popup.Error(
×
534
                  Builtins.sformat(
535
                    _("The \"%1\" attribute is mandatory.\nEnter a value."),
536
                    attr
537
                  )
538
                )
539
                UI.SetFocus(Id(:table))
×
540
                cont = true
×
541
              end
542
            end
543
          end
544
          next if cont
×
545
          break
×
546
        end
547
        # now solve events inside the tabs
548
        if current_tab == :pwchange && Ops.is_integer?(result)
×
549
          UI.ChangeWidget(Id("pwdMinLength"), :Enabled, result != 0)
×
550
        end
551
        if current_tab == :lockout && result == "pwdLockout"
×
552
          pwdlockout = Convert.to_boolean(
×
553
            UI.QueryWidget(Id("pwdLockout"), :Value)
554
          )
555
          UI.ChangeWidget(Id("pwdMaxFailure"), :Enabled, pwdlockout)
×
556
          Builtins.foreach(["d", "h", "m", "s"]) do |suffix|
×
557
            UI.ChangeWidget(
×
558
              Id(Ops.add("pwdFailureCountInterval", suffix)),
559
              :Enabled,
560
              pwdlockout
561
            )
562
            UI.ChangeWidget(
×
563
              Id(Ops.add("pwdLockoutDuration", suffix)),
564
              :Enabled,
565
              pwdlockout
566
            )
567
          end
568
        end
569
      end
570
      Wizard.CloseDialog
×
571

572
      ret = {}
×
573
      if result == :next
×
574
        Builtins.foreach(
×
575
          Convert.convert(ppolicy, :from => "map", :to => "map <string, any>")
576
        ) do |key, val|
577
          if !Builtins.haskey(ppolicy_orig, key) &&
×
578
              (val == Ops.get(default_values, key) || val == "0")
579
            next
×
580
          end
581
          if val != Ops.get(ppolicy_orig, key)
×
582
            val = val == true ? "TRUE" : "FALSE" if Ops.is_boolean?(val)
×
583
            Ops.set(ret, key, val)
×
584
          end
585
        end
586
      end
587
      result == :next ? ret : nil
×
588
    end
589

590
    # Dialog for administering User & Group specific LDAP settigns
591
    def LdapAdministrationDialog
1✔
592
      Users.SetLdapSettingsRead(Ldap.Read) if !Users.LdapSettingsRead
×
593

594
      base_dn = Ldap.GetBaseDN
×
595
      file_server = Ldap.file_server
×
596
      modified = true
×
597

598
      ppolicy_list = []
×
599

600
      ppolicies_enabled = false
×
601
      ppolicies = {}
×
602
      ppolicies_orig = {}
×
603
      ppolicies_deleted = [] # list of DN
×
604

605
      # map with modifications of Password Policies objects
606
      write_ppolicies = {}
×
607

608
      # read the list of pwdpolicy objects under base_config_dn
609
      read_ppolicies = lambda do
×
610
        return if base_dn == ""
×
611

612
        if Ldap.ldap_initialized && Ldap.tls_when_initialized != Ldap.ldap_tls
×
613
          Ldap.LDAPClose
×
614
        end
615

616
        if Ldap.ldap_initialized || Ldap.LDAPInit == ""
×
617
          ppolicies_enabled = Convert.to_boolean(
×
618
            SCR.Execute(
619
              path(".ldap.ppolicy"),
620
              {
621
                "hostname" => Ldap.GetFirstServer(Ldap.server),
622
                "bind_dn"  => Ldap.GetBaseDN
623
              }
624
            )
625
          )
626

627
          schemas = Convert.to_list(
×
628
            SCR.Read(
629
              path(".ldap.search"),
630
              {
631
                "base_dn" => "",
632
                "attrs"   => ["subschemaSubentry"],
633
                "scope"   => 0
634
              }
635
            )
636
          )
637
          schema_dn = Ops.get_string(schemas, [0, "subschemaSubentry", 0], "")
×
638
          if schemas != nil && schema_dn != "" &&
×
639
              SCR.Execute(path(".ldap.schema"), { "schema_dn" => schema_dn }) == true
640
            pp = Convert.convert(
×
641
              SCR.Read(
642
                path(".ldap.search"),
643
                {
644
                  "base_dn"      => base_dn,
645
                  "filter"       => "objectClass=pwdPolicy",
646
                  "scope"        => 2,
647
                  "map"          => true,
648
                  "not_found_ok" => true
649
                }
650
              ),
651
              :from => "any",
652
              :to   => "map <string, map>"
653
            )
654
            if pp != nil
×
655
              ppolicies = deep_copy(pp)
×
656
              ppolicies_orig = deep_copy(ppolicies)
×
657
            end
658
          end
659
        end
660

661
        nil
×
662
      end
663

664
      read_ppolicies.call
×
665

666
      help_text = _("<p><b>Home Directories</b></p>") +
×
667
        # help text
668
        _(
669
          "<p>If home directories of LDAP users should be stored on this machine,\n" +
670
            "check the appropriate option. Changing this value does not cause any direct\n" +
671
            "action.  It is only information for the YaST users module, which can manage\n" +
672
            "user home directories.</p>\n"
673
        ) + # help text caption
674
        # help text
675
        _(
676
          "<p>Press <b>Configure</b> to configure settings stored on the\n" +
677
            "LDAP server. You will be asked for the password if you are not connected yet or\n" +
678
            "have changed your configuration.</p>\n"
679
        ) +
680
        # password policy help text caption
681
        _("<p><b>Password Policy</b></p>") +
682
        # password policy help
683
        _(
684
          "<p>Configure the selected password policy with <b>Edit</b>. Use <b>Add</b> to add a new password policy. The configuration is only possible,\n  if the password policies are already enabled on the LDAP server.</p>"
685
        )
686

687
      contents = VBox(
×
688
        VSpacing(0.4),
689
        Left(
690
          CheckBox(
691
            Id(:file_server),
692
            # checkbox label
693
            _("&Home Directories on This Machine"),
694
            file_server
695
          )
696
        ),
697
        VSpacing(0.5),
698
        Right(
699
          PushButton(
700
            Id(:configure),
701
            # pushbutton label
702
            _("Configure User Management &Settings...")
703
          )
704
        ),
705
        VSpacing(),
706
        Table(
707
          Id(:ppolicy_table),
708
          Opt(:notify),
709
          Header(
710
            # table header
711
            _("Password Policy")
712
          ),
713
          Builtins.maplist(ppolicies) { |dn, pp| Item(Id(dn), dn) }
×
714
        ),
715
        HBox(
716
          PushButton(Id(:add), Label.AddButton),
717
          PushButton(Id(:edit), Label.EditButton),
718
          PushButton(Id(:delete), Label.DeleteButton),
719
          HStretch()
720
        ),
721
        VSpacing(0.4)
722
      )
723

724
      Wizard.CreateDialog
×
725
      # dialog title
726
      Wizard.SetContentsButtons(
×
727
        _("LDAP Administration Settings"),
728
        contents,
729
        help_text,
730
        Label.CancelButton,
731
        Label.OKButton
732
      )
733
      Wizard.HideAbortButton
×
734

735
      Builtins.foreach([:ppolicy_table, :add, :edit, :delete]) do |s|
×
736
        UI.ChangeWidget(Id(s), :Enabled, ppolicies_enabled)
×
737
      end
738

739
      ret = :cancel
×
740

741
      while true
×
742
        ret = Convert.to_symbol(UI.UserInput)
×
743
        if ret == :add
×
744
          suffix = base_dn
×
745
          UI.OpenDialog(
×
746
            Opt(:decorated),
747
            HBox(
748
              HSpacing(1),
749
              VBox(
750
                # InputField label
751
                InputField(
752
                  Id(:cn),
753
                  Opt(:hstretch),
754
                  _("Name of Password Policy Object")
755
                ),
756
                ReplacePoint(
757
                  Id(:rp_suf),
758
                  HBox(
759
                    # text label,suffix will follow in next label
760
                    Label(Id(:suffix_label), _("Suffix:")),
761
                    Label(Id(:suffix), base_dn),
762
                    # pushbutton label
763
                    PushButton(Id(:br_suf), _("Change Suffix"))
764
                  )
765
                ),
766
                ButtonBox(
767
                  PushButton(Id(:ok), Opt(:default, :key_F10), Label.OKButton),
768
                  PushButton(Id(:cancel), Opt(:key_F9), Label.CancelButton)
769
                )
770
              ),
771
              HSpacing(1)
772
            )
773
          )
774
          UI.SetFocus(Id(:cn))
×
775
          ret2 = nil
×
776
          new_dn = ""
×
777
          while true
×
778
            ret2 = UI.UserInput
×
779
            break if ret2 == :cancel
×
780
            if ret2 == :br_suf
×
781
              suf = LdapPopup.InitAndBrowseTree(
×
782
                base_dn,
783
                {
784
                  "hostname"   => Ldap.GetFirstServer(Ldap.server),
785
                  "port"       => Ldap.GetFirstPort(Ldap.server),
786
                  "use_tls"    => Ldap.ldap_tls ? "yes" : "no",
×
787
                  "cacertdir"  => Ldap.tls_cacertdir,
788
                  "cacertfile" => Ldap.tls_cacertfile
789
                }
790
              )
791
              if suf != ""
×
792
                UI.ReplaceWidget(
×
793
                  Id(:rp_suf),
794
                  HBox(
795
                    # text label,suffix will follow in next label
796
                    Label(Id(:suffix_label), _("Suffix:")),
797
                    Label(Id(:suffix), suf),
798
                    # pushbutton label
799
                    PushButton(Id(:br_suf), _("Change Suffix"))
800
                  )
801
                )
802
              end
803
            end
804
            if ret2 == :ok
×
805
              cn = Convert.to_string(UI.QueryWidget(Id(:cn), :Value))
×
806
              break if cn == ""
×
807
              suffix2 = Convert.to_string(UI.QueryWidget(Id(:suffix), :Value))
×
808
              new_dn = Builtins.sformat("cn=%1,%2", cn, suffix2)
×
809
              if Builtins.haskey(ppolicies, new_dn)
×
810
                Popup.Error(
×
811
                  Builtins.sformat(
812
                    _(
813
                      "The Policy '%1' already exists.\nPlease select another one."
814
                    ),
815
                    new_dn
816
                  )
817
                )
818
                next
×
819
              end
820
              break
×
821
            end
822
          end
823
          UI.CloseDialog
×
824
          if ret2 == :ok && new_dn != ""
×
825
            new = PasswordPolicyDialog({ "dn" => new_dn })
×
826
            if new != nil
×
827
              Ops.set(ppolicies, new_dn, new)
×
828
              UI.ChangeWidget(
×
829
                Id(:ppolicy_table),
830
                :Items,
831
                Builtins.maplist(ppolicies) { |dn, pp| Item(Id(dn), dn) }
×
832
              )
833
              UI.ChangeWidget(
×
834
                Id(:edit),
835
                :Enabled,
836
                Ops.greater_than(Builtins.size(ppolicies), 0)
837
              )
838
              UI.ChangeWidget(
×
839
                Id(:delete),
840
                :Enabled,
841
                Ops.greater_than(Builtins.size(ppolicies), 0)
842
              )
843
            end
844
          end
845
        end
846
        if ret == :edit || ret == :ppolicy_table
×
847
          dn = Convert.to_string(
×
848
            UI.QueryWidget(Id(:ppolicy_table), :CurrentItem)
849
          )
850
          changes = PasswordPolicyDialog(Ops.get(ppolicies, dn, {}))
×
851
          if changes != nil
×
852
            Ops.set(
×
853
              ppolicies,
854
              dn,
855
              Builtins.union(Ops.get(ppolicies, dn, {}), changes)
856
            )
857
          end
858
        end
859
        if ret == :delete
×
860
          dn = Convert.to_string(
×
861
            UI.QueryWidget(Id(:ppolicy_table), :CurrentItem)
862
          )
863
          ppolicies = Builtins.remove(ppolicies, dn)
×
864
          ppolicies_deleted = Convert.convert(
×
865
            Builtins.union(ppolicies_deleted, [dn]),
866
            :from => "list",
867
            :to   => "list <string>"
868
          )
869
          UI.ChangeWidget(
×
870
            Id(:ppolicy_table),
871
            :Items,
872
            Builtins.maplist(ppolicies) { |dn2, pp| Item(Id(dn2), dn2) }
×
873
          )
874
          UI.ChangeWidget(
×
875
            Id(:edit),
876
            :Enabled,
877
            Ops.greater_than(Builtins.size(ppolicies), 0)
878
          )
879
          UI.ChangeWidget(
×
880
            Id(:delete),
881
            :Enabled,
882
            Ops.greater_than(Builtins.size(ppolicies), 0)
883
          )
884
        end
885
        # open "LDAP User objects configuration"
886
        if ret == :configure
×
887
          result = WFM.CallFunction("ldap_config")
×
888
          modified = true if result == :next
×
889
          next
×
890
        end
891
        break if ret == :back || ret == :cancel || ret == :abort
×
892
        if ret == :next
×
893
          file_server = Convert.to_boolean(
×
894
            UI.QueryWidget(Id(:file_server), :Value)
895
          )
896
          if file_server != Ldap.file_server
×
897
            Users.SetLdapSysconfigModified(true)
×
898
            Ldap.file_server = file_server
×
899
          end
900
          Builtins.foreach(ppolicies) do |dn, ppolicy|
×
901
            # new ppolicy
902
            if !Builtins.haskey(ppolicies_orig, dn)
×
903
              Ops.set(ppolicy, "modified", "added")
×
904
              Ops.set(ppolicy, "pwdAttribute", "userPassword")
×
905
              Ops.set(ppolicy, "objectClass", ["pwdPolicy", "namedObject"])
×
906
              Ops.set(ppolicy, "cn", Ldap.get_cn(dn))
×
907
              Ops.set(write_ppolicies, dn, ppolicy)
×
908
            else
909
              pp = {}
×
910
              Builtins.foreach(
×
911
                Convert.convert(
912
                  ppolicy,
913
                  :from => "map",
914
                  :to   => "map <string, any>"
915
                )
916
              ) do |a, val|
917
                Ops.set(pp, a, val) if val != Ops.get(ppolicies_orig, [dn, a])
×
918
              end
919
              if pp != {}
×
920
                Ops.set(pp, "modified", "edited")
×
921
                Ops.set(write_ppolicies, dn, pp)
×
922
              end
923
            end
924
          end
925
          # deleted ppolicies
926
          Builtins.foreach(ppolicies_deleted) do |dn|
×
927
            pp = Ops.get(write_ppolicies, dn, {})
×
928
            if Ops.get_string(pp, "modified", "") == "added"
×
929
              write_ppolicies = Builtins.remove(write_ppolicies, dn)
×
930
            elsif Builtins.haskey(ppolicies_orig, dn)
×
931
              Ops.set(pp, "modified", "deleted")
×
932
              Ops.set(write_ppolicies, dn, pp)
×
933
            end
934
          end
935
          if write_ppolicies != {}
×
936
            Ldap.WriteLDAP(write_ppolicies)
×
937
            write_ppolicies = {}
×
938
          end
939
          break
×
940
        end
941
      end
942
      Wizard.CloseDialog
×
943
      modified || ret == :next
×
944
    end
945
  end
946
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc