001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019: package org.openharmonise.rm.resources.users;
020:
021: import java.sql.*;
022: import java.util.Vector;
023: import java.util.logging.*;
024:
025: import org.openharmonise.commons.dsi.*;
026: import org.openharmonise.commons.dsi.dml.*;
027: import org.openharmonise.rm.*;
028: import org.openharmonise.rm.config.*;
029: import org.openharmonise.rm.dsi.DataStoreObject;
030: import org.openharmonise.rm.metadata.Profile;
031: import org.openharmonise.rm.publishing.*;
032: import org.openharmonise.rm.resources.*;
033: import org.openharmonise.rm.resources.lifecycle.*;
034: import org.openharmonise.rm.security.authentication.*;
035: import org.w3c.dom.*;
036:
037: /**
038: * This class represents a user within Harmonise.
039: *
040: * @author Michael Bell
041: * @author jejking
042: * @version $Revision: 1.10 $
043: *
044: */
045: public class User extends AbstractChildObject implements
046: DataStoreObject, Publishable, Editable, Cloneable, Comparable {
047:
048: //XML constants
049: public static final String TAG_USER = "User";
050: public static final String TAG_PASSWORD = "Password";
051:
052: //DB constants
053: public static final String TBL_USER = "users";
054: protected static final String CLMN_PASSWORD = "password";
055: protected static final String CLMN_IS_SUPER = "isSuper";
056: protected static final String CLMN_SALT = "salt";
057:
058: //user's passwd
059: protected String m_sPassword = "";
060:
061: /**
062: * Holds cryptographic salt if <code>PWD_ENCRYPTION</code> system property is set.
063: * Otherwise, will be an empty string and not used.
064: */
065: protected String m_sSalt = "";
066: protected boolean m_bIsSuper = false;
067:
068: /**
069: * Logger for this class
070: */
071: private final static Logger m_logger = Logger.getLogger(User.class
072: .getName());
073:
074: /**
075: * Basic constructor.
076: *
077: */
078: public User() {
079: super ();
080: String crypto = "NONE";
081: try {
082: // set up a new salt string
083: crypto = ConfigSettings.getProperty("PWD_ENCRYPTION",
084: "NONE");
085: m_logger.log(Level.INFO, "Got crypto property: " + crypto);
086: } catch (ConfigException e) {
087: m_logger.log(Level.SEVERE, "config exception", e);
088: }
089:
090: if (crypto.equals("MD5")) {
091: m_sSalt = PasswordCryptUtil.getNewSalt(32);
092: m_logger.log(Level.FINE, "Got 32 character salt for user "
093: + m_sName + " " + m_sSalt);
094: } else if (crypto.equals("SHA-1")) {
095: m_sSalt = PasswordCryptUtil.getNewSalt(40);
096: m_logger.log(Level.FINE, "Got 40 character salt for user "
097: + m_sName + " " + m_sSalt);
098: } else {
099: m_sSalt = "";
100: }
101: }
102:
103: /**
104: * Constructor for a historical object with an interface to the DB.
105: *
106: * @param dbinterf
107: * @param bHist
108: * @throws Exception
109: */
110: public User(AbstractDataStoreInterface dbinterf, boolean bHist) {
111: super (dbinterf);
112:
113: }
114:
115: /**
116: * Standard constructor for a known user
117: *
118: * @param dbinterf
119: * @param nId
120: */
121: public User(AbstractDataStoreInterface dbinterf, int nId) {
122: super (dbinterf, nId);
123:
124: }
125:
126: /**
127: * Standard constructor for a known historical user.
128: *
129: * @param dbinterf
130: * @param nId
131: * @param bHist
132: */
133: public User(AbstractDataStoreInterface dbinterf, int nId, int nKey,
134: boolean bHist) {
135: super (dbinterf, nId, nKey, bHist);
136:
137: }
138:
139: /**
140: * Constructor which sets up an interface to the DB.
141: *
142: * @param dbinterf
143: * @throws Exception
144: */
145: public User(AbstractDataStoreInterface dbinterf) {
146: super (dbinterf);
147:
148: }
149:
150: /**
151: * Returns the password for this user.
152: *
153: * @return
154: * @throws DataAccessException
155: */
156: public String getPassword() throws DataAccessException {
157: if ((m_sPassword == null || m_sPassword.length() == 0)
158: && isPopulated() == false) {
159: try {
160: populateFromDatabase();
161: } catch (PopulateException e) {
162: throw new DataAccessException(
163: "Error occured populating user:"
164: + e.getLocalizedMessage());
165: }
166: }
167:
168: return m_sPassword;
169: }
170:
171: /**
172: * Sets the password for this user.
173: *
174: * @param sPassword
175: * @throws Exception
176: */
177: public void setPassword(String sPassword) {
178: if (isPopulated() == true) {
179: if (m_sPassword.equals(sPassword) == false) {
180: m_bIsChanged = true;
181: }
182: }
183: m_sPassword = sPassword;
184: }
185:
186: /**
187: * Returns <code>true</code> if this user is a super user.
188: *
189: * @return
190: * @throws DataAccessException
191: */
192: public boolean isSuper() throws DataAccessException {
193: if (isPopulated() == false) {
194: try {
195: populateFromDatabase();
196: } catch (PopulateException e) {
197: throw new DataAccessException(e.getLocalizedMessage(),
198: e);
199: }
200: }
201:
202: return m_bIsSuper;
203: }
204:
205: /**
206: * Sets whether this user is a super user.
207: *
208: * @param bIsSuper
209: */
210: public void setIsSuper(boolean bIsSuper) {
211: if (isPopulated() == true) {
212: if (m_bIsSuper != bIsSuper) {
213: m_bIsChanged = true;
214: }
215: }
216:
217: m_bIsSuper = bIsSuper;
218: }
219:
220: /* (non-Javadoc)
221: * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
222: */
223: public Element publish(Element topEl, HarmoniseOutput xmlDoc,
224: State state) throws PublishException {
225:
226: Element docEl = null;
227: String sTagName = topEl.getTagName();
228: Text txt = null;
229:
230: if (sTagName.equals(TAG_PASSWORD)) {
231: docEl = xmlDoc.createElement(TAG_PASSWORD);
232:
233: try {
234: txt = xmlDoc.createTextNode(getPassword());
235: } catch (Exception e) {
236: throw new PublishException(
237: "Error occured getting password for user:"
238: + e.getLocalizedMessage());
239: }
240: docEl.appendChild(txt);
241:
242: xmlDoc.copyChildren(docEl, topEl, new Vector());
243: } else {
244: docEl = super .publish(topEl, xmlDoc, state);
245: }
246:
247: return docEl;
248: }
249:
250: /* (non-Javadoc)
251: * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
252: */
253: public void populate(Element xmlElement, State state)
254: throws PopulateException {
255: String sTagName = xmlElement.getTagName();
256: Text txt = null;
257:
258: if (sTagName.equals(TAG_PASSWORD)) {
259: txt = (Text) xmlElement.getFirstChild();
260: setPassword(txt.getNodeValue());
261: } else {
262: super .populate(xmlElement, state);
263: }
264: }
265:
266: /* (non-Javadoc)
267: * @see java.lang.Object#toString()
268: */
269: public String toString() {
270: StringBuffer sReturn = new StringBuffer();
271:
272: try {
273: sReturn.append(" User_id=[")
274: .append(Integer.toString(m_nId)).append("]");
275: sReturn.append(" UserName=[").append(m_sName).append("]");
276: sReturn.append(" Password=[").append(m_sPassword).append(
277: "]");
278:
279: Profile prof = getProfile();
280:
281: if (prof != null) {
282: sReturn.append(" Profile=[").append(prof.toString())
283: .append("]");
284: }
285:
286: } catch (Exception e) {
287: m_logger.log(Level.INFO, e.getLocalizedMessage(), e);
288: }
289:
290: return sReturn.toString();
291: }
292:
293: /* (non-Javadoc)
294: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceColumnRef(java.lang.String, boolean)
295: */
296: public ColumnRef getInstanceColumnRef(String columnRef,
297: boolean bIsHist) throws DataStoreException {
298: ColumnRef colRef = null;
299:
300: String sTable = getTableName(bIsHist);
301:
302: if (columnRef.equals(TAG_PASSWORD) == true
303: || columnRef.equals(CLMN_PASSWORD)) {
304: colRef = new ColumnRef(sTable, CLMN_PASSWORD,
305: ColumnRef.TEXT);
306: } else if (columnRef.equals(CLMN_IS_SUPER)) {
307: colRef = new ColumnRef(sTable, CLMN_IS_SUPER,
308: ColumnRef.NUMBER);
309: } else if (columnRef.equals(CLMN_SALT)) {
310: colRef = new ColumnRef(sTable, CLMN_SALT, ColumnRef.TEXT);
311: } else {
312: colRef = super .getInstanceColumnRef(columnRef, bIsHist);
313: }
314:
315: return colRef;
316: }
317:
318: /* (non-Javadoc)
319: * @see org.openharmonise.rm.resources.AbstractChildObject#getParentObjectClassName()
320: */
321: public String getParentObjectClassName() {
322: return UserGroup.class.getName();
323: }
324:
325: /* (non-Javadoc)
326: * @see org.openharmonise.rm.dsi.DataStoreObject#getDBTableName()
327: */
328: public String getDBTableName() {
329: return TBL_USER;
330: }
331:
332: /* (non-Javadoc)
333: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceJoinConditions(java.lang.String, boolean)
334: */
335: public JoinConditions getInstanceJoinConditions(String sObjectTag,
336: boolean bIsOuter) throws DataStoreException {
337: //nothing to return
338: return null;
339: }
340:
341: /* (non-Javadoc)
342: * @see org.openharmonise.rm.publishing.Publishable#getTagName()
343: */
344: public String getTagName() {
345: return TAG_USER;
346: }
347:
348: /**
349: * @return cryptographic salt for the user
350: */
351: public String getSalt() {
352: return this .m_sSalt;
353: }
354:
355: /*----------------------------------------------------------------------------
356: Protected methods
357: -----------------------------------------------------------------------------*/
358:
359: /* (non-Javadoc)
360: * @see org.openharmonise.rm.resources.AbstractEditableObject#addDataToSave(org.openharmonise.commons.dsi.dml.InsertStatement)
361: */
362: protected void addDataToSave(InsertStatement insert)
363: throws DataStoreException {
364:
365: insert.addColumnValue(getInstanceColumnRef(CLMN_PASSWORD,
366: isHistorical()), this .m_sPassword);
367:
368: int nSuper = 0;
369:
370: if (m_bIsSuper == true) {
371: nSuper = 1;
372: }
373:
374: insert.addColumnValue(getInstanceColumnRef(CLMN_IS_SUPER,
375: isHistorical()), nSuper);
376:
377: insert.addColumnValue(getInstanceColumnRef(CLMN_SALT,
378: isHistorical()), m_sSalt);
379: m_logger.log(Level.FINE, "Saving user " + m_sName
380: + " with salt " + m_sSalt);
381:
382: super .addDataToSave(insert);
383: }
384:
385: /* (non-Javadoc)
386: * @see org.openharmonise.rm.resources.AbstractObject#populateFromResultSetRow(java.sql.ResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
387: */
388: protected void populateFromResultSetRow(ResultSet rs,
389: SelectStatement select) throws PopulateException {
390:
391: if (isPopulated() == false) {
392: try {
393: ColumnRef colref = getInstanceColumnRef(CLMN_PASSWORD,
394: isHistorical());
395:
396: if (select.containsSelectColumn(colref) == true) {
397: String sTemp = null;
398:
399: sTemp = rs.getString(select
400: .getResultSetIndex(colref));
401:
402: if ((sTemp != null) && (sTemp.length() > 0)) {
403: if ((m_sPassword == null)
404: || (m_sPassword.length() == 0)) {
405: m_sPassword = sTemp;
406: } else if (m_sPassword.equals(sTemp) == false) {
407: setIsChanged(true);
408: }
409: }
410:
411: }
412:
413: colref = getInstanceColumnRef(CLMN_IS_SUPER,
414: isHistorical());
415:
416: if (select.containsSelectColumn(colref) == true) {
417: String sTemp = null;
418:
419: m_bIsSuper = rs.getBoolean(select
420: .getResultSetIndex(colref));
421:
422: }
423:
424: // and the salt
425: colref = getInstanceColumnRef(CLMN_SALT, isHistorical());
426:
427: if (select.containsSelectColumn(colref) == true) {
428: m_sSalt = rs.getString(select
429: .getResultSetIndex(colref));
430: }
431:
432: super .populateFromResultSetRow(rs, select);
433: } catch (SQLException e) {
434: throw new PopulateException(
435: "Error occured accessing password", e);
436: } catch (DataStoreException e) {
437: throw new PopulateException(
438: "Error occured getting column ref", e);
439:
440: }
441: }
442: }
443:
444: /* (non-Javadoc)
445: * @see org.openharmonise.rm.resources.AbstractEditableObject#saveNonCoreData()
446: */
447: protected void saveNonCoreData() throws EditException {
448: //no non core data
449: }
450:
451: /*----------------------------------------------------------------------------
452: Protected methods
453: -----------------------------------------------------------------------------*/
454:
455: /**
456: * Populates this object with an id and key from the given user name and
457: * password.
458: *
459: * @param sUserName
460: * @param sPassword
461: * @throws DataStoreException
462: * @throws ObjectNotFoundException
463: */
464: private void populateIdFromUsernamePassword(String sUserName,
465: String sPassword) throws DataStoreException,
466: ObjectNotFoundException {
467: ResultSet rs = null;
468: boolean bFound = false;
469:
470: try {
471: SelectStatement newQuery = new SelectStatement();
472:
473: newQuery.addSelectColumn(this .getInstanceColumnRef(
474: ATTRIB_KEY, false));
475: newQuery.addSelectColumn(this .getInstanceColumnRef(
476: ATTRIB_ID, false));
477:
478: newQuery.addWhereCondition(this .getInstanceColumnRef(
479: TAG_NAME, false), "=", sUserName);
480: newQuery.addWhereCondition(this .getInstanceColumnRef(
481: CLMN_PASSWORD, false), "=", sPassword);
482: newQuery.addWhereCondition(this .getInstanceColumnRef(
483: TAG_STATUS, false), "=", 0);
484:
485: rs = m_dsi.executeQuery(newQuery);
486:
487: while (rs.next()) {
488: m_nObjectKey = rs.getInt(1);
489: m_nId = rs.getInt(2);
490: bFound = true;
491: }
492:
493: if (bFound == false) {
494: rs.close();
495:
496: newQuery.clear();
497:
498: newQuery.addSelectColumn(getInstanceColumnRef(
499: ATTRIB_KEY, false));
500: newQuery.addSelectColumn(getInstanceColumnRef(
501: ATTRIB_ID, false));
502:
503: newQuery.addWhereCondition(getInstanceColumnRef(
504: TAG_NAME, false), "=", sUserName);
505: newQuery.addWhereCondition(getInstanceColumnRef(
506: CLMN_PASSWORD, false), "=", sPassword);
507:
508: rs = m_dsi.executeQuery(newQuery);
509:
510: while (rs.next()) {
511: m_nObjectKey = rs.getInt(1);
512: m_nId = rs.getInt(2);
513: bFound = true;
514: }
515: }
516:
517: if (bFound == false) {
518: throw new ObjectNotFoundException();
519: }
520: } catch (SQLException e) {
521: throw new DataStoreException(e);
522: } finally {
523: if (rs != null) {
524: try {
525: rs.close();
526: } catch (SQLException e) {
527: throw new DataStoreException(e);
528: }
529: }
530: }
531: }
532:
533: /* (non-Javadoc)
534: * @see org.openharmonise.rm.resources.AbstractObject#addColumnsToPopulateQuery(org.openharmonise.commons.dsi.dml.SelectStatement, boolean)
535: */
536: protected void addColumnsToPopulateQuery(SelectStatement select,
537: boolean bIsHist) throws DataStoreException {
538: super .addColumnsToPopulateQuery(select, bIsHist);
539: select.addSelectColumn(getInstanceColumnRef(CLMN_PASSWORD,
540: bIsHist));
541: select.addSelectColumn(getInstanceColumnRef(CLMN_IS_SUPER,
542: bIsHist));
543: select
544: .addSelectColumn(getInstanceColumnRef(CLMN_SALT,
545: bIsHist));
546: }
547:
548: /* (non-Javadoc)
549: * @see org.openharmonise.rm.resources.AbstractObject#setName(java.lang.String)
550: */
551: public void setName(String sName) throws InvalidNameException {
552: try {
553: if ((m_sName != null && m_sName.equals(sName) == false && isNameValid(sName) == true)
554: || isNameValid(sName) == true) {
555: super .setName(sName);
556: } else {
557: throw new InvalidNameException(sName
558: + " is an invalid name for this user");
559: }
560: } catch (DataStoreException e) {
561: throw new InvalidNameException(
562: "Error occured checking name validity", e);
563: } catch (SQLException e) {
564: throw new InvalidNameException(
565: "Error occured checking name validity", e);
566: }
567:
568: }
569:
570: /**
571: * @param sName
572: * @return
573: */
574: private boolean isNameValid(String sName)
575: throws DataStoreException, SQLException {
576: boolean bIsNameValid = true;
577:
578: SelectStatement select = new SelectStatement();
579: ResultSet rs = null;
580:
581: try {
582: ColumnRef nameCol = getInstanceColumnRef(TAG_NAME,
583: isHistorical());
584:
585: select.addSelectColumn(nameCol);
586:
587: select.addWhereCondition(nameCol, "=", sName);
588:
589: if (m_nId > 0) {
590: select.addWhereCondition(getInstanceColumnRef(
591: ATTRIB_ID, isHistorical()), "!=", m_nId);
592:
593: select.addWhereCondition(getInstanceColumnRef(
594: TAG_LIVE_VERSION, isHistorical()), "!=", m_nId);
595: }
596:
597: rs = m_dsi.execute(select);
598:
599: if (rs.next()) {
600: bIsNameValid = false;
601: }
602: } finally {
603: if (rs != null) {
604: try {
605: rs.close();
606: } catch (SQLException e) {
607: m_logger.log(Level.WARNING,
608: e.getLocalizedMessage(), e);
609: }
610: }
611: }
612: return bIsNameValid;
613: }
614:
615: }
|