UnboundID Server SDK

Ping Identity
UnboundID Server SDK Documentation

ExampleAccessTokenValidator.java

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * docs/licenses/cddl.txt
 * or http://www.opensource.org/licenses/cddl1.php.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * docs/licenses/cddl.txt.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2015-2018 Ping Identity Corporation
 */

package com.unboundid.directory.sdk.examples;

import com.unboundid.directory.sdk.broker.api.AccessTokenValidator;
import com.unboundid.directory.sdk.broker.config.AccessTokenValidatorConfig;
import com.unboundid.directory.sdk.broker.types.BrokerContext;
import com.unboundid.directory.sdk.broker.types.TokenValidationResult;
import com.unboundid.scim2.common.GenericScimResource;
import com.unboundid.scim2.common.messages.ListResponse;
import com.unboundid.util.args.ArgumentParser;

import java.util.Arrays;
import java.util.HashSet;

/**
 * Example Access Token Validator that processes access tokens issued from
 * a fictional external IDP.  The format of the fictional access token is:
 * <p>
 * ExternalTestToken:[validity]:[owner]:[scope]
 * <UL>
 *   <LI>ExternalTestToken -- tells this validator that the token is one
 *                    of "ours".</LI>
 *   <LI>validity -- token is valid if this is equal to "TrustMe".</LI>
 *   <LI>owner -- userName, for this example assumed to be common between
 *                    the external IDP and local user store</LI>
 *   <LI>scope -- scopes granted by this token, space-delimited</LI>
 * </UL>
 */

public class ExampleAccessTokenValidator extends AccessTokenValidator {

  /**
   * Prefix for all tokens that can be validated by this validator.
   */
  public static final String TOKEN_PREFIX = "ExternalTestToken";

  /**
   * String value indicating that the token is valid.
   */
  public static final String VALID_TOKEN = "TrustMe";

  /**
   * The SCIM endpoint that contains the local user records for token owners.
   */
  public static final String USERS_ENDPOINT = "Users";


  private BrokerContext serverContext;


  /**
   * {@inheritDoc}
   */
  @Override
  public String getExtensionName() {
    return "Example Access Token Validator";
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public String[] getExtensionDescription() {
    return new String[]
    {
      "This access token validator serves as an example that may be used to " +
          "demonstrate the process for creating a third-party access token " +
          "validator.  It validates human-readable access tokens whose " +
          "value includes whether the token is valid, the owner of the " +
          "token, and the scopes granted to the token."
    };
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public void initializeTokenValidator(
      final BrokerContext serverContext,
      final AccessTokenValidatorConfig config,
      final ArgumentParser parser) throws Exception {

    super.initializeTokenValidator(serverContext, config, parser);
    this.serverContext = serverContext;
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public TokenValidationResult validate(
      final String encodedAccessToken)
      throws Exception {

    TokenValidationResult tokenValidationResult = null;
    String[] tokenParts = encodedAccessToken.split(":");

    if (tokenParts.length == 4 && tokenParts[0].equals(TOKEN_PREFIX)) {

      // this token is recognized, so populate a result object

      boolean isValid = tokenParts[1].equals(VALID_TOKEN);
      String userName = tokenParts[2];
      String scope = tokenParts[3];

      TokenValidationResult.Builder builder =
          new TokenValidationResult.Builder(isValid);

      // convert the user name into the required format for subject
      // which is "SCIMEndpoint/SCIMId".  This requires searching for the
      // user's record in the local user store.

      String filter = "username eq \"" + userName + "\"";
      ListResponse<GenericScimResource> searchResults =
          serverContext.getInternalScimInterface().search(
              USERS_ENDPOINT, filter, GenericScimResource.class);

      if (searchResults.getTotalResults() == 0) {
        throw new Exception("No user found that matches token name.");
      }
      else if (searchResults.getTotalResults() > 1) {
        throw new Exception("Found multiple users matching token user name.");
      }

      GenericScimResource localUser = searchResults.getResources().get(0);
      builder.setSubjectToken(USERS_ENDPOINT + "/" + localUser.getId());

      builder.setScope(new HashSet<String>(Arrays.asList(scope.split(" "))));
      tokenValidationResult = builder.build();
    }
    return tokenValidationResult;
  }
}