SystemResource.java
/*
** Module : SystemResource.java
** Abstract : plugin to manage access to the "system" abstract resource
**
** Copyright (c) 2005-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------Description----------------------
** 001 NVS 20050318 @20425 Created the initial version. This class is
** responsible for the "system" abstract
** resource which offers controllable access to
** the "logon" instance of the resource.
** 002 NVS 20050411 @20678 Fixed few javadoc issues
** 003 NVS 20050412 @20688 Using new expressions interface that takes
** the Rights instance.
** 004 NVS 20050414 @20708 Added rights search tracing for debugging.
** 005 NVS 20050524 @21274 Some methods and members are moved to base
** abstract class.
** 006 NVS 20060412 @25496 Added new resource instances, "accounts" and
** "extensions" and new check methods for them.
** 007 GES 20081105 @40342 Minor cleanup.
** 008 NVS 20090318 @41628 Added new resource instance, "admin" and
** a new check method for it. This instance will
** protect the admin APIs for now.
** 009 NVS 20090707 @43079 Added getRightsEditorName() method.
** 010 HC 20170612 Changes related to implementation of new GWT-based Admin client.
** 011 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.security;
import com.goldencode.p2j.directory.*;
import com.goldencode.expr.*;
import com.goldencode.p2j.util.logging.*;
import java.util.logging.*;
/**
* Implements the "system" abstract resource. Instances of this resource
* control access to various features of the P2J application. Currently
*defined instances are:
* <ul>
* <li>logon - allows logging on to the P2J server
* <li>context - names security context related events for audit
* <li>change - controls access to the batch editing feature
* <li>shutdown - controls access to the server shutdown
* <li>debug - controls access to the debug level change
* </ul>
*/
class SystemResource
extends AbstractResource
{
/** the only access mode for "system" resources */
static final int SYSTEM_ACCESS = 0;
/** context related event constant */
static final int SYSTEM_CONTEXT_CREATE = 1;
/** context related event constant */
static final int SYSTEM_CONTEXT_DELETE = 2;
/** context related event constant */
static final int SYSTEM_CONTEXT_SWITCH = 4;
/** array of valid instance names */
private static final String[] validInstances = new String[]
{
"logon",
"context",
"change",
"shutdown",
"debug",
"accounts",
"extensions",
"admin",
};
/** Logger. */
private static final CentralLogger LOG = CentralLogger.get(SystemResource.class);
/**
* Package private constructor.
*/
SystemResource()
{
}
/**
* Returns the plugin resource type name as a string.
*
* @return plugin resource type name
*/
public String getTypeName()
{
return "system";
}
/**
* Returns an array of descriptions, one object per the plugin's access
* rights item.
*
* @return array of <code>Description</code>s, one per each plugin's access
* rights item.
*/
public Description[] describeRights()
{
Description[] items = new Description[1];
items[0] = new Description(AttributeType.ATTR_STRING, // string
false, // mandatory
true, // var.size
0, // size
"check", // text label
"enables access if evaluates to true"
);
return items;
}
/**
* Instantiates a plugin's class that implements the Rights interface,
* using the array of objects representing a set of access rights fields.
*
* @param rights
* an array of objects of proper types representing items in a set
* of access rights
*
* @return the reference to the interface.
*/
public Rights getRightsInstance(Object[] rights)
{
return new SystemRights((String)rights[0]);
}
/**
* Checks whether a given string is a valid resource name
* for this resource type.
*
* @param resource
* string naming a resource
*
* @return <code>true</code> if the name is syntactically correct
*/
public boolean isInstanceNameValid(String resource)
{
for (int i = 0; i < validInstances.length; i ++)
{
if (resource.equals(validInstances[i]))
return true;
}
return false;
}
/**
* Checks whether a given array of objects representing a set of access
* rights fields is acceptable.
*
* @param rights
* an array of objects of proper types representing items in a set
* of access rights
*
* @return <code>true</code> if the array is acceptable for an instance
* of access rights
*/
public boolean isRightsSetValid(Object[] rights)
{
if (rights.length != 1)
return false;
if (!rights[0].getClass().isInstance(""))
return false;
return true;
}
/**
* Checks access rights of the current subject with regards to the "logon"
* instance of the "system" abstract resource.
*
* @return <code>true</code> if access is allowed.
*/
boolean checkLogonAccess()
{
return systemAccessWorker("logon", SYSTEM_ACCESS);
}
/**
* Checks access rights of the current subject with regards to the "change"
* instance of the "system" abstract resource.
*
* @return <code>true</code> if access is allowed.
*/
boolean checkChangeAccess()
{
return systemAccessWorker("change", SYSTEM_ACCESS);
}
/**
* Checks access rights of the current subject with regards to the
* "shutdown" instance of the "system" abstract resource.
*
* @return <code>true</code> if access is allowed.
*/
boolean checkShutdownAccess()
{
return systemAccessWorker("shutdown", SYSTEM_ACCESS);
}
/**
* Checks access rights of the current subject with regards to the
* "debug" instance of the "system" abstract resource.
*
* @return <code>true</code> if access is allowed.
*/
boolean checkDebugAccess()
{
return systemAccessWorker("debug", SYSTEM_ACCESS);
}
/**
* Checks access rights of the current subject with regards to the
* "accounts" instance of the "system" abstract resource.
*
* @return <code>true</code> if access is allowed.
*/
boolean checkAccountsAccess()
{
return systemAccessWorker("accounts", SYSTEM_ACCESS);
}
/**
* Checks access rights of the current subject with regards to the
* "extensions" instance of the "system" abstract resource.
*
* @return <code>true</code> if access is allowed.
*/
boolean checkExtensionsAccess()
{
return systemAccessWorker("extensions", SYSTEM_ACCESS);
}
/**
* Checks access rights of the current subject with regards to the
* "admin" instance of the "system" abstract resource.
*
* @return <code>true</code> if access is allowed.
*/
boolean checkAdminAccess()
{
return systemAccessWorker("admin", SYSTEM_ACCESS);
}
/**
* Implements generalized access rights check worker.
*
* @param instanceName
* name of the particular instance of the abstract resource about
* to be accessed
*
* @param mode
* an integer value encoding the access mode specific to this
* resource
*
* @return <code>true</code> if access is allowed.
*/
private boolean systemAccessWorker(String instanceName, int mode)
{
Boolean cached = null;
boolean decision = false;
// check to see if there is a cached decision
cached = sm.getCachedDecision(resourceIndex, instanceName, mode);
if (cached != null)
{
return cached.booleanValue();
}
// initiate the ACL search
int handle = sm.openRightsSearch(resourceIndex, instanceName, mode);
boolean isFinerLoggable = LOG.isLoggable(Level.FINER);
if (isFinerLoggable)
{
LOG.finer("Search open: resId " + resourceIndex + ", instance " +
instanceName + ", mode " + mode + ", handle " + handle);
}
// rights check loop
SystemRights rights = (SystemRights) sm.getNextRights(handle);
while (rights != null)
{
if (isFinerLoggable)
{
LOG.finer("Search next: handle " + handle + ", rights " + rights);
}
decision = checkSingle(rights);
if (decision)
break;
rights = (SystemRights) sm.getNextRights(handle);
}
if (isFinerLoggable)
{
LOG.finer("Search done: handle " + handle + ", decision " +
decision + ", cache false");
}
// close the ACL search
sm.closeRightsSearch(handle, decision, false);
return decision;
}
/**
* Implements a worker that performs access rights check on a single
* instance of the SystemRights object.
*
* @param rights
* The instance of SystemRights to check, must not be
* <code>null</code>.
*
* @return <code>true</code> if access is allowed.
*/
private boolean checkSingle(SystemRights rights)
{
Object obj = sm.evaluate(resourceIndex, rights, rights.getCondition());
if (obj == null || !Boolean.class.isInstance(obj))
return false;
Boolean result = (Boolean) obj;
return result.booleanValue();
}
}