001package com.identityworksllc.iiq.common;
002
003import com.identityworksllc.iiq.common.access.AccessCheck;
004import com.identityworksllc.iiq.common.access.AccessCheckInput;
005import com.identityworksllc.iiq.common.annotation.CoreStable;
006import com.identityworksllc.iiq.common.auth.DummyPluginResource;
007import org.apache.commons.logging.Log;
008import org.apache.commons.logging.LogFactory;
009import sailpoint.api.SailPointContext;
010import sailpoint.object.*;
011import sailpoint.rest.plugin.BasePluginResource;
012import sailpoint.tools.GeneralException;
013import sailpoint.web.UserContext;
014
015import java.util.Map;
016
017/**
018 * Implements the "Common Security" protocol described in the documentation. This
019 * allows more detailed authorization to check access to various objects within IIQ.
020 *
021 * There are two users involved in thing access: an subject Identity and a target
022 * Identity. The subject is the one doing the thing while the target is the one
023 * the thing is being done to. Some actions may be 'self' actions, where both the
024 * subject and the target are the same. Other actions don't have a 'target' concept
025 * and are treated as 'self' actions.
026 *
027 * See the `COMMON-SECURITY.adoc` documentation.
028 *
029 * @see AccessCheck
030 */
031@CoreStable
032@SuppressWarnings("unused")
033public final class ThingAccessUtils {
034
035    /**
036     * The logger
037     */
038    private static final Log log = LogFactory.getLog(ThingAccessUtils.class);
039
040    /**
041     * Returns true if the logged in user can access the item based on the Common Security configuration parameters.
042     *
043     * @param pluginContext The plugin context, which provides user details
044     * @param configuration The configuration for the field or button or other object
045     * @return True if the user has access to the thing based on the configuration
046     * @throws GeneralException if any check failures occur (this should be interpreted as "no access")
047     */
048    public static boolean checkThingAccess(UserContext pluginContext, Map<String, Object> configuration) throws GeneralException {
049        return checkThingAccess(pluginContext, null, AccessCheck.ANONYMOUS_THING, configuration);
050    }
051
052    /**
053     * Returns true if the logged in user can access the item based on the Common Security configuration parameters.
054     *
055     * @param pluginContext The plugin context, which provides user details
056     * @param configuration The configuration for the field or button or other object
057     * @return True if the user has access to the thing based on the configuration
058     * @throws GeneralException if any check failures occur (this should be interpreted as "no access")
059     */
060    public static boolean checkThingAccess(BasePluginResource pluginContext, Map<String, Object> configuration) throws GeneralException {
061        return checkThingAccess(pluginContext, null, AccessCheck.ANONYMOUS_THING, configuration);
062    }
063
064    /**
065     * Returns true if the logged in user can access the item based on the CommonSecurityConfig object
066     *
067     * @param pluginContext The plugin context, which provides user details
068     * @param config the CommonSecurityConfig object
069     * @return True if the user has access to the thing based on the configuration
070     * @throws GeneralException if any check failures occur (this should be interpreted as "no access")
071     */
072    public static boolean checkThingAccess(UserContext pluginContext, CommonSecurityConfig config) throws GeneralException {
073        return checkThingAccess(pluginContext, null, AccessCheck.ANONYMOUS_THING, config);
074    }
075
076    /**
077     * Returns true if the logged in user can access the item based on the CommonSecurityConfig object
078     *
079     * @param pluginContext The plugin context, which provides user details
080     * @param config the CommonSecurityConfig object
081     * @return True if the user has access to the thing based on the configuration
082     * @throws GeneralException if any check failures occur (this should be interpreted as "no access")
083     */
084    public static boolean checkThingAccess(BasePluginResource pluginContext, CommonSecurityConfig config) throws GeneralException {
085        return checkThingAccess(pluginContext, null, AccessCheck.ANONYMOUS_THING, config);
086    }
087
088    /**
089     * Returns true if the logged in user can access the item based on the common configuration parameters.
090     *
091     * @param pluginContext The login context, which provides user details
092     * @param targetIdentity The target identity for the action (as opposed to the actor)
093     * @param configuration The configuration for the field or button or other object
094     * @return True if the user has access to the thing based on the configuration
095     * @throws GeneralException if any check failures occur (this should be interpreted as "no access")
096     */
097    public static boolean checkThingAccess(UserContext pluginContext, Identity targetIdentity, Map<String, Object> configuration) throws GeneralException {
098        return checkThingAccess(pluginContext, targetIdentity, AccessCheck.ANONYMOUS_THING, configuration);
099    }
100
101    /**
102     * Returns true if the logged in user can access the item based on the common configuration parameters.
103     *
104     * @param pluginContext The plugin context, which provides user details
105     * @param targetIdentity The target identity for the action (as opposed to the actor)
106     * @param configuration The configuration for the field or button or other object
107     * @return True if the user has access to the thing based on the configuration
108     * @throws GeneralException if any check failures occur (this should be interpreted as "no access")
109     */
110    public static boolean checkThingAccess(BasePluginResource pluginContext, Identity targetIdentity, Map<String, Object> configuration) throws GeneralException {
111        return checkThingAccess(pluginContext, targetIdentity, AccessCheck.ANONYMOUS_THING, configuration);
112    }
113
114    /**
115     * Returns true if the logged in user can access the item based on the common configuration parameters.
116     *
117     * @param pluginContext The plugin context, which provides user details
118     * @param targetIdentity The target identity for the action (as opposed to the actor)
119     * @param configuration The configuration for the field or button or other object
120     * @return True if the user has access to the thing based on the configuration
121     * @throws GeneralException if any check failures occur (this should be interpreted as "no access")
122     */
123    public static boolean checkThingAccess(BasePluginResource pluginContext, Identity targetIdentity, String thingName, Map<String, Object> configuration) throws GeneralException {
124        return checkThingAccess((UserContext) pluginContext, targetIdentity, AccessCheck.ANONYMOUS_THING, configuration);
125    }
126
127    /**
128     * Returns true if the logged in user can access the item based on the common configuration parameters.
129     *
130     * @param pluginContext A plugin REST API resource (or fake equivalent) used to get some details and settings. This must not be null.
131     * @param targetIdentity The target identity
132     * @param thingName The thing being checked
133     * @param configuration The configuration for the field or button or other object
134     * @return True if the user has access to the thing based on the configuration
135     * @throws GeneralException if any check failures occur (this should be interpreted as "no access")
136     */
137    public static boolean checkThingAccess(UserContext pluginContext, Identity targetIdentity, String thingName, Map<String, Object> configuration) throws GeneralException {
138        Identity currentUser = pluginContext.getLoggedInUser();
139        Identity target = targetIdentity;
140        if (target == null) {
141            target = currentUser;
142        }
143        if (configuration == null || configuration.isEmpty()) {
144            Configuration systemConfig = Configuration.getSystemConfig();
145            boolean defaultDeny = systemConfig.getBoolean("IIQCommon.ThingAccessUtils.denyOnEmpty", false);
146            if (defaultDeny) {
147                log.debug("Configuration for " + thingName + " is empty; assuming that access is NOT allowed");
148                return false;
149            } else {
150                log.debug("Configuration for " + thingName + " is empty; assuming that access is allowed");
151                return true;
152            }
153        }
154        CommonSecurityConfig config = CommonSecurityConfig.decode(configuration);
155        return checkThingAccess(pluginContext, target, thingName, config);
156    }
157
158    /**
159     * Returns true if the logged in user can access the item based on the common configuration parameters.
160     *
161     * Results for the same CommonSecurityConfig, source, and target user will be cached for up to one minute
162     * unless the CommonSecurityConfig object has noCache set to true.
163     *
164     * @param pluginContext A plugin REST API resource (or fake equivalent) used to get some details and settings. This must not be null.
165     * @param target The target identity
166     * @param thingName The thing being checked, entirely for logging purposes
167     * @param config The configuration specifying security rights
168     * @return True if the user has access to the thing based on the configuration
169     * @throws GeneralException if any check failures occur (this should be interpreted as "no access")
170     */
171    public static boolean checkThingAccess(UserContext pluginContext, Identity target, String thingName, CommonSecurityConfig config) throws GeneralException {
172        AccessCheckInput input = new AccessCheckInput(pluginContext, target, thingName, config);
173
174        return AccessCheck.accessCheck(input).isAllowed();
175    }
176
177    /**
178     * An optional clear-cache method that can be used by plugin code
179     */
180    public static void clearCachedResults() {
181        AccessCheck.clearCachedResults();
182    }
183
184    /**
185     * Creates a fake plugin context for use with {@link ThingAccessUtils#checkThingAccess(UserContext, Identity, String, Map)} outside of a plugin. This constructs a new instance of a dummy BasePluginResource web service endpoint class.
186     * @param context The SailPointContext to return from {@link BasePluginResource#getContext()}
187     * @param loggedInUser The Identity to return from various getLoggedIn... methods
188     * @param pluginName The name of the plugin to include in the fake plugin context
189     * @return The fake plugin resource
190     */
191    public static BasePluginResource createFakePluginContext(final SailPointContext context, final Identity loggedInUser, String pluginName) {
192        return new DummyPluginResource(context, loggedInUser, pluginName);
193    }
194
195}