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 * Portions Copyright 2010-2024 Ping Identity Corporation 026 */ 027package com.unboundid.directory.sdk.ds.scripting; 028 029 030 031import java.util.List; 032 033import com.unboundid.directory.sdk.common.internal.Reconfigurable; 034import com.unboundid.directory.sdk.ds.config.IdentityMapperConfig; 035import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension; 036import com.unboundid.directory.sdk.ds.types.DirectoryServerContext; 037import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension; 038import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension; 039import com.unboundid.ldap.sdk.LDAPException; 040import com.unboundid.ldap.sdk.ResultCode; 041import com.unboundid.util.Extensible; 042import com.unboundid.util.ThreadSafety; 043import com.unboundid.util.ThreadSafetyLevel; 044import com.unboundid.util.args.ArgumentException; 045import com.unboundid.util.args.ArgumentParser; 046 047 048 049/** 050 * This class defines an API that must be implemented by scripted extensions 051 * which attempt to map a username to a user defined in the server. This is 052 * generally used when processing an authorization ID, as might be provided when 053 * performing SASL authentication or in a control like the proxied authorization 054 * or intermediate client controls. In order for the mapping to be established, 055 * the identity mapper must locate exactly one entry in the server corresponding 056 * to the provided username. If no entries are found, or if multiple entries 057 * are found, then the mapping attempt must fail. 058 * <BR> 059 * <H2>Configuring Groovy-Scripted Identity Mappers</H2> 060 * In order to configure a scripted identity mapper based on this API and 061 * written in the Groovy scripting language, use a command like: 062 * <PRE> 063 * dsconfig create-identity-mapper \ 064 * --mapper-name "<I>{mapper-name}</I>" \ 065 * --type groovy-scripted \ 066 * --set enabled:true \ 067 * --set "script-class:<I>{class-name}</I>" \ 068 * --set "script-argument:<I>{name=value}</I>" 069 * </PRE> 070 * where "<I>{mapper-name}</I>" is the name to use for the identity mapper 071 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Groovy 072 * class written using this API, and "<I>{name=value}</I>" represents name-value 073 * pairs for any arguments to provide to the identity mapper. If multiple 074 * arguments should be provided to the identity mapper, then the 075 * "<CODE>--set script-argument:<I>{name=value}</I></CODE>" option should be 076 * provided multiple times. 077 * 078 * @see com.unboundid.directory.sdk.ds.api.IdentityMapper 079 */ 080@Extensible() 081@DirectoryServerExtension() 082@DirectoryProxyServerExtension(appliesToLocalContent=true, 083 appliesToRemoteContent=false) 084@SynchronizationServerExtension(appliesToLocalContent=true, 085 appliesToSynchronizedContent=false) 086@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE) 087public abstract class ScriptedIdentityMapper 088 implements Reconfigurable<IdentityMapperConfig> 089{ 090 /** 091 * Creates a new instance of this identity mapper. All identity mapper 092 * implementations must include a default constructor, but any initialization 093 * should generally be done in the {@code initializeIdentityMapper} method. 094 */ 095 public ScriptedIdentityMapper() 096 { 097 // No implementation is required. 098 } 099 100 101 102 /** 103 * {@inheritDoc} 104 */ 105 public void defineConfigArguments(final ArgumentParser parser) 106 throws ArgumentException 107 { 108 // No arguments will be allowed by default. 109 } 110 111 112 113 /** 114 * Initializes this identity mapper. 115 * 116 * @param serverContext A handle to the server context for the server in 117 * which this extension is running. 118 * @param config The general configuration for this identity mapper. 119 * @param parser The argument parser which has been initialized from 120 * the configuration for this identity mapper. 121 * 122 * @throws LDAPException If a problem occurs while initializing this 123 * identity mapper. 124 */ 125 public void initializeIdentityMapper( 126 final DirectoryServerContext serverContext, 127 final IdentityMapperConfig config, 128 final ArgumentParser parser) 129 throws LDAPException 130 { 131 // No initialization will be performed by default. 132 } 133 134 135 136 /** 137 * Performs any cleanup which may be necessary when this identity mapper is 138 * to be taken out of service. 139 */ 140 public void finalizeIdentityMapper() 141 { 142 // No implementation is required. 143 } 144 145 146 147 /** 148 * {@inheritDoc} 149 */ 150 public boolean isConfigurationAcceptable(final IdentityMapperConfig config, 151 final ArgumentParser parser, 152 final List<String> unacceptableReasons) 153 { 154 // No extended validation will be performed. 155 return true; 156 } 157 158 159 160 /** 161 * {@inheritDoc} 162 */ 163 public ResultCode applyConfiguration(final IdentityMapperConfig config, 164 final ArgumentParser parser, 165 final List<String> adminActionsRequired, 166 final List<String> messages) 167 { 168 // By default, no configuration changes will be applied. If there are any 169 // arguments, then add an admin action message indicating that the extension 170 // needs to be restarted for any changes to take effect. 171 if (! parser.getNamedArguments().isEmpty()) 172 { 173 adminActionsRequired.add( 174 "No configuration change has actually been applied. The new " + 175 "configuration will not take effect until this identity " + 176 "mapper is disabled and re-enabled or until the server is " + 177 "restarted."); 178 } 179 180 return ResultCode.SUCCESS; 181 } 182 183 184 185 /** 186 * Performs any processing which may be necessary to map the provided username 187 * to a user within the server. 188 * 189 * @param username The username to be mapped to a user within the server. 190 * 191 * @return The DN of the user within the server to which the provided 192 * username corresponds. 193 * 194 * @throws LDAPException If the provided username cannot be mapped to 195 * exactly one user in the server. 196 */ 197 public abstract String mapUsername(final String username) 198 throws LDAPException; 199}