View Javadoc
1   package org.argeo.cms.ui.widgets.auth;
2   
3   import static org.argeo.cms.CmsMsg.password;
4   import static org.argeo.cms.CmsMsg.username;
5   
6   import java.io.IOException;
7   import java.util.List;
8   import java.util.Locale;
9   
10  import javax.security.auth.Subject;
11  import javax.security.auth.callback.Callback;
12  import javax.security.auth.callback.CallbackHandler;
13  import javax.security.auth.callback.LanguageCallback;
14  import javax.security.auth.callback.NameCallback;
15  import javax.security.auth.callback.PasswordCallback;
16  import javax.security.auth.callback.UnsupportedCallbackException;
17  import javax.security.auth.login.LoginContext;
18  import javax.security.auth.login.LoginException;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.argeo.api.NodeConstants;
23  import org.argeo.api.NodeState;
24  import org.argeo.cms.CmsMsg;
25  import org.argeo.cms.LocaleUtils;
26  import org.argeo.cms.auth.HttpRequestCallback;
27  import org.argeo.cms.ui.CmsStyles;
28  import org.argeo.cms.ui.CmsView;
29  import org.argeo.cms.ui.internal.Activator;
30  import org.argeo.cms.ui.util.CmsUiUtils;
31  import org.argeo.eclipse.ui.specific.UiContext;
32  import org.eclipse.swt.SWT;
33  import org.eclipse.swt.events.MouseAdapter;
34  import org.eclipse.swt.events.MouseEvent;
35  import org.eclipse.swt.events.SelectionAdapter;
36  import org.eclipse.swt.events.SelectionEvent;
37  import org.eclipse.swt.events.SelectionListener;
38  import org.eclipse.swt.events.TraverseEvent;
39  import org.eclipse.swt.events.TraverseListener;
40  import org.eclipse.swt.layout.GridData;
41  import org.eclipse.swt.layout.GridLayout;
42  import org.eclipse.swt.widgets.Button;
43  import org.eclipse.swt.widgets.Composite;
44  import org.eclipse.swt.widgets.Control;
45  import org.eclipse.swt.widgets.Label;
46  import org.eclipse.swt.widgets.Shell;
47  import org.eclipse.swt.widgets.Text;
48  
49  public class CmsLogin implements CmsStyles, CallbackHandler {
50  	private final static Log log = LogFactory.getLog(CmsLogin.class);
51  
52  	private Composite parent;
53  	private Text usernameT, passwordT;
54  	private Composite credentialsBlock;
55  	private final SelectionListener loginSelectionListener;
56  
57  	private final Locale defaultLocale;
58  	private LocaleChoice localeChoice = null;
59  
60  	private final CmsView cmsView;
61  
62  	// optional subject to be set explicitly
63  	private Subject subject = null;
64  
65  	public CmsLogin(CmsView cmsView) {
66  		this.cmsView = cmsView;
67  		NodeState nodeState = Activator.getNodeState();
68  		if (nodeState != null) {
69  			defaultLocale = nodeState.getDefaultLocale();
70  			List<Locale> locales = nodeState.getLocales();
71  			if (locales != null)
72  				localeChoice = new LocaleChoice(locales, defaultLocale);
73  		} else {
74  			defaultLocale = Locale.getDefault();
75  		}
76  		loginSelectionListener = new SelectionListener() {
77  			private static final long serialVersionUID = -8832133363830973578L;
78  
79  			@Override
80  			public void widgetSelected(SelectionEvent e) {
81  				login();
82  			}
83  
84  			@Override
85  			public void widgetDefaultSelected(SelectionEvent e) {
86  			}
87  		};
88  	}
89  
90  	protected boolean isAnonymous() {
91  		return cmsView.isAnonymous();
92  	}
93  
94  	public final void createUi(Composite parent) {
95  		this.parent = parent;
96  		createContents(parent);
97  	}
98  
99  	protected void createContents(Composite parent) {
100 		defaultCreateContents(parent);
101 	}
102 
103 	public final void defaultCreateContents(Composite parent) {
104 		parent.setLayout(CmsUiUtils.noSpaceGridLayout());
105 		Composite credentialsBlock = createCredentialsBlock(parent);
106 		if (parent instanceof Shell) {
107 			credentialsBlock.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
108 		}
109 	}
110 
111 	public final Composite createCredentialsBlock(Composite parent) {
112 		if (isAnonymous()) {
113 			return anonymousUi(parent);
114 		} else {
115 			return userUi(parent);
116 		}
117 	}
118 
119 	protected Composite getCredentialsBlock() {
120 		return credentialsBlock;
121 	}
122 
123 	protected Composite userUi(Composite parent) {
124 		Locale locale = localeChoice == null ? this.defaultLocale : localeChoice.getSelectedLocale();
125 		credentialsBlock = new Composite(parent, SWT.NONE);
126 		credentialsBlock.setLayout(new GridLayout());
127 		// credentialsBlock.setLayoutData(CmsUiUtils.fillAll());
128 
129 		specificUserUi(credentialsBlock);
130 
131 		Label l = new Label(credentialsBlock, SWT.NONE);
132 		CmsUiUtils.style(l, CMS_USER_MENU_ITEM);
133 		l.setText(CmsMsg.logout.lead(locale));
134 		GridData lData = CmsUiUtils.fillWidth();
135 		lData.widthHint = 120;
136 		l.setLayoutData(lData);
137 
138 		l.addMouseListener(new MouseAdapter() {
139 			private static final long serialVersionUID = 6444395812777413116L;
140 
141 			public void mouseDown(MouseEvent e) {
142 				logout();
143 			}
144 		});
145 		return credentialsBlock;
146 	}
147 
148 	/** To be overridden */
149 	protected void specificUserUi(Composite parent) {
150 
151 	}
152 
153 	protected Composite anonymousUi(Composite parent) {
154 		Locale locale = localeChoice == null ? this.defaultLocale : localeChoice.getSelectedLocale();
155 		// We need a composite for the traversal
156 		credentialsBlock = new Composite(parent, SWT.NONE);
157 		credentialsBlock.setLayout(new GridLayout());
158 		// credentialsBlock.setLayoutData(CmsUiUtils.fillAll());
159 		CmsUiUtils.style(credentialsBlock, CMS_LOGIN_DIALOG);
160 
161 		Integer textWidth = 120;
162 		if (parent instanceof Shell)
163 			CmsUiUtils.style(parent, CMS_USER_MENU);
164 		// new Label(this, SWT.NONE).setText(CmsMsg.username.lead());
165 		usernameT = new Text(credentialsBlock, SWT.BORDER);
166 		usernameT.setMessage(username.lead(locale));
167 		CmsUiUtils.style(usernameT, CMS_LOGIN_DIALOG_USERNAME);
168 		GridData gd = CmsUiUtils.fillWidth();
169 		gd.widthHint = textWidth;
170 		usernameT.setLayoutData(gd);
171 
172 		// new Label(this, SWT.NONE).setText(CmsMsg.password.lead());
173 		passwordT = new Text(credentialsBlock, SWT.BORDER | SWT.PASSWORD);
174 		passwordT.setMessage(password.lead(locale));
175 		CmsUiUtils.style(passwordT, CMS_LOGIN_DIALOG_PASSWORD);
176 		gd = CmsUiUtils.fillWidth();
177 		gd.widthHint = textWidth;
178 		passwordT.setLayoutData(gd);
179 
180 		TraverseListener tl = new TraverseListener() {
181 			private static final long serialVersionUID = -1158892811534971856L;
182 
183 			public void keyTraversed(TraverseEvent e) {
184 				if (e.detail == SWT.TRAVERSE_RETURN)
185 					login();
186 			}
187 		};
188 		credentialsBlock.addTraverseListener(tl);
189 		usernameT.addTraverseListener(tl);
190 		passwordT.addTraverseListener(tl);
191 		parent.setTabList(new Control[] { credentialsBlock });
192 		credentialsBlock.setTabList(new Control[] { usernameT, passwordT });
193 
194 		// Button
195 		Button loginButton = new Button(credentialsBlock, SWT.PUSH);
196 		loginButton.setText(CmsMsg.login.lead(locale));
197 		loginButton.setLayoutData(CmsUiUtils.fillWidth());
198 		loginButton.addSelectionListener(loginSelectionListener);
199 
200 		extendsCredentialsBlock(credentialsBlock, locale, loginSelectionListener);
201 		if (localeChoice != null)
202 			createLocalesBlock(credentialsBlock);
203 		return credentialsBlock;
204 	}
205 
206 	/**
207 	 * To be overridden in order to provide custom login button and other links.
208 	 */
209 	protected void extendsCredentialsBlock(Composite credentialsBlock, Locale selectedLocale,
210 			SelectionListener loginSelectionListener) {
211 
212 	}
213 
214 	protected void updateLocale(Locale selectedLocale) {
215 		// save already entered values
216 		String usernameStr = usernameT.getText();
217 		char[] pwd = passwordT.getTextChars();
218 
219 		for (Control child : parent.getChildren())
220 			child.dispose();
221 		createContents(parent);
222 		if (parent.getParent() != null)
223 			parent.getParent().layout();
224 		else
225 			parent.layout();
226 		usernameT.setText(usernameStr);
227 		passwordT.setTextChars(pwd);
228 	}
229 
230 	protected Composite createLocalesBlock(final Composite parent) {
231 		Composite c = new Composite(parent, SWT.NONE);
232 		CmsUiUtils.style(c, CMS_USER_MENU_ITEM);
233 		c.setLayout(CmsUiUtils.noSpaceGridLayout());
234 		c.setLayoutData(CmsUiUtils.fillAll());
235 
236 		SelectionListener selectionListener = new SelectionAdapter() {
237 			private static final long serialVersionUID = 4891637813567806762L;
238 
239 			public void widgetSelected(SelectionEvent event) {
240 				Button button = (Button) event.widget;
241 				if (button.getSelection()) {
242 					localeChoice.setSelectedIndex((Integer) event.widget.getData());
243 					updateLocale(localeChoice.getSelectedLocale());
244 				}
245 			};
246 		};
247 
248 		List<Locale> locales = localeChoice.getLocales();
249 		for (Integer i = 0; i < locales.size(); i++) {
250 			Locale locale = locales.get(i);
251 			Button button = new Button(c, SWT.RADIO);
252 			CmsUiUtils.style(button, CMS_USER_MENU_ITEM);
253 			button.setData(i);
254 			button.setText(LocaleUtils.lead(locale.getDisplayName(locale), locale) + " (" + locale + ")");
255 			// button.addListener(SWT.Selection, listener);
256 			button.addSelectionListener(selectionListener);
257 			if (i == localeChoice.getSelectedIndex())
258 				button.setSelection(true);
259 		}
260 		return c;
261 	}
262 
263 	protected boolean login() {
264 		// TODO use CmsVie in order to retrieve subject?
265 		// Subject subject = cmsView.getLoginContext().getSubject();
266 		// LoginContext loginContext = cmsView.getLoginContext();
267 		try {
268 			//
269 			// LOGIN
270 			//
271 			// loginContext.logout();
272 			LoginContext loginContext;
273 			if (subject == null)
274 				loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, this);
275 			else
276 				loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, subject, this);
277 			loginContext.login();
278 			cmsView.authChange(loginContext);
279 			return true;
280 		} catch (LoginException e) {
281 			if (log.isTraceEnabled())
282 				log.warn("Login failed: " + e.getMessage(), e);
283 			else
284 				log.warn("Login failed: " + e.getMessage());
285 
286 			try {
287 				Thread.sleep(3000);
288 			} catch (InterruptedException e2) {
289 				// silent
290 			}
291 			// ErrorFeedback.show("Login failed", e);
292 			return false;
293 		}
294 		// catch (LoginException e) {
295 		// log.error("Cannot login", e);
296 		// return false;
297 		// }
298 	}
299 
300 	protected void logout() {
301 		cmsView.logout();
302 		cmsView.navigateTo("~");
303 	}
304 
305 	@Override
306 	public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
307 		for (Callback callback : callbacks) {
308 			if (callback instanceof NameCallback && usernameT != null)
309 				((NameCallback) callback).setName(usernameT.getText());
310 			else if (callback instanceof PasswordCallback && passwordT != null)
311 				((PasswordCallback) callback).setPassword(passwordT.getTextChars());
312 			else if (callback instanceof HttpRequestCallback) {
313 				((HttpRequestCallback) callback).setRequest(UiContext.getHttpRequest());
314 				((HttpRequestCallback) callback).setResponse(UiContext.getHttpResponse());
315 			} else if (callback instanceof LanguageCallback) {
316 				Locale toUse = null;
317 				if (localeChoice != null)
318 					toUse = localeChoice.getSelectedLocale();
319 				else if (defaultLocale != null)
320 					toUse = defaultLocale;
321 
322 				if (toUse != null) {
323 					((LanguageCallback) callback).setLocale(toUse);
324 					UiContext.setLocale(toUse);
325 				}
326 
327 			}
328 		}
329 	}
330 
331 	public void setSubject(Subject subject) {
332 		this.subject = subject;
333 	}
334 
335 }