001 /*
002 * Copyright 2015 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2015 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.unboundidds;
022
023
024
025 import java.io.OutputStream;
026 import java.io.Serializable;
027 import java.util.ArrayList;
028 import java.util.LinkedHashMap;
029 import java.util.List;
030
031 import com.unboundid.ldap.sdk.LDAPConnection;
032 import com.unboundid.ldap.sdk.LDAPException;
033 import com.unboundid.ldap.sdk.ResultCode;
034 import com.unboundid.ldap.sdk.Version;
035 import com.unboundid.ldap.sdk.unboundidds.extensions.
036 DeliverPasswordResetTokenExtendedRequest;
037 import com.unboundid.ldap.sdk.unboundidds.extensions.
038 DeliverPasswordResetTokenExtendedResult;
039 import com.unboundid.util.Debug;
040 import com.unboundid.util.LDAPCommandLineTool;
041 import com.unboundid.util.ObjectPair;
042 import com.unboundid.util.StaticUtils;
043 import com.unboundid.util.ThreadSafety;
044 import com.unboundid.util.ThreadSafetyLevel;
045 import com.unboundid.util.args.ArgumentException;
046 import com.unboundid.util.args.ArgumentParser;
047 import com.unboundid.util.args.DNArgument;
048 import com.unboundid.util.args.StringArgument;
049
050 import static com.unboundid.ldap.sdk.unboundidds.UnboundIDDSMessages.*;
051
052
053
054 /**
055 * <BLOCKQUOTE>
056 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
057 * LDAP SDK for Java. It is not available for use in applications that
058 * include only the Standard Edition of the LDAP SDK, and is not supported for
059 * use in conjunction with non-UnboundID products.
060 * </BLOCKQUOTE>
061 * This class provides a utility that may be used to request that the Directory
062 * Server deliver a single-use password reset token to a user through some
063 * out-of-band mechanism.
064 */
065 @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
066 public final class DeliverPasswordResetToken
067 extends LDAPCommandLineTool
068 implements Serializable
069 {
070 /**
071 * The serial version UID for this serializable class.
072 */
073 private static final long serialVersionUID = 5793619963770997266L;
074
075
076
077 // The DN of the user to whom the password reset token should be sent.
078 private DNArgument userDN;
079
080 // The text to include after the password reset token in the "compact"
081 // message.
082 private StringArgument compactTextAfterToken;
083
084 // The text to include before the password reset token in the "compact"
085 // message.
086 private StringArgument compactTextBeforeToken;
087
088 // The name of the mechanism through which the one-time password should be
089 // delivered.
090 private StringArgument deliveryMechanism;
091
092 // The text to include after the password reset token in the "full" message.
093 private StringArgument fullTextAfterToken;
094
095 // The text to include before the password reset token in the "full" message.
096 private StringArgument fullTextBeforeToken;
097
098 // The subject to use for the message containing the delivered token.
099 private StringArgument messageSubject;
100
101
102
103 /**
104 * Parse the provided command line arguments and perform the appropriate
105 * processing.
106 *
107 * @param args The command line arguments provided to this program.
108 */
109 public static void main(final String... args)
110 {
111 final ResultCode resultCode = main(args, System.out, System.err);
112 if (resultCode != ResultCode.SUCCESS)
113 {
114 System.exit(resultCode.intValue());
115 }
116 }
117
118
119
120 /**
121 * Parse the provided command line arguments and perform the appropriate
122 * processing.
123 *
124 * @param args The command line arguments provided to this program.
125 * @param outStream The output stream to which standard out should be
126 * written. It may be {@code null} if output should be
127 * suppressed.
128 * @param errStream The output stream to which standard error should be
129 * written. It may be {@code null} if error messages
130 * should be suppressed.
131 *
132 * @return A result code indicating whether the processing was successful.
133 */
134 public static ResultCode main(final String[] args,
135 final OutputStream outStream,
136 final OutputStream errStream)
137 {
138 final DeliverPasswordResetToken tool =
139 new DeliverPasswordResetToken(outStream, errStream);
140 return tool.runTool(args);
141 }
142
143
144
145 /**
146 * Creates a new instance of this tool.
147 *
148 * @param outStream The output stream to which standard out should be
149 * written. It may be {@code null} if output should be
150 * suppressed.
151 * @param errStream The output stream to which standard error should be
152 * written. It may be {@code null} if error messages
153 * should be suppressed.
154 */
155 public DeliverPasswordResetToken(final OutputStream outStream,
156 final OutputStream errStream)
157 {
158 super(outStream, errStream);
159
160 userDN = null;
161 compactTextAfterToken = null;
162 compactTextBeforeToken = null;
163 deliveryMechanism = null;
164 fullTextAfterToken = null;
165 fullTextBeforeToken = null;
166 messageSubject = null;
167 }
168
169
170
171 /**
172 * {@inheritDoc}
173 */
174 @Override()
175 public String getToolName()
176 {
177 return "deliver-password-reset-token";
178 }
179
180
181
182 /**
183 * {@inheritDoc}
184 */
185 @Override()
186 public String getToolDescription()
187 {
188 return INFO_DELIVER_PW_RESET_TOKEN_TOOL_DESCRIPTION.get();
189 }
190
191
192
193 /**
194 * {@inheritDoc}
195 */
196 @Override()
197 public String getToolVersion()
198 {
199 return Version.NUMERIC_VERSION_STRING;
200 }
201
202
203
204 /**
205 * {@inheritDoc}
206 */
207 @Override()
208 public void addNonLDAPArguments(final ArgumentParser parser)
209 throws ArgumentException
210 {
211 userDN = new DNArgument('b', "userDN", true, 1,
212 INFO_DELIVER_PW_RESET_TOKEN_PLACEHOLDER_DN.get(),
213 INFO_DELIVER_PW_RESET_TOKEN_DESCRIPTION_USER_DN.get());
214 parser.addArgument(userDN);
215
216 deliveryMechanism = new StringArgument('m', "deliveryMechanism", false, 0,
217 INFO_DELIVER_PW_RESET_TOKEN_PLACEHOLDER_NAME.get(),
218 INFO_DELIVER_PW_RESET_TOKEN_DESCRIPTION_MECH.get());
219 parser.addArgument(deliveryMechanism);
220
221 messageSubject = new StringArgument('s', "messageSubject", false, 1,
222 INFO_DELIVER_PW_RESET_TOKEN_PLACEHOLDER_SUBJECT.get(),
223 INFO_DELIVER_PW_RESET_TOKEN_DESCRIPTION_SUBJECT.get());
224 parser.addArgument(messageSubject);
225
226 fullTextBeforeToken = new StringArgument('f', "fullTextBeforeToken", false,
227 1, INFO_DELIVER_PW_RESET_TOKEN_PLACEHOLDER_FULL_BEFORE.get(),
228 INFO_DELIVER_PW_RESET_TOKEN_DESCRIPTION_FULL_BEFORE.get());
229 parser.addArgument(fullTextBeforeToken);
230
231 fullTextAfterToken = new StringArgument('F', "fullTextAfterToken", false,
232 1, INFO_DELIVER_PW_RESET_TOKEN_PLACEHOLDER_FULL_AFTER.get(),
233 INFO_DELIVER_PW_RESET_TOKEN_DESCRIPTION_FULL_AFTER.get());
234 parser.addArgument(fullTextAfterToken);
235
236 compactTextBeforeToken = new StringArgument('c', "compactTextBeforeToken",
237 false, 1, INFO_DELIVER_PW_RESET_TOKEN_PLACEHOLDER_COMPACT_BEFORE.get(),
238 INFO_DELIVER_PW_RESET_TOKEN_DESCRIPTION_COMPACT_BEFORE.get());
239 parser.addArgument(compactTextBeforeToken);
240
241 compactTextAfterToken = new StringArgument('C', "compactTextAfterToken",
242 false, 1, INFO_DELIVER_PW_RESET_TOKEN_PLACEHOLDER_COMPACT_AFTER.get(),
243 INFO_DELIVER_PW_RESET_TOKEN_DESCRIPTION_COMPACT_AFTER.get());
244 parser.addArgument(compactTextAfterToken);
245 }
246
247
248
249 /**
250 * {@inheritDoc}
251 */
252 @Override()
253 public ResultCode doToolProcessing()
254 {
255 // Get the set of preferred delivery mechanisms.
256 final ArrayList<ObjectPair<String,String>> preferredDeliveryMechanisms;
257 if (deliveryMechanism.isPresent())
258 {
259 final List<String> dmList = deliveryMechanism.getValues();
260 preferredDeliveryMechanisms =
261 new ArrayList<ObjectPair<String,String>>(dmList.size());
262 for (final String s : dmList)
263 {
264 preferredDeliveryMechanisms.add(new ObjectPair<String,String>(s, null));
265 }
266 }
267 else
268 {
269 preferredDeliveryMechanisms = null;
270 }
271
272
273 // Get a connection to the directory server.
274 final LDAPConnection conn;
275 try
276 {
277 conn = getConnection();
278 }
279 catch (final LDAPException le)
280 {
281 Debug.debugException(le);
282 err(ERR_DELIVER_PW_RESET_TOKEN_CANNOT_GET_CONNECTION.get(
283 StaticUtils.getExceptionMessage(le)));
284 return le.getResultCode();
285 }
286
287 try
288 {
289 // Create and send the extended request
290 final DeliverPasswordResetTokenExtendedRequest request =
291 new DeliverPasswordResetTokenExtendedRequest(userDN.getStringValue(),
292 messageSubject.getValue(), fullTextBeforeToken.getValue(),
293 fullTextAfterToken.getValue(),
294 compactTextBeforeToken.getValue(),
295 compactTextAfterToken.getValue(), preferredDeliveryMechanisms);
296 final DeliverPasswordResetTokenExtendedResult result;
297 try
298 {
299 result = (DeliverPasswordResetTokenExtendedResult)
300 conn.processExtendedOperation(request);
301 }
302 catch (final LDAPException le)
303 {
304 Debug.debugException(le);
305 err(ERR_DELIVER_PW_RESET_TOKEN_ERROR_PROCESSING_EXTOP.get(
306 StaticUtils.getExceptionMessage(le)));
307 return le.getResultCode();
308 }
309
310 if (result.getResultCode() == ResultCode.SUCCESS)
311 {
312 final String mechanism = result.getDeliveryMechanism();
313 final String id = result.getRecipientID();
314 if (id == null)
315 {
316 out(INFO_DELIVER_PW_RESET_TOKEN_SUCCESS_RESULT_WITHOUT_ID.get(
317 mechanism));
318 }
319 else
320 {
321 out(INFO_DELIVER_PW_RESET_TOKEN_SUCCESS_RESULT_WITH_ID.get(mechanism,
322 id));
323 }
324
325 final String message = result.getDeliveryMessage();
326 if (message != null)
327 {
328 out(INFO_DELIVER_PW_RESET_TOKEN_SUCCESS_MESSAGE.get(message));
329 }
330 }
331 else
332 {
333 if (result.getDiagnosticMessage() == null)
334 {
335 err(ERR_DELIVER_PW_RESET_TOKEN_ERROR_RESULT_NO_MESSAGE.get(
336 String.valueOf(result.getResultCode())));
337 }
338 else
339 {
340 err(ERR_DELIVER_PW_RESET_TOKEN_ERROR_RESULT.get(
341 String.valueOf(result.getResultCode()),
342 result.getDiagnosticMessage()));
343 }
344 }
345
346 return result.getResultCode();
347 }
348 finally
349 {
350 conn.close();
351 }
352 }
353
354
355
356 /**
357 * {@inheritDoc}
358 */
359 @Override()
360 public LinkedHashMap<String[],String> getExampleUsages()
361 {
362 final LinkedHashMap<String[],String> exampleMap =
363 new LinkedHashMap<String[],String>(1);
364
365 final String[] args =
366 {
367 "--hostname", "server.example.com",
368 "--port", "389",
369 "--bindDN", "uid=password.admin,ou=People,dc=example,dc=com",
370 "--bindPassword", "password",
371 "--userDN", "uid=test.user,ou=People,dc=example,dc=com",
372 "--deliveryMechanism", "SMS",
373 "--deliveryMechanism", "E-Mail",
374 "--messageSubject", "Your password reset token",
375 "--fullTextBeforeToken", "Your single-use password reset token is '",
376 "--fullTextAfterToken", "'.",
377 "--compactTextBeforeToken", "Your single-use password reset token is '",
378 "--compactTextAfterToken", "'.",
379 };
380 exampleMap.put(args,
381 INFO_DELIVER_PW_RESET_TOKEN_EXAMPLE.get());
382
383 return exampleMap;
384 }
385 }