/* * 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-2019 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; } }