001: package com.xoetrope.service;
002:
003: import com.xoetrope.carousel.build.BuildProperties;
004: import com.xoetrope.service.servlet.SessionManager;
005: import java.awt.Color;
006: import java.awt.Component;
007: import java.awt.Dimension;
008: import java.awt.Frame;
009: import java.awt.Rectangle;
010: import java.awt.Toolkit;
011: import java.awt.event.ActionEvent;
012: import java.awt.event.ActionListener;
013: import java.util.Hashtable;
014: import java.util.Vector;
015: import javax.swing.JButton;
016: import javax.swing.JDialog;
017: import javax.swing.JLabel;
018: import javax.swing.JPasswordField;
019: import javax.swing.JTextField;
020: import net.xoetrope.optional.service.ServiceContext;
021: import net.xoetrope.optional.service.ServiceProxy;
022: import net.xoetrope.optional.service.ServiceProxyArgs;
023: import net.xoetrope.optional.service.ServiceProxyException;
024: import net.xoetrope.optional.service.XRouteManager;
025: import net.xoetrope.xui.XProjectManager;
026: import net.xoetrope.xui.data.XModel;
027:
028: /**
029: * Description ServiceProxy Object for handling user authentication. This class
030: * should be overloaded so as to implement the required authentication on
031: * the server. The 'selfmanaged' attribute should be set to 'true' in the XML
032: * declatation if the instance of this class should automatically take care of
033: * User Authentication. Set it to false if the user information will be managed
034: * manually.
035: *
036: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
037: * the GNU Public License (GPL), please see license.txt for more details. If
038: * you make commercial use of this software you must purchase a commercial
039: * license from Xoetrope.</p>
040: * <p> $Revision: 1.16 $</p>
041: */
042: public class AuthenticationService extends ServiceProxy {
043: private XModel uidMdl;
044: private String userID;
045: private JDialog logonDlg;
046: protected String username, password;
047: protected boolean okClicked, checkSessionAlive;
048:
049: /**
050: * Error sent back in the case that invalid credentials have been provided.
051: */
052: public static final String ERR_INVALID_CREDENTIALS = "authenticationerror:invalidcredentials";
053:
054: /**
055: * The userId pass and return parameters name
056: */
057: public static final String ARG_NAME_USERID = "authentication:userid";
058:
059: /**
060: * The password pass parameter
061: */
062: public static final String ARG_NAME_PASSWORD = "authentication:password";
063:
064: /**
065: * The path into the model where the userid is stored if the instance is
066: * selfmanaged.
067: */
068: public static final String ARG_NAME_MODELID = "authentication:modeluserid";
069:
070: /**
071: * indicates whether or not User Authentication should be managed automatically
072: */
073: protected boolean selfManaged = false;
074:
075: /**
076: * Call this proxy with the specified arguments
077: * @return the result of the call
078: * @param context The ServiceContext contain pass and return parameters
079: * @param serviceName the name of the service being called
080: * @throws net.xoetrope.optional.service.ServiceProxyException Throw an exception if there is a problem with the call
081: */
082: public Object call(String serviceName, ServiceContext context)
083: throws ServiceProxyException {
084: try {
085: status = STARTED;
086: ServiceProxyArgs args = context.getArgs();
087: if (side == XRouteManager.CLIENT_SIDE) {
088: if (BuildProperties.IS_EVAL)
089: LicenceCheck.checkLicence();
090:
091: /*
092: * if the userID is null show the logon dialog and call the next proxy
093: * if OK was clicked. Do this until the user is authenticated or cancel
094: * is clicked.
095: */
096: userID = (String) args.getPassParam(ARG_NAME_USERID);
097: if (userID == null) {
098: String modelid = (String) args
099: .getPassParam(ARG_NAME_MODELID);
100: if (modelid != null && modelid.length() > 0) {
101: uidMdl = (XModel) XProjectManager.getModel()
102: .get(modelid);
103: }
104: if (uidMdl != null)
105: userID = (String) uidMdl.get();
106: }
107:
108: if (selfManaged && userID == null)
109: logon(serviceName, context, null);
110: else {
111: if ((selfManaged) && (!context.hasErrors())) {
112: if ((userID == null) && (uidMdl != null))
113: userID = (String) uidMdl.get();
114: args.setPassParam(ARG_NAME_USERID, userID);
115: }
116: Object ret = callNextProxy(serviceName, context,
117: null);
118: String logonErr = getLogonError(context);
119: if (logonErr != null)
120: logon(serviceName, context, logonErr);
121:
122: if (uidMdl != null)
123: uidMdl
124: .set(args
125: .getReturnParam(ARG_NAME_USERID));
126: return ret;
127: }
128: return null;
129: } else {
130: /*
131: * On the server the user name and password needs to be checked using
132: * the overloaded checkCredentials method. If the user cannot be
133: * authenticated remove the userid argument and send back an error
134: * message.
135: */
136: String userID = (String) args
137: .getPassParam(ARG_NAME_USERID);
138: String password = (String) args
139: .getPassParam(ARG_NAME_PASSWORD);
140: boolean error = false;
141: if (!checkCredentials(args, userID, password)) {
142: args.setReturnParam(ARG_NAME_USERID, "");
143: args.addError(ERR_INVALID_CREDENTIALS);
144: error = true;
145: } else
146: args.setReturnParam(ARG_NAME_USERID, userID);
147:
148: if (error)
149: return null;
150: else
151: return callNextProxy(serviceName, context, null);
152: }
153: } catch (ServiceProxyException ex) {
154: status = FAILED;
155: throw (ex);
156: }
157: }
158:
159: /**
160: * Attempt to logon to the server and loop until it works.
161: * @param serviceName the name of the service being called
162: * @param context the ServiceContext for the current call
163: * @param errorMsg the error message to diplay if an error was generated.
164: */
165: protected void logon(String serviceName, ServiceContext context,
166: String errorMsg) throws ServiceProxyException {
167: try {
168: ServiceProxyArgs args = context.getArgs();
169: boolean error = true;
170: okClicked = true;
171: while (okClicked && error) {
172: getUserLogon(context, errorMsg);
173: if (okClicked) {
174: args.setPassParam(ARG_NAME_USERID, getUsername());
175: args.setPassParam(ARG_NAME_PASSWORD, getPassword());
176: args.getErrors().clear();
177: nextProxy.call(serviceName, context);
178: errorMsg = getLogonError(context);
179: error = (errorMsg != null);
180: }
181: }
182:
183: if ((okClicked) && (!args.hasErrors()) && (selfManaged)) {
184: userID = (String) args.getReturnParam(ARG_NAME_USERID);
185: if (uidMdl != null)
186: uidMdl.set(userID);
187: }
188: } catch (ServiceProxyException ex) {
189: status = FAILED;
190: throw (ex);
191: }
192: }
193:
194: /**
195: * Retrieve the entered user name
196: * @return the user name
197: */
198: protected String getUsername() {
199: return username;
200: }
201:
202: /**
203: * Retrieve the entered password
204: * @return the password
205: */
206: protected String getPassword() {
207: return password;
208: }
209:
210: /**
211: * Overload this method in order to implement custom authentication on the
212: * server.
213: * @param userID the userID to be authenticated
214: * @param password the password of the user
215: * @return boolean indicating whether or not user was successfully authenticated
216: */
217: protected boolean checkCredentials(ServiceProxyArgs args,
218: String userID, String password) {
219: return false;
220: }
221:
222: /*
223: * Check the return errors vector for logon errors or session errors if we are
224: * checking the session state.
225: * @param context the ServiceContext for the current call
226: */
227: protected String getLogonError(ServiceContext context) {
228: Vector errors = context.getErrors();
229: for (int i = 0; i < errors.size(); i++) {
230: String err = (String) errors.get(i);
231: if (err.compareTo(ERR_INVALID_CREDENTIALS) == 0) {
232: return ERR_INVALID_CREDENTIALS;
233: } else if ((checkSessionAlive)
234: && (err
235: .compareTo(SessionManager.ERR_SESSION_EXPIRED) == 0)) {
236: return SessionManager.ERR_SESSION_EXPIRED;
237: }
238: }
239: return null;
240: }
241:
242: /**
243: * Construct a user login screen to capture userid and password.
244: * @param context the context of the call
245: * @param error if the screen is being displayed as a result of an invalid
246: * login an error will need to be displayed.
247: */
248: protected void getUserLogon(ServiceContext context, String error) {
249: LogonDialog dlg = new LogonDialog(context, error);
250: }
251:
252: /**
253: * Center the screen on the parent
254: * @param c The component to be centered
255: */
256: public void centerScreen(Component c) {
257: Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
258: Rectangle abounds = c.getBounds();
259: c.setLocation((dim.width - abounds.width) / 2,
260: (dim.height - abounds.height) / 2);
261: }
262:
263: /**
264: * Set the attributes for this service proxy. Retrieve the 'selfmanaged'
265: * attribute and store it in the class variable
266: * @param attribs The Hashtable of attributes as found in the XML declaration
267: */
268: public void setAttributes(Hashtable attribs) {
269: String temp = (String) attribs.get("selfmanaged");
270: if (temp != null) {
271: selfManaged = temp.compareTo("true") == 0;
272: }
273: if (side == XRouteManager.CLIENT_SIDE) {
274: String modelid = (String) attribs.get("modelid");
275: if (modelid != null)
276: uidMdl = (XModel) XProjectManager.getModel().get(
277: modelid);
278:
279: String checkSession = (String) attribs
280: .get("checksessionalive");
281: if (checkSession != null)
282: checkSessionAlive = (checkSession.compareTo("true") == 0);
283: }
284: }
285:
286: protected String getErrorMsg(String error) {
287: if (error == null)
288: return null;
289: if (error.compareTo(ERR_INVALID_CREDENTIALS) == 0)
290: return "Invalid credentials... please try again!";
291: else if (error.compareTo(SessionManager.ERR_SESSION_EXPIRED) == 0)
292: return "Your session has expired... please logon again!";
293: return null;
294: }
295:
296: /**
297: * inner class to get the users logon details.
298: * @todo replace this with a XUI based dialog
299: */
300: private class LogonDialog extends JDialog {
301: /*
302: * private constructor to setup the logon dialog
303: * @param contect the current ServiceContext
304: * @param error the error, if any, which prompted the logon
305: */
306: private LogonDialog(ServiceContext context, String error) {
307: Frame fra = XProjectManager.getCurrentProject()
308: .getAppFrame();
309:
310: getContentPane().setLayout(null);
311: /// Text Fields
312: if (context.hasErrors()) {
313: String prompt = null;
314: JLabel lbl = new JLabel(getErrorMsg(error));
315: lbl.setForeground(Color.red);
316: lbl.setBounds(10, 10, 300, 20);
317: add(lbl);
318: }
319:
320: JLabel lbl = new JLabel("User ID");
321: lbl.setBounds(100, 50, 100, 20);
322: add(lbl);
323:
324: lbl = new JLabel("Password");
325: lbl.setBounds(100, 80, 100, 20);
326: add(lbl);
327:
328: final JTextField userText = new JTextField();
329: userText.setBounds(200, 50, 100, 20);
330: add(userText);
331:
332: final JPasswordField passwordEdit = new JPasswordField();
333: passwordEdit.setBounds(200, 80, 100, 20);
334: passwordEdit.setEchoChar('*');
335: add(passwordEdit);
336:
337: /// Buttons
338: JButton btnOK = new JButton("OK");
339: btnOK.setBounds(40, 130, 140, 25);
340: add(btnOK);
341: btnOK.addActionListener(new ActionListener() {
342: public void actionPerformed(ActionEvent e) {
343: okClicked = true;
344: setVisible(false);
345: username = userText.getText();
346: password = new String(passwordEdit.getPassword());
347: dispose();
348: }
349: });
350:
351: JButton btnCancel = new JButton("Cancel");
352: btnCancel.setBounds(220, 130, 140, 25);
353: add(btnCancel);
354: btnCancel.addActionListener(new ActionListener() {
355: public void actionPerformed(ActionEvent e) {
356: okClicked = false;
357: setVisible(false);
358: username = null;
359: password = null;
360: dispose();
361: }
362: });
363:
364: /// setup
365: setSize(400, 200);
366: setModal(true);
367: centerScreen(this );
368: setVisible(true);
369: }
370: }
371: }
|