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