[Opensource] Bug in DBController.stateAllowed()
Michael Rimov
rimovm at centercomp.com
Mon Nov 17 15:13:37 PST 2003
Ken,
I took a good look at this, and I don't think that Expresso 5.3 code has
this issue, the biggest reason is that caching is stored by group now
rather than user and a search is done for any groups that a cached security
entry could be found.
Can you take a fresh look at the code and see if I'm missing something?
-Mike
At 01:46 AM 11/13/2003, you wrote:
>I think I've found a bug related to a user that is a member of multiple
>Security Groups. Here's the scenario:
>
> - I've defined two Security Groups: Reader and Creator
> - the group Creator is a member of the group Reader
> - Reader has access to the states promptUserUpdate and processUserUpdate in
>MemberController
> - Creator has access to the states promptUserSearch, processUserSearch in
>MemberController
> - logged on user is in the Creator group
>
> - when DBController.stateAllowed() is invoked with nextState
>promptUserSearch for the MemberController
> . for the group Creator with allowedStates="promptUserSearch,
>processUserSearch", a match
> is found, and allowedStates="promptUserSearch, processUserSearch" is
>saved in the cache
> . for the group Reader with allowedStates="promptUserUpdate and
>processUserUpdate", NO match
> is found, and nothing is saved in the cache
>
> - when DBController.stateAllowed() is invoked again with nextState
>promptUserUpdate for the MemberController
> . a match is found in the cache with allowedStates="promptUserSearch,
>processUserSearch"
> . promptUserUpdate is not contained in the allowedStates retrieved from
>the cache
> . stateAllowed() incorrectly returns false (because not all the allowed
>states for the uid|MemberController
> are stored in the cache)
>
>I'm currently working with Expresso 5.0.3, but have also reviewed the 5.0.5
>and 5.3 RC5 code and they appear to have the same problem.
>
>I've attached a revised version of stateAllowed() with the problem corrected
>by accumulating all allowed states for the user (from all groups that the
>user is a member of) before adding to the cache. I suspect that this may not
>be the best way to fix the problem since there may be side-effects that I'm
>nor aware of, but it appears to be working.
>
>Ken Chow
>
>-----------------------------------------------------------
>
> public synchronized boolean stateAllowed(String newState,
> ControllerRequest myRequest)
> throws ControllerException {
> try {
>
> /* if the security cache is available, use it */
> if
>(CacheManager.getInstance().existsCache(myRequest.getDBName(), cacheName)) {
> ValidValue secVal = (ValidValue)
>CacheManager.getInstance().getItem(
> myRequest.getDBName(), cacheName,
> myRequest.getUid() + "|" +
> getClass().getName());
>
> /* if there is an entry for this user */
> if (secVal != null) {
> String sec = secVal.getDescription();
>
>
> if (containsAllowedState(sec, newState)) {
> if (log.isDebugEnabled()) {
> log.debug("User '" + myRequest.getUid() +
> "' allowed state '" + newState +
> "' via cache");
> }
>
> return true;
> } else {
>
> /* otherwise they are denied */
> if (log.isDebugEnabled()) {
> log.debug("User '" + myRequest.getUid() +
> "' denied state '" + newState +
> "' via cache in db '" +
> myRequest.getDBName() +
> "'. Cache entry was '" + sec + "'");
> }
>
> return false;
> }
> }
>
> /* otherwise there was no entry, so check the DB directly */
> }
>
> /* if security cache is available */
> User thisUser = new User();
> thisUser.setDBName(myRequest.getDBName());
> thisUser.setUid(myRequest.getUid());
> thisUser.retrieve();
>
> ControllerSecurity cs = new ControllerSecurity();
> cs.setDBName(myRequest.getDBName());
>
> String oneGroupName = null;
> ControllerSecurity oneSecurityEntry = null;
> String allowedStates = null;
>// start of inserted code
> FastStringBuffer accumulatedAllowedStates = new
>FastStringBuffer();
>// end of inserted code
> boolean allowed = false;
>
> for (Enumeration eg = thisUser.getGroups().elements();
> eg.hasMoreElements();) {
> oneGroupName = (String) eg.nextElement();
> cs.clear();
> cs.setField("ControllerClass", getClass().getName());
> cs.setField("GroupName", oneGroupName);
>
> for (Iterator cse = cs.searchAndRetrieveList().iterator();
> cse.hasNext();) {
>
> oneSecurityEntry = (ControllerSecurity) cse.next();
> allowedStates = oneSecurityEntry.getField("States");
>// start of inserted code
> if ((allowedStates != null) &&
>(!allowedStates.equals(""))) {
> if (accumulatedAllowedStates.length() > 0) {
> accumulatedAllowedStates.append(",");
> }
> accumulatedAllowedStates.append(allowedStates);
> }
>// end of inserted code
>
> if (containsAllowedState(allowedStates, newState)) {
> allowed = true;
>// start of deleted code
>// addCachedSecurity(myRequest.getUid(),
>// myRequest.getDBName(),
>// getClass().getName(), allowedStates);
>// end of deleted code
> }
> } /* for */
>
> } /* for each user group */
>
>// start of inserted code
> addCachedSecurity(myRequest.getUid(), myRequest.getDBName(),
> getClass().getName(),
>accumulatedAllowedStates.toString());
>// end of inserted code
>
> if (!allowed) {
>// start of deleted code
>// addCachedSecurity(myRequest.getUid(),
>myRequest.getDBName(),
>// getClass().getName(), "");
>// DelayThread.delay();
>// end of deleted code
>
> if (log.isDebugEnabled()) {
> log.debug("User " + myRequest.getUid() +
> " denied all states in " + getClass().getName()
>+
> " in db '" + myRequest.getDBName() + "'");
> }
> }
>
> return allowed;
> } catch (DBException de) {
> throw new ControllerException("Unable to check Controller " +
> "security", de);
> } catch (CacheException ce) {
> throw new ControllerException("Cache exception checking " +
> "Controller security", ce);
> }
> } /* stateAllowed(String) */
>
>
>
>_______________________________________________
>Opensource mailing list
>Opensource at jcorporate.com
>http://mail.jcorporate.com/mailman/listinfo/opensource
>Archives: http://mail.jcorporate.com/pipermail/opensource/
More information about the Opensource
mailing list