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 2016-2021 Ping Identity Corporation
026 */
027
028
029package com.unboundid.directory.sdk.common.api;
030
031import com.unboundid.directory.sdk.broker.internal.BrokerExtension;
032import com.unboundid.directory.sdk.common.config.AccessTokenValidatorConfig;
033import com.unboundid.directory.sdk.common.types.TokenValidationResult;
034import com.unboundid.directory.sdk.common.internal.Configurable;
035import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
036import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
037import com.unboundid.directory.sdk.common.types.ServerContext;
038import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
039import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
040import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
041import com.unboundid.directory.sdk.metrics.internal.MetricsEngineExtension;
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 * This class defines an API that may be implemented by PingAuthorize Server
054 * extensions that validate externally generated access tokens.  Implementing
055 * extensions that support this API enables the PingAuthorize Server
056 * to accept access tokens generated from external Identity Providers.
057 *
058 * <H2>Configuring Access Token Validators</H2>
059 * In order to configure an Access Token Validator created using this API, use
060 * a command like:
061 * <PRE>
062 *      dsconfig create-token-validator \
063 *           ---validator-name "<I>{name}</I>" \
064 *           --type third-party \
065 *           --set "extension-class:<I>{class-name}</I>" \
066 *           --set "extension-argument:<I>{name=value}</I>"
067 * </PRE>
068 * where "<I>{name}</I>" is the name to use for the Access Token Validator
069 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java class
070 * that extends
071 * {@code com.unboundid.directory.sdk.common.api.AccessTokenValidator},
072 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
073 * provide to the Access Token Validator. If multiple arguments should be
074 * provided to the extension, then the
075 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
076 * provided multiple times.
077 */
078@Extensible()
079@BrokerExtension
080@DirectoryServerExtension
081@SynchronizationServerExtension(appliesToLocalContent=true,
082  appliesToSynchronizedContent=false)
083@MetricsEngineExtension
084@DirectoryProxyServerExtension(
085    appliesToLocalContent = true,
086    appliesToRemoteContent = true
087)
088@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
089public abstract class AccessTokenValidator
090    implements UnboundIDExtension, Configurable, ExampleUsageProvider {
091
092  /**
093   * Creates a new instance of this Access Token Validator.  All
094   * implementations must include a default constructor, but any
095   * initialization should generally be done in the
096   * {@link #initializeTokenValidator} method.
097   */
098  public AccessTokenValidator()
099  {
100    // No implementation is required.
101  }
102
103  /**
104   * {@inheritDoc}
105   */
106  @Override
107  public abstract String getExtensionName();
108
109
110
111  /**
112   * {@inheritDoc}
113   */
114  @Override
115  public abstract String[] getExtensionDescription();
116
117
118
119  /**
120   * {@inheritDoc}
121   */
122  @Override
123  public Map<List<String>,String> getExamplesArgumentSets()
124  {
125    return Collections.emptyMap();
126  }
127
128  /**
129   * {@inheritDoc}
130   */
131  @Override
132  public void defineConfigArguments(final ArgumentParser parser)
133      throws ArgumentException
134  {
135    // No arguments will be allowed by default.
136  }
137
138
139  /**
140   * Initializes this access token validator.
141   *
142   * @param  serverContext  A handle to the server context for the server in
143   *                        which this extension is running.
144   * @param  config         The general configuration for this token validator.
145   * @param  parser         The argument parser which has been initialized from
146   *                        the configuration for this token validator.
147   *
148   * @throws Exception      If a problem occurs while initializing this
149   *                        token validator.
150   */
151  public void initializeTokenValidator(
152      final ServerContext serverContext,
153      final AccessTokenValidatorConfig config,
154      final ArgumentParser parser)
155      throws Exception
156  {
157    // No initialization will be performed by default.
158  }
159
160
161  /**
162   * Performs any cleanup which may be necessary when this token validator
163   * is to be taken out of service.
164   */
165  public void finalizeTokenValidator()
166  {
167    // No implementation is performed by default.
168  }
169
170
171  /**
172   * Validate the provided access token.
173   * @param encodedAccessToken access token string as it is received from the
174   *                           requesting client.
175   * @return The PingAuthorize Server may be configured to accept access tokens
176   * from multiple sources so it is important that each validator differentiate
177   * between a token format that it does not recognize and a token that it can
178   * process but is not valid.
179   *
180   * If the token can be processed, the validator must return a
181   * TokenValidationResult object containing token properties.  Most
182   * importantly the {@code active} field of the TokenValidationResult must be
183   * set by the validator.
184   *
185   * The decision as to whether an access token is accepted or not is made by
186   * the servlet hosting the token validator.
187   *
188   * If the token cannot be introspected by the Access Token Validator it must
189   * return null to allow other validators to have a chance to process the
190   * token.
191   *
192   * @throws Exception if an error occurs during the processing of a token
193   * that can be introspected by the validator.  Exceptions should only be
194   * thrown for unexpected internal errors.   Sensitive information should not
195   * be included in the exception message as the message may be returned to
196   * the client application that has passed the token.
197   */
198  public abstract TokenValidationResult validate(String encodedAccessToken)
199      throws Exception;
200
201}