All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.ldap.sdk.unboundidds.tools.GenerateTOTPSharedSecret Maven / Gradle / Ivy

Go to download

The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use Java API for communicating with LDAP directory servers and performing related tasks like reading and writing LDIF, encoding and decoding data using base64 and ASN.1 BER, and performing secure communication. This package contains the Standard Edition of the LDAP SDK, which is a complete, general-purpose library for communicating with LDAPv3 directory servers.

The newest version!
/*
 * Copyright 2016-2024 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2016-2024 Ping Identity Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * Copyright (C) 2016-2024 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.ldap.sdk.unboundidds.tools;



import java.io.OutputStream;
import java.util.LinkedHashMap;

import com.unboundid.ldap.sdk.ExtendedResult;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.Version;
import com.unboundid.ldap.sdk.unboundidds.extensions.
            GenerateTOTPSharedSecretExtendedRequest;
import com.unboundid.ldap.sdk.unboundidds.extensions.
            GenerateTOTPSharedSecretExtendedResult;
import com.unboundid.ldap.sdk.unboundidds.extensions.
            RevokeTOTPSharedSecretExtendedRequest;
import com.unboundid.util.Debug;
import com.unboundid.util.LDAPCommandLineTool;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.PasswordReader;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;
import com.unboundid.util.args.BooleanArgument;
import com.unboundid.util.args.FileArgument;
import com.unboundid.util.args.StringArgument;

import static com.unboundid.ldap.sdk.unboundidds.tools.ToolMessages.*;



/**
 * This class provides a tool that can be used to generate a TOTP shared secret
 * for a user.  That shared secret may be used to generate TOTP authentication
 * codes for the purpose of authenticating with the UNBOUNDID-TOTP SASL
 * mechanism, or as a form of step-up authentication for external applications
 * using the validate TOTP password extended operation.
 * 
*
* NOTE: This class, and other classes within the * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only * supported for use against Ping Identity, UnboundID, and * Nokia/Alcatel-Lucent 8661 server products. These classes provide support * for proprietary functionality or for external specifications that are not * considered stable or mature enough to be guaranteed to work in an * interoperable way with other types of LDAP servers. *
*/ @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) public final class GenerateTOTPSharedSecret extends LDAPCommandLineTool { // Indicates that the tool should interactively prompt for the static password // for the user for whom the TOTP secret is to be generated. @Nullable private BooleanArgument promptForUserPassword = null; // Indicates that the tool should revoke all existing TOTP shared secrets for // the user. @Nullable private BooleanArgument revokeAll = null; // The path to a file containing the static password for the user for whom the // TOTP secret is to be generated. @Nullable private FileArgument userPasswordFile = null; // The username for the user for whom the TOTP shared secret is to be // generated. @Nullable private StringArgument authenticationID = null; // The TOTP shared secret to revoke. @Nullable private StringArgument revoke = null; // The static password for the user for whom the TOTP shared sec ret is to be // generated. @Nullable private StringArgument userPassword = null; /** * Invokes the tool with the provided set of arguments. * * @param args The command-line arguments provided to this program. */ public static void main(@NotNull final String... args) { final ResultCode resultCode = main(System.out, System.err, args); if (resultCode != ResultCode.SUCCESS) { System.exit(resultCode.intValue()); } } /** * Invokes the tool with the provided set of arguments. * * @param out The output stream to use for standard out. It may be * {@code null} if standard out should be suppressed. * @param err The output stream to use for standard error. It may be * {@code null} if standard error should be suppressed. * @param args The command-line arguments provided to this program. * * @return A result code with the status of the tool processing. Any result * code other than {@link ResultCode#SUCCESS} should be considered a * failure. */ @NotNull() public static ResultCode main(@Nullable final OutputStream out, @Nullable final OutputStream err, @NotNull final String... args) { final GenerateTOTPSharedSecret tool = new GenerateTOTPSharedSecret(out, err); return tool.runTool(args); } /** * Creates a new instance of this tool with the provided arguments. * * @param out The output stream to use for standard out. It may be * {@code null} if standard out should be suppressed. * @param err The output stream to use for standard error. It may be * {@code null} if standard error should be suppressed. */ public GenerateTOTPSharedSecret(@Nullable final OutputStream out, @Nullable final OutputStream err) { super(out, err); } /** * {@inheritDoc} */ @Override() @NotNull() public String getToolName() { return "generate-totp-shared-secret"; } /** * {@inheritDoc} */ @Override() @NotNull() public String getToolDescription() { return INFO_GEN_TOTP_SECRET_TOOL_DESC.get(); } /** * {@inheritDoc} */ @Override() @NotNull() public String getToolVersion() { return Version.NUMERIC_VERSION_STRING; } /** * {@inheritDoc} */ @Override() public boolean supportsInteractiveMode() { return true; } /** * {@inheritDoc} */ @Override() public boolean defaultsToInteractiveMode() { return true; } /** * {@inheritDoc} */ @Override() public boolean supportsPropertiesFile() { return true; } /** * {@inheritDoc} */ @Override() protected boolean supportsOutputFile() { return true; } /** * {@inheritDoc} */ @Override() protected boolean supportsDebugLogging() { return true; } /** * {@inheritDoc} */ @Override() protected boolean supportsAuthentication() { return true; } /** * {@inheritDoc} */ @Override() protected boolean defaultToPromptForBindPassword() { return true; } /** * {@inheritDoc} */ @Override() protected boolean supportsSASLHelp() { return true; } /** * {@inheritDoc} */ @Override() protected boolean includeAlternateLongIdentifiers() { return true; } /** * {@inheritDoc} */ @Override() protected boolean supportsSSLDebugging() { return true; } /** * {@inheritDoc} */ @Override() protected boolean logToolInvocationByDefault() { return true; } /** * {@inheritDoc} */ @Override() public void addNonLDAPArguments(@NotNull final ArgumentParser parser) throws ArgumentException { // Create the authentication ID argument, which will identify the target // user. authenticationID = new StringArgument(null, "authID", true, 1, INFO_GEN_TOTP_SECRET_PLACEHOLDER_AUTH_ID.get(), INFO_GEN_TOTP_SECRET_DESCRIPTION_AUTH_ID.get()); authenticationID.addLongIdentifier("authenticationID", true); authenticationID.addLongIdentifier("auth-id", true); authenticationID.addLongIdentifier("authentication-id", true); parser.addArgument(authenticationID); // Create the arguments that may be used to obtain the static password for // the target user. userPassword = new StringArgument(null, "userPassword", false, 1, INFO_GEN_TOTP_SECRET_PLACEHOLDER_USER_PW.get(), INFO_GEN_TOTP_SECRET_DESCRIPTION_USER_PW.get( authenticationID.getIdentifierString())); userPassword.setSensitive(true); userPassword.addLongIdentifier("user-password", true); parser.addArgument(userPassword); userPasswordFile = new FileArgument(null, "userPasswordFile", false, 1, null, INFO_GEN_TOTP_SECRET_DESCRIPTION_USER_PW_FILE.get( authenticationID.getIdentifierString()), true, true, true, false); userPasswordFile.addLongIdentifier("user-password-file", true); parser.addArgument(userPasswordFile); promptForUserPassword = new BooleanArgument(null, "promptForUserPassword", INFO_GEN_TOTP_SECRET_DESCRIPTION_PROMPT_FOR_USER_PW.get( authenticationID.getIdentifierString())); promptForUserPassword.addLongIdentifier("prompt-for-user-password", true); parser.addArgument(promptForUserPassword); // Create the arguments that may be used to revoke shared secrets rather // than generate them. revoke = new StringArgument(null, "revoke", false, 1, INFO_GEN_TOTP_SECRET_PLACEHOLDER_SECRET.get(), INFO_GEN_TOTP_SECRET_DESCRIPTION_REVOKE.get()); parser.addArgument(revoke); revokeAll = new BooleanArgument(null, "revokeAll", 1, INFO_GEN_TOTP_SECRET_DESCRIPTION_REVOKE_ALL.get()); revokeAll.addLongIdentifier("revoke-all", true); parser.addArgument(revokeAll); // At most one of the userPassword, userPasswordFile, and // promptForUserPassword arguments must be present. parser.addExclusiveArgumentSet(userPassword, userPasswordFile, promptForUserPassword); // If any of the userPassword, userPasswordFile, or promptForUserPassword // arguments is present, then the authenticationID argument must also be // present. parser.addDependentArgumentSet(userPassword, authenticationID); parser.addDependentArgumentSet(userPasswordFile, authenticationID); parser.addDependentArgumentSet(promptForUserPassword, authenticationID); // At most one of the revoke and revokeAll arguments may be provided. parser.addExclusiveArgumentSet(revoke, revokeAll); } /** * {@inheritDoc} */ @Override() @NotNull() public ResultCode doToolProcessing() { // Establish a connection to the Directory Server. final LDAPConnection conn; try { conn = getConnection(); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, ERR_GEN_TOTP_SECRET_CANNOT_CONNECT.get( StaticUtils.getExceptionMessage(le))); return le.getResultCode(); } try { // Get the authentication ID and static password to include in the // request. final String authID = authenticationID.getValue(); final byte[] staticPassword; if (userPassword.isPresent()) { staticPassword = StaticUtils.getBytes(userPassword.getValue()); } else if (userPasswordFile.isPresent()) { try { final char[] pwChars = getPasswordFileReader().readPassword( userPasswordFile.getValue()); staticPassword = StaticUtils.getBytes(new String(pwChars)); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, ERR_GEN_TOTP_SECRET_CANNOT_READ_PW_FROM_FILE.get( userPasswordFile.getValue().getAbsolutePath(), StaticUtils.getExceptionMessage(e))); return ResultCode.LOCAL_ERROR; } } else if (promptForUserPassword.isPresent()) { try { getOut().print(INFO_GEN_TOTP_SECRET_ENTER_PW.get(authID)); staticPassword = PasswordReader.readPassword(); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, ERR_GEN_TOTP_SECRET_CANNOT_READ_PW_FROM_STDIN.get( StaticUtils.getExceptionMessage(e))); return ResultCode.LOCAL_ERROR; } } else { staticPassword = null; } // Create and send the appropriate request based on whether we should // generate or revoke a TOTP shared secret. ExtendedResult result; if (revoke.isPresent()) { final RevokeTOTPSharedSecretExtendedRequest request = new RevokeTOTPSharedSecretExtendedRequest(authID, staticPassword, revoke.getValue()); try { result = conn.processExtendedOperation(request); } catch (final LDAPException le) { Debug.debugException(le); result = new ExtendedResult(le); } if (result.getResultCode() == ResultCode.SUCCESS) { wrapOut(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, INFO_GEN_TOTP_SECRET_REVOKE_SUCCESS.get(revoke.getValue())); } else { wrapErr(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, ERR_GEN_TOTP_SECRET_REVOKE_FAILURE.get(revoke.getValue())); } } else if (revokeAll.isPresent()) { final RevokeTOTPSharedSecretExtendedRequest request = new RevokeTOTPSharedSecretExtendedRequest(authID, staticPassword, null); try { result = conn.processExtendedOperation(request); } catch (final LDAPException le) { Debug.debugException(le); result = new ExtendedResult(le); } if (result.getResultCode() == ResultCode.SUCCESS) { wrapOut(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, INFO_GEN_TOTP_SECRET_REVOKE_ALL_SUCCESS.get()); } else { wrapErr(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, ERR_GEN_TOTP_SECRET_REVOKE_ALL_FAILURE.get()); } } else { final GenerateTOTPSharedSecretExtendedRequest request = new GenerateTOTPSharedSecretExtendedRequest(authID, staticPassword); try { result = conn.processExtendedOperation(request); } catch (final LDAPException le) { Debug.debugException(le); result = new ExtendedResult(le); } if (result.getResultCode() == ResultCode.SUCCESS) { wrapOut(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, INFO_GEN_TOTP_SECRET_GEN_SUCCESS.get( ((GenerateTOTPSharedSecretExtendedResult) result). getTOTPSharedSecret())); } else { wrapErr(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, ERR_GEN_TOTP_SECRET_GEN_FAILURE.get()); } } // If the result is a failure result, then present any additional details // to the user. if (result.getResultCode() != ResultCode.SUCCESS) { wrapErr(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, ERR_GEN_TOTP_SECRET_RESULT_CODE.get( String.valueOf(result.getResultCode()))); final String diagnosticMessage = result.getDiagnosticMessage(); if (diagnosticMessage != null) { wrapErr(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, ERR_GEN_TOTP_SECRET_DIAGNOSTIC_MESSAGE.get(diagnosticMessage)); } final String matchedDN = result.getMatchedDN(); if (matchedDN != null) { wrapErr(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, ERR_GEN_TOTP_SECRET_MATCHED_DN.get(matchedDN)); } for (final String referralURL : result.getReferralURLs()) { wrapErr(0, StaticUtils.TERMINAL_WIDTH_COLUMNS, ERR_GEN_TOTP_SECRET_REFERRAL_URL.get(referralURL)); } } return result.getResultCode(); } finally { conn.close(); } } /** * {@inheritDoc} */ @Override() @NotNull() public LinkedHashMap getExampleUsages() { final LinkedHashMap examples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); examples.put( new String[] { "--hostname", "ds.example.com", "--port", "389", "--authID", "u:john.doe", "--promptForUserPassword", }, INFO_GEN_TOTP_SECRET_GEN_EXAMPLE.get()); examples.put( new String[] { "--hostname", "ds.example.com", "--port", "389", "--authID", "u:john.doe", "--userPasswordFile", "password.txt", "--revokeAll" }, INFO_GEN_TOTP_SECRET_REVOKE_ALL_EXAMPLE.get()); return examples; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy