001package com.identityworksllc.iiq.common.access; 002 003import com.identityworksllc.iiq.common.CommonSecurityConfig; 004import sailpoint.object.Identity; 005import sailpoint.rest.plugin.BasePluginResource; 006import sailpoint.tools.GeneralException; 007import sailpoint.tools.Util; 008import sailpoint.web.UserContext; 009 010import java.util.HashMap; 011import java.util.Map; 012 013/** 014 * Access check input 015 */ 016public final class AccessCheckInput { 017 /** 018 * Configuration 019 */ 020 private CommonSecurityConfig configuration; 021 022 /** 023 * The debug flag 024 */ 025 private boolean debug; 026 027 /** 028 * The state from this access check 029 */ 030 private Map<String, Object> state; 031 032 /** 033 * The target Identity being checked (may be null) 034 */ 035 private transient Identity target; 036 037 /** 038 * The target Identity name 039 */ 040 private String targetName; 041 042 /** 043 * The target object type 044 * TODO use this 045 */ 046 private String targetType; 047 048 /** 049 * The name of the thing being checked 050 */ 051 private String thingName; 052 053 /** 054 * The UserContext, specifying which user is the subject of the access check. 055 * If this is also a {@link sailpoint.plugin.PluginContext}, as it would be if 056 * it is a {@link BasePluginResource}, then it will be used for plugin-specific 057 * checks. 058 */ 059 private UserContext userContext; 060 061 /** 062 * Constructs a basic access check input 063 */ 064 public AccessCheckInput() { 065 this.thingName = AccessCheck.ANONYMOUS_THING; 066 this.debug = false; 067 } 068 069 /** 070 * Copy constructor allowing override of an input 071 * 072 * @param parent The parent config 073 * @param config The 'child' config to replace with 074 */ 075 public AccessCheckInput(AccessCheckInput parent, CommonSecurityConfig config) { 076 this(parent.userContext, parent.target, parent.thingName, config, parent.state); 077 } 078 079 /** 080 * Access check input taking a plugin or target 081 * 082 * @param userContext The user context (likely a BasePluginResource) 083 * @param config The config 084 */ 085 public AccessCheckInput(UserContext userContext, CommonSecurityConfig config) { 086 this(userContext, null, AccessCheck.ANONYMOUS_THING, config, null); 087 } 088 /** 089 * Access check input taking a plugin or target 090 * 091 * @param userContext The user context (likely a BasePluginResource) 092 * @param target The target 093 * @param config The config 094 */ 095 public AccessCheckInput(UserContext userContext, Identity target, CommonSecurityConfig config) { 096 this(userContext, target, AccessCheck.ANONYMOUS_THING, config, null); 097 } 098 099 /** 100 * Access check input taking a plugin or target 101 * 102 * @param userContext The user context (likely a BasePluginResource) 103 * @param target The target 104 * @param thingName The thing name 105 * @param config The config 106 */ 107 public AccessCheckInput(UserContext userContext, Identity target, String thingName, CommonSecurityConfig config) { 108 this(userContext, target, thingName, config, null); 109 } 110 111 /** 112 * Access check input taking a plugin or target 113 * 114 * @param userContext The user context (likely a {@link BasePluginResource} or {@link com.identityworksllc.iiq.common.auth.DummyAuthContext}) 115 * @param target The target 116 * @param thingName The thing name 117 * @param config The config 118 * @param state Any persistent state in the access checks 119 */ 120 public AccessCheckInput(UserContext userContext, Identity target, String thingName, CommonSecurityConfig config, Map<String, Object> state) { 121 this.userContext = userContext; 122 this.target = target; 123 if (this.target != null) { 124 this.targetName = target.getName(); 125 } 126 this.configuration = config; 127 if (thingName == null || thingName.isEmpty()) { 128 this.thingName = AccessCheck.ANONYMOUS_THING; 129 } else { 130 this.thingName = thingName; 131 } 132 this.state = (state != null) ? state : new HashMap<>(); 133 this.debug = false; 134 } 135 136 /** 137 * Gets the configuration object 138 * @return The common security configuration object 139 * @see CommonSecurityConfig 140 */ 141 public CommonSecurityConfig getConfiguration() { 142 return configuration; 143 } 144 145 /** 146 * @deprecated Use {@link #getUserContext()} instead 147 * @return The configured plugin resource / user context 148 */ 149 @Deprecated 150 public UserContext getPluginResource() { 151 return userContext; 152 } 153 154 /** 155 * Gets the state {@link Map} 156 * @return The state Map 157 */ 158 public Map<String, Object> getState() { 159 return state; 160 } 161 162 /** 163 * Gets the stored target Identity if one exists. If one does not exist, 164 * returns the subject Identity. 165 * 166 * @return The target Identity 167 * @throws GeneralException if anything fails 168 */ 169 public Identity getTarget() throws GeneralException { 170 if (this.target != null) { 171 return target; 172 } else if (Util.isNotNullOrEmpty(targetName)) { 173 this.target = userContext.getContext().getObject(Identity.class, targetName); 174 return target; 175 } else { 176 return userContext.getLoggedInUser(); 177 } 178 } 179 180 /** 181 * Gets the currently configured thing name 182 * @return The configured thing name 183 */ 184 public String getThingName() { 185 return thingName; 186 } 187 188 /** 189 * Gets the user context 190 * @return The user context, containing the subject user 191 */ 192 public UserContext getUserContext() { 193 return userContext; 194 } 195 196 /** 197 * Returns the value of the debug flag on this access check request 198 * @return The debug flag 199 */ 200 public boolean isDebug() { 201 return debug; 202 } 203 204 /** 205 * Puts a value into the access check state map 206 * @param name The key 207 * @param value The value 208 * @return This object, for chaining 209 */ 210 public AccessCheckInput putState(String name, Object value) { 211 if (this.state == null) { 212 this.state = new HashMap<>(); 213 } 214 215 this.state.put(name, value); 216 return this; 217 } 218 219 /** 220 * Sets the common security configuration as a Map, which will be decoded. 221 * 222 * @see CommonSecurityConfig#decode(Map) 223 * @see com.identityworksllc.iiq.common.ObjectMapper#decode(Map) 224 * @param configuration The configuration to decode and store 225 * @return This object, for chaining 226 * @throws GeneralException if the configuration cannot be decoded 227 */ 228 public AccessCheckInput setConfiguration(Map<String, Object> configuration) throws GeneralException { 229 this.configuration = CommonSecurityConfig.decode(configuration); 230 return this; 231 } 232 233 /** 234 * Sets the common security configuration 235 * @param configuration The common security configuration 236 * @return This object, for chaining 237 */ 238 public AccessCheckInput setConfiguration(CommonSecurityConfig configuration) { 239 this.configuration = configuration; 240 return this; 241 } 242 243 /** 244 * Sets the debug flag on the access check 245 * @param debug The debug flag to set 246 */ 247 public AccessCheckInput setDebug(boolean debug) { 248 this.debug = debug; 249 return this; 250 } 251 252 /** 253 * Sets the plugin resource, simply forwarding to {@link #setUserContext(UserContext)}, 254 * because {@link BasePluginResource} is an instance of {@link UserContext}. 255 * 256 * @param pluginResource The plugin resource to set 257 * @return This object, for chaining 258 * @throws GeneralException if a targetName has been set and loading the Identity fails 259 */ 260 @Deprecated 261 public AccessCheckInput setPluginResource(BasePluginResource pluginResource) throws GeneralException { 262 return setUserContext(pluginResource); 263 } 264 265 /** 266 * Sets the state map, which will be provided to any access check rules or 267 * access check scripts. 268 * 269 * @param state The access check state to set; this map will be copied 270 * @return This object, for chaining 271 */ 272 public AccessCheckInput setState(Map<String, Object> state) { 273 if (state == null) { 274 this.state = new HashMap<>(); 275 } else { 276 this.state = new HashMap<>(state); 277 } 278 return this; 279 } 280 281 /** 282 * Sets the target Identity and target name 283 * 284 * @param target The target Identity 285 * @return This object, for chaining 286 */ 287 public AccessCheckInput setTarget(Identity target) { 288 this.target = target; 289 this.targetName = target.getName(); 290 return this; 291 } 292 293 /** 294 * Sets the target name or ID. This will be resolved to an {@link Identity} 295 * on the first call to {@link #getTarget()}. 296 * 297 * @param targetName The target's name or ID 298 * @return This object, for chaining 299 */ 300 public AccessCheckInput setTarget(String targetName){ 301 this.targetName = targetName; 302 return this; 303 } 304 305 /** 306 * Sets the thing name, for caching and display purposes 307 * @param thingName The thing name 308 * @return This object, for chaining 309 */ 310 public AccessCheckInput setThingName(String thingName) { 311 this.thingName = thingName; 312 return this; 313 } 314 315 /** 316 * Sets the user context, containing the 'subject' of the access check 317 * @param userContext The context specifying the subject of the access check 318 * @return This object, for chaining 319 */ 320 public AccessCheckInput setUserContext(UserContext userContext) { 321 this.userContext = userContext; 322 return this; 323 } 324 325 /** 326 * Validates the configuration before it executes 327 * @throws AccessCheckException if validation fails 328 */ 329 public void validate() throws AccessCheckException { 330 if (this.userContext == null) { 331 throw new AccessCheckException("UserContext is required"); 332 } 333 if (this.configuration == null) { 334 throw new AccessCheckException("Configuration is required"); 335 } 336 } 337}