001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * docs/licenses/cddl.txt
011 * or http://www.opensource.org/licenses/cddl1.php.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * docs/licenses/cddl.txt.  If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 *      Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 *      Copyright 2017-2019 Ping Identity Corporation
026 */
027
028
029package com.unboundid.directory.sdk.broker.api;
030
031import com.unboundid.directory.sdk.broker.config.PolicyObligationConfig;
032import com.unboundid.directory.sdk.broker.internal.BrokerExtension;
033import com.unboundid.directory.sdk.broker.types.BrokerContext;
034import com.unboundid.directory.sdk.broker.types.NotFulfilledException;
035import com.unboundid.directory.sdk.broker.types.ObligationContext;
036import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
037import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
038
039import com.unboundid.scim2.common.GenericScimResource;
040import com.unboundid.scim2.common.exceptions.ScimException;
041import com.unboundid.scim2.common.messages.PatchRequest;
042import com.unboundid.util.Extensible;
043import com.unboundid.util.ThreadSafety;
044import com.unboundid.util.ThreadSafetyLevel;
045import com.unboundid.util.args.ArgumentException;
046import com.unboundid.util.args.ArgumentParser;
047
048import java.util.Collections;
049import java.util.List;
050import java.util.Map;
051
052
053/**
054 * This class defines an API that must be implemented by extensions that
055 * implement custom Policy Obligations.  This obligation is invoked when
056 * policy evaluation results in this type of obligation being returned to the
057 * Policy Enforcement Point.
058 *
059 * <H2>Configuring Policy Obligation</H2>
060 * In order to configure a policy obligation created using this API,
061 * use a command like:
062 *
063 * <PRE>
064 *      dsconfig create-policy-obligation \
065 *           --obligation-name "<I>{name}</I>" \
066 *           --type third-party \
067 *           --policy-name "<I>{policy-name}</I>" \
068 *           --rule-name "<I>{rule-name}</I>" \
069 *           --set "extension-class:<I>{class-name}</I>" \
070 *           --set "extension-argument:<I>{name=value}</I>" \
071 *           --set "obligation-arguments:<I>{name=jexlExpression}</I>" \
072 *           --set "evaluation-order-index:<I>{index}</I>
073 * </PRE>
074 * where "<I>{name}</I>" is the name to use for the policy obligation
075 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java
076 * class that extends
077 * {@code com.unboundid.directory.sdk.broker.api.PolicyObligation},
078 * "<I>{policy-name}</I>" and <I>{rule-name}</I>" identify the policy and
079 * policy rule, respectively, that will contain this obligation expression.
080 * <I>{name=jexlExpression}</I> pairs specified using obligation-arguments
081 * identify arguments whose value may be specified or computed during policy
082 * evaluation before being passed into this obligation implementation.
083 * "<I>{index}</I>" is an integer from 1 to 9999 that is used to determine the
084 * order in which this type of obligation should be invoked relative to other
085 * obligations that may be returned from the same policy evaluation.
086 * "<I>{name=value}</I>" pairs specified using extension-arguments are
087 * constant-valued arguments that are provided to the obligation implementation
088 * at initialization time.
089 * If multiple obligation arguments should be provided at each invocation, then
090 * the "<CODE>--set obligation-argument:<I>{name=jexlExpression}</I></CODE>"
091 * option should be provided multiple times.
092 * If multiple initialization arguments should be provided to the extension,
093 * then the "<CODE>--set extension-argument:<I>{name=value}</I></CODE>"
094 * option should be provided multiple times.
095 */
096@Extensible()
097@BrokerExtension
098@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
099public abstract class PolicyObligation
100    implements UnboundIDExtension,
101    ExampleUsageProvider {
102
103  /**
104   * No-args constructor.
105   */
106  public PolicyObligation() {
107    // No implementation is required.
108  }
109
110
111  /**
112   * {@inheritDoc}
113   */
114  @Override
115  public abstract String getExtensionName();
116
117
118  /**
119   * {@inheritDoc}
120   */
121  @Override
122  public abstract String[] getExtensionDescription();
123
124
125  /**
126   * {@inheritDoc}
127   */
128  @Override
129  public Map<List<String>,String> getExamplesArgumentSets() {
130    return Collections.emptyMap();
131  }
132
133
134  /**
135   * {@inheritDoc}
136   */
137  @Override
138  public void defineConfigArguments(final ArgumentParser parser)
139      throws ArgumentException {
140    // No arguments will be allowed by default.
141  }
142
143
144  /**
145   * Initializes this Policy Obligation implementation.
146   * @param  serverContext  A handle to the server context for the server in
147   *                        which this extension is running.
148   * @param  config         The general configuration for this policy
149   *                        obligation.
150   * @param  parser         The argument parser which has been initialized from
151   *                        the configuration for this policy obligation.
152   *
153   * @throws Exception      If a problem occurs while initializing this
154   *                        policy obligation.
155   */
156  public void initializePolicyObligation(
157      final BrokerContext serverContext,
158      final PolicyObligationConfig config,
159      final ArgumentParser parser) throws Exception {
160    // No initialization will be performed by default.
161  }
162
163
164  /**
165   * Performs any cleanup which may be necessary when this policy obligation
166   * is to be taken out of service.
167   */
168  public void finalizePolicyObligation() {
169    // no implementation is required
170  }
171
172
173  /**
174   * This method is invoked if this obligation is returned from policy during a
175   * SCIM create operation.  The method is invoked before the new resource
176   * has been saved to the data store.
177   *
178   * @param context     ObligationContext containing any arguments passed
179   *                    from policy.
180   * @param resource    The resource to be created.
181   * @return            The (possibly modified) resource to be created.
182   * @throws NotFulfilledException thrown if the obligation cannot be
183   *                    fulfilled.   Will abort the SCIM create operation and
184   *                    will cause an unauthorized response to be returned to
185   *                    the caller.
186   * @throws ScimException thrown if an internal error occurs.
187   */
188  public GenericScimResource onScimCreate(
189      final ObligationContext context,
190      final GenericScimResource resource)
191      throws NotFulfilledException, ScimException {
192
193    // no implementation required
194    return resource;
195  }
196
197
198  /**
199   * This method is invoked if this obligation is returned from policy during
200   * a SCIM delete operation.   The method is invoked before the deletion is
201   * committed to the data store.
202   *
203   * @param context     ObligationContext containing any arguments passed
204   *                    from policy.
205   * @throws NotFulfilledException thrown if the obligation cannot be
206   *                    fulfilled.   Will abort the SCIM delete operation and
207   *                    will cause an unauthorized response to be returned to
208   *                    the caller.
209   * @throws ScimException thrown if an internal error occurs.
210   */
211  public void onScimDelete(
212      final ObligationContext context)
213      throws NotFulfilledException, ScimException {
214
215    // no implementation required
216  }
217
218
219  /**
220   * This method is invoked if this obligation is returned from policy during a
221   * SCIM PATCH or PUT operation.  The method is invoked before the modified
222   * resource has been saved to the data store.
223   *
224   * @param context     ObligationContext containing any arguments passed
225   *                    from policy.
226   * @param patchRequest A normalized SCIM patch request describing the
227   *                     requested modifications.  A "normalized" patch request
228   *                     in this context means that the patch will have the
229   *                     following characteristics:
230   *
231   *                     For add and remove operations, sub-attributes will
232   *                     always appear in the value portion rather than in the
233   *                     path.
234   *
235   *                     Paths referencing core attributes will not contain the
236   *                     schema URN.
237   *
238   *                     Operations without a path will be broken down into
239   *                     separate operations for each attribute originally
240   *                     referenced in the value portion.
241   *
242   * @return            The (possibly modified) patch request.
243   * @throws NotFulfilledException thrown if the obligation cannot be
244   *                    fulfilled.   Will abort the SCIM modify operation and
245   *                    will cause an unauthorized response to be returned to
246   *                    the caller.
247   * @throws ScimException thrown if an internal error occurs.
248   */
249  public PatchRequest onScimModify(
250      final ObligationContext context,
251      final PatchRequest patchRequest)
252      throws NotFulfilledException, ScimException {
253
254    // no implementation required
255    return patchRequest;
256  }
257
258
259  /**
260   * This method is invoked if this obligation is returned from policy during a
261   * SCIM retrieve operation.  The method is invoked before the resource
262   * is added to the SCIM response.
263   *
264   * @param context     ObligationContext containing any arguments passed
265   *                    from policy.
266   * @param resource    The resource to be returned to the client.
267   * @return            The (possibly modified) resource to be returned.
268   * @throws NotFulfilledException thrown if the obligation cannot be
269   *                    fulfilled.   Will abort the SCIM retrieve operation and
270   *                    will cause an unauthorized response to be returned to
271   *                    the caller.
272   * @throws ScimException thrown if an internal error occurs.
273   */
274  public GenericScimResource onScimRetrieve(
275      final ObligationContext context,
276      final GenericScimResource resource)
277      throws NotFulfilledException, ScimException {
278
279    // no implementation required
280    return resource;
281  }
282
283
284  /**
285   * This method is invoked if this obligation is returned from policy prior to
286   * a SCIM search operation.  The method is invoked before the search is
287   * executed.
288   *
289   * @param context     ObligationContext containing any arguments passed
290   *                    from policy.
291   * @param filter      The SCIM search filter requested by the client, or
292   *                    null if no filter was specified.
293   * @return            The (possibly modified) SCIM search filter.
294   * @throws NotFulfilledException thrown if the obligation cannot be
295   *                    fulfilled.   Will abort the SCIM search operation and
296   *                    will cause an unauthorized response to be returned to
297   *                    the caller.
298   * @throws ScimException thrown if an internal error occurs.
299   */
300  public String onScimSearch(
301      final ObligationContext context,
302      final String filter)
303      throws NotFulfilledException, ScimException {
304
305    // no implementation required
306    return filter;
307  }
308
309}