Merge ~jibel/ubiquity:active_directory into ubiquity:master

Proposed by Jean-Baptiste Lallement
Status: Merged
Merged at revision: b153322202eba093b3a0b5d96ef3731a373e682a
Proposed branch: ~jibel/ubiquity:active_directory
Merge into: ubiquity:master
Diff against target: 1436 lines (+849/-274)
8 files modified
debian/changelog (+8/-0)
debian/ubiquity.templates (+81/-1)
gui/gtk/stepUserInfo.ui (+532/-269)
scripts/plugininstall.py (+70/-0)
tests/test_usersetup.py (+1/-0)
ubiquity/components/plugininstall.py (+2/-0)
ubiquity/frontend/gtk_ui.py (+9/-1)
ubiquity/plugins/ubi-usersetup.py (+146/-3)
Reviewer Review Type Date Requested Status
Matthew Paul Thomas (community) design Needs Fixing
Iain Lane Approve
Review via email: mp+390221@code.launchpad.net

Commit message

Support for Active directory to the GTK UI.

To post a comment you must log in.
Revision history for this message
Iain Lane (laney) wrote :

Cheers. Looks mostly good code-wise, just a few small-ish comments/questions down there.

I'm going to also request a 'design' review from Matthew. (I guess that for this it would be appreciated if you could upload .debs somewhere maybe...)

review: Needs Fixing
Revision history for this message
Jean-Baptiste Lallement (jibel) wrote :

@Laney, thanks for the review.

Here is the design review https://docs.google.com/document/d/1_KEGJa2-ka1oNCzMvLlQg9rNW9JESzHAcgqrjP3DkW4/edit?ts=5f561950#

The comments from mpt have all been addressed.

Revision history for this message
Jean-Baptiste Lallement (jibel) :
Revision history for this message
Jean-Baptiste Lallement (jibel) wrote :

Branch as been updated.

Revision history for this message
Iain Lane (laney) wrote :

Looks ok to me, thanks for the updates.

I'll email mpt to give a design 'approve', should be a quick job given it's already been through review.

One thing though, can you please get seb128 to check all the translations are ok here? It's weird/difficult with ubiquity and Seb's helped me fix things there before.

review: Approve
Revision history for this message
Iain Lane (laney) wrote :

I saw this got merged without the two things I requested, but I would still appreciate them happening.

Revision history for this message
Matthew Paul Thomas (mpt) wrote :

Thanks for working on the design changes I requested:

❓ Move the Active Directory checkbox down so that it doesn’t look like part of the password group: commented as “Done”, but not shown in the screenshot.

✔ Add an explanatory caption below the checkbox label: Done.

✘ Move the “Test” button to the right of the field to better explain what it was for: Done, but unfortunately at the same time it was renamed to “Test connection”. Ubuntu buttons use Title Case, so this should be either “Test”, or “Test Connection” with a capital C.

✘ If connection fails, tell people to visit ubuntu.com/activedirectory to fix it after installation: Done, but the URL was formatted as a link (perhaps misled by Google Docs auto-linking the URL in my comment). If it’s not actually possible to fix it before installation finishes, people shouldn’t visit the page during installation, so making it a link would be misleading. Also, remember to submit a request for the Web team to set up that URL as a redirect.

review: Needs Fixing (design)
Revision history for this message
Iain Lane (laney) wrote :

Thanks mpt.

For me it's OK to follow up on those requests with a separate upload, if you'd prefer to do that, so that the stuff we have now can get out there for testing.

Same with the translations, given Seb is not around right now.

Revision history for this message
Jean-Baptiste Lallement (jibel) wrote :

@mpt, thanks for your comment.

1. The AD checkbox has been moved outside of the GtkBox containing the 2 radio buttons. It follows the same space than other pages. padding of 6px for the alignment that contains it, no margin for the widget. However, I added a margin of 6px between the group of radio buttons and the checkbox to make the separation clearer.

3. Fixed.

4. Fixed.

The gdoc has been updated.

Revision history for this message
Jean-Baptiste Lallement (jibel) wrote :
Revision history for this message
Jean-Baptiste Lallement (jibel) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index 286dc17..739798c 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,11 @@
6+ubiquity (20.10.10) UNRELEASED; urgency=medium
7+
8+ [ Didier Roche ]
9+ [ Jean-Baptiste Lallement ]
10+ * AD integration for GTK UI.
11+
12+ -- Jean-Baptiste Lallement <jean-baptiste.lallement@ubuntu.com> Tue, 25 Aug 2020 10:06:29 +0200
13+
14 ubiquity (20.10.9) groovy; urgency=medium
15
16 * gtk_ui, prepare: Run 'apt update' before installing OEM metapackages. We
17diff --git a/debian/ubiquity.templates b/debian/ubiquity.templates
18index 89a32e1..eb6d724 100644
19--- a/debian/ubiquity.templates
20+++ b/debian/ubiquity.templates
21@@ -656,6 +656,10 @@ Template: ubiquity/install/bootloader
22 Type: text
23 _Description: Configuring boot loader...
24
25+Template: ubiquity/install/activedirectory
26+Type: text
27+_Description: Configuring Active Directory...
28+
29 Template: ubiquity/install/apt_clone_save
30 Type: text
31 _Description: Saving installed packages...
32@@ -770,6 +774,14 @@ _Description: Error restoring installed applications
33 installation will continue, but you may have to manually reinstall some
34 applications after the computer reboots.
35
36+Template: ubiquity/install/broken_active_directory
37+Type: error
38+_Description: Error configuring connection to Active Directory
39+ Sorry, Active Directory can't be set up at the moment. Once your system is up
40+ and running, visit
41+ <a href="https://discourse.ubuntu.com/t/service-sssd/11579">ubuntu.com/activedirectory</a>
42+ for help.
43+
44 Template: ubiquity/install/md5_check
45 Type: boolean
46 Default: true
47@@ -1637,4 +1649,72 @@ _Description:
48
49 Template: ubiquity/zfs_keystore_key
50 Type: password
51-_Description: Key to secure the keystore on ZFS installations
52\ No newline at end of file
53+_Description: Key to secure the keystore on ZFS installations
54+
55+Template: ubiquity/login_use_directory
56+Type: text
57+_Description: Authenticate against a directory
58+
59+Template: ubiquity/directory_domain
60+Type: text
61+_Description: Active Directory domain name
62+
63+Template: ubiquity/directory_user
64+Type: text
65+_Description: Administrator to join the domain
66+
67+Template: ubiquity/directory_passwd
68+Type: password
69+_Description: Administrator password to join the domain
70+
71+Template: ubiquity/text/login_directory
72+Type: text
73+_Description:
74+ Use Active Directory
75+
76+Template: ubiquity/text/login_directory_extra_label
77+Type: text
78+_Description:
79+ You'll enter domain and other details in the next step.
80+
81+Template: ubiquity/text/domain_label
82+Type: text
83+_Description:
84+ Domain:
85+
86+Template: ubiquity/text/domain_name_error_label
87+Type: text
88+_Description:
89+ You must enter a domain name
90+
91+Template: ubiquity/text/directory_testbutton
92+Type: text
93+_Description:
94+ Test connection
95+
96+Template: ubiquity/text/domain_user_label
97+Type: text
98+_Description:
99+ Domain Administrator:
100+
101+Template: ubiquity/text/domain_user_error_label
102+Type: text
103+_Description:
104+ You must enter a user name
105+
106+Template: ubiquity/text/domain_passwd_label
107+Type: text
108+_Description:
109+ Password:
110+
111+Template: ubiquity/text/directory_information_title
112+Type: text
113+_Description: Configure Active Directory
114+
115+Template: ubiquity/text/hostname_error
116+Type: text
117+_Description: That name already exists on the network.
118+
119+Template: ubiquity/text/domain_connection_error
120+Type: text
121+_Description: Failed to connect to domain.
122diff --git a/gui/gtk/stepUserInfo.ui b/gui/gtk/stepUserInfo.ui
123index 9d64ed2..1eee3ad 100644
124--- a/gui/gtk/stepUserInfo.ui
125+++ b/gui/gtk/stepUserInfo.ui
126@@ -1,6 +1,7 @@
127 <?xml version="1.0" encoding="UTF-8"?>
128+<!-- Generated with glade 3.22.2 -->
129 <interface>
130- <requires lib="gtk+" version="2.16"/>
131+ <requires lib="gtk+" version="3.20"/>
132 <object class="GtkBox" id="stepUserInfo">
133 <property name="visible">True</property>
134 <property name="can_focus">False</property>
135@@ -19,344 +20,514 @@
136 </packing>
137 </child>
138 <child>
139- <object class="GtkGrid" id="userinfo_table">
140+ <object class="GtkNotebook" id="userinfo_notebook">
141 <property name="visible">True</property>
142- <property name="can_focus">False</property>
143- <property name="border_width">20</property>
144- <property name="column_spacing">6</property>
145- <property name="row_spacing">6</property>
146- <child>
147- <object class="GtkLabel" id="fullname_label">
148- <property name="visible">True</property>
149- <property name="can_focus">False</property>
150- <property name="xalign">1</property>
151- <property name="label" translatable="yes">Your name:</property>
152- </object>
153- </child>
154- <child>
155- <object class="GtkLabel" id="username_label">
156- <property name="visible">True</property>
157- <property name="can_focus">False</property>
158- <property name="xalign">1</property>
159- <property name="label" translatable="yes">Pick a username:</property>
160- <property name="justify">right</property>
161- </object>
162- <packing>
163- <property name="left_attach">0</property>
164- <property name="top_attach">2</property>
165- </packing>
166- </child>
167- <child>
168- <object class="GtkLabel" id="password_label">
169- <property name="visible">True</property>
170- <property name="can_focus">False</property>
171- <property name="xalign">1</property>
172- <property name="label" translatable="yes">Choose a password:</property>
173- <property name="justify">right</property>
174- </object>
175- <packing>
176- <property name="left_attach">0</property>
177- <property name="top_attach">3</property>
178- </packing>
179- </child>
180- <child>
181- <object class="GtkLabel" id="verified_password_label">
182- <property name="visible">True</property>
183- <property name="can_focus">False</property>
184- <property name="xalign">1</property>
185- <property name="label" translatable="yes">Confirm your password:</property>
186- <property name="justify">right</property>
187- </object>
188- <packing>
189- <property name="left_attach">0</property>
190- <property name="top_attach">4</property>
191- </packing>
192- </child>
193+ <property name="can_focus">True</property>
194+ <property name="show_tabs">False</property>
195+ <property name="show_border">False</property>
196 <child>
197- <object class="GtkBox" id="login_vbox">
198+ <object class="GtkGrid" id="userinfo_table">
199 <property name="visible">True</property>
200 <property name="can_focus">False</property>
201- <property name="orientation">vertical</property>
202- <property name="spacing">3</property>
203+ <property name="border_width">20</property>
204+ <property name="row_spacing">6</property>
205+ <property name="column_spacing">6</property>
206 <child>
207- <object class="GtkRadioButton" id="login_auto">
208- <property name="label" translatable="yes">Log in automatically</property>
209+ <object class="GtkLabel" id="fullname_label">
210 <property name="visible">True</property>
211- <property name="can_focus">True</property>
212- <property name="receives_default">False</property>
213- <property name="use_action_appearance">False</property>
214- <property name="xalign">0</property>
215- <property name="draw_indicator">True</property>
216- <property name="group">login_pass</property>
217+ <property name="can_focus">False</property>
218+ <property name="label" translatable="yes">Your name:</property>
219+ <property name="xalign">1</property>
220 </object>
221 <packing>
222- <property name="expand">False</property>
223- <property name="fill">False</property>
224- <property name="position">0</property>
225+ <property name="left_attach">0</property>
226+ <property name="top_attach">0</property>
227 </packing>
228 </child>
229 <child>
230- <object class="GtkRadioButton" id="login_pass">
231- <property name="label" translatable="yes">Require my password to log in</property>
232+ <object class="GtkLabel" id="username_label">
233 <property name="visible">True</property>
234- <property name="can_focus">True</property>
235- <property name="receives_default">False</property>
236- <property name="use_action_appearance">False</property>
237- <property name="xalign">0</property>
238- <property name="active">True</property>
239- <property name="draw_indicator">True</property>
240+ <property name="can_focus">False</property>
241+ <property name="label" translatable="yes">Pick a username:</property>
242+ <property name="justify">right</property>
243+ <property name="xalign">1</property>
244 </object>
245 <packing>
246- <property name="expand">False</property>
247- <property name="fill">False</property>
248- <property name="position">1</property>
249+ <property name="left_attach">0</property>
250+ <property name="top_attach">2</property>
251 </packing>
252 </child>
253- </object>
254- <packing>
255- <property name="left_attach">1</property>
256- <property name="top_attach">5</property>
257- </packing>
258- </child>
259- <child>
260- <object class="GtkBox" id="hbox1">
261- <property name="visible">True</property>
262- <property name="can_focus">False</property>
263- <property name="spacing">6</property>
264 <child>
265- <object class="GtkEntry" id="password">
266+ <object class="GtkLabel" id="password_label">
267 <property name="visible">True</property>
268- <property name="can_focus">True</property>
269- <property name="visibility">False</property>
270- <property name="invisible_char">●</property>
271- <property name="activates_default">True</property>
272- <property name="width_chars">20</property>
273- <property name="invisible_char_set">True</property>
274- <accessibility>
275- <relation type="labelled-by" target="password_label"/>
276- </accessibility>
277- <signal name="changed" handler="info_loop" swapped="no"/>
278+ <property name="can_focus">False</property>
279+ <property name="label" translatable="yes">Choose a password:</property>
280+ <property name="justify">right</property>
281+ <property name="xalign">1</property>
282 </object>
283 <packing>
284- <property name="expand">False</property>
285- <property name="fill">False</property>
286- <property name="position">0</property>
287+ <property name="left_attach">0</property>
288+ <property name="top_attach">3</property>
289 </packing>
290 </child>
291 <child>
292- <object class="GtkLabel" id="password_strength">
293+ <object class="GtkLabel" id="verified_password_label">
294+ <property name="visible">True</property>
295 <property name="can_focus">False</property>
296- <property name="xalign">0</property>
297- <property name="label" translatable="yes">&lt;small&gt;&lt;span color="darkgreen"&gt;Strong password&lt;/span&gt;&lt;/small&gt;</property>
298- <property name="use_markup">True</property>
299+ <property name="label" translatable="yes">Confirm your password:</property>
300+ <property name="justify">right</property>
301+ <property name="xalign">1</property>
302 </object>
303 <packing>
304- <property name="expand">False</property>
305- <property name="fill">False</property>
306- <property name="position">1</property>
307+ <property name="left_attach">0</property>
308+ <property name="top_attach">4</property>
309 </packing>
310 </child>
311- </object>
312- <packing>
313- <property name="left_attach">1</property>
314- <property name="top_attach">3</property>
315- </packing>
316- </child>
317- <child>
318- <object class="GtkBox" id="hbox2">
319- <property name="visible">True</property>
320- <property name="can_focus">False</property>
321- <property name="spacing">6</property>
322 <child>
323- <object class="GtkEntry" id="verified_password">
324+ <object class="GtkBox" id="login_vbox">
325 <property name="visible">True</property>
326- <property name="can_focus">True</property>
327- <property name="visibility">False</property>
328- <property name="invisible_char">●</property>
329- <property name="activates_default">True</property>
330- <property name="width_chars">20</property>
331- <property name="invisible_char_set">True</property>
332- <accessibility>
333- <relation type="labelled-by" target="verified_password_label"/>
334- </accessibility>
335- <signal name="changed" handler="info_loop" swapped="no"/>
336+ <property name="can_focus">False</property>
337+ <property name="orientation">vertical</property>
338+ <property name="spacing">3</property>
339+ <child>
340+ <object class="GtkRadioButton" id="login_auto">
341+ <property name="label" translatable="yes">Log in automatically</property>
342+ <property name="visible">True</property>
343+ <property name="can_focus">True</property>
344+ <property name="receives_default">False</property>
345+ <property name="draw_indicator">True</property>
346+ <property name="group">login_pass</property>
347+ </object>
348+ <packing>
349+ <property name="expand">False</property>
350+ <property name="fill">False</property>
351+ <property name="position">0</property>
352+ </packing>
353+ </child>
354+ <child>
355+ <object class="GtkRadioButton" id="login_pass">
356+ <property name="label" translatable="yes">Require my password to log in</property>
357+ <property name="visible">True</property>
358+ <property name="can_focus">True</property>
359+ <property name="receives_default">False</property>
360+ <property name="active">True</property>
361+ <property name="draw_indicator">True</property>
362+ </object>
363+ <packing>
364+ <property name="expand">False</property>
365+ <property name="fill">False</property>
366+ <property name="position">1</property>
367+ </packing>
368+ </child>
369 </object>
370 <packing>
371- <property name="expand">False</property>
372- <property name="fill">False</property>
373- <property name="position">0</property>
374+ <property name="left_attach">1</property>
375+ <property name="top_attach">5</property>
376 </packing>
377 </child>
378 <child>
379- <object class="GtkImage" id="password_ok">
380+ <object class="GtkBox" id="hbox1">
381+ <property name="visible">True</property>
382 <property name="can_focus">False</property>
383- <property name="stock">gtk-yes</property>
384+ <property name="spacing">6</property>
385+ <child>
386+ <object class="GtkEntry" id="password">
387+ <property name="visible">True</property>
388+ <property name="can_focus">True</property>
389+ <property name="visibility">False</property>
390+ <property name="invisible_char">●</property>
391+ <property name="activates_default">True</property>
392+ <property name="width_chars">20</property>
393+ <signal name="changed" handler="info_loop" swapped="no"/>
394+ <accessibility>
395+ <relation type="labelled-by" target="password_label"/>
396+ </accessibility>
397+ </object>
398+ <packing>
399+ <property name="expand">False</property>
400+ <property name="fill">False</property>
401+ <property name="position">0</property>
402+ </packing>
403+ </child>
404+ <child>
405+ <object class="GtkLabel" id="password_strength">
406+ <property name="can_focus">False</property>
407+ <property name="label" translatable="yes">&lt;small&gt;&lt;span color="darkgreen"&gt;Strong password&lt;/span&gt;&lt;/small&gt;</property>
408+ <property name="use_markup">True</property>
409+ <property name="xalign">0</property>
410+ </object>
411+ <packing>
412+ <property name="expand">False</property>
413+ <property name="fill">False</property>
414+ <property name="position">1</property>
415+ </packing>
416+ </child>
417 </object>
418 <packing>
419- <property name="expand">False</property>
420- <property name="fill">False</property>
421- <property name="position">1</property>
422+ <property name="left_attach">1</property>
423+ <property name="top_attach">3</property>
424 </packing>
425 </child>
426 <child>
427- <object class="GtkLabel" id="password_error_label">
428+ <object class="GtkBox" id="hbox2">
429 <property name="visible">True</property>
430 <property name="can_focus">False</property>
431- <property name="xalign">0</property>
432- <property name="label" translatable="yes">&lt;small&gt;&lt;span color="darkred"&gt;You must enter a username&lt;/span&gt;&lt;/small&gt;</property>
433- <property name="use_markup">True</property>
434+ <property name="spacing">6</property>
435+ <child>
436+ <object class="GtkEntry" id="verified_password">
437+ <property name="visible">True</property>
438+ <property name="can_focus">True</property>
439+ <property name="visibility">False</property>
440+ <property name="invisible_char">●</property>
441+ <property name="activates_default">True</property>
442+ <property name="width_chars">20</property>
443+ <signal name="changed" handler="info_loop" swapped="no"/>
444+ <accessibility>
445+ <relation type="labelled-by" target="verified_password_label"/>
446+ </accessibility>
447+ </object>
448+ <packing>
449+ <property name="expand">False</property>
450+ <property name="fill">False</property>
451+ <property name="position">0</property>
452+ </packing>
453+ </child>
454+ <child>
455+ <object class="GtkImage" id="password_ok">
456+ <property name="can_focus">False</property>
457+ <property name="stock">gtk-yes</property>
458+ </object>
459+ <packing>
460+ <property name="expand">False</property>
461+ <property name="fill">False</property>
462+ <property name="position">1</property>
463+ </packing>
464+ </child>
465+ <child>
466+ <object class="GtkLabel" id="password_error_label">
467+ <property name="visible">True</property>
468+ <property name="can_focus">False</property>
469+ <property name="label" translatable="yes">&lt;small&gt;&lt;span color="darkred"&gt;You must enter a username&lt;/span&gt;&lt;/small&gt;</property>
470+ <property name="use_markup">True</property>
471+ <property name="xalign">0</property>
472+ </object>
473+ <packing>
474+ <property name="expand">False</property>
475+ <property name="fill">False</property>
476+ <property name="position">2</property>
477+ </packing>
478+ </child>
479 </object>
480 <packing>
481- <property name="expand">False</property>
482- <property name="fill">False</property>
483- <property name="position">2</property>
484+ <property name="left_attach">1</property>
485+ <property name="top_attach">4</property>
486 </packing>
487 </child>
488- </object>
489- <packing>
490- <property name="left_attach">1</property>
491- <property name="top_attach">4</property>
492- </packing>
493- </child>
494- <child>
495- <object class="GtkBox" id="hbox3">
496- <property name="visible">True</property>
497- <property name="can_focus">False</property>
498- <property name="spacing">6</property>
499 <child>
500- <object class="GtkEntry" id="fullname">
501+ <object class="GtkBox" id="hbox3">
502 <property name="visible">True</property>
503- <property name="can_focus">True</property>
504- <property name="invisible_char">•</property>
505- <property name="activates_default">True</property>
506- <property name="width_chars">40</property>
507- <accessibility>
508- <relation type="labelled-by" target="fullname_label"/>
509- </accessibility>
510- <signal name="changed" handler="info_loop" swapped="no"/>
511+ <property name="can_focus">False</property>
512+ <property name="spacing">6</property>
513+ <child>
514+ <object class="GtkEntry" id="fullname">
515+ <property name="visible">True</property>
516+ <property name="can_focus">True</property>
517+ <property name="invisible_char">•</property>
518+ <property name="activates_default">True</property>
519+ <property name="width_chars">40</property>
520+ <signal name="changed" handler="info_loop" swapped="no"/>
521+ <accessibility>
522+ <relation type="labelled-by" target="fullname_label"/>
523+ </accessibility>
524+ </object>
525+ <packing>
526+ <property name="expand">False</property>
527+ <property name="fill">False</property>
528+ <property name="position">0</property>
529+ </packing>
530+ </child>
531+ <child>
532+ <object class="GtkImage" id="fullname_ok">
533+ <property name="can_focus">False</property>
534+ <property name="stock">gtk-yes</property>
535+ </object>
536+ <packing>
537+ <property name="expand">False</property>
538+ <property name="fill">False</property>
539+ <property name="position">1</property>
540+ </packing>
541+ </child>
542 </object>
543 <packing>
544- <property name="expand">False</property>
545- <property name="fill">False</property>
546- <property name="position">0</property>
547+ <property name="left_attach">1</property>
548+ <property name="top_attach">0</property>
549 </packing>
550 </child>
551 <child>
552- <object class="GtkImage" id="fullname_ok">
553+ <object class="GtkBox" id="username_box">
554+ <property name="visible">True</property>
555 <property name="can_focus">False</property>
556- <property name="stock">gtk-yes</property>
557+ <property name="spacing">6</property>
558+ <child>
559+ <object class="GtkEntry" id="username">
560+ <property name="visible">True</property>
561+ <property name="can_focus">True</property>
562+ <property name="max_length">32</property>
563+ <property name="invisible_char">•</property>
564+ <property name="activates_default">True</property>
565+ <property name="width_chars">15</property>
566+ <signal name="changed" handler="info_loop" swapped="no"/>
567+ <accessibility>
568+ <relation type="labelled-by" target="username_label"/>
569+ </accessibility>
570+ </object>
571+ <packing>
572+ <property name="expand">False</property>
573+ <property name="fill">False</property>
574+ <property name="position">0</property>
575+ </packing>
576+ </child>
577+ <child>
578+ <object class="GtkImage" id="username_ok">
579+ <property name="can_focus">False</property>
580+ <property name="stock">gtk-yes</property>
581+ </object>
582+ <packing>
583+ <property name="expand">False</property>
584+ <property name="fill">False</property>
585+ <property name="position">1</property>
586+ </packing>
587+ </child>
588+ <child>
589+ <object class="GtkLabel" id="username_error_label">
590+ <property name="visible">True</property>
591+ <property name="can_focus">False</property>
592+ <property name="label" translatable="yes">&lt;small&gt;&lt;span color="darkred"&gt;You must enter a username&lt;/span&gt;&lt;/small&gt;</property>
593+ <property name="use_markup">True</property>
594+ <property name="wrap">True</property>
595+ <property name="xalign">0</property>
596+ </object>
597+ <packing>
598+ <property name="expand">False</property>
599+ <property name="fill">False</property>
600+ <property name="position">2</property>
601+ </packing>
602+ </child>
603 </object>
604 <packing>
605- <property name="expand">False</property>
606- <property name="fill">False</property>
607- <property name="position">1</property>
608+ <property name="left_attach">1</property>
609+ <property name="top_attach">2</property>
610 </packing>
611 </child>
612- </object>
613- <packing>
614- <property name="left_attach">1</property>
615- </packing>
616- </child>
617- <child>
618- <object class="GtkBox" id="username_box">
619- <property name="visible">True</property>
620- <property name="can_focus">False</property>
621- <property name="spacing">6</property>
622 <child>
623- <object class="GtkEntry" id="username">
624+ <object class="GtkBox" id="box1">
625 <property name="visible">True</property>
626- <property name="can_focus">True</property>
627- <property name="max_length">32</property>
628- <property name="invisible_char">•</property>
629- <property name="activates_default">True</property>
630- <property name="width_chars">15</property>
631- <accessibility>
632- <relation type="labelled-by" target="username_label"/>
633- </accessibility>
634- <signal name="changed" handler="info_loop" swapped="no"/>
635+ <property name="can_focus">False</property>
636+ <property name="orientation">vertical</property>
637+ <child>
638+ <placeholder/>
639+ </child>
640 </object>
641 <packing>
642- <property name="expand">False</property>
643- <property name="fill">False</property>
644- <property name="position">0</property>
645+ <property name="left_attach">0</property>
646+ <property name="top_attach">5</property>
647 </packing>
648 </child>
649 <child>
650- <object class="GtkImage" id="username_ok">
651+ <object class="GtkBox" id="hostname_box">
652+ <property name="visible">True</property>
653 <property name="can_focus">False</property>
654- <property name="stock">gtk-yes</property>
655+ <property name="orientation">vertical</property>
656+ <property name="spacing">3</property>
657+ <child>
658+ <object class="GtkBox" id="box3">
659+ <property name="visible">True</property>
660+ <property name="can_focus">False</property>
661+ <property name="spacing">6</property>
662+ <child>
663+ <object class="GtkEntry" id="hostname">
664+ <property name="visible">True</property>
665+ <property name="can_focus">True</property>
666+ <property name="invisible_char">•</property>
667+ <signal name="changed" handler="info_loop" swapped="no"/>
668+ <accessibility>
669+ <relation type="labelled-by" target="hostname_label"/>
670+ <relation type="labelled-by" target="hostname_extra_label"/>
671+ </accessibility>
672+ </object>
673+ <packing>
674+ <property name="expand">False</property>
675+ <property name="fill">True</property>
676+ <property name="position">0</property>
677+ </packing>
678+ </child>
679+ <child>
680+ <object class="GtkImage" id="hostname_ok">
681+ <property name="can_focus">False</property>
682+ <property name="stock">gtk-yes</property>
683+ </object>
684+ <packing>
685+ <property name="expand">False</property>
686+ <property name="fill">False</property>
687+ <property name="position">1</property>
688+ </packing>
689+ </child>
690+ <child>
691+ <object class="GtkLabel" id="hostname_error_label">
692+ <property name="visible">True</property>
693+ <property name="can_focus">False</property>
694+ <property name="label" translatable="yes">&lt;small&gt;&lt;span color="darkred"&gt;You must enter a name&lt;/span&gt;&lt;/small&gt;</property>
695+ <property name="use_markup">True</property>
696+ <property name="wrap">True</property>
697+ </object>
698+ <packing>
699+ <property name="expand">False</property>
700+ <property name="fill">True</property>
701+ <property name="position">2</property>
702+ </packing>
703+ </child>
704+ </object>
705+ <packing>
706+ <property name="expand">False</property>
707+ <property name="fill">True</property>
708+ <property name="position">0</property>
709+ </packing>
710+ </child>
711+ <child>
712+ <object class="GtkLabel" id="hostname_extra_label">
713+ <property name="visible">True</property>
714+ <property name="can_focus">False</property>
715+ <property name="label" translatable="yes">The name it uses when it talks to other computers.</property>
716+ <property name="xalign">0</property>
717+ <attributes>
718+ <attribute name="scale" value="0.83333333333333304"/>
719+ </attributes>
720+ </object>
721+ <packing>
722+ <property name="expand">False</property>
723+ <property name="fill">True</property>
724+ <property name="position">1</property>
725+ </packing>
726+ </child>
727 </object>
728 <packing>
729- <property name="expand">False</property>
730- <property name="fill">False</property>
731- <property name="position">1</property>
732+ <property name="left_attach">1</property>
733+ <property name="top_attach">1</property>
734 </packing>
735 </child>
736 <child>
737- <object class="GtkLabel" id="username_error_label">
738+ <object class="GtkAlignment" id="alignment2">
739 <property name="visible">True</property>
740 <property name="can_focus">False</property>
741- <property name="xalign">0</property>
742- <property name="label" translatable="yes">&lt;small&gt;&lt;span color="darkred"&gt;You must enter a username&lt;/span&gt;&lt;/small&gt;</property>
743- <property name="use_markup">True</property>
744- <property name="wrap">True</property>
745+ <property name="bottom_padding">20</property>
746+ <child>
747+ <object class="GtkLabel" id="hostname_label">
748+ <property name="visible">True</property>
749+ <property name="can_focus">False</property>
750+ <property name="label" translatable="yes">Your computer's name:</property>
751+ <property name="xalign">1</property>
752+ </object>
753+ </child>
754 </object>
755 <packing>
756- <property name="expand">False</property>
757- <property name="fill">False</property>
758- <property name="position">2</property>
759+ <property name="left_attach">0</property>
760+ <property name="top_attach">1</property>
761+ </packing>
762+ </child>
763+ <child>
764+ <object class="GtkBox">
765+ <property name="visible">True</property>
766+ <property name="can_focus">False</property>
767+ <property name="orientation">vertical</property>
768+ <property name="spacing">6</property>
769+ <child>
770+ <object class="GtkCheckButton" id="login_directory">
771+ <property name="label" translatable="yes">Use Active Directory</property>
772+ <property name="visible">True</property>
773+ <property name="can_focus">True</property>
774+ <property name="receives_default">False</property>
775+ <property name="draw_indicator">True</property>
776+ <signal name="toggled" handler="on_login_directory_toggled" swapped="no"/>
777+ </object>
778+ <packing>
779+ <property name="expand">False</property>
780+ <property name="fill">False</property>
781+ <property name="position">0</property>
782+ </packing>
783+ </child>
784+ <child>
785+ <object class="GtkLabel" id="login_directory_extra_label">
786+ <property name="visible">True</property>
787+ <property name="can_focus">False</property>
788+ <property name="label" translatable="yes"> You'll enter domain and other details in the next step.</property>
789+ <property name="xalign">0</property>
790+ <attributes>
791+ <attribute name="scale" value="0.83333333333333304"/>
792+ </attributes>
793+ </object>
794+ <packing>
795+ <property name="expand">False</property>
796+ <property name="fill">True</property>
797+ <property name="position">1</property>
798+ </packing>
799+ </child>
800+ </object>
801+ <packing>
802+ <property name="left_attach">1</property>
803+ <property name="top_attach">6</property>
804 </packing>
805 </child>
806- </object>
807- <packing>
808- <property name="left_attach">1</property>
809- <property name="top_attach">2</property>
810- </packing>
811- </child>
812- <child>
813- <object class="GtkBox" id="box1">
814- <property name="visible">True</property>
815- <property name="can_focus">False</property>
816- <property name="orientation">vertical</property>
817 <child>
818 <placeholder/>
819 </child>
820 </object>
821- <packing>
822- <property name="left_attach">0</property>
823- <property name="top_attach">5</property>
824- </packing>
825+ </child>
826+ <child type="tab">
827+ <placeholder/>
828 </child>
829 <child>
830- <object class="GtkBox" id="hostname_box">
831+ <object class="GtkGrid" id="directory_table">
832 <property name="visible">True</property>
833 <property name="can_focus">False</property>
834- <property name="orientation">vertical</property>
835- <property name="spacing">3</property>
836+ <property name="border_width">20</property>
837+ <property name="row_spacing">6</property>
838+ <property name="column_spacing">6</property>
839 <child>
840- <object class="GtkBox" id="box3">
841+ <object class="GtkLabel" id="domain_user_label">
842+ <property name="visible">True</property>
843+ <property name="can_focus">False</property>
844+ <property name="label" translatable="yes">Domain administrator:</property>
845+ <property name="justify">right</property>
846+ <property name="xalign">1</property>
847+ </object>
848+ <packing>
849+ <property name="left_attach">0</property>
850+ <property name="top_attach">1</property>
851+ </packing>
852+ </child>
853+ <child>
854+ <object class="GtkBox" id="domain_user_box">
855 <property name="visible">True</property>
856 <property name="can_focus">False</property>
857 <property name="spacing">6</property>
858 <child>
859- <object class="GtkEntry" id="hostname">
860+ <object class="GtkEntry" id="domain_user">
861 <property name="visible">True</property>
862 <property name="can_focus">True</property>
863+ <property name="max_length">32</property>
864 <property name="invisible_char">•</property>
865- <accessibility>
866- <relation type="labelled-by" target="hostname_label"/>
867- <relation type="labelled-by" target="hostname_extra_label"/>
868- </accessibility>
869- <signal name="changed" handler="info_loop" swapped="no"/>
870+ <property name="activates_default">True</property>
871+ <property name="width_chars">15</property>
872+ <signal name="changed" handler="validate_directory_info" swapped="no"/>
873 </object>
874 <packing>
875 <property name="expand">False</property>
876- <property name="fill">True</property>
877+ <property name="fill">False</property>
878 <property name="position">0</property>
879 </packing>
880 </child>
881 <child>
882- <object class="GtkImage" id="hostname_ok">
883+ <object class="GtkImage" id="domain_user_ok">
884 <property name="can_focus">False</property>
885 <property name="stock">gtk-yes</property>
886 </object>
887@@ -367,71 +538,163 @@
888 </packing>
889 </child>
890 <child>
891- <object class="GtkLabel" id="hostname_error_label">
892+ <object class="GtkLabel" id="domain_user_error_label">
893 <property name="visible">True</property>
894 <property name="can_focus">False</property>
895- <property name="label" translatable="yes">&lt;small&gt;&lt;span color="darkred"&gt;You must enter a name&lt;/span&gt;&lt;/small&gt;</property>
896+ <property name="label" translatable="yes">&lt;small&gt;&lt;span color="darkred"&gt;You must enter a user name&lt;/span&gt;&lt;/small&gt;</property>
897 <property name="use_markup">True</property>
898 <property name="wrap">True</property>
899+ <property name="xalign">0</property>
900 </object>
901 <packing>
902 <property name="expand">False</property>
903- <property name="fill">True</property>
904+ <property name="fill">False</property>
905 <property name="position">2</property>
906 </packing>
907 </child>
908 </object>
909 <packing>
910- <property name="expand">False</property>
911- <property name="fill">True</property>
912- <property name="position">0</property>
913+ <property name="left_attach">1</property>
914+ <property name="top_attach">1</property>
915 </packing>
916 </child>
917 <child>
918- <object class="GtkLabel" id="hostname_extra_label">
919+ <object class="GtkLabel" id="domain_passwd_label">
920 <property name="visible">True</property>
921 <property name="can_focus">False</property>
922- <property name="xalign">0</property>
923- <property name="label" translatable="yes">The name it uses when it talks to other computers.</property>
924- <attributes>
925- <attribute name="scale" value="0.83333333333333304"/>
926- </attributes>
927+ <property name="label" translatable="yes">Password:</property>
928+ <property name="justify">right</property>
929+ <property name="xalign">1</property>
930 </object>
931 <packing>
932- <property name="expand">False</property>
933- <property name="fill">True</property>
934- <property name="position">1</property>
935+ <property name="left_attach">0</property>
936+ <property name="top_attach">2</property>
937 </packing>
938 </child>
939- </object>
940- <packing>
941- <property name="left_attach">1</property>
942- <property name="top_attach">1</property>
943- </packing>
944- </child>
945- <child>
946- <object class="GtkAlignment" id="alignment2">
947- <property name="visible">True</property>
948- <property name="can_focus">False</property>
949- <property name="bottom_padding">20</property>
950 <child>
951- <object class="GtkLabel" id="hostname_label">
952+ <object class="GtkBox" id="di_hbox">
953 <property name="visible">True</property>
954 <property name="can_focus">False</property>
955+ <property name="spacing">6</property>
956+ <child>
957+ <object class="GtkEntry" id="domain_passwd">
958+ <property name="visible">True</property>
959+ <property name="can_focus">True</property>
960+ <property name="visibility">False</property>
961+ <property name="invisible_char">●</property>
962+ <property name="activates_default">True</property>
963+ <property name="width_chars">20</property>
964+ <signal name="changed" handler="validate_directory_info" swapped="no"/>
965+ </object>
966+ <packing>
967+ <property name="expand">False</property>
968+ <property name="fill">False</property>
969+ <property name="position">0</property>
970+ </packing>
971+ </child>
972+ <child>
973+ <placeholder/>
974+ </child>
975+ </object>
976+ <packing>
977+ <property name="left_attach">1</property>
978+ <property name="top_attach">2</property>
979+ </packing>
980+ </child>
981+ <child>
982+ <object class="GtkLabel" id="domain_label">
983+ <property name="visible">True</property>
984+ <property name="can_focus">False</property>
985+ <property name="label" translatable="yes">Domain:</property>
986 <property name="xalign">1</property>
987- <property name="label" translatable="yes">Your computer's name:</property>
988 </object>
989+ <packing>
990+ <property name="left_attach">0</property>
991+ <property name="top_attach">0</property>
992+ </packing>
993+ </child>
994+ <child>
995+ <object class="GtkBox" id="di_box">
996+ <property name="visible">True</property>
997+ <property name="can_focus">False</property>
998+ <property name="spacing">6</property>
999+ <child>
1000+ <object class="GtkEntry" id="domain_name">
1001+ <property name="visible">True</property>
1002+ <property name="can_focus">True</property>
1003+ <property name="invisible_char">•</property>
1004+ <signal name="changed" handler="validate_directory_info" swapped="no"/>
1005+ </object>
1006+ <packing>
1007+ <property name="expand">False</property>
1008+ <property name="fill">True</property>
1009+ <property name="position">0</property>
1010+ </packing>
1011+ </child>
1012+ <child>
1013+ <object class="GtkButton" id="directory_testbutton">
1014+ <property name="label" translatable="yes">Test connection</property>
1015+ <property name="visible">True</property>
1016+ <property name="sensitive">False</property>
1017+ <property name="can_focus">True</property>
1018+ <property name="receives_default">True</property>
1019+ <signal name="clicked" handler="on_testdomain_click" swapped="no"/>
1020+ </object>
1021+ <packing>
1022+ <property name="expand">False</property>
1023+ <property name="fill">True</property>
1024+ <property name="position">1</property>
1025+ </packing>
1026+ </child>
1027+ <child>
1028+ <object class="GtkImage" id="domain_name_ok">
1029+ <property name="can_focus">False</property>
1030+ <property name="stock">gtk-yes</property>
1031+ </object>
1032+ <packing>
1033+ <property name="expand">False</property>
1034+ <property name="fill">False</property>
1035+ <property name="position">2</property>
1036+ </packing>
1037+ </child>
1038+ <child>
1039+ <object class="GtkLabel" id="domain_name_error_label">
1040+ <property name="visible">True</property>
1041+ <property name="can_focus">False</property>
1042+ <property name="label" translatable="yes">&lt;small&gt;&lt;span color="darkred"&gt;You must enter a domain name&lt;/span&gt;&lt;/small&gt;</property>
1043+ <property name="use_markup">True</property>
1044+ <property name="wrap">True</property>
1045+ </object>
1046+ <packing>
1047+ <property name="expand">False</property>
1048+ <property name="fill">True</property>
1049+ <property name="position">3</property>
1050+ </packing>
1051+ </child>
1052+ </object>
1053+ <packing>
1054+ <property name="left_attach">1</property>
1055+ <property name="top_attach">0</property>
1056+ </packing>
1057 </child>
1058 </object>
1059 <packing>
1060- <property name="left_attach">0</property>
1061- <property name="top_attach">1</property>
1062+ <property name="position">1</property>
1063 </packing>
1064 </child>
1065+ <child type="tab">
1066+ <placeholder/>
1067+ </child>
1068+ <child>
1069+ <placeholder/>
1070+ </child>
1071+ <child type="tab">
1072+ <placeholder/>
1073+ </child>
1074 </object>
1075 <packing>
1076 <property name="expand">False</property>
1077- <property name="fill">False</property>
1078+ <property name="fill">True</property>
1079 <property name="position">1</property>
1080 </packing>
1081 </child>
1082diff --git a/scripts/plugininstall.py b/scripts/plugininstall.py
1083index e9acdc9..434fd3b 100755
1084--- a/scripts/plugininstall.py
1085+++ b/scripts/plugininstall.py
1086@@ -228,6 +228,10 @@ class Install(install_misc.InstallBase):
1087 self.configure_zsys()
1088
1089 self.next_region()
1090+ self.db.progress('INFO', 'ubiquity/install/activedirectory')
1091+ self.configure_active_directory()
1092+
1093+ self.next_region()
1094 self.db.progress('INFO', 'ubiquity/install/bootloader')
1095 self.copy_mok()
1096 self.configure_bootloader()
1097@@ -968,6 +972,72 @@ class Install(install_misc.InstallBase):
1098 if use_zfs:
1099 misc.execute_root('/usr/share/ubiquity/zsys-setup', 'finalize')
1100
1101+ def configure_active_directory(self):
1102+ """ Join Active Directory domain and enable pam_mkhomedir """
1103+ use_directory = self.db.get('ubiquity/login_use_directory')
1104+ if use_directory != 'true':
1105+ return
1106+
1107+ from socket import gethostname
1108+ hostname_cur = gethostname()
1109+ hostname_new = ''
1110+ with open(self.target_file('etc/hostname'), 'r') as f:
1111+ hostname_new = f.read().strip()
1112+
1113+ # Set hostname for AD to determine FQDN (no fqdn option in realm join, only adcli)
1114+ misc.execute_root('hostname', hostname_new)
1115+
1116+ directory_domain = self.db.get('ubiquity/directory_domain')
1117+ directory_user = self.db.get('ubiquity/directory_user')
1118+ directory_passwd = self.db.get('ubiquity/directory_passwd')
1119+
1120+ binds = ("/proc", "/sys", "/dev", "/run")
1121+ try:
1122+ for bind in binds:
1123+ misc.execute('mount', '--bind', bind, self.target + bind)
1124+ # join AD on host (services are running on host)
1125+ if not self.join_domain(hostname_new, directory_domain, directory_user, directory_passwd):
1126+ self.db.input('critical', 'ubiquity/install/broken_active_directory')
1127+ self.db.go()
1128+ finally:
1129+ for bind in binds:
1130+ misc.execute('umount', '-f', self.target + bind)
1131+ # Reset hostname
1132+ misc.execute_root('hostname', hostname_cur)
1133+
1134+ # Enable pam_mkhomedir
1135+ try:
1136+ subprocess.check_call(['chroot', self.target, 'pam-auth-update',
1137+ '--package', '--enable', 'mkhomedir'],
1138+ preexec_fn=install_misc.debconf_disconnect)
1139+ except subprocess.CalledProcessError:
1140+ self.db.input('critical', 'ubiquity/install/broken_active_directory')
1141+ self.db.go()
1142+
1143+ def join_domain(self, hostname, directory_domain, directory_user, directory_passwd):
1144+ """ Join an Active Directory domain """
1145+ log_args = ['log-output', '-t', 'ubiquity']
1146+ log_args.extend(['realm', 'join', '--install', self.target,
1147+ '--user', directory_user, '--computer-name', hostname,
1148+ '--unattended', directory_domain])
1149+ try:
1150+ p = subprocess.run(log_args, input=directory_passwd, timeout=60, encoding="utf-8")
1151+ except TimeoutError as e:
1152+ syslog.syslog(syslog.LOG_ERR, ' '.join(log_args))
1153+ syslog.syslog(syslog.LOG_ERR, "Command timed out(%s): %s" % (e.errno, e.strerror))
1154+ return False
1155+ except IOError as e:
1156+ syslog.syslog(syslog.LOG_ERR, ' '.join(log_args))
1157+ syslog.syslog(syslog.LOG_ERR, "OS error(%s): %s" % (e.errno, e.strerror))
1158+ return False
1159+
1160+ if p.returncode != 0:
1161+ syslog.syslog(syslog.LOG_ERR, ' '.join(log_args))
1162+ return False
1163+
1164+ syslog.syslog(' '.join(log_args))
1165+ return True
1166+
1167 def copy_mok(self):
1168 if 'UBIQUITY_OEM_USER_CONFIG' in os.environ:
1169 return
1170diff --git a/tests/test_usersetup.py b/tests/test_usersetup.py
1171index 0d6c178..33f4949 100644
1172--- a/tests/test_usersetup.py
1173+++ b/tests/test_usersetup.py
1174@@ -41,6 +41,7 @@ class UserSetupTests(unittest.TestCase):
1175 error_msg = 'That name already exists on the network.'
1176 self.gtk.resolver = UbiquityMockResolver.MockResolver(
1177 hostname='myhostname')
1178+ self.gtk.plugin_translate('en')
1179 self.gtk.hostname_ok.show()
1180 self.gtk.hostname.set_text('myhostname')
1181 self.gtk.hostname_error = mock.Mock()
1182diff --git a/ubiquity/components/plugininstall.py b/ubiquity/components/plugininstall.py
1183index 213b57e..dcb04d6 100644
1184--- a/ubiquity/components/plugininstall.py
1185+++ b/ubiquity/components/plugininstall.py
1186@@ -65,6 +65,8 @@ class Install(FilteredCommand):
1187 return True
1188 elif question == 'apt-setup/security-updates-failed':
1189 fatal = False
1190+ elif question == 'ubiquity/install/broken_active_directory':
1191+ fatal = False
1192 else:
1193 fatal = True
1194 self.frontend.error_dialog(self.description(question),
1195diff --git a/ubiquity/frontend/gtk_ui.py b/ubiquity/frontend/gtk_ui.py
1196index 7280f96..c3a7dea 100644
1197--- a/ubiquity/frontend/gtk_ui.py
1198+++ b/ubiquity/frontend/gtk_ui.py
1199@@ -1887,14 +1887,22 @@ class Wizard(BaseFrontend):
1200 msg = title
1201 dialog = Gtk.MessageDialog(
1202 self.live_installer, Gtk.DialogFlags.MODAL,
1203- Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, msg)
1204+ Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, "")
1205 dialog.set_title(title)
1206+ dialog.set_markup(msg)
1207+ for label in dialog.get_message_area().get_children():
1208+ if not isinstance(label, Gtk.Label):
1209+ continue
1210+ label.connect('activate-link', self.on_link_clicked)
1211 dialog.run()
1212 self.set_busy_cursor(saved_busy_cursor)
1213 dialog.hide()
1214 if fatal:
1215 self.return_to_partitioning()
1216
1217+ def on_link_clicked(self, widget, uri):
1218+ misc.launch_uri(uri)
1219+
1220 def toggle_grub_fail(self, unused_widget):
1221 if self.grub_no_new_device.get_active():
1222 self.no_grub_warn.show()
1223diff --git a/ubiquity/plugins/ubi-usersetup.py b/ubiquity/plugins/ubi-usersetup.py
1224index 57f2a35..b61d74a 100644
1225--- a/ubiquity/plugins/ubi-usersetup.py
1226+++ b/ubiquity/plugins/ubi-usersetup.py
1227@@ -31,7 +31,7 @@ import re
1228
1229 import debconf
1230
1231-from ubiquity import misc, plugin, validation
1232+from ubiquity import i18n, misc, plugin, validation
1233
1234
1235 NAME = 'usersetup'
1236@@ -146,6 +146,10 @@ class PageBase(plugin.PluginUI):
1237 def set_allow_password_empty(self, empty):
1238 self.allow_password_empty = empty
1239
1240+ def plugin_translate(self, lang):
1241+ self.hostname_error_text = i18n.get_string('hostname_error', lang)
1242+ self.domain_connection_error_text = i18n.get_string('domain_connection_error', lang)
1243+
1244
1245 class PageGtk(PageBase):
1246 plugin_title = 'ubiquity/text/userinfo_heading_label'
1247@@ -186,6 +190,19 @@ class PageGtk(PageBase):
1248 self.password_ok = builder.get_object('password_ok')
1249 self.password_strength = builder.get_object('password_strength')
1250
1251+ self.login_directory = builder.get_object('login_directory')
1252+ self.login_directory_extra_label = builder.get_object('login_directory_extra_label')
1253+ self.domain_name = builder.get_object('domain_name')
1254+ self.domain_name_ok = builder.get_object('domain_name_ok')
1255+ self.domain_name_error_label = builder.get_object('domain_name_error_label')
1256+ self.domain_user = builder.get_object('domain_user')
1257+ self.domain_user_ok = builder.get_object('domain_user_ok')
1258+ self.domain_user_error_label = builder.get_object('domain_user_error_label')
1259+ self.domain_passwd = builder.get_object('domain_passwd')
1260+ self.directory_testbutton = builder.get_object('directory_testbutton')
1261+
1262+ self.userinfo_notebook = builder.get_object('userinfo_notebook')
1263+
1264 # Dodgy hack to let us center the contents of the page without it
1265 # moving as elements appear and disappear, specifically the full name
1266 # okay check icon and the hostname error messages.
1267@@ -204,6 +221,11 @@ class PageGtk(PageBase):
1268 self.hostname_changed_id = self.hostname.connect(
1269 'changed', self.on_hostname_changed)
1270
1271+ if not os.path.exists('/usr/sbin/realm'):
1272+ self.login_directory.hide()
1273+ self.login_directory_extra_label.hide()
1274+ self.login_directory_extra_label.set_sensitive(False)
1275+
1276 if self.controller.oem_config:
1277 self.fullname.set_text('OEM Configuration (temporary user)')
1278 self.fullname.set_editable(False)
1279@@ -272,11 +294,41 @@ class PageGtk(PageBase):
1280 def set_hostname(self, value):
1281 self.hostname.set_text(value)
1282
1283+ def get_login_directory(self):
1284+ """ Use a directory for authentication """
1285+ return self.login_directory.get_active()
1286+
1287+ def get_domain_name(self):
1288+ """ Get the domain name """
1289+ return self.domain_name.get_text()
1290+
1291+ def get_domain_user(self):
1292+ """ Get the domain name """
1293+ return self.domain_user.get_text()
1294+
1295+ def get_domain_passwd(self):
1296+ """ Get the domain name """
1297+ return self.domain_passwd.get_text()
1298+
1299+ def domain_name_error(self, msg):
1300+ self.domain_name_ok.hide()
1301+ m = '<small><span foreground="darkred"><b>%s</b></span></small>' % msg
1302+ self.domain_name_error_label.set_markup(m)
1303+ self.domain_name_error_label.show()
1304+
1305+ def domain_user_error(self, msg):
1306+ self.domain_user_ok.hide()
1307+ m = '<small><span foreground="darkred"><b>%s</b></span></small>' % msg
1308+ self.domain_user_error_label.set_markup(m)
1309+ self.domain_user_error_label.show()
1310+
1311 def clear_errors(self):
1312 self.username_error_label.hide()
1313 self.hostname_error_label.hide()
1314 self.password_error_label.hide()
1315
1316+ self.domain_name_error_label.hide()
1317+
1318 # Callback functions.
1319
1320 def info_loop(self, widget):
1321@@ -380,8 +432,7 @@ class PageGtk(PageBase):
1322 except GLib.GError:
1323 pass
1324 else:
1325- # FIXME: i18n
1326- self.hostname_error('That name already exists on the network.')
1327+ self.hostname_error(self.hostname_error_text)
1328 self.hostname_ok.hide()
1329
1330 def hostname_timeout(self, widget):
1331@@ -407,6 +458,91 @@ class PageGtk(PageBase):
1332 else:
1333 self.resolver_ok = False
1334
1335+ def validate_directory_info(self, widget=None):
1336+ """ Validate domain information """
1337+ domain_name_is_valid = True
1338+ domain_info_complete = True
1339+
1340+ domain_name_txt = self.domain_name.get_text().strip()
1341+ domain_user_txt = self.domain_user.get_text()
1342+ domain_passwd_txt = self.domain_passwd.get_text()
1343+
1344+ self.domain_name_ok.hide()
1345+ if domain_name_txt:
1346+ errors = check_hostname(domain_name_txt)
1347+ if errors:
1348+ self.domain_name_error(make_error_string(self.controller, errors))
1349+ domain_name_is_valid = False
1350+ else:
1351+ self.domain_name_error_label.hide()
1352+ else:
1353+ self.domain_name_error_label.hide()
1354+ domain_name_is_valid = False
1355+ self.directory_testbutton.set_sensitive(domain_name_is_valid)
1356+ domain_info_complete = domain_name_is_valid
1357+
1358+ if domain_user_txt:
1359+ # Don't enforce lower case for AD administrator.
1360+ errors = check_username(domain_user_txt.lower())
1361+ if errors:
1362+ self.domain_user_error(make_error_string(self.controller, errors))
1363+ domain_info_complete = False
1364+ else:
1365+ self.domain_user_ok.show()
1366+ self.domain_user_error_label.hide()
1367+ else:
1368+ self.domain_user_ok.hide()
1369+ self.domain_user_error_label.hide()
1370+ domain_info_complete = False
1371+
1372+ if not domain_passwd_txt:
1373+ domain_info_complete = False
1374+
1375+ self.controller.allow_go_forward(domain_info_complete)
1376+
1377+ def switch_userinfo_tab(self, tab):
1378+ self.userinfo_notebook.set_current_page(tab)
1379+
1380+ if tab == 1:
1381+ self.title = 'ubiquity/text/directory_information_title'
1382+ self.controller.allow_go_backward(True)
1383+ self.validate_directory_info()
1384+ else:
1385+ self.title = self.plugin_title
1386+ self.controller.allow_go_backward(False)
1387+ self.controller.allow_go_forward(True)
1388+
1389+ self.controller._wizard.set_page_title(self)
1390+
1391+ def plugin_set_online_state(self, state):
1392+ if not state:
1393+ self.login_directory.set_active(False)
1394+ self.login_directory.set_sensitive(state)
1395+
1396+ def plugin_on_next_clicked(self):
1397+ if self.userinfo_notebook.get_current_page() == 0 and self.get_login_directory():
1398+ self.switch_userinfo_tab(1)
1399+ return True
1400+ return False
1401+
1402+ def plugin_on_back_clicked(self):
1403+ if self.userinfo_notebook.get_current_page() == 1:
1404+ self.switch_userinfo_tab(0)
1405+ return True
1406+ return False
1407+
1408+ def on_testdomain_click(self, widget):
1409+ if misc.execute('realm', 'discover', self.domain_name.get_text()):
1410+ self.domain_name_ok.show()
1411+ self.domain_name_error_label.hide()
1412+ else:
1413+ self.domain_name_ok.hide()
1414+ self.domain_name_error(self.domain_connection_error_text)
1415+ self.domain_name_error_label.show()
1416+
1417+ def on_login_directory_toggled(self, widget):
1418+ self.login_directory_extra_label.set_sensitive(widget.get_active())
1419+
1420
1421 class PageKde(PageBase):
1422 plugin_breadcrumb = 'ubiquity/text/breadcrumb_user'
1423@@ -746,6 +882,13 @@ class Page(plugin.Plugin):
1424 else:
1425 self.preseed('netcfg/get_domain', '')
1426
1427+ if hasattr(self.ui, 'get_login_directory'):
1428+ self.preseed_bool('ubiquity/login_use_directory', self.ui.get_login_directory())
1429+ if self.ui.get_login_directory():
1430+ self.preseed('ubiquity/directory_domain', self.ui.get_domain_name())
1431+ self.preseed('ubiquity/directory_user', self.ui.get_domain_user())
1432+ self.preseed('ubiquity/directory_passwd', self.ui.get_domain_passwd())
1433+
1434 plugin.Plugin.ok_handler(self)
1435
1436 def error(self, priority, question):

Subscribers

People subscribed via source and target branches