0001: /* ====================================================================
0002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
0003: *
0004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * 1. Redistributions of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * 2. Redistributions in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in
0015: * the documentation and/or other materials provided with the
0016: * distribution.
0017: *
0018: * 3. The end-user documentation included with the redistribution,
0019: * if any, must include the following acknowledgment:
0020: * "This product includes software developed by Jcorporate Ltd.
0021: * (http://www.jcorporate.com/)."
0022: * Alternately, this acknowledgment may appear in the software itself,
0023: * if and wherever such third-party acknowledgments normally appear.
0024: *
0025: * 4. "Jcorporate" and product names such as "Expresso" must
0026: * not be used to endorse or promote products derived from this
0027: * software without prior written permission. For written permission,
0028: * please contact info@jcorporate.com.
0029: *
0030: * 5. Products derived from this software may not be called "Expresso",
0031: * or other Jcorporate product names; nor may "Expresso" or other
0032: * Jcorporate product names appear in their name, without prior
0033: * written permission of Jcorporate Ltd.
0034: *
0035: * 6. No product derived from this software may compete in the same
0036: * market space, i.e. framework, without prior written permission
0037: * of Jcorporate Ltd. For written permission, please contact
0038: * partners@jcorporate.com.
0039: *
0040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
0044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
0046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0051: * SUCH DAMAGE.
0052: * ====================================================================
0053: *
0054: * This software consists of voluntary contributions made by many
0055: * individuals on behalf of the Jcorporate Ltd. Contributions back
0056: * to the project(s) are encouraged when you make modifications.
0057: * Please send them to support@jcorporate.com. For more information
0058: * on Jcorporate Ltd. and its products, please see
0059: * <http://www.jcorporate.com/>.
0060: *
0061: * Portions of this software are based upon other open source
0062: * products and are subject to their respective licenses.
0063: */
0064:
0065: package com.jcorporate.expresso.core.dbobj;
0066:
0067: import com.jcorporate.expresso.core.cache.CacheException;
0068: import com.jcorporate.expresso.core.cache.CacheManager;
0069: import com.jcorporate.expresso.core.cache.CacheSystem;
0070: import com.jcorporate.expresso.core.controller.ControllerRequest;
0071: import com.jcorporate.expresso.core.dataobjects.Securable;
0072: import com.jcorporate.expresso.core.db.DBConnection;
0073: import com.jcorporate.expresso.core.db.DBException;
0074: import com.jcorporate.expresso.core.i18n.Messages;
0075: import com.jcorporate.expresso.core.misc.StringUtil;
0076: import com.jcorporate.expresso.core.security.User;
0077: import com.jcorporate.expresso.kernel.util.ClassLocator;
0078: import com.jcorporate.expresso.kernel.util.FastStringBuffer;
0079: import com.jcorporate.expresso.services.dbobj.DBObjSecurity;
0080: import com.jcorporate.expresso.services.dbobj.DefaultUserInfo;
0081: import com.jcorporate.expresso.services.dbobj.GroupMembers;
0082: import com.jcorporate.expresso.services.dbobj.UserGroup;
0083: import org.apache.log4j.Logger;
0084:
0085: import java.util.ArrayList;
0086: import java.util.Enumeration;
0087: import java.util.Iterator;
0088: import java.util.Vector;
0089:
0090: /**
0091: * A database object can be stored in a table (or tables),
0092: * can be retrieved, and various other operations
0093: * Specific database objects extend this object
0094: *
0095: * @author Michael Nash
0096: */
0097: public abstract class SecuredDBObject extends DBObject implements
0098: Securable {
0099:
0100: /**
0101: * Used in the constructor. If you use the SYSTEM_ACCOUNT, there are no
0102: * security checks performed before a Database Object is used. BE CAREFUL
0103: * ON USING THIS as it effectively bypasses security!
0104: */
0105: public static final int SYSTEM_ACCOUNT = -1;
0106:
0107: /**
0108: * Used in the deprecated constructor. If you use this, there are no
0109: * security checks performed before a Database Object is used. BE CAREFUL
0110: * ON USING THIS as it effectively bypasses security!
0111: */
0112: public static final String SYSTEM_ACCOUNT_NAME = "SYSTEM";
0113:
0114: /**
0115: * Cache name for the system security
0116: */
0117: protected static final String CACHE_NAME = SecuredDBObject.class
0118: .getName()
0119: + ".securityCache";
0120:
0121: /**
0122: * Cache Default Expiration Default value of 30 minutes.
0123: */
0124: protected static final long CACHE_TTY = 60 * 1000 * 30;
0125:
0126: /**
0127: * Field constants for add update search and delete functionality.
0128: * Designates an add operation
0129: */
0130: public static final String ADD = "A";
0131:
0132: /**
0133: * Designates a Delete Operation
0134: */
0135: public static final String DELETE = "D";
0136:
0137: /**
0138: * Desginates an Search Operation
0139: */
0140: public static final String SEARCH = "S";
0141:
0142: /**
0143: * Designates an Update Operation
0144: */
0145: public static final String UPDATE = "U";
0146:
0147: /**
0148: * all possible manipution functions
0149: */
0150: public static final String[] ALL_FUNCTIONS = { ADD, DELETE, SEARCH,
0151: UPDATE };
0152:
0153: private static Logger log = Logger.getLogger(SecuredDBObject.class);
0154:
0155: //////////////////////////////////////////////
0156: // instance data members
0157: ///////////////////////////////////////////////////
0158:
0159: /* The uid gives us the Expresso user's id number for the user */
0160: /* accessing this DBObject. -1 indicates "SYSTEM" access, e.g. no */
0161: /* limitations on security access at all, and should be used only within */
0162: /* applications where security is being handled separately */
0163: private int uid = SYSTEM_ACCOUNT;
0164:
0165: /**
0166: * Constructor
0167: */
0168: public SecuredDBObject() throws DBException {
0169: super ();
0170:
0171: } /* SecuredDBObject() */
0172:
0173: /**
0174: * Constructor that sets the connection on create
0175: *
0176: * @param newConnection The dbConnection object to associate with this
0177: * object
0178: */
0179: public SecuredDBObject(DBConnection newConnection)
0180: throws DBException {
0181: this (newConnection, newConnection.getDataContext());
0182: } /* SecuredDBObject(DBConnection) */
0183:
0184: /**
0185: * <p/>
0186: * Constructor that sets a connection as the object is created - typically
0187: * this is used when a particular DBConnection is required for the purposes of
0188: * maintaining a database transaction. If a specific connection is not used,
0189: * there is no way to use commit() and rollback() in the event of failure, as a
0190: * different DBConnection might be used for each phase of the transaction.
0191: * Critial sections should therefore explicity request a DBConnection from the
0192: * connection pool and pass it to each of the DB objects in that section.
0193: * </p>
0194: * <p>This constructor is neceesary to work with otherDBMap and transaction
0195: * capabilities</p>
0196: *
0197: * @param newConnection The DBConnection to utilize
0198: * @param setupTablesContext The data context that contains the setup (and
0199: * security) tables for this object
0200: * @since Expresso 5.0.1
0201: */
0202: public SecuredDBObject(DBConnection newConnection,
0203: String setupTablesContext) throws DBException {
0204: super (newConnection, setupTablesContext);
0205: } /* DBObject(DBConnection) */
0206:
0207: /**
0208: * Constructor that sets user ID and data context from request
0209: *
0210: * @param request the request from which to set user, context
0211: * @throws DBException upon construction error
0212: */
0213: public SecuredDBObject(ControllerRequest request)
0214: throws DBException {
0215: this (request.getUid());
0216: setDataContext(request.getDataContext());
0217: }
0218:
0219: /**
0220: * New version of "setUser()" to to speak.
0221: *
0222: * @param newUid Sets the UID for this DBObject. Used for security checks.
0223: * @since Expresso 4.0
0224: */
0225: public void setRequestingUid(int newUid) {
0226: uid = newUid;
0227: }
0228:
0229: /**
0230: * New version of "setUser()", returns the integer UID of the
0231: * permissions this dbobject is operating under
0232: *
0233: * @return The User's UID for which the DBObject is set to. [-1 if it's
0234: * the system account]
0235: * @since Expresso 4.0
0236: */
0237: public int getRequestingUid() {
0238: return uid;
0239: }
0240:
0241: /**
0242: * Constructor: Specify a DB connection AND user
0243: *
0244: * @param newUid User ID attempting to use this object.
0245: * If this is SecuredDBObject.SYSTEM_ACCOUNT, then
0246: * full permissions are granted. Note that you cannot log in
0247: * as SecuredDBObject.SYSTEM_ACCOUNT,
0248: * t can only be used from within a method.
0249: * @throws DBException If the object cannot be created
0250: */
0251: public SecuredDBObject(int newUid) throws DBException {
0252: super ();
0253: setRequestingUid(newUid);
0254: }
0255:
0256: /**
0257: * Constructor: Specify a DB connection AND user id
0258: *
0259: * @param theConnection A DBConnection that this object should
0260: * use to connect to the database
0261: * @param theUser User name attempting to use this object.
0262: * If this is "SYSTEM", then
0263: * full permissions are granted. Note that you cannot log in
0264: * as "SYSTEM", it can only be used from within a method.
0265: * @throws DBException If the object cannot be created
0266: */
0267: public SecuredDBObject(DBConnection theConnection, int theUser)
0268: throws DBException {
0269: super (theConnection);
0270: setRequestingUid(theUser);
0271: } /* SecuredDBObject(DBConnection, int) */
0272:
0273: /**
0274: * For using DBObjects within Controllers. Initializes based
0275: * upon the current login user id, locale, and the requested
0276: * db context.
0277: *
0278: * @param request - The controller request handed to you by the framework.
0279: * @throws DBException if there's an error constructing the SecuredDBObject
0280: */
0281: public SecuredDBObject(RequestContext request) throws DBException {
0282: // The next line does not work because the expresso DB object makes
0283: // class initialisations base on the static subclass type
0284: // *PP* Wed Jan 01 19:51:39 GMT 2003
0285: // super( request )
0286: setRequestingUid(request.getUid());
0287: setDataContext(request.getDBName());
0288: setLocale(request.getLocale());
0289: }
0290:
0291: /**
0292: * Alternate form of constructor, specifying the db name/context and the
0293: * user at once
0294: *
0295: * @param dbKey db/Context key for the context being requested
0296: * @param theUser User id of the user requesting access
0297: */
0298: public SecuredDBObject(String dbKey, int theUser)
0299: throws DBException {
0300: super (dbKey);
0301: setRequestingUid(theUser);
0302: } /* SecuredDBObject(String, int) */
0303:
0304: /**
0305: * If the user is allowed to add, invoke the superclass add
0306: *
0307: * @throws DBException If the user is not permitted to add
0308: * or if the add fails
0309: */
0310: public void add() throws DBException {
0311: isAllowed(ADD);
0312: super .add();
0313: } /* add() */
0314:
0315: /**
0316: * See if the current user has permission to perform the permissions
0317: *
0318: * @param requestedFunction (A)dd, (U)pdate, (D)elete, (S)earch
0319: * @return boolean: true if the operation is allowed, or false if it is not
0320: * @see #isAllowed
0321: */
0322: public boolean checkAllowed(String requestedFunction)
0323: throws DBException {
0324: try {
0325: isAllowed(requestedFunction);
0326: } catch (SecurityException de) {
0327: log.debug(de);
0328:
0329: return false;
0330: }
0331:
0332: return true;
0333: } /* checkAllowed(String) */
0334:
0335: /**
0336: * Delete a record from the target table
0337: *
0338: * @throws DBException if delete is not allowed for the current user
0339: */
0340: public void delete() throws DBException {
0341: isAllowed(DELETE);
0342: super .delete();
0343: } /* delete() */
0344:
0345: /**
0346: * Just like retrieve, but works with any fields, not just the key field.
0347: * Finds only first record matching the criteria
0348: *
0349: * @return boolean If a matching record is found, else false
0350: * @throws DBException if search is not allowed
0351: */
0352: public boolean find() throws DBException {
0353: isAllowed(SEARCH);
0354:
0355: return super .find();
0356: } /* find() */
0357:
0358: /**
0359: * Creates the security caches
0360: * Synchronized to provide thread safety since
0361: * this is accessing a system-wide object.
0362: *
0363: * @throws CacheException if there's an error creating the cache or
0364: * adding the listeners.
0365: */
0366: protected synchronized void createSecurityCache()
0367: throws CacheException {
0368:
0369: // retest existance of cache after getting sync lock--another thread
0370: // might have just finished the job of cache creation
0371: synchronized (SecuredDBObject.class) {
0372: CacheSystem cs = CacheManager
0373: .getCacheSystem(getDataContext());
0374: if (cs == null) {
0375: //If cs == null this data context does not have caching installed.
0376: return;
0377: }
0378:
0379: if (!cs.existsCache(CACHE_NAME)) {
0380: if (log.isDebugEnabled()) {
0381: log.debug("Cache did not exist - creating");
0382: }
0383:
0384: cs.createCache(CACHE_NAME, false, 1000);
0385: cs
0386: .addListener(CACHE_NAME, GroupMembers.class
0387: .getName());
0388: cs.addListener(CACHE_NAME, DBObjSecurity.class
0389: .getName());
0390: cs.addListener(CACHE_NAME, DefaultUserInfo.class
0391: .getName());
0392: cs.addListener(CACHE_NAME, UserGroup.class.getName());
0393: }
0394: }
0395: }
0396:
0397: /**
0398: * See if the current user of this DB object is allowed to perform the
0399: * requested function, given the function's code.
0400: *
0401: * @param requestedFunction The code of the requested function. The codes are:
0402: * <ol><li>A: Add<li>
0403: * <li>S: Search<li>
0404: * <li>U: Update<li>
0405: * <li>D: Delete<li>
0406: * </ol>
0407: * @throws DBException If the requested operation is not permitted to this user
0408: */
0409: public void isAllowed(String requestedFunction)
0410: throws SecurityException, DBException {
0411: if (log.isDebugEnabled()) {
0412: log.debug("Checking permission for function '"
0413: + requestedFunction + "' for user " + uid);
0414: }
0415: if (uid == 0) {
0416: throw new DBException("User not specified. Must have a "
0417: + "valid user id to access database object '"
0418: + getMetaData().getDescription() + "'");
0419: }
0420: /* User 'SYSTEM' or 'Admin' is always allowed permissions */
0421: if (uid == -1 || User.getAdminId(getDataContext()) == uid) {
0422: if (log.isDebugEnabled()) {
0423: log.debug("User was SYSTEM - permission granted");
0424: }
0425:
0426: return;
0427: }
0428: try {
0429: CacheSystem cs = CacheManager
0430: .getCacheSystem(getDataContext());
0431: if (cs != null) {
0432: if (!cs.existsCache(CACHE_NAME)) {
0433: createSecurityCache();
0434: }
0435: }
0436:
0437: ValidValue sec = null;
0438: if (cs != null) {
0439: sec = (ValidValue) cs.getItem(CACHE_NAME, uid + "|"
0440: + getClass().getName());
0441: }
0442:
0443: if (sec == null) {
0444: User u = new User();
0445:
0446: u.setDataContext(StringUtil.notNull(getDataContext()));
0447: u.setUid(uid);
0448: u.retrieve();
0449:
0450: Vector groups = u.getGroups();
0451:
0452: if (log.isDebugEnabled()) {
0453: log.debug("User '" + u.getLoginName()
0454: + "' in db/context '" + getDataContext()
0455: + "' who requested function '"
0456: + requestedFunction
0457: + "' on database object '"
0458: + getClass().getName() + "' is in "
0459: + groups.size() + " groups.");
0460: }
0461:
0462: DBObjSecurity dbSec = new DBObjSecurity();
0463: dbSec.setDataContext(StringUtil
0464: .notNull(getDataContext()));
0465:
0466: if (log.isDebugEnabled()) {
0467: log.debug("User '" + u.getLoginName()
0468: + "' in db/context '"
0469: + this .getMappedDataContext()
0470: + "' requested function '"
0471: + requestedFunction
0472: + "' on database object '"
0473: + getClass().getName()
0474: + "' which is in original db '"
0475: + this .getDataContext() + "'");
0476: }
0477:
0478: DBObjSecurity oneSec = null;
0479: String oneGroupName = null;
0480:
0481: FastStringBuffer currentSecurity = new FastStringBuffer(
0482: 6);
0483: for (Enumeration e = groups.elements(); e
0484: .hasMoreElements();) {
0485: oneGroupName = (String) e.nextElement();
0486:
0487: if (log.isDebugEnabled()) {
0488: log.debug("User '" + u.getLoginName()
0489: + "' in db/context '"
0490: + getDataContext()
0491: + "' who requested function '"
0492: + requestedFunction
0493: + "' on database object '"
0494: + getClass().getName()
0495: + "' is in group '" + oneGroupName
0496: + "'");
0497: }
0498:
0499: dbSec.clear();
0500: dbSec.setField("GroupName", oneGroupName);
0501: dbSec
0502: .setField("DBObjectName", getClass()
0503: .getName());
0504:
0505: String newSec = null;
0506:
0507: for (Iterator esec = dbSec.searchAndRetrieveList()
0508: .iterator(); esec.hasNext();) {
0509: oneSec = (DBObjSecurity) esec.next();
0510: newSec = oneSec.getField("MethodCode");
0511:
0512: /* if we already have the permission, don't add it again */
0513: if (currentSecurity.toString().indexOf(newSec) < 0) {
0514: currentSecurity.append(newSec);
0515: if (currentSecurity.length() >= 4) {
0516: // we have all possible privileges; no need to loop further
0517: break;
0518: }
0519: }
0520: }
0521: } /* for each group this user belongs to */
0522:
0523: sec = new ValidValue(uid + "|" + getClass().getName(),
0524: currentSecurity.toString());
0525:
0526: if (cs != null) {
0527: cs.addItem(CACHE_NAME, sec, CACHE_TTY);
0528: }
0529:
0530: if (log.isDebugEnabled()) {
0531: log
0532: .debug("User '"
0533: + u.getLoginName()
0534: + "' in db/context '"
0535: + getDataContext()
0536: + "' who requested function '"
0537: + requestedFunction
0538: + "' on database object '"
0539: + getClass().getName()
0540: + "'. Security string created from database is '"
0541: + sec.getDescription() + "'");
0542: }
0543: } else {
0544: if (log.isDebugEnabled()) {
0545: log.debug("User '" + uid + "' in db/context '"
0546: + getDataContext()
0547: + "' who requested function '"
0548: + requestedFunction
0549: + "' on database object '"
0550: + getClass().getName()
0551: + "'. Security string from cache is '"
0552: + sec.getDescription() + "'");
0553: }
0554: }
0555: /* if the appropriate permission character is found, we're done */
0556: if (sec.getDescription().indexOf(requestedFunction) != -1) {
0557: return;
0558: }
0559: if (log.isDebugEnabled()) {
0560: log
0561: .debug("User '"
0562: + uid
0563: + "' in db/context '"
0564: + getDataContext()
0565: + "' is denied permission to perform function '"
0566: + requestedFunction
0567: + "' on database object '"
0568: + getClass().getName()
0569: + "'. Security string is '"
0570: + sec.getDescription()
0571: + "', which did not contain '"
0572: + requestedFunction + "'");
0573: }
0574:
0575: String permString = null;
0576:
0577: if (requestedFunction.equalsIgnoreCase(ADD)) {
0578: permString = ("Add");
0579: } else if (requestedFunction.equalsIgnoreCase(SEARCH)) {
0580: permString = ("Search");
0581: } else if (requestedFunction.equalsIgnoreCase(UPDATE)) {
0582: permString = ("Update");
0583: } else if (requestedFunction.equalsIgnoreCase(DELETE)) {
0584: permString = ("Delete");
0585: } else {
0586: permString = ("perform operation '" + requestedFunction + "'");
0587: }
0588:
0589: String[] args = new String[4];
0590: args[0] = "'"
0591: + User.getLoginFromId(getRequestingUid(),
0592: getDataContext()) + " ("
0593: + getRequestingUid() + ")'";
0594: args[1] = "'" + permString + "'";
0595: args[2] = "'" + getMetaData().getDescription() + "'";
0596: args[3] = "'" + getDataContext() + "'";
0597:
0598: throw new SecurityException(Messages.getString(
0599: "knownUserSecException", args));
0600: } catch (CacheException ce) {
0601: throw new DBException(ce);
0602: }
0603: } /* isAllowed(String) */
0604:
0605: /**
0606: * Retrieve the uid of the 'System Account'
0607: *
0608: * @return usually -1. May vary depending on the implementation.
0609: */
0610: public int getSystemUid() {
0611: return SecuredDBObject.SYSTEM_ACCOUNT;
0612: }
0613:
0614: /**
0615: * Get a particular record from the database into this object's fields
0616: * Assumes that the key fields are set to the key of the object to
0617: * be retrieved
0618: *
0619: * @throws DBException if search is not allowed or if no record is found
0620: */
0621: public void retrieve() throws DBException {
0622: isAllowed(SEARCH);
0623: super .retrieve();
0624: } /* retrieve() */
0625:
0626: /**
0627: * Find a set of keys of all of the objects that match the current
0628: * search critieria in the fields
0629: * Assumes that the fields are populated with search criteria instead
0630: * of data
0631: * NOTE: Criteria in 'text' type colums is ignored (SQL Server limitation)
0632: *
0633: * @throws DBException if search is not allowed for the current user
0634: */
0635: public synchronized void search() throws DBException {
0636: isAllowed(SEARCH);
0637: super .search();
0638: } /* search() */
0639:
0640: /**
0641: * Find a set of records of all of the objects that match the current
0642: * search critieria in the fields
0643: * and retrieve the list of all records that match this criteria
0644: * NOTE: Criteria in 'text' type colums is ignored (SQL Server limitation)
0645: *
0646: * @return An ArrayList containing all of the objects matching the criteria
0647: * @throws DBException if search is not allowed for the current user
0648: * @since Expresso 4.0
0649: */
0650: public synchronized ArrayList searchAndRetrieveList()
0651: throws DBException {
0652: isAllowed(SEARCH);
0653: return super .searchAndRetrieveList();
0654: }
0655:
0656: /**
0657: * Find a set of records of all of the objects that match the current
0658: * search critieria in the fields
0659: * and retrieve the list of all records that match this criteria
0660: * NOTE: Criteria in 'text' type colums is ignored (SQL Server limitation)
0661: *
0662: * @param sortKeys A list of field names, seperated by pipes,
0663: * that determine the order
0664: * in which the records retrieved are sorted
0665: * @return java.util.ArrayList of DBObjects found.
0666: * @throws DBException if search is not allowed for the current user
0667: * @since Expreso 4.0
0668: */
0669: public synchronized ArrayList searchAndRetrieveList(String sortKeys)
0670: throws DBException {
0671: isAllowed(SEARCH);
0672: return super .searchAndRetrieveList(sortKeys);
0673: } /* searchAndRetrieve(String) */
0674:
0675: /**
0676: * Update the database with the new info
0677: *
0678: * @throws DBException if update is not allowed for the current user
0679: */
0680: public void update() throws DBException {
0681: isAllowed(UPDATE);
0682: super .update();
0683: } /* update() */
0684:
0685: /**
0686: * Convenience method to get a local language string from within any
0687: * SecuredDBObject by using the user's language perferences automatically
0688: *
0689: * @param stringCode The string code in the MessagesBundle to retrieve
0690: * @param args The i18n formatting arguments which equals the standard arguments
0691: * for a normal Java i18n APi
0692: * @return The properly formatted string.
0693: * @throws DBException if there's an error recovering the message string.
0694: */
0695: protected String getString(String stringCode, Object[] args)
0696: throws DBException {
0697: return Messages.getString(getJDBCMetaData().getSchema(),
0698: getLocale(), stringCode, args);
0699: } /* getString(String, Object[]) */
0700:
0701: /**
0702: * Convenience factory method to create a SecuredDBObject object from it's name
0703: *
0704: * @param className The classname to instantiate of this DBObject.
0705: * @return The fully constructed SecuredDBObject
0706: * @throws DBException if there's an error constructing the DBOBject
0707: */
0708: public static SecuredDBObject instantiate(String className)
0709: throws DBException {
0710: StringUtil.assertNotBlank(className,
0711: "DBObject class name may not be blank or null here");
0712:
0713: try {
0714: Class c = ClassLocator.loadClass(className);
0715:
0716: return (SecuredDBObject) c.newInstance();
0717: } catch (ClassNotFoundException cn) {
0718: throw new DBException("DBObject object '" + className
0719: + "' not found", cn);
0720: } catch (InstantiationException ie) {
0721: throw new DBException("DBObject object '" + className
0722: + "' cannot be instantiated", ie);
0723: } catch (IllegalAccessException iae) {
0724: throw new DBException("llegal access loading "
0725: + "DBObject object '" + className
0726: + "' doesn't have a public default constructor",
0727: iae);
0728: }
0729: } /* instantiate(String) */
0730:
0731: /**
0732: * Convenience method of the above with no arguments
0733: *
0734: * @param stringCode The string code to retrieve from the MessagesBundle.
0735: * @return The formatted message string
0736: * @throws DBException if there's an error retrieving the text
0737: */
0738: protected String getString(String stringCode) throws DBException {
0739: Object[] args = {};
0740:
0741: return getString(stringCode, args);
0742: } /* getString(String) */
0743:
0744: /**
0745: * Convenience method of the above without array arguments
0746: *
0747: * @param arg1 Formatting Argument #1
0748: * @param stringCode The string code to retrieve from the MessagesBundle.
0749: * @return The formatted message string
0750: * @throws DBException if there's an error retrieving the text
0751: */
0752: protected String getString(String stringCode, String arg1)
0753: throws DBException {
0754: Object[] args = { arg1 };
0755:
0756: return getString(stringCode, args);
0757: }
0758:
0759: /**
0760: * Convenience method of the above without array arguments
0761: *
0762: * @param stringCode The string code to retrieve from the MessagesBundle.
0763: * @param arg1 Formatting Argument #1
0764: * @param arg2 Formatting Argument #2
0765: * @return The formatted message string
0766: * @throws DBException if there's an error retrieving the text
0767: */
0768: protected String getString(String stringCode, String arg1,
0769: String arg2) throws DBException {
0770: Object[] args = { arg1, arg2 };
0771:
0772: return getString(stringCode, args);
0773: }
0774:
0775: /**
0776: * Convenience method of the above without array arguments
0777: *
0778: * @param stringCode The string code to retrieve from the MessagesBundle.
0779: * @param arg1 Formatting Argument #1
0780: * @param arg2 Formatting Argument #2
0781: * @param arg3 Formatting Argument #3
0782: * @return The formatted message string
0783: * @throws DBException if there's an error retrieving the text
0784: */
0785: protected String getString(String stringCode, String arg1,
0786: String arg2, String arg3) throws DBException {
0787: Object[] args = { arg1, arg2, arg3 };
0788:
0789: return getString(stringCode, args);
0790: }
0791:
0792: /**
0793: * Convenience method of the above without array arguments
0794: *
0795: * @param stringCode The string code to retrieve from the MessagesBundle.
0796: * @param arg1 Formatting Argument #1
0797: * @param arg2 Formatting Argument #2
0798: * @param arg3 Formatting Argument #3
0799: * @param arg4 Formatting Argument #4
0800: * @return The formatted message string
0801: * @throws DBException if there's an error retrieving the text
0802: */
0803: protected String getString(String stringCode, String arg1,
0804: String arg2, String arg3, String arg4) throws DBException {
0805: Object[] args = { arg1, arg2, arg3, arg4 };
0806:
0807: return getString(stringCode, args);
0808: }
0809:
0810: /**
0811: * this method should make sure that the 'returnObj'
0812: * object is properly initialized with copied UID and data context as this (parent) object
0813: *
0814: * @param returnObj the object to copy the attributes into.
0815: * @throws DBException upon error
0816: */
0817: public void copyAttributes(DBObject returnObj) throws DBException {
0818: super .copyAttributes(returnObj);
0819: if (returnObj instanceof SecuredDBObject) {
0820: ((SecuredDBObject) returnObj)
0821: .setRequestingUid(getRequestingUid());
0822: }
0823: }
0824:
0825: /**
0826: * Security check on count
0827: *
0828: * @return the count
0829: * @throws com.jcorporate.expresso.core.db.DBException
0830: * or security exception
0831: * if search permissions is not allowed
0832: */
0833: public synchronized int count()
0834: throws com.jcorporate.expresso.core.db.DBException {
0835: isAllowed(SEARCH);
0836: return super .count();
0837: }
0838:
0839: /**
0840: * Security check on deleteAll
0841: */
0842: public synchronized void deleteAll()
0843: throws com.jcorporate.expresso.core.db.DBException {
0844: isAllowed(DELETE);
0845: super .deleteAll();
0846: }
0847:
0848: /**
0849: * determine if getRequestingUid has rights to read this kind of object
0850: * (not just this particular object, but ALL INSTANCES of this kind of object)
0851: *
0852: * @return true if getRequestingUid has rights to read this row
0853: * @throws DBException upon database communication error
0854: */
0855: public boolean canRequesterRead() throws DBException {
0856: boolean result = false;
0857:
0858: int userId = this .getRequestingUid();
0859:
0860: if (userId == SYSTEM_ACCOUNT) {
0861: return true;
0862: }
0863:
0864: User user = new User();
0865: user.setUid(userId);
0866: user.setDataContext(this .getDataContext());
0867:
0868: if (!user.find()) {
0869: throw new DBException(
0870: "cannot find requesting user with ID: "
0871: + getRequestingUid());
0872: }
0873:
0874: if (user.isAdmin()) {
0875: return true;
0876: }
0877:
0878: try {
0879: this .isAllowed(SEARCH);
0880: result = true;
0881: } catch (Exception e) {
0882: result = false;
0883: }
0884:
0885: return result;
0886: }
0887:
0888: /**
0889: * determine if getRequestingUid has rights to add this kind of object
0890: * (not just this particular object, but ALL INSTANCES of this kind of object)
0891: *
0892: * @return true if requesting id has permission to add
0893: * @throws DBException upon database communication error
0894: */
0895: public boolean canRequesterAdd() throws DBException {
0896: boolean result = false;
0897:
0898: int userId = this .getRequestingUid();
0899:
0900: if (userId == SYSTEM_ACCOUNT) {
0901: return true;
0902: }
0903:
0904: User user = new User();
0905: user.setUid(userId);
0906: user.setDataContext(this .getDataContext());
0907:
0908: if (!user.find()) {
0909: throw new DBException(
0910: "cannot find requesting user with ID: "
0911: + getRequestingUid());
0912: }
0913:
0914: if (user.getLoginName().equals(User.ADMIN_USER)) {
0915: return true;
0916: }
0917:
0918: try {
0919: this .isAllowed(ADD);
0920: result = true;
0921: } catch (Exception e) {
0922: result = false;
0923: }
0924:
0925: return result;
0926: }
0927:
0928: /**
0929: * determine if getRequestingUid has rights to delete this kind of object
0930: * (not just this particular object, but ALL INSTANCES of this kind of object)
0931: *
0932: * @return true if requesting id has permission to delete
0933: * @throws DBException upon database communication error
0934: */
0935: public boolean canRequesterDelete() throws DBException {
0936: boolean result = false;
0937:
0938: int userId = this .getRequestingUid();
0939:
0940: if (userId == SYSTEM_ACCOUNT) {
0941: return true;
0942: }
0943:
0944: User user = new User();
0945: user.setUid(userId);
0946: user.setDataContext(this .getDataContext());
0947:
0948: if (!user.find()) {
0949: throw new DBException(
0950: "cannot find requesting user with ID: "
0951: + getRequestingUid());
0952: }
0953:
0954: if (user.getLoginName().equals(User.ADMIN_USER)) {
0955: return true;
0956: }
0957:
0958: try {
0959: this .isAllowed(DELETE);
0960: result = true;
0961: } catch (Exception e) {
0962: result = false;
0963: }
0964:
0965: return result;
0966: }
0967:
0968: /**
0969: * determine if getRequestingUid has rights to update this kind of object
0970: * (not just this particular object, but ALL INSTANCES of this kind of object)
0971: *
0972: * @return true if requesting id has permission to update
0973: * @throws DBException upon database communication error
0974: */
0975: public boolean canRequesterUpdate() throws DBException {
0976: boolean result = false;
0977:
0978: int userId = this .getRequestingUid();
0979:
0980: if (userId == SYSTEM_ACCOUNT) {
0981: return true;
0982: }
0983:
0984: User user = new User();
0985: user.setUid(userId);
0986: user.setDataContext(this .getDataContext());
0987:
0988: if (!user.find()) {
0989: throw new DBException(
0990: "cannot find requesting user with ID: "
0991: + getRequestingUid());
0992: }
0993:
0994: if (user.getLoginName().equals(User.ADMIN_USER)) {
0995: return true;
0996: }
0997:
0998: try {
0999: this .isAllowed(UPDATE);
1000: result = true;
1001: } catch (Exception e) {
1002: result = false;
1003: }
1004:
1005: return result;
1006: }
1007:
1008: } /* SecuredDBObject */
|