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 2013-2017 Ping Identity Corporation
026 */
027
028package com.unboundid.directory.sdk.broker.api;
029
030import com.unboundid.directory.sdk.broker.internal.BrokerExtension;
031import com.unboundid.directory.sdk.broker.types.BrokerContext;
032import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
033import com.unboundid.directory.sdk.common.internal.Reconfigurable;
034import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
035import com.unboundid.directory.sdk.broker.config.
036    PolicyInformationProviderConfig;
037import com.unboundid.directory.sdk.broker.types.RequestAttribute;
038import com.unboundid.directory.sdk.broker.types.RequestContext;
039import com.unboundid.ldap.sdk.ResultCode;
040import com.unboundid.util.Extensible;
041import com.unboundid.util.ThreadSafety;
042import com.unboundid.util.ThreadSafetyLevel;
043import com.unboundid.util.args.ArgumentException;
044import com.unboundid.util.args.ArgumentParser;
045
046import java.util.Collections;
047import java.util.List;
048import java.util.Map;
049
050
051/**
052 * This class defines an API that must be implemented by Broker
053 * extensions that retrieve XACML attributes as part of the Policy Information
054 * Point (PIP).
055 *
056 * <H2>Configuring Policy Information Providers</H2>
057 * In order to configure a policy information provider created using this API,
058 * use a command like:
059 *
060 * <PRE>
061 *      dsconfig create-policy-information-provider \
062 *           --provider-name "<I>{name}</I>" \
063 *           --type third-party \
064 *           --set enabled:true \
065 *           --set "extension-class:<I>{class-name}</I>" \
066 *           --set "extension-argument:<I>{name=value}</I>" \
067 *           --set "xacml-attribute-id:<I>{attributeId}</I> \
068 *           --set "evaluation-order-index:<I>{index}</I>
069 * </PRE>
070 * where "<I>{name}</I>" is the name to use for the policy information provider
071 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java
072 * class that extends
073 * {@code com.unboundid.directory.sdk.broker.api.PolicyInformationProvider},
074 * "<I>{index}</I>" is an integer from 1 to 9999 that is used to determine the
075 * position of this Policy Information Provider in the order of evaluation
076 * among all Policy Information Providers, "<I>{attributeId}</I>" identifies
077 * the XACML attribute(s) that this provider knows how to retrieve, and
078 * "<I>{name=value}</I>" represents name-value pairs for any additional
079 * arguments to provide to the Policy Information Provider. If multiple
080 * arguments should be provided to extension, then the
081 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
082 * provided multiple times.  If the Policy Information Provider can retrieve
083 * more than one attribute type, then the
084 * "<CODE>--set xacml-attribute-id:<I>{attributeId}</I></CODE>" option can also
085 * be provided multiple times.
086 */
087@Extensible()
088@BrokerExtension()
089@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
090public abstract class PolicyInformationProvider
091    implements UnboundIDExtension,
092       Reconfigurable<PolicyInformationProviderConfig>,
093       ExampleUsageProvider
094{
095
096  /**
097   * {@inheritDoc}
098   */
099  public abstract String getExtensionName();
100
101  /**
102   * {@inheritDoc}
103   */
104  public abstract String[] getExtensionDescription();
105
106
107  /**
108   * {@inheritDoc}
109   */
110  public void defineConfigArguments(final ArgumentParser parser)
111      throws ArgumentException
112  {
113    // No arguments will be allowed by default.
114  }
115
116
117  /**
118   * Initializes this policy information provider.
119   *
120   * @param  serverContext  A handle to the server context for the server in
121   *                        which this extension is running.
122   * @param  config         The general configuration for this policy
123   *                        information provider.
124   * @param  parser         The argument parser which has been initialized from
125   *                        the configuration for this policy information
126   *                        provider.
127   *
128   * @throws Exception      If a problem occurs while initializing this
129   *                        policy information provider.
130   */
131  public void initializePolicyInformationProvider(
132      final BrokerContext serverContext,
133      final PolicyInformationProviderConfig config,
134      final ArgumentParser parser)
135      throws Exception
136  {
137    // No initialization will be performed by default.
138  }
139
140
141  /**
142   * {@inheritDoc}
143   */
144  public boolean isConfigurationAcceptable(
145      final PolicyInformationProviderConfig config,
146      final ArgumentParser parser,
147      final List<String> unacceptableReasons)
148  {
149
150    // No extended validation will be performed by default.
151    return true;
152  }
153
154
155  /**
156   * {@inheritDoc}
157   */
158  public ResultCode applyConfiguration(
159      final PolicyInformationProviderConfig config,
160      final ArgumentParser parser,
161      final List<String> adminActionsRequired,
162      final List<String> messages)
163  {
164    // By default, no configuration changes will be applied.  If there are any
165    // arguments, then add an admin action message indicating that the
166    // extension needs to be restarted for any changes to take effect.
167    if (! parser.getNamedArguments().isEmpty())
168    {
169      adminActionsRequired.add(
170          "No configuration change has actually been applied.  The new " +
171              "configuration will not take effect until this policy " +
172              "information provider is disabled and re-enabled or until " +
173              "the server is restarted.");
174    }
175    return ResultCode.SUCCESS;
176
177  }
178
179
180  /**
181   * Performs any cleanup which may be necessary when this policy information
182   * provider is to be taken out of service.
183   */
184  public void finalizePolicyInformationProvider()
185  {
186    // no implementation is required
187  }
188
189
190  /**
191   * Retrieve an attribute that has been requested by the policy engine in order
192   * to resolve a XACML AttributeDesignator element.
193   * @param categoryId XACML category identifier.  This is the category Id
194   *                   specified by the AttributeDesignator element in the
195   *                   policy that is requesting this attribute.
196   * @param attributeId XACML attribute identifier.  This will be one of the
197   *                   identifiers specified by the xacml-attribute-id
198   *                   property of the configuration for this Policy
199   *                   Information Provider.
200   * @param context request context, can be used to retrieve other
201   *                attributes from the request that may be needed
202   *                in order to evaluate the requested attribute
203   * @return RequestAttribute object containing the requested attribute,
204   *                never null.
205   * @throws Exception if an error occurs retrieving the attribute
206   */
207  public abstract RequestAttribute getAttribute(
208      final String categoryId,
209      final String attributeId,
210      final RequestContext context) throws Exception;
211
212  /**
213   * Retrieve JSON content that has been requested by the policy engine in
214   * order to resolve a XACML AttributeSelector element.
215   * @param categoryId XACML category identifier.  This is the category Id
216   *                   specified by the AttributeSelector element in the
217   *                   policy that is requesting this attribute.
218   * @param context request context, can be used to retrieve other
219   *                attributes from the request that may be needed
220   *                in order to retrieve the requested content
221   * @return a JSON-formatted object string, or null if no content
222   *                  is available.
223   * @throws Exception if an error occurs retrieving the content
224   */
225  public abstract String getJsonContent(
226      final String categoryId,
227      final RequestContext context) throws Exception;
228
229  /**
230   * Retrieve additional or narrowed JSON content using the specified context
231   * selector.
232   * @param categoryContent Previously retrieved content for the Attributes
233   *                        category.
234   * @param contextSelectorId optional ContextSelectorId.  This is the
235   *                          context selector string specified in the
236   *                          AttributeSelector.
237   * @param context request context, can be used to retrieve other
238   *                attributes from the request that may be needed
239   *                in order to retrieve the requested content
240   * @return a JSON-formatted object string, or null if no content
241   *                is available.
242   * @throws Exception if an error occurs retrieving the content
243   */
244  public String getJsonContent(
245      final String categoryContent,
246      final String contextSelectorId,
247      final RequestContext context) throws Exception {
248
249    // default implementation:  context selectors not supported. Override
250    // this if the extension can support contextSelector elements.
251    throw new UnsupportedOperationException(
252        String.format("Context Selectors not supported by PIP extension %s",
253            this.getExtensionName()));
254  }
255
256
257  /**
258   * Determine whether this Policy Information Provider can retrieve the
259   * specified attribute from the specified attributes category.
260   * @param categoryId XACML category identifier.  This is the category Id
261   *                   specified by the AttributeDesignator element in the
262   *                   policy that is requesting this attribute.
263   * @param attributeId XACML attribute identifier as specified in the
264   *                   AttributeDesignator element in the policy that is
265   *                   requesting the attribute.
266   * @param context request context
267   * @return true if this PolicyInformationProvider is able to retrieve the
268   * specified attribute.
269   */
270  public abstract boolean canGetAttribute(
271      final String categoryId,
272      final String attributeId,
273      final RequestContext context);
274
275
276  /**
277   * Determine whether this Policy Information Provider can retrieve JSON
278   * content for the specified attributes category and optionally,
279   * ContextSelectorId.
280   * @param categoryId XACML category identifier.  This is the category Id
281   *                   specified by the AttributeSelector element in the
282   *                   policy that is requesting this attribute.
283   * @param contextSelectorId optional ContextSelectorId.  This is the
284   *                   context selector string specified in the
285   *                   AttributeSelector.
286   * @param context request context
287   * @return true if this PolicyInformationProvider is able to retrieve the
288   * specified content.
289   */
290  public abstract boolean canGetJsonContent(
291      final String categoryId,
292      final String contextSelectorId,
293      final RequestContext context);
294
295
296  /**
297   * {@inheritDoc}
298   */
299  public Map<List<String>,String> getExamplesArgumentSets()
300  {
301    return Collections.emptyMap();
302  }
303}
304