source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/Authentication.java@ 25734

Last change on this file since 25734 was 25734, checked in by sjm84, 12 years ago

Adding a fix for reCaptcha not working. Not completely happy with it as it relies on a timeout, but it will do for now

File size: 31.2 KB
RevLine 
[14295]1package org.greenstone.gsdl3.service;
2
[25722]3import java.io.File;
4import java.io.Serializable;
[25318]5import java.math.BigInteger;
[25722]6import java.security.MessageDigest;
7import java.sql.SQLException;
[25258]8import java.util.ArrayList;
[25124]9import java.util.HashMap;
[25258]10import java.util.UUID;
[14295]11import java.util.Vector;
12import java.util.regex.Pattern;
13
[25258]14import net.tanesha.recaptcha.ReCaptchaImpl;
15import net.tanesha.recaptcha.ReCaptchaResponse;
16
[25722]17import org.greenstone.gsdl3.util.DerbyWrapper;
18import org.greenstone.gsdl3.util.GSXML;
19import org.greenstone.gsdl3.util.UserQueryResult;
20import org.greenstone.gsdl3.util.UserTermInfo;
21import org.w3c.dom.Element;
22import org.w3c.dom.NodeList;
23
[24978]24public class Authentication extends ServiceRack
25{
[25258]26 //Error codes
27 protected static final int NO_ERROR = 0;
28 protected static final int ERROR_REQUEST_HAS_NO_PARAM_LIST = -1;
29 protected static final int ERROR_NOT_LOGGED_IN = -2;
30 protected static final int ERROR_ADMIN_NOT_LOGGED_IN = -3;
31 protected static final int ERROR_COULD_NOT_GET_USER_INFO = -4;
32 protected static final int ERROR_USERNAME_NOT_SPECIFIED = -5;
33 protected static final int ERROR_REQUESTED_USER_NOT_FOUND = -6;
34 protected static final int ERROR_SQL_EXCEPTION = -7;
35 protected static final int ERROR_INVALID_USERNAME = -8;
36 protected static final int ERROR_INVALID_PASSWORD = -9;
37 protected static final int ERROR_INCORRECT_PASSWORD = -10;
38 protected static final int ERROR_USER_ALREADY_EXISTS = -11;
39 protected static final int ERROR_ADDING_USER = -12;
40 protected static final int ERROR_REMOVING_USER = -13;
41 protected static final int ERROR_CAPTCHA_DOES_NOT_MATCH = -14;
42 protected static final int ERROR_CAPTCHA_MISSING = -15;
43 protected static final int ERROR_NOT_AUTHORISED = -16;
44
45 protected static final HashMap<Integer, String> _errorMessageMap;
46 static
47 {
48 //Corresponding error messages
49 HashMap<Integer, String> errorMessageMap = new HashMap<Integer, String>();
50 errorMessageMap.put(ERROR_REQUEST_HAS_NO_PARAM_LIST, "The list of parameters for this request was empty.");
51 errorMessageMap.put(ERROR_NOT_LOGGED_IN, "You must be logged in to access this page.");
52 errorMessageMap.put(ERROR_ADMIN_NOT_LOGGED_IN, "You must be logged in as an administrator to access this page.");
53 errorMessageMap.put(ERROR_COULD_NOT_GET_USER_INFO, "There was a error getting the user information.");
54 errorMessageMap.put(ERROR_USERNAME_NOT_SPECIFIED, "No username was specified.");
55 errorMessageMap.put(ERROR_REQUESTED_USER_NOT_FOUND, "The requested user was not found in the database.");
56 errorMessageMap.put(ERROR_SQL_EXCEPTION, "There was an SQL exception while accessing the database.");
57 errorMessageMap.put(ERROR_INVALID_USERNAME, "The username specified was invalid.");
58 errorMessageMap.put(ERROR_INVALID_PASSWORD, "The password specified was invalid.");
59 errorMessageMap.put(ERROR_INCORRECT_PASSWORD, "The password specified was incorrect.");
60 errorMessageMap.put(ERROR_USER_ALREADY_EXISTS, "This user already exists and therefore cannot be added.");
61 errorMessageMap.put(ERROR_ADDING_USER, "There was an error adding this user to the database.");
62 errorMessageMap.put(ERROR_REMOVING_USER, "There was an error removing this user from the database.");
63 errorMessageMap.put(ERROR_CAPTCHA_DOES_NOT_MATCH, "The words you entered did not match the image, please try again.");
64 errorMessageMap.put(ERROR_CAPTCHA_MISSING, "The information from the captcha is missing.");
65 errorMessageMap.put(ERROR_NOT_AUTHORISED, "You are not authorised to access this page.");
66
67 _errorMessageMap = errorMessageMap;
68 }
69
70 //Admin-required operations
71 protected static final String LIST_USERS = "ListUsers";
72 protected static final String PERFORM_ADD = "PerformAdd";
73 protected static final String PERFORM_EDIT = "PerformEdit";
74 protected static final String ADD_USER = "AddUser";
75 protected static final String EDIT_USER = "EditUser";
76 protected static final String PERFORM_DELETE_USER = "PerformDeleteUser";
77
78 protected static final ArrayList<String> _adminOpList;
79 static
80 {
81 ArrayList<String> opList = new ArrayList<String>();
82 opList.add(LIST_USERS);
83 opList.add(PERFORM_ADD);
84 opList.add(PERFORM_EDIT);
85 opList.add(EDIT_USER);
86 opList.add(PERFORM_DELETE_USER);
87
88 _adminOpList = opList;
89 }
90
91 //User-required operations
92 protected static final String ACCOUNT_SETTINGS = "AccountSettings";
93 protected static final String PERFORM_ACCOUNT_EDIT = "PerformAccEdit";
94 protected static final String PERFORM_RESET_PASSWORD = "PerformResetPassword";
95 protected static final ArrayList<String> _userOpList;
96 static
97 {
98 ArrayList<String> opList = new ArrayList<String>();
99 opList.add(ACCOUNT_SETTINGS);
100 opList.add(PERFORM_ACCOUNT_EDIT);
101 opList.add(PERFORM_RESET_PASSWORD);
102 opList.addAll(_adminOpList);
103 _userOpList = opList;
104 }
105
106 //Other operations
107 protected static final String REGISTER = "Register";
108 protected static final String PERFORM_REGISTER = "PerformRegister";
109 protected static final String LOGIN = "Login";
110
[17452]111 //the services on offer
[24978]112 protected static final String AUTHENTICATION_SERVICE = "Authentication";
[25124]113 protected static final String GET_USER_INFORMATION_SERVICE = "GetUserInformation";
[14295]114
[25258]115 protected DerbyWrapper _derbyWrapper = null;
116
[25311]117 protected String _recaptchaPrivateKey = null;
118 protected String _recaptchaPublicKey = null;
119
[17452]120 /** constructor */
121 public Authentication()
[24978]122 {
123 }
[14295]124
[24978]125 public boolean configure(Element info, Element extra_info)
[17452]126 {
127 logger.info("Configuring Authentication...");
128 this.config_info = info;
[14295]129
[17452]130 // set up Authentication service info - for now just has name and type
[24978]131 Element authentication_service = this.doc.createElement(GSXML.SERVICE_ELEM);
132 authentication_service.setAttribute(GSXML.TYPE_ATT, "authen");
[17452]133 authentication_service.setAttribute(GSXML.NAME_ATT, AUTHENTICATION_SERVICE);
134 this.short_service_info.appendChild(authentication_service);
[14295]135
[25124]136 // set up Authentication service info - for now just has name and type
137 Element getUserInformation_service = this.doc.createElement(GSXML.SERVICE_ELEM);
138 getUserInformation_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
139 getUserInformation_service.setAttribute(GSXML.NAME_ATT, GET_USER_INFORMATION_SERVICE);
140 this.short_service_info.appendChild(getUserInformation_service);
141
[25311]142 NodeList recaptchaElems = info.getElementsByTagName("recaptcha");
143
144 for (int i = 0; i < recaptchaElems.getLength(); i++)
145 {
146 Element currentElem = (Element) recaptchaElems.item(i);
147 if (currentElem.getAttribute(GSXML.NAME_ATT) != null && currentElem.getAttribute(GSXML.NAME_ATT).equals("public_key"))
148 {
149 if (currentElem.getAttribute(GSXML.VALUE_ATT) != null)
150 {
151 _recaptchaPublicKey = currentElem.getAttribute(GSXML.VALUE_ATT);
152 }
153 }
154 else if (currentElem.getAttribute(GSXML.NAME_ATT) != null && currentElem.getAttribute(GSXML.NAME_ATT).equals("private_key"))
155 {
156 if (currentElem.getAttribute(GSXML.VALUE_ATT) != null)
157 {
158 _recaptchaPrivateKey = currentElem.getAttribute(GSXML.VALUE_ATT);
159 }
160 }
161 }
162
[17452]163 return true;
164 }
[14295]165
[24978]166 protected Element getServiceDescription(String service_id, String lang, String subset)
[17452]167 {
168
[24978]169 Element authen_service = this.doc.createElement(GSXML.SERVICE_ELEM);
[17452]170
[24978]171 if (service_id.equals(AUTHENTICATION_SERVICE))
172 {
173 authen_service.setAttribute(GSXML.TYPE_ATT, "authen");
[17452]174 authen_service.setAttribute(GSXML.NAME_ATT, AUTHENTICATION_SERVICE);
[24978]175 }
[25124]176 else if (service_id.equals(GET_USER_INFORMATION_SERVICE))
177 {
178 authen_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
179 authen_service.setAttribute(GSXML.NAME_ATT, GET_USER_INFORMATION_SERVICE);
180 }
[24978]181 else
182 {
[17452]183 return null;
184 }
185
[25124]186 if (service_id.equals(AUTHENTICATION_SERVICE) && (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER)))
[24978]187 {
188 authen_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getServiceName(service_id, lang)));
[17452]189 authen_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getServiceDescription(service_id, lang)));
190 }
[24978]191 return authen_service;
[14295]192 }
[17452]193
[24978]194 protected String getServiceName(String service_id, String lang)
195 {
196 return getTextString(service_id + ".name", lang);
[14295]197 }
198
[24978]199 protected String getServiceSubmit(String service_id, String lang)
200 {
201 return getTextString(service_id + ".submit", lang);
[17452]202 }
[14295]203
[24978]204 protected String getServiceDescription(String service_id, String lang)
205 {
206 return getTextString(service_id + ".description", lang);
[17452]207 }
[14295]208
[24978]209 protected void addCustomParams(String service, Element param_list, String lang)
210 {
[17452]211 }
[14295]212
[24978]213 protected void createParameter(String name, Element param_list, String lang)
214 {
[17452]215 }
[14295]216
[25124]217 protected Element processGetUserInformation(Element request)
218 {
219 // Create a new (empty) result message
220 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
221
222 result.setAttribute(GSXML.FROM_ATT, GET_USER_INFORMATION_SERVICE);
223 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
224
225 Element paramList = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
226 if (paramList == null)
227 {
[25258]228 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_REQUEST_HAS_NO_PARAM_LIST));
229 return result;
[25124]230 }
231
[25635]232 HashMap<String, Serializable> params = GSXML.extractParams(paramList, true);
[25124]233
234 String username = (String) params.get("username");
235
236 if (username == null)
237 {
[25258]238 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_USERNAME_NOT_SPECIFIED));
[25124]239 return result;
240 }
241
242 DerbyWrapper dbWrapper = new DerbyWrapper();
243
244 String usersDB_dir = this.site_home + File.separatorChar + "etc" + File.separatorChar + "usersDB";
245 dbWrapper.connectDatabase(usersDB_dir, true);
246
247 UserQueryResult userQueryResult;
248 try
249 {
250 userQueryResult = dbWrapper.findUser(username);
251 Vector<UserTermInfo> terms = userQueryResult.getUserTerms();
252
253 if (terms.size() == 0)
254 {
[25258]255 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_REQUESTED_USER_NOT_FOUND));
[25124]256 return result;
257 }
258
259 UserTermInfo userInfo = terms.get(0);
260 Element userInfoList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
261 result.appendChild(userInfoList);
262
[25258]263 Element usernameField = GSXML.createParameter(this.doc, "username", userInfo.username);
264 Element passwordField = GSXML.createParameter(this.doc, "password", userInfo.password);
265 Element groupsField = GSXML.createParameter(this.doc, "groups", userInfo.groups);
266 Element accountStatusField = GSXML.createParameter(this.doc, "accountstatus", userInfo.accountstatus);
267 Element commentField = GSXML.createParameter(this.doc, "comment", userInfo.comment);
[25124]268
269 userInfoList.appendChild(usernameField);
270 userInfoList.appendChild(passwordField);
271 userInfoList.appendChild(groupsField);
272 userInfoList.appendChild(accountStatusField);
273 userInfoList.appendChild(commentField);
274 }
[25258]275 catch (SQLException ex)
[25124]276 {
[25258]277 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_SQL_EXCEPTION));
[25124]278 ex.printStackTrace();
279 }
280
281 return result;
282 }
283
[25258]284 protected Element processAuthentication(Element request)
[24978]285 {
[25258]286 checkAdminUserExists();
[14295]287
[17452]288 // Create a new (empty) result message
289 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
290 result.setAttribute(GSXML.FROM_ATT, AUTHENTICATION_SERVICE);
291 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
[14295]292
[25258]293 // Create an Authentication node put into the result
294 Element authenNode = this.doc.createElement(GSXML.AUTHEN_NODE_ELEM);
295 result.appendChild(authenNode);
296 result.appendChild(getCollectList(this.site_home + File.separatorChar + "collect"));
297
298 // Create a service node added into the Authentication node
299 Element serviceNode = this.doc.createElement(GSXML.SERVICE_ELEM);
300 authenNode.appendChild(serviceNode);
301
[17452]302 // Get the parameters of the request
[24978]303 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
304 if (param_list == null)
305 {
[25258]306 serviceNode.setAttribute("operation", LOGIN);
307 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_REQUEST_HAS_NO_PARAM_LIST));
[24978]308 return result; // Return the empty result
[17452]309 }
[25635]310 HashMap<String, Serializable> paramMap = GSXML.extractParams(param_list, false);
[25258]311 String op = (String) paramMap.get("authpage");
312 serviceNode.setAttribute("operation", op);
[14295]313
[25258]314 String username = null;
315 String groups = null;
[14295]316
[25258]317 Element userInformation = (Element) GSXML.getChildByTagName(request, GSXML.USER_INFORMATION_ELEM);
318 if (userInformation == null && _userOpList.contains(op))
319 {
320 serviceNode.setAttribute("operation", LOGIN);
321 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_NOT_LOGGED_IN));
322 return result;
323 }
[14295]324
[25258]325 if (userInformation != null)
326 {
327 username = userInformation.getAttribute(GSXML.USERNAME_ATT);
328 groups = userInformation.getAttribute(GSXML.GROUPS_ATT);
329 }
[17452]330
[25258]331 if (username == null && _userOpList.contains(op))
332 {
333 serviceNode.setAttribute("operation", LOGIN);
334 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_NOT_LOGGED_IN));
335 return result;
336 }
[24978]337
[25258]338 if (_adminOpList.contains(op) && (groups == null || !groups.matches(".*\\badministrator\\b.*")))
[24978]339 {
[25258]340 serviceNode.setAttribute("operation", LOGIN);
341 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_ADMIN_NOT_LOGGED_IN));
342 return result;
343 }
[17452]344
[25258]345 if (op.equals(LIST_USERS))
346 {
347 int error = addUserInformationToNode(null, serviceNode);
348 if (error != NO_ERROR)
[24978]349 {
[25258]350 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
[24978]351 }
[25258]352 }
353 else if (op.equals(PERFORM_ADD))
354 {
355 String newUsername = (String) paramMap.get("username");
356 String newPassword = (String) paramMap.get("password");
357 String newGroups = (String) paramMap.get("groups");
358 String newStatus = (String) paramMap.get("status");
359 String newComment = (String) paramMap.get("comment");
360 String newEmail = (String) paramMap.get("email");
[25722]361
[25311]362 //Check the given user name
363 int error;
364 if ((error = checkUsername(newUsername)) != NO_ERROR)
365 {
366 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
367 return result;
368 }
[25258]369
[25311]370 //Check the given password
371 if ((error = checkPassword(newPassword)) != NO_ERROR)
372 {
373 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
374 return result;
375 }
376
377 newPassword = hashPassword(newPassword);
378
379 error = addUser(newUsername, newPassword, newGroups, newStatus, newComment, newEmail);
[25258]380 if (error != NO_ERROR)
[24978]381 {
[25258]382 serviceNode.setAttribute("operation", ADD_USER);
383 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
[24978]384 }
[25258]385 else
[24978]386 {
[25258]387 addUserInformationToNode(null, serviceNode);
388 serviceNode.setAttribute("operation", LIST_USERS);
[24978]389 }
[25258]390 }
391 else if (op.equals(PERFORM_REGISTER))
392 {
393 String newUsername = (String) paramMap.get("username");
394 String newPassword = (String) paramMap.get("password");
395 String newEmail = (String) paramMap.get("email");
[25722]396
[25311]397 //Check the given user name
398 int error;
399 if ((error = checkUsername(newUsername)) != NO_ERROR)
[24978]400 {
[25311]401 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
[25258]402 return result;
[24978]403 }
[25258]404
[25311]405 //Check the given password
406 if ((error = checkPassword(newPassword)) != NO_ERROR)
[24978]407 {
[25311]408 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
[25258]409 return result;
[24978]410 }
[25722]411
[25311]412 newPassword = hashPassword(newPassword);
[25258]413
[25725]414 if (_recaptchaPrivateKey != null && _recaptchaPrivateKey.length() > 0)
[25311]415 {
416 ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
417 reCaptcha.setPrivateKey(_recaptchaPrivateKey);
[25722]418
[25725]419 try
[25311]420 {
[25734]421 //If this line throws an exception then we'll assume the user has a firewall that is too restrictive
422 //(or that they're not connected to the Internet) to allow access to google services.
423 //In this situation we won't use the recaptcha test.
[25725]424 reCaptcha.checkAnswer(request.getAttribute("remoteAddress"), "", "");
[25722]425
[25725]426 String challenge = (String) paramMap.get("recaptcha_challenge_field");
427 String uResponse = (String) paramMap.get("recaptcha_response_field");
[25722]428
[25725]429 if (challenge == null || uResponse == null)
430 {
431 serviceNode.setAttribute("operation", REGISTER);
432 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_CAPTCHA_MISSING));
433 return result;
434 }
435
436 ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(request.getAttribute("remoteAddress"), challenge, uResponse);
437
438 if (!reCaptchaResponse.isValid())
439 {
440 serviceNode.setAttribute("operation", REGISTER);
441 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_CAPTCHA_DOES_NOT_MATCH));
442 return result;
443 }
444 }
445 catch (Exception ex)
[25311]446 {
447 }
448 }
449
450 error = addUser(newUsername, newPassword, "", "true", "", newEmail);
[25258]451 if (error != NO_ERROR)
[24978]452 {
[25258]453 serviceNode.setAttribute("operation", REGISTER);
454 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
[24978]455 }
[25258]456 }
457 else if (op.equals(PERFORM_EDIT))
458 {
459 String previousUsername = (String) paramMap.get("prevUsername");
460 String newUsername = (String) paramMap.get("newUsername");
461 String newPassword = (String) paramMap.get("password");
462 String newGroups = (String) paramMap.get("groups");
463 String newStatus = (String) paramMap.get("status");
464 String newComment = (String) paramMap.get("comment");
465 String newEmail = (String) paramMap.get("email");
466
[25311]467 //Check the given user name
468 int error;
469 if ((error = checkUsername(newUsername)) != NO_ERROR)
470 {
471 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
472 return result;
473 }
474
[25258]475 if (newPassword == null)
[24978]476 {
[25258]477 newPassword = retrieveDataForUser(previousUsername, "password");
[24978]478 }
[25311]479 else
480 {
481 //Check the given password
482 if ((error = checkPassword(newPassword)) != NO_ERROR)
483 {
484 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
485 return result;
486 }
[25722]487
[25311]488 newPassword = hashPassword(newPassword);
489 }
[25722]490
[25311]491 error = removeUser(previousUsername);
[25258]492 if (error != NO_ERROR)
[24978]493 {
[25258]494 if (error == ERROR_USERNAME_NOT_SPECIFIED)
495 {
496 addUserInformationToNode(null, serviceNode);
497 serviceNode.setAttribute("operation", LIST_USERS);
498 }
499 else
500 {
501 serviceNode.setAttribute("operation", EDIT_USER);
502 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
503 }
504 return result;
[24978]505 }
[25311]506
[25258]507 error = addUser(newUsername, newPassword, newGroups, newStatus, newComment, newEmail);
508 if (error != NO_ERROR)
[24978]509 {
[25258]510 serviceNode.setAttribute("operation", EDIT_USER);
511 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
[24978]512 }
[25258]513 else
[24978]514 {
[25258]515 addUserInformationToNode(null, serviceNode);
516 serviceNode.setAttribute("operation", LIST_USERS);
[24978]517 }
[25258]518 }
519 else if (op.equals(PERFORM_ACCOUNT_EDIT))
520 {
521 String previousUsername = (String) paramMap.get("prevUsername");
522 String newUsername = (String) paramMap.get("newUsername");
523 String oldPassword = (String) paramMap.get("oldPassword");
524 String newPassword = (String) paramMap.get("newPassword");
525 String newEmail = (String) paramMap.get("newEmail");
526
527 //Make sure the user name does not already exist
528 if (!previousUsername.equals(newUsername) && checkUserExists(newUsername))
[24978]529 {
[25258]530 addUserInformationToNode(previousUsername, serviceNode);
531 serviceNode.setAttribute("operation", ACCOUNT_SETTINGS);
532 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_USER_ALREADY_EXISTS));
533 return result;
[24978]534 }
[17452]535
[25258]536 String prevPassword = retrieveDataForUser(previousUsername, "password");
[14295]537
[25258]538 if (newPassword != null)
539 {
540 oldPassword = hashPassword(oldPassword);
[17452]541
[25258]542 if (oldPassword == null || !oldPassword.equals(prevPassword))
[24978]543 {
[25258]544 addUserInformationToNode(previousUsername, serviceNode);
545 serviceNode.setAttribute("operation", ACCOUNT_SETTINGS);
[25352]546 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_INCORRECT_PASSWORD), "Incorrect Password");
[17452]547 return result;
548 }
[25722]549
[25311]550 //Check the given password
551 int error;
552 if ((error = checkPassword(newPassword)) != NO_ERROR)
553 {
554 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
555 return result;
556 }
[25722]557
[25311]558 newPassword = hashPassword(newPassword);
[17452]559 }
[25258]560 else
561 {
562 newPassword = prevPassword;
563 }
[25722]564
[25311]565 //Check the given user name
566 int error;
567 if ((error = checkUsername(newUsername)) != NO_ERROR)
568 {
569 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
570 return result;
571 }
[25722]572
[25258]573 String prevGroups = retrieveDataForUser(previousUsername, "groups");
574 String prevStatus = retrieveDataForUser(previousUsername, "status");
575 String prevComment = retrieveDataForUser(previousUsername, "comment");
576
[25311]577 error = removeUser(previousUsername);
[25258]578 if (error != NO_ERROR)
[24978]579 {
[25258]580 if (error == ERROR_USERNAME_NOT_SPECIFIED)
[24978]581 {
[25258]582 addUserInformationToNode(null, serviceNode);
583 serviceNode.setAttribute("operation", LIST_USERS);
[17452]584 }
[24978]585 else
586 {
[25258]587 addUserInformationToNode(previousUsername, serviceNode);
588 serviceNode.setAttribute("operation", ACCOUNT_SETTINGS);
589 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
[17452]590 }
[25258]591 return result;
[14295]592 }
[17452]593
[25258]594 error = addUser(newUsername, newPassword, prevGroups, prevStatus, prevComment, newEmail);
595 if (error != NO_ERROR)
[24978]596 {
[25258]597 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
[14295]598 }
[25258]599
600 addUserInformationToNode(null, serviceNode);
601 serviceNode.setAttribute("operation", LIST_USERS);
[14295]602 }
[25258]603 else if (op.equals(EDIT_USER))
[24978]604 {
[25258]605 String editUsername = (String) paramMap.get("username");
606 int error = addUserInformationToNode(editUsername, serviceNode);
607 if (error != NO_ERROR)
[24978]608 {
[25258]609 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
610 }
611 }
612 else if (op.equals(ACCOUNT_SETTINGS))
613 {
614 String editUsername = (String) paramMap.get("username");
[25311]615
616 if (editUsername == null)
[25258]617 {
618 serviceNode.setAttribute("operation", "");
619 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_USERNAME_NOT_SPECIFIED));
[17452]620 return result;
621 }
[25311]622
623 if (!editUsername.equals(username))
[24978]624 {
[25258]625 serviceNode.setAttribute("operation", LOGIN);
626 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_NOT_AUTHORISED));
[17452]627 return result;
628 }
[25258]629 int error = addUserInformationToNode(editUsername, serviceNode);
630 if (error != NO_ERROR)
[24978]631 {
[25258]632 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
[17452]633 }
[14295]634 }
[25258]635 else if (op.equals(PERFORM_RESET_PASSWORD))
[24978]636 {
[25258]637 String passwordResetUser = (String) paramMap.get("username");
[25311]638
[25258]639 String newPassword = UUID.randomUUID().toString();
640 newPassword = newPassword.substring(0, newPassword.indexOf("-"));
[25311]641
[25258]642 String email = retrieveDataForUser(passwordResetUser, "email");
643 String from = "[email protected]";
644 String host = request.getAttribute("remoteAddress");
[25311]645
[25270]646 //TODO: FINISH THIS
[25258]647 }
[25311]648 else if (op.equals(REGISTER))
649 {
[25725]650 if (_recaptchaPrivateKey != null && _recaptchaPrivateKey.length() > 0)
[25311]651 {
[25725]652 try
653 {
654 ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
655 reCaptcha.setPrivateKey(_recaptchaPrivateKey);
656 reCaptcha.checkAnswer(request.getAttribute("remoteAddress"), "", "");
657 }
658 catch (Exception ex)
659 {
660 return result;
661 }
[25722]662 }
663
664 if (_recaptchaPublicKey != null && _recaptchaPrivateKey != null)
665 {
[25311]666 Element recaptchaElem = this.doc.createElement("recaptcha");
667 recaptchaElem.setAttribute("publicKey", _recaptchaPublicKey);
668 recaptchaElem.setAttribute("privateKey", _recaptchaPrivateKey);
669 result.appendChild(recaptchaElem);
670 }
671 }
[25258]672 else if (op.equals(PERFORM_DELETE_USER))
673 {
674 String usernameToDelete = (String) paramMap.get("username");
675 int error = removeUser(usernameToDelete);
676 if (error != NO_ERROR)
[24978]677 {
[25258]678 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
[17452]679 }
[25258]680 addUserInformationToNode(null, serviceNode);
681 serviceNode.setAttribute("operation", LIST_USERS);
682 }
[17452]683
[25258]684 return result;
685 }
[25722]686
[25311]687 public int checkUsernameAndPassword(String username, String password)
688 {
689 int uResult = checkUsername(username);
690 int pResult = checkPassword(password);
[25722]691
[25311]692 return (uResult != NO_ERROR ? uResult : (pResult != NO_ERROR ? pResult : NO_ERROR));
693 }
[25722]694
[25311]695 public int checkUsername(String username)
696 {
697 //Check the given user name
698 if ((username == null) || (username.length() < 2) || (username.length() > 30) || (!(Pattern.matches("[a-zA-Z0-9//_//.]+", username))))
699 {
700 return ERROR_INVALID_USERNAME;
701 }
702 return NO_ERROR;
703 }
[25722]704
[25311]705 public int checkPassword(String password)
706 {
707 //Check the given password
708 if ((password == null) || (password.length() < 3) || (password.length() > 8) || (!(Pattern.matches("[\\p{ASCII}]+", password))))
709 {
710 return ERROR_INVALID_PASSWORD;
711 }
712 return NO_ERROR;
713 }
[17452]714
[25258]715 public static String hashPassword(String password)
716 {
717 String hashedPassword = null;
718 try
719 {
720 MessageDigest digest = MessageDigest.getInstance("SHA-1");
721 digest.reset();
[25318]722 hashedPassword = new String(digest.digest(password.getBytes("US-ASCII"))); // toHex after using ASCII charset will result in acceptable length of hex string
723 hashedPassword = toHex(hashedPassword); // this conversion is required to avoid the strange error of login failure on some legal password strings
[14295]724 }
[25258]725 catch (Exception ex)
726 {
727 ex.printStackTrace();
728 }
729 return hashedPassword;
730 }
[14295]731
[25722]732 // This method can also be used for printing out the password in hex (in case
733 // the password used the UTF-8 Charset), or the hex values in any unicode string.
734 // From http://stackoverflow.com/questions/923863/converting-a-string-to-hexadecimal-in-java
735 public static String toHex(String arg)
736 {
737 try
738 {
739 return String.format("%x", new BigInteger(arg.getBytes("US-ASCII"))); // set to same charset as used by hashPassword
740 }
741 catch (Exception e)
742 { // UnsupportedEncodingException
743 e.printStackTrace();
744 }
745 return "Unable to print";
746 }
[25318]747
[25258]748 private void checkAdminUserExists()
749 {
750 if (_derbyWrapper == null)
[24978]751 {
[25258]752 openDatabase();
753 }
[17452]754
[25258]755 UserQueryResult userQueryResult = _derbyWrapper.findUser(null, null);
756 closeDatabase();
[17452]757
[25258]758 if (userQueryResult != null)
759 {
760 Vector userInfo = userQueryResult.users;
[17452]761
[25258]762 boolean adminFound = false;
763 for (int i = 0; i < userQueryResult.getSize(); i++)
[24978]764 {
[25258]765 if (((UserTermInfo) userInfo.get(i)).groups != null && ((UserTermInfo) userInfo.get(i)).groups.matches(".*\\badministrator\\b.*"))
[24978]766 {
[25258]767 adminFound = true;
[17452]768 }
769 }
770
[25258]771 if (!adminFound)
[24978]772 {
[25258]773 addUser("admin", "admin", "administrator", "true", "Change the password for this account as soon as possible", "");
[17452]774 }
[14295]775 }
776
[25258]777 closeDatabase();
778 }
779
780 private boolean openDatabase()
781 {
782 _derbyWrapper = new DerbyWrapper();
783
784 // check the usersDb database, if it isn't existing, check the etc dir, create the etc dir if it isn't existing, then create the user database and add a "admin" user
785 String usersDB_dir = this.site_home + File.separatorChar + "etc" + File.separatorChar + "usersDB";
786 File usersDB_file = new File(usersDB_dir);
787 if (!usersDB_file.exists())
[24978]788 {
[25258]789 String etc_dir = this.site_home + File.separatorChar + "etc";
790 File etc_file = new File(etc_dir);
791 if (!etc_file.exists())
[24978]792 {
[25258]793 boolean success = etc_file.mkdir();
794 if (!success)
795 {
796 logger.error("Couldn't create the etc dir under " + this.site_home + ".");
797 return false;
798 }
[17452]799 }
[25258]800 _derbyWrapper.connectDatabase(usersDB_dir, true);
801 _derbyWrapper.createDatabase();
802 }
803 else
804 {
805 _derbyWrapper.connectDatabase(usersDB_dir, false);
806 }
807 return true;
808 }
[14295]809
[25258]810 private void closeDatabase()
811 {
812 if (_derbyWrapper != null)
813 {
814 _derbyWrapper.closeDatabase();
815 _derbyWrapper = null;
816 }
817 }
[17452]818
[25258]819 private int addUserInformationToNode(String username, Element serviceNode)
820 {
821 if (_derbyWrapper == null)
822 {
823 openDatabase();
824 }
[17452]825
[25258]826 UserQueryResult userQueryResult = _derbyWrapper.findUser(username, null);
827 closeDatabase();
[17452]828
[25258]829 if (userQueryResult != null)
830 {
831 Element user_node = getUserNode(userQueryResult);
832 serviceNode.appendChild(user_node);
833 closeDatabase();
834 return NO_ERROR;
835 }
[17452]836
[25258]837 closeDatabase();
838 return ERROR_COULD_NOT_GET_USER_INFO;
839 }
[17452]840
[25258]841 private int removeUser(String username)
842 {
843 if (username == null)
844 {
845 return ERROR_USERNAME_NOT_SPECIFIED;
846 }
[17452]847
[25258]848 if (_derbyWrapper == null)
849 {
850 openDatabase();
851 }
852
853 boolean success = _derbyWrapper.deleteUser(username);
854 closeDatabase();
855
856 if (success)
857 {
858 return NO_ERROR;
859 }
860
861 return ERROR_REMOVING_USER;
862 }
863
864 private int addUser(String newUsername, String newPassword, String newGroups, String newStatus, String newComment, String newEmail)
865 {
866 if (_derbyWrapper == null)
867 {
868 openDatabase();
869 }
870
871 newGroups = newGroups.replaceAll(" ", "");
872
873 //Check if the user already exists
874 UserQueryResult userQueryResult = _derbyWrapper.findUser(newUsername, null);
875 if (userQueryResult != null)
876 {
[25311]877 closeDatabase();
[25258]878 return ERROR_USER_ALREADY_EXISTS;
879 }
880 else
881 {
882 System.err.println("ADDING " + newUsername + " " + newPassword);
883 boolean success = _derbyWrapper.addUser(newUsername, newPassword, newGroups, newStatus, newComment, newEmail);
884 if (!success)
[24978]885 {
[25258]886 closeDatabase();
887 return ERROR_ADDING_USER;
[17452]888 }
[25258]889 }
890 closeDatabase();
891 return NO_ERROR;
892 }
[17452]893
[25258]894 private boolean checkUserExists(String username)
895 {
896 if (_derbyWrapper == null)
897 {
898 openDatabase();
899 }
900
901 try
902 {
903 UserQueryResult result = _derbyWrapper.findUser(username);
904
905 if (result != null)
[24978]906 {
[25258]907 return true;
[24978]908 }
909 else
910 {
[25258]911 return false;
[17452]912 }
[25258]913
[14295]914 }
[25258]915 catch (Exception ex)
916 {
917 return false;
918 }
919 finally
920 {
921 closeDatabase();
922 }
923 }
[17452]924
[25258]925 private String retrieveDataForUser(String username, String dataType)
926 {
927 if (_derbyWrapper == null)
[24978]928 {
[25258]929 openDatabase();
930 }
931
932 String password = null;
933
934 try
935 {
936 UserQueryResult result = _derbyWrapper.findUser(username);
937 Vector userInfo = result.users;
938
939 for (int i = 0; i < result.getSize(); i++)
[24978]940 {
[25258]941 if (dataType.equals("password"))
[24978]942 {
[25258]943 return ((UserTermInfo) userInfo.get(i)).password;
[24978]944 }
[25258]945 else if (dataType.equals("groups"))
[24978]946 {
[25258]947 return ((UserTermInfo) userInfo.get(i)).groups;
[17452]948 }
[25258]949 else if (dataType.equals("status"))
950 {
951 return ((UserTermInfo) userInfo.get(i)).accountstatus;
952 }
953 else if (dataType.equals("comment"))
954 {
955 return ((UserTermInfo) userInfo.get(i)).comment;
956 }
957 else if (dataType.equals("email"))
958 {
959 return ((UserTermInfo) userInfo.get(i)).email;
960 }
[24978]961 }
[14295]962 }
[25258]963 catch (Exception ex)
964 {
965 ex.printStackTrace();
966 }
[14295]967
[25258]968 closeDatabase();
969 return password;
[14295]970 }
971
[24978]972 private Element getUserNode(UserQueryResult userQueryResult)
973 {
974 Element user_list_node = this.doc.createElement(GSXML.USER_NODE_ELEM + "List");
[14295]975
[25258]976 Vector userInfo = userQueryResult.users;
[14295]977
[24978]978 for (int i = 0; i < userQueryResult.getSize(); i++)
979 {
980 Element user_node = this.doc.createElement(GSXML.USER_NODE_ELEM);
[25258]981 String username = ((UserTermInfo) userInfo.get(i)).username;
982 String groups = ((UserTermInfo) userInfo.get(i)).groups;
983 String accountstatus = ((UserTermInfo) userInfo.get(i)).accountstatus;
984 String comment = ((UserTermInfo) userInfo.get(i)).comment;
985 String email = ((UserTermInfo) userInfo.get(i)).email;
986 user_node.setAttribute("username", username);
987 user_node.setAttribute("groups", groups);
988 user_node.setAttribute("status", accountstatus);
989 user_node.setAttribute("comment", comment);
990 user_node.setAttribute("email", email);
[14295]991
[17452]992 user_list_node.appendChild(user_node);
[14295]993 }
[24978]994 return user_list_node;
[14295]995 }
996
[24978]997 private Element getCollectList(String collect)
998 {
999 Element collect_list_node = this.doc.createElement(GSXML.COLLECTION_ELEM + "List");
1000 File[] collect_dir = (new File(collect)).listFiles();
1001 if (collect_dir != null && collect_dir.length > 0)
1002 {
1003 for (int i = 0; i < collect_dir.length; i++)
1004 {
1005 if (collect_dir[i].isDirectory() && (!collect_dir[i].getName().startsWith(".svn")))
1006 {
[17452]1007 Element collect_node = this.doc.createElement(GSXML.COLLECTION_ELEM);
[24978]1008 collect_node.setAttribute("name", collect_dir[i].getName());
[17452]1009 collect_list_node.appendChild(collect_node);
1010 }
1011 }
[14402]1012 }
[17452]1013 return collect_list_node;
[14402]1014 }
[14295]1015}
Note: See TracBrowser for help on using the repository browser.