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-2023 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.common.types.Entry; 035import com.unboundid.directory.sdk.ds.config.PasswordGeneratorConfig; 036import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension; 037import com.unboundid.directory.sdk.ds.types.DirectoryServerContext; 038import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension; 039import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension; 040import com.unboundid.ldap.sdk.LDAPException; 041import com.unboundid.ldap.sdk.ResultCode; 042import com.unboundid.util.ByteString; 043import com.unboundid.util.Extensible; 044import com.unboundid.util.ThreadSafety; 045import com.unboundid.util.ThreadSafetyLevel; 046import com.unboundid.util.args.ArgumentException; 047import com.unboundid.util.args.ArgumentParser; 048 049 050 051/** 052 * This class defines an API that must be implemented by scripted extensions 053 * which generate user passwords. This is primarily used when processing a 054 * password modify extended operation in order to generate a new password for 055 * the target user if the request did not explicitly provide the new password 056 * that should be used. The generated password will not be subject to the 057 * constraints of any defined password validators. 058 * <BR> 059 * <H2>Configuring Groovy-Scripted Password Generators</H2> 060 * In order to configure a scripted password generator based on this API and 061 * written in the Groovy scripting language, use a command like: 062 * <PRE> 063 * dsconfig create-password-generator \ 064 * --generator-name "<I>{generator-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>{generator-name}</I>" is the name to use for the password generator 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 password generator. If multiple 074 * arguments should be provided to the password generator, 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.PasswordGenerator 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 ScriptedPasswordGenerator 088 implements Reconfigurable<PasswordGeneratorConfig> 089{ 090 /** 091 * Creates a new instance of this password generator. All password generator 092 * implementations must include a default constructor, but any initialization 093 * should generally be done in the {@code initializePasswordGenerator} method. 094 */ 095 public ScriptedPasswordGenerator() 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 password generator. 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 password 119 * generator. 120 * @param parser The argument parser which has been initialized from 121 * the configuration for this password generator. 122 * 123 * @throws LDAPException If a problem occurs while initializing this 124 * password generator. 125 */ 126 public void initializePasswordGenerator( 127 final DirectoryServerContext serverContext, 128 final PasswordGeneratorConfig config, 129 final ArgumentParser parser) 130 throws LDAPException 131 { 132 // No initialization will be performed by default. 133 } 134 135 136 137 /** 138 * Performs any cleanup which may be necessary when this password generator is 139 * to be taken out of service. 140 */ 141 public void finalizePasswordGenerator() 142 { 143 // No implementation is required. 144 } 145 146 147 148 /** 149 * {@inheritDoc} 150 */ 151 public boolean isConfigurationAcceptable(final PasswordGeneratorConfig config, 152 final ArgumentParser parser, 153 final List<String> unacceptableReasons) 154 { 155 // No extended validation will be performed. 156 return true; 157 } 158 159 160 161 /** 162 * {@inheritDoc} 163 */ 164 public ResultCode applyConfiguration(final PasswordGeneratorConfig config, 165 final ArgumentParser parser, 166 final List<String> adminActionsRequired, 167 final List<String> messages) 168 { 169 // By default, no configuration changes will be applied. If there are any 170 // arguments, then add an admin action message indicating that the extension 171 // needs to be restarted for any changes to take effect. 172 if (! parser.getNamedArguments().isEmpty()) 173 { 174 adminActionsRequired.add( 175 "No configuration change has actually been applied. The new " + 176 "configuration will not take effect until this password " + 177 "generator is disabled and re-enabled or until the server is " + 178 "restarted."); 179 } 180 181 return ResultCode.SUCCESS; 182 } 183 184 185 186 /** 187 * Performs any processing which may be necessary to generate a user 188 * password. 189 * 190 * @param userEntry The entry of the user for whom to generate the password. 191 * 192 * @return The generated password. 193 * 194 * @throws LDAPException If a problem occurs while attempting to generate a 195 * password for the user. 196 */ 197 public abstract ByteString generatePassword(final Entry userEntry) 198 throws LDAPException; 199}