001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2013-2015 ForgeRock AS. 015 */ 016 017package org.forgerock.opendj.examples; 018 019import static org.forgerock.opendj.ldap.LDAPConnectionFactory.*; 020 021import org.forgerock.opendj.ldap.Connection; 022import org.forgerock.opendj.ldap.DN; 023import org.forgerock.opendj.ldap.LdapException; 024import org.forgerock.opendj.ldap.LDAPConnectionFactory; 025import org.forgerock.opendj.ldap.ModificationType; 026import org.forgerock.opendj.ldap.ResultCode; 027import org.forgerock.opendj.ldap.SSLContextBuilder; 028import org.forgerock.opendj.ldap.TrustManagers; 029import org.forgerock.opendj.ldap.requests.ModifyRequest; 030import org.forgerock.opendj.ldap.requests.Requests; 031import org.forgerock.util.Options; 032 033import javax.net.ssl.SSLContext; 034import java.nio.charset.Charset; 035import java.security.GeneralSecurityException; 036 037/** 038 * This command-line client demonstrates how to reset a user password in 039 * Microsoft Active Directory. 040 * <br> 041 * The client takes as arguments the host and port of the Active Directory 042 * server, a flag indicating whether this is a self-reset (user changing own 043 * password) or an administrative reset (administrator changing a password), 044 * the DN and password of the user performing the reset, and target user DN 045 * and new user password. 046 */ 047public final class PasswordResetForAD { 048 049 /** 050 * Reset a user password in Microsoft Active Directory. 051 * <br> 052 * The connection should be LDAPS, not LDAP, in order to perform the 053 * modification. 054 * 055 * @param args The command line arguments: host, port, "admin"|"self", 056 * DN, password, targetDN, newPassword 057 */ 058 public static void main(final String[] args) { 059 // --- JCite main --- 060 if (args.length != 7) { 061 System.err.println("Usage: host port \"admin\"|\"self\" DN " 062 + "password targetDN newPassword"); 063 System.err.println("For example: ad.example.com 636 admin " 064 + "cn=administrator,cn=Users,DC=ad,DC=example,DC=com " 065 + "Secret123 cn=testuser,cn=Users,DC=ad,DC=example,DC=com " 066 + "NewP4s5w0rd"); 067 System.exit(1); 068 } 069 final String host = args[0]; 070 final int port = Integer.parseInt(args[1]); 071 final String mode = args[2]; 072 final String bindDN = args[3]; 073 final String bindPassword = args[4]; 074 final String targetDN = args[5]; 075 final String newPassword = args[6]; 076 077 Connection connection = null; 078 try { 079 final LDAPConnectionFactory factory = 080 new LDAPConnectionFactory(host, port, getTrustAllOptions()); 081 connection = factory.getConnection(); 082 connection.bind(bindDN, bindPassword.toCharArray()); 083 084 ModifyRequest request = 085 Requests.newModifyRequest(DN.valueOf(targetDN)); 086 String passwordAttribute = "unicodePwd"; 087 088 if ("admin".equalsIgnoreCase(mode)) { 089 // Request modify, replacing the password with the new. 090 091 request.addModification( 092 ModificationType.REPLACE, 093 passwordAttribute, 094 encodePassword(newPassword) 095 ); 096 } else if ("self".equalsIgnoreCase(mode)) { 097 // Request modify, deleting the old password, adding the new. 098 099 // The default password policy for Active Directory domain 100 // controller systems sets minimum password age to 1 (day). 101 // If you get a constraint violation error when trying this 102 // example, set this minimum password age to 0 by executing 103 // cmd.exe as Administrator and entering the following 104 // command at the prompt: 105 // 106 // net accounts /MINPWAGE:0 107 108 request.addModification( 109 ModificationType.DELETE, 110 passwordAttribute, 111 encodePassword(bindPassword) 112 ); 113 request.addModification( 114 ModificationType.ADD, 115 passwordAttribute, 116 encodePassword(newPassword) 117 ); 118 } else { 119 System.err.println("Mode must be admin or self, not " + mode); 120 System.exit(1); 121 } 122 123 connection.modify(request); 124 125 System.out.println("Successfully changed password for " 126 + targetDN + " to " + newPassword + "."); 127 } catch (final LdapException e) { 128 System.err.println(e.getMessage()); 129 System.exit(e.getResult().getResultCode().intValue()); 130 } catch (final GeneralSecurityException e) { 131 System.err.println(e.getMessage()); 132 System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue()); 133 } finally { 134 if (connection != null) { 135 connection.close(); 136 } 137 } 138 // --- JCite main --- 139 } 140 141 // --- JCite encodePassword --- 142 /** 143 * Encode new password in UTF-16LE format for use with Active Directory. 144 * 145 * @param password String representation of the password 146 * @return Byte array containing encoded password 147 */ 148 public static byte[] encodePassword(final String password) { 149 return ("\"" + password + "\"").getBytes(Charset.forName("UTF-16LE")); 150 } 151 // --- JCite encodePassword --- 152 153 /** 154 * For SSL the connection factory needs SSL context options. This 155 * implementation simply trusts all server certificates. 156 */ 157 private static Options getTrustAllOptions() throws GeneralSecurityException { 158 Options options = Options.defaultOptions(); 159 SSLContext sslContext = new SSLContextBuilder() 160 .setTrustManager(TrustManagers.trustAll()).getSSLContext(); 161 options.set(SSL_CONTEXT, sslContext); 162 return options; 163 } 164 165 /** 166 * Constructor not used. 167 */ 168 private PasswordResetForAD() { 169 // Not used. 170 } 171}