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-2016 UnboundID Corp.
026 */
027
028package com.unboundid.directory.sdk.broker.api;
029
030import com.unboundid.directory.sdk.broker.internal.IdentityBrokerExtension;
031import com.unboundid.directory.sdk.broker.types.IdentityBrokerContext;
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 Identity 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@IdentityBrokerExtension()
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 IdentityBrokerContext 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.
192   * @param categoryId XACML category identifier.  This is the category Id
193   *                   specified by the AttributeDesignator element in the
194   *                   policy that is requesting this attribute.
195   * @param attributeId XACML attribute identifier.  This will be one of the
196   *                   identifiers specified by the xacml-attribute-id
197   *                   property of the configuration for this Policy
198   *                   Information Provider.
199   * @param context request context, can be used to retrieve other
200   *                attributes from the request that may be needed
201   *                in order to evaluate the requested attribute
202   * @return RequestAttribute object containing the requested attribute,
203   *                never null.
204   * @throws Exception if an error occurs retrieving the attribute
205   */
206  public abstract RequestAttribute getAttribute(
207      final String categoryId,
208      final String attributeId,
209      RequestContext context) throws Exception;
210
211
212  /**
213   * {@inheritDoc}
214   */
215  public Map<List<String>,String> getExamplesArgumentSets()
216  {
217    return Collections.emptyMap();
218  }
219}
220