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