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 2012-2024 Ping Identity Corporation 026 */ 027package com.unboundid.directory.sdk.ds.api; 028 029 030 031import java.util.Collections; 032import java.util.List; 033import java.util.Map; 034 035import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider; 036import com.unboundid.directory.sdk.common.internal.Reconfigurable; 037import com.unboundid.directory.sdk.common.internal.UnboundIDExtension; 038import com.unboundid.directory.sdk.common.operation.SASLBindRequest; 039import com.unboundid.directory.sdk.common.types.Entry; 040import com.unboundid.directory.sdk.common.types.OperationContext; 041import com.unboundid.directory.sdk.ds.config.SASLMechanismHandlerConfig; 042import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension; 043import com.unboundid.directory.sdk.ds.types.DirectoryServerContext; 044import com.unboundid.directory.sdk.ds.types.SASLBindResult; 045import com.unboundid.directory.sdk.ds.types.SASLBindResultFactory; 046import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension; 047import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension; 048import com.unboundid.ldap.sdk.LDAPException; 049import com.unboundid.ldap.sdk.ResultCode; 050import com.unboundid.util.Extensible; 051import com.unboundid.util.ThreadSafety; 052import com.unboundid.util.ThreadSafetyLevel; 053import com.unboundid.util.args.ArgumentException; 054import com.unboundid.util.args.ArgumentParser; 055 056 057 058/** 059 * This class defines an API that must be implemented by extensions which add 060 * support for custom SASL mechanisms to the server, which can provide support 061 * for custom authentication (and optionally, authorization) methods. 062 * <BR> 063 * <H2>Configuring SASL Mechanism Handlers</H2> 064 * In order to configure a SASL mechanism handler created using this API, use a 065 * command like: 066 * <PRE> 067 * dsconfig create-sasl-mechanism-handler \ 068 * --handler-name "<I>{handler-name}</I>" \ 069 * --type third-party \ 070 * --set enabled:true \ 071 * --set "extension-class:<I>{class-name}</I>" \ 072 * --set "extension-argument:<I>{name=value}</I>" 073 * </PRE> 074 * where "<I>{handler-name}</I>" is the name to use for the SASL mechanism 075 * handler instance, "<I>{class-name}</I>" is the fully-qualified name of the 076 * Java class that extends 077 * {@code com.unboundid.directory.sdk.ds.api.SASLMechanismHandler}, and 078 * "<I>{name=value}</I>" represents name-value pairs for any arguments to 079 * provide to the handler. If multiple arguments should be provided to the SASL 080 * mechanism handler, then the 081 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be 082 * provided multiple times. 083 */ 084@Extensible() 085@DirectoryServerExtension() 086@DirectoryProxyServerExtension(appliesToLocalContent=true, 087 appliesToRemoteContent=true, 088 notes="Any SASL bind requests received by the Directory Proxy Server " + 089 "will be processed by the Directory Proxy Server itself rather " + 090 "than being forwarded to backend servers. However, a SASL " + 091 "mechanism handler running in the Directory Proxy Server may " + 092 "perform internal operations which reference content in the " + 093 "backend servers as if it was contained locally in the server.") 094@SynchronizationServerExtension(appliesToLocalContent=true, 095 appliesToSynchronizedContent=false) 096@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE) 097public abstract class SASLMechanismHandler 098 implements UnboundIDExtension, 099 Reconfigurable<SASLMechanismHandlerConfig>, 100 ExampleUsageProvider 101{ 102 /** 103 * Creates a new instance of this SASL mechanism handler. All SASL 104 * mechanism handler implementations must include a default constructor, but 105 * any initialization 106 * should generally be done in the {@code initializeSASLMechanismHandler} 107 * method. 108 */ 109 public SASLMechanismHandler() 110 { 111 // No implementation is required. 112 } 113 114 115 116 /** 117 * {@inheritDoc} 118 */ 119 public abstract String getExtensionName(); 120 121 122 123 /** 124 * {@inheritDoc} 125 */ 126 public abstract String[] getExtensionDescription(); 127 128 129 130 /** 131 * {@inheritDoc} 132 */ 133 public void defineConfigArguments(final ArgumentParser parser) 134 throws ArgumentException 135 { 136 // No arguments will be allowed by default. 137 } 138 139 140 141 /** 142 * Initializes this SASL mechanism handler. 143 * 144 * @param serverContext A handle to the server context for the server in 145 * which this extension is running. 146 * @param config The general configuration for this SASL mechanism 147 * handler. 148 * @param parser The argument parser which has been initialized from 149 * the configuration for this SASL mechanism handler. 150 * 151 * @throws LDAPException If a problem occurs while initializing this SASL 152 * mechanism handler. 153 */ 154 public void initializeSASLMechanismHandler( 155 final DirectoryServerContext serverContext, 156 final SASLMechanismHandlerConfig config, 157 final ArgumentParser parser) 158 throws LDAPException 159 { 160 // No initialization will be performed by default. 161 } 162 163 164 165 /** 166 * {@inheritDoc} 167 */ 168 public boolean isConfigurationAcceptable( 169 final SASLMechanismHandlerConfig config, 170 final ArgumentParser parser, 171 final List<String> unacceptableReasons) 172 { 173 // No extended validation will be performed by default. 174 return true; 175 } 176 177 178 179 /** 180 * {@inheritDoc} 181 */ 182 public ResultCode applyConfiguration(final SASLMechanismHandlerConfig config, 183 final ArgumentParser parser, 184 final List<String> adminActionsRequired, 185 final List<String> messages) 186 { 187 // By default, no configuration changes will be applied. If there are any 188 // arguments, then add an admin action message indicating that the extension 189 // needs to be restarted for any changes to take effect. 190 if (! parser.getNamedArguments().isEmpty()) 191 { 192 adminActionsRequired.add( 193 "No configuration change has actually been applied. The new " + 194 "configuration will not take effect until this SASL " + 195 "mechanism handler is disabled and re-enabled or until the " + 196 "server is restarted."); 197 } 198 199 return ResultCode.SUCCESS; 200 } 201 202 203 204 /** 205 * Performs any cleanup which may be necessary when this SASL mechanism 206 * handler is to be taken out of service. 207 */ 208 public void finalizeSASLMechanismHandler() 209 { 210 // No implementation is required. 211 } 212 213 214 215 /** 216 * Retrieves a list of the names of the SASL mechanisms supported by this 217 * SASL mechanism handler. This method will be invoked only immediately after 218 * the {@link #initializeSASLMechanismHandler} method is called. 219 * 220 * @return A list of the names of the SASL mechanisms supported by this SASL 221 * mechanism handler. 222 */ 223 public abstract List<String> getSASLMechanismNames(); 224 225 226 227 /** 228 * Indicates whether the SASL authentication process using the specified 229 * mechanism may be considered secure (i.e., that a third party able to 230 * observe the communication, potentially over an insecure communication 231 * channel, would not be able to reproduce the authentication process). 232 * 233 * @param mechanism The name of the mechanism for which to make the 234 * determination. This will only be invoked with names of 235 * mechanisms returned by the 236 * {@link #getSASLMechanismNames} method. 237 * 238 * @return {@code true} if the specified SASL mechanism should be considered 239 * secure, or {@code false} if not. 240 */ 241 public abstract boolean isSecure(final String mechanism); 242 243 244 245 /** 246 * Indicates whether the SASL authentication process using the specified 247 * mechanism involves the use of a password stored locally in the server 248 * (optionally in combination with other forms of credentials). 249 * 250 * @param mechanism The name of the mechanism for which to make the 251 * determination. This will only be invoked with names of 252 * mechanisms returned by the 253 * {@link #getSASLMechanismNames} method. 254 * 255 * @return {@code true} if the specified SASL mechanism makes use of a local 256 * password, or {@code false} if not. 257 */ 258 public abstract boolean isPasswordBased(final String mechanism); 259 260 261 262 /** 263 * Performs the appropriate processing for the provided SASL bind request. 264 * 265 * @param operationContext The context for the bind operation. 266 * @param bindRequest The SASL bind request to be processed. 267 * @param resultFactory A factory object that will be used to construct 268 * the result to return. 269 * 270 * @return An object with information about the result of the SASL bind 271 * processing. 272 */ 273 public abstract SASLBindResult processSASLBind( 274 final OperationContext operationContext, 275 final SASLBindRequest bindRequest, 276 final SASLBindResultFactory resultFactory); 277 278 279 280 /** 281 * {@inheritDoc} 282 */ 283 public Map<List<String>,String> getExamplesArgumentSets() 284 { 285 return Collections.emptyMap(); 286 } 287 288 289 290 /** 291 * Indicates whether the specified SASL mechanism, which is listed as 292 * supported by this handler, is available for use by the given user. 293 * 294 * @param mechanism The name of the SASL mechanism for which to make 295 * the determination. It will be one of the 296 * mechanisms for which this handler is registered. 297 * @param passwordAttribute The name of the attribute used to hold the 298 * password for the user. 299 * @param userEntry The entry for the user for whom to make the 300 * determination. 301 * 302 * @return {@code true} if the SASL mechanism is supported for the user, 303 * {@code false} if not, or {@code null} if it could not be 304 * determined. 305 */ 306 public Boolean isMechanismAvailableForUser(final String mechanism, 307 final String passwordAttribute, 308 final Entry userEntry) 309 { 310 // This should be overridden by subclasses that wish to implement this 311 // functionality. 312 return null; 313 } 314 315 316 317 /** 318 * Indicates whether the specified SASL mechanism may require multiple stages 319 * to process. 320 * 321 * @param mechanism The mechanism for which to make the determination. 322 * 323 * @return {@code true} if the specified SASL mechanism may require multiple 324 * stages to process, {@code false} if not, or {@code null} if the 325 * answer is not known for the specified mechanism. 326 */ 327 public Boolean isMultiStageMechanism(final String mechanism) 328 { 329 // This should be overridden by subclasses that wish to impelement this 330 // functionality. 331 return null; 332 } 333}