View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.argeo.cms.ui.workbench.internal.useradmin.commands;
17  
18  import java.util.Dictionary;
19  import java.util.List;
20  import java.util.Map;
21  
22  import javax.naming.InvalidNameException;
23  import javax.naming.ldap.LdapName;
24  import javax.naming.ldap.Rdn;
25  
26  import org.argeo.cms.ArgeoNames;
27  import org.argeo.cms.CmsException;
28  import org.argeo.cms.ui.workbench.WorkbenchUiPlugin;
29  import org.argeo.cms.ui.workbench.internal.useradmin.UiAdminUtils;
30  import org.argeo.cms.ui.workbench.internal.useradmin.UserAdminWrapper;
31  import org.argeo.cms.util.UserAdminUtils;
32  import org.argeo.eclipse.ui.EclipseUiUtils;
33  import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
34  import org.argeo.naming.LdapAttrs;
35  import org.argeo.osgi.useradmin.UserAdminConf;
36  import org.eclipse.core.commands.AbstractHandler;
37  import org.eclipse.core.commands.ExecutionEvent;
38  import org.eclipse.core.commands.ExecutionException;
39  import org.eclipse.jface.wizard.Wizard;
40  import org.eclipse.jface.wizard.WizardDialog;
41  import org.eclipse.jface.wizard.WizardPage;
42  import org.eclipse.swt.SWT;
43  import org.eclipse.swt.events.ModifyEvent;
44  import org.eclipse.swt.events.ModifyListener;
45  import org.eclipse.swt.layout.GridData;
46  import org.eclipse.swt.layout.GridLayout;
47  import org.eclipse.swt.widgets.Combo;
48  import org.eclipse.swt.widgets.Composite;
49  import org.eclipse.swt.widgets.Label;
50  import org.eclipse.swt.widgets.Text;
51  import org.eclipse.ui.handlers.HandlerUtil;
52  import org.osgi.service.useradmin.Role;
53  import org.osgi.service.useradmin.User;
54  import org.osgi.service.useradmin.UserAdminEvent;
55  
56  /** Open a wizard that enables creation of a new user. */
57  public class NewUser extends AbstractHandler {
58  	// private final static Log log = LogFactory.getLog(NewUser.class);
59  	public final static String ID = WorkbenchUiPlugin.PLUGIN_ID + ".newUser";
60  
61  	/* DEPENDENCY INJECTION */
62  	private UserAdminWrapper userAdminWrapper;
63  
64  	public Object execute(ExecutionEvent event) throws ExecutionException {
65  		NewUserWizard newUserWizard = new NewUserWizard();
66  		newUserWizard.setWindowTitle("User creation");
67  		WizardDialog dialog = new WizardDialog(
68  				HandlerUtil.getActiveShell(event), newUserWizard);
69  		dialog.open();
70  		return null;
71  	}
72  
73  	private class NewUserWizard extends Wizard {
74  
75  		// pages
76  		private MainUserInfoWizardPage mainUserInfo;
77  
78  		// End user fields
79  		private Text dNameTxt, usernameTxt, firstNameTxt, lastNameTxt,
80  				primaryMailTxt, pwd1Txt, pwd2Txt;
81  		private Combo baseDnCmb;
82  
83  		public NewUserWizard() {
84  
85  		}
86  
87  		@Override
88  		public void addPages() {
89  			mainUserInfo = new MainUserInfoWizardPage();
90  			addPage(mainUserInfo);
91  			String message = "Default wizard that also eases user creation tests:\n "
92  					+ "Mail and last name are automatically "
93  					+ "generated form the uid. Password are defauted to 'demo'.";
94  			mainUserInfo.setMessage(message, WizardPage.WARNING);
95  		}
96  
97  		@SuppressWarnings({ "rawtypes", "unchecked" })
98  		@Override
99  		public boolean performFinish() {
100 			if (!canFinish())
101 				return false;
102 			String username = mainUserInfo.getUsername();
103 			userAdminWrapper.beginTransactionIfNeeded();
104 			try {
105 				User user = (User) userAdminWrapper.getUserAdmin().createRole(
106 						getDn(username), Role.USER);
107 
108 				Dictionary props = user.getProperties();
109 
110 				String lastNameStr = lastNameTxt.getText();
111 				if (EclipseUiUtils.notEmpty(lastNameStr))
112 					props.put(LdapAttrs.sn.name(), lastNameStr);
113 
114 				String firstNameStr = firstNameTxt.getText();
115 				if (EclipseUiUtils.notEmpty(firstNameStr))
116 					props.put(LdapAttrs.givenName.name(), firstNameStr);
117 
118 				String cn = UserAdminUtils.buildDefaultCn(firstNameStr,
119 						lastNameStr);
120 				if (EclipseUiUtils.notEmpty(cn))
121 					props.put(LdapAttrs.cn.name(), cn);
122 
123 				String mailStr = primaryMailTxt.getText();
124 				if (EclipseUiUtils.notEmpty(mailStr))
125 					props.put(LdapAttrs.mail.name(), mailStr);
126 
127 				char[] password = mainUserInfo.getPassword();
128 				user.getCredentials().put(null, password);
129 				userAdminWrapper.commitOrNotifyTransactionStateChange();
130 				userAdminWrapper.notifyListeners(new UserAdminEvent(null,
131 						UserAdminEvent.ROLE_CREATED, user));
132 				return true;
133 			} catch (Exception e) {
134 				ErrorFeedback.show("Cannot create new user " + username, e);
135 				return false;
136 			}
137 		}
138 
139 		private class MainUserInfoWizardPage extends WizardPage implements
140 				ModifyListener, ArgeoNames {
141 			private static final long serialVersionUID = -3150193365151601807L;
142 
143 			public MainUserInfoWizardPage() {
144 				super("Main");
145 				setTitle("Required Information");
146 			}
147 
148 			@Override
149 			public void createControl(Composite parent) {
150 				Composite composite = new Composite(parent, SWT.NONE);
151 				composite.setLayout(new GridLayout(2, false));
152 				dNameTxt = EclipseUiUtils.createGridLT(composite,
153 						"Distinguished name", this);
154 				dNameTxt.setEnabled(false);
155 
156 				baseDnCmb = createGridLC(composite, "Base DN");
157 				initialiseDnCmb(baseDnCmb);
158 				baseDnCmb.addModifyListener(this);
159 				baseDnCmb.addModifyListener(new ModifyListener() {
160 					private static final long serialVersionUID = -1435351236582736843L;
161 
162 					@Override
163 					public void modifyText(ModifyEvent event) {
164 						String name = usernameTxt.getText();
165 						dNameTxt.setText(getDn(name));
166 					}
167 				});
168 
169 				usernameTxt = EclipseUiUtils.createGridLT(composite,
170 						"Local ID", this);
171 				usernameTxt.addModifyListener(new ModifyListener() {
172 					private static final long serialVersionUID = -1435351236582736843L;
173 
174 					@Override
175 					public void modifyText(ModifyEvent event) {
176 						String name = usernameTxt.getText();
177 						if (name.trim().equals("")) {
178 							dNameTxt.setText("");
179 							lastNameTxt.setText("");
180 							primaryMailTxt.setText("");
181 							pwd1Txt.setText("");
182 							pwd2Txt.setText("");
183 						} else {
184 							dNameTxt.setText(getDn(name));
185 							lastNameTxt.setText(name.toUpperCase());
186 							primaryMailTxt.setText(getMail(name));
187 							pwd1Txt.setText("demo");
188 							pwd2Txt.setText("demo");
189 						}
190 					}
191 				});
192 
193 				primaryMailTxt = EclipseUiUtils.createGridLT(composite,
194 						"Email", this);
195 				firstNameTxt = EclipseUiUtils.createGridLT(composite,
196 						"First name", this);
197 				lastNameTxt = EclipseUiUtils.createGridLT(composite,
198 						"Last name", this);
199 				pwd1Txt = EclipseUiUtils.createGridLP(composite, "Password",
200 						this);
201 				pwd2Txt = EclipseUiUtils.createGridLP(composite,
202 						"Repeat password", this);
203 				setControl(composite);
204 
205 				// Initialize buttons
206 				setPageComplete(false);
207 				getContainer().updateButtons();
208 			}
209 
210 			@Override
211 			public void modifyText(ModifyEvent event) {
212 				String message = checkComplete();
213 				if (message != null) {
214 					setMessage(message, WizardPage.ERROR);
215 					setPageComplete(false);
216 				} else {
217 					setMessage("Complete", WizardPage.INFORMATION);
218 					setPageComplete(true);
219 				}
220 				getContainer().updateButtons();
221 			}
222 
223 			/** @return error message or null if complete */
224 			protected String checkComplete() {
225 				String name = usernameTxt.getText();
226 
227 				if (name.trim().equals(""))
228 					return "User name must not be empty";
229 				Role role = userAdminWrapper.getUserAdmin()
230 						.getRole(getDn(name));
231 				if (role != null)
232 					return "User " + name + " already exists";
233 				if (!primaryMailTxt.getText().matches(UiAdminUtils.EMAIL_PATTERN))
234 					return "Not a valid email address";
235 				if (lastNameTxt.getText().trim().equals(""))
236 					return "Specify a last name";
237 				if (pwd1Txt.getText().trim().equals(""))
238 					return "Specify a password";
239 				if (pwd2Txt.getText().trim().equals(""))
240 					return "Repeat the password";
241 				if (!pwd2Txt.getText().equals(pwd1Txt.getText()))
242 					return "Passwords are different";
243 				return null;
244 			}
245 
246 			@Override
247 			public void setVisible(boolean visible) {
248 				super.setVisible(visible);
249 				if (visible)
250 					if (baseDnCmb.getSelectionIndex() == -1)
251 						baseDnCmb.setFocus();
252 					else
253 						usernameTxt.setFocus();
254 			}
255 
256 			public String getUsername() {
257 				return usernameTxt.getText();
258 			}
259 
260 			public char[] getPassword() {
261 				return pwd1Txt.getTextChars();
262 			}
263 
264 		}
265 
266 		private Map<String, String> getDns() {
267 			return userAdminWrapper.getKnownBaseDns(true);
268 		}
269 
270 		private String getDn(String uid) {
271 			Map<String, String> dns = getDns();
272 			String bdn = baseDnCmb.getText();
273 			if (EclipseUiUtils.notEmpty(bdn)) {
274 				Dictionary<String, ?> props = UserAdminConf.uriAsProperties(dns
275 						.get(bdn));
276 				String dn = LdapAttrs.uid.name() + "=" + uid + ","
277 						+ UserAdminConf.userBase.getValue(props) + "," + bdn;
278 				return dn;
279 			}
280 			return null;
281 		}
282 
283 		private void initialiseDnCmb(Combo combo) {
284 			Map<String, String> dns = userAdminWrapper.getKnownBaseDns(true);
285 			if (dns.isEmpty())
286 				throw new CmsException(
287 						"No writable base dn found. Cannot create user");
288 			combo.setItems(dns.keySet().toArray(new String[0]));
289 			if (dns.size() == 1)
290 				combo.select(0);
291 		}
292 
293 		private String getMail(String username) {
294 			if (baseDnCmb.getSelectionIndex() == -1)
295 				return null;
296 			String baseDn = baseDnCmb.getText();
297 			try {
298 				LdapName name = new LdapName(baseDn);
299 				List<Rdn> rdns = name.getRdns();
300 				return username + "@" + (String) rdns.get(1).getValue() + '.'
301 						+ (String) rdns.get(0).getValue();
302 			} catch (InvalidNameException e) {
303 				throw new CmsException("Unable to generate mail for "
304 						+ username + " with base dn " + baseDn, e);
305 			}
306 		}
307 	}
308 
309 	private Combo createGridLC(Composite parent, String label) {
310 		Label lbl = new Label(parent, SWT.LEAD);
311 		lbl.setText(label);
312 		lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
313 		Combo combo = new Combo(parent, SWT.LEAD | SWT.BORDER | SWT.READ_ONLY);
314 		combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
315 		return combo;
316 	}
317 
318 	/* DEPENDENCY INJECTION */
319 	public void setUserAdminWrapper(UserAdminWrapper userAdminWrapper) {
320 		this.userAdminWrapper = userAdminWrapper;
321 	}
322 }