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-2018 Ping Identity Corporation
026 */
027
028
029package com.unboundid.directory.sdk.broker.api;
030
031import com.unboundid.directory.sdk.broker.config.PolicyAdviceConfig;
032import com.unboundid.directory.sdk.broker.internal.BrokerExtension;
033import com.unboundid.directory.sdk.broker.types.AdviceContext;
034import com.unboundid.directory.sdk.broker.types.BrokerContext;
035import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
036import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
037import com.unboundid.scim2.common.exceptions.ScimException;
038import com.unboundid.scim2.common.messages.ErrorResponse;
039import com.unboundid.util.Extensible;
040import com.unboundid.util.ThreadSafety;
041import com.unboundid.util.ThreadSafetyLevel;
042import com.unboundid.util.args.ArgumentException;
043import com.unboundid.util.args.ArgumentParser;
044
045import java.util.Collections;
046import java.util.List;
047import java.util.Map;
048
049
050/**
051 * This class defines an API that must be implemented by extensions that
052 * implement custom Policy Advice.  This advice is invoked when policy
053 * evaluation results in this type of advice being returned to the Policy
054 * Enforcement Point.
055 *
056 * <H2>Configuring Policy Advice</H2>
057 * In order to configure policy advice created using this API,
058 * use a command like:
059 *
060 * <PRE>
061 *      dsconfig create-policy-advice \
062 *           --advice-name "<I>{name}</I>" \
063 *           --type third-party \
064 *           --policy-name "<I>{policy-name}</I>" \
065 *           --rule-name "<I>{rule-name}</I>" \
066 *           --set "extension-class:<I>{class-name}</I>" \
067 *           --set "extension-argument:<I>{name=value}</I>" \
068 *           --set "advice-arguments:<I>{name=jexlExpression}</I>" \
069 *           --set "evaluation-order-index:<I>{index}</I>
070 * </PRE>
071 * where "<I>{name}</I>" is the name to use for the policy advice
072 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java
073 * class that extends
074 * {@code com.unboundid.directory.sdk.broker.api.PolicyAdvice},
075 * "<I>{policy-name}</I>" and <I>{rule-name}</I>" identify the policy and
076 * policy rule, respectively, that will contain this advice expression.
077 * <I>{name=jexlExpression}</I> pairs specified using advice-arguments identify
078 * arguments whose value may be specified or computed during policy evaluation
079 * before being passed into this advice implementation.
080 * "<I>{index}</I>" is an integer from 1 to 9999 that is used to determine the
081 * order in which this type of advice should be invoked relative to other advice
082 * that may be returned from the same policy evaluation.
083 * "<I>{name=value}</I>" pairs specified using extension-arguments are values
084 * that are provided to the advice implementation at initialization time.
085 * If multiple advice arguments should be provided at each invocation, then the
086 * "<CODE>--set advice-argument:<I>{name=jexlExpression}</I></CODE>" option
087 * should be provided multiple times.
088 * If multiple initialization arguments should be provided to the extension,
089 * then the "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option
090 * should be provided multiple times.
091 */
092@Extensible()
093@BrokerExtension
094@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
095public abstract class PolicyAdvice
096    implements UnboundIDExtension,
097    ExampleUsageProvider {
098
099  /**
100   * No-args constructor.
101   */
102  public PolicyAdvice() {
103    // no implementation required.
104  }
105
106
107  /**
108   * {@inheritDoc}
109   */
110  @Override
111  public abstract String getExtensionName();
112
113
114  /**
115   * {@inheritDoc}
116   */
117  @Override
118  public abstract String[] getExtensionDescription();
119
120
121  /**
122   * {@inheritDoc}
123   */
124  @Override
125  public Map<List<String>,String> getExamplesArgumentSets() {
126    return Collections.emptyMap();
127  }
128
129
130  /**
131   * {@inheritDoc}
132   */
133  @Override
134  public void defineConfigArguments(final ArgumentParser parser)
135      throws ArgumentException {
136    // No arguments will be allowed by default.
137  }
138
139
140  /**
141   * Initializes this Policy Advice implementation.
142   * @param  serverContext  A handle to the server context for the server in
143   *                        which this extension is running.
144   * @param  adviceCfg      The general configuration for this policy advice.
145   * @param  parser         The argument parser which has been initialized from
146   *                        the configuration for this policy advice.
147   *
148   * @throws Exception      If a problem occurs while initializing this
149   *                        policy advice.
150   */
151  public void initializePolicyAdvice(
152      final BrokerContext serverContext,
153      final PolicyAdviceConfig adviceCfg,
154      final ArgumentParser parser) throws Exception {
155    // No initialization will be performed by default.
156  }
157
158
159  /**
160   * Performs any cleanup which may be necessary when this policy advice
161   * is to be taken out of service.
162   */
163  public void finalizePolicyAdvice() {
164    // no implementation is required
165  }
166
167
168  /**
169   * This method is called if this advice is returned by policy when a SCIM
170   * request is denied.
171   * @param context     AdviceContext containing any arguments passed
172   *                    from policy.
173   * @param errorInfo   the default error information that will be
174   *                    returned if nothing is done by the advice
175   *                    implementation.
176   * @return            the modified error info
177   * @throws ScimException if an internal error occurs trying to generate
178   *                    the advice.
179   */
180  public ErrorResponse onScimDeny(
181      final AdviceContext context,
182      final ErrorResponse errorInfo) throws ScimException {
183
184    // default implementation:  no-op.
185    return errorInfo;
186  }
187}