1818package com .sun .enterprise .admin .servermgmt ;
1919
2020import com .sun .enterprise .admin .servermgmt .pe .PEFileLayout ;
21- import com .sun .enterprise .universal .glassfish .ASenvPropertyReader ;
22- import com .sun .enterprise .universal .io .SmartFile ;
23- import com .sun .enterprise .universal .process .ProcessManager ;
24- import com .sun .enterprise .universal .process .ProcessManagerException ;
25- import com .sun .enterprise .universal .process .ProcessUtils ;
2621import com .sun .enterprise .util .OS ;
2722import com .sun .enterprise .util .i18n .StringManager ;
2823import com .sun .enterprise .util .net .NetUtils ;
2924
3025import java .io .File ;
31- import java .io .FileInputStream ;
3226import java .io .IOException ;
27+ import java .lang .System .Logger ;
28+ import java .security .Key ;
3329import java .security .KeyStore ;
30+ import java .security .UnrecoverableKeyException ;
3431import java .util .ArrayList ;
3532import java .util .Arrays ;
36- import java .util .Enumeration ;
33+ import java .util .Collections ;
3734import java .util .List ;
3835import java .util .regex .Pattern ;
3936
4037import org .glassfish .main .jdke .security .KeyTool ;
4138
42- import static com .sun .enterprise .admin .servermgmt .SLogger .UNHANDLED_EXCEPTION ;
43- import static com .sun .enterprise .admin .servermgmt .SLogger .getLogger ;
4439import static com .sun .enterprise .admin .servermgmt .domain .DomainConstants .KEYSTORE_FILE ;
4540import static com .sun .enterprise .admin .servermgmt .domain .DomainConstants .TRUSTSTORE_FILE ;
46- import static java .util .logging .Level .SEVERE ;
47- import static org .glassfish .embeddable .GlassFishVariable .JAVA_ROOT ;
41+ import static java .lang .System .Logger .Level .WARNING ;
4842
4943/**
5044 * @author kebbs
5145 */
5246public class KeystoreManager {
5347
54- private static final String KEYTOOL_CMD ;
55- private static final String KEYTOOL_EXE_NAME = OS .isWindows () ? "keytool.exe" : "keytool" ;
48+ private static final Logger LOG = System .getLogger (KeystoreManager .class .getName ());
5649 private static final String CERTIFICATE_DN_PREFIX = "CN=" ;
5750 private static final String CERTIFICATE_DN_SUFFIX = ",OU=GlassFish,O=Eclipse Foundation" ;
5851 public static final String CERTIFICATE_ALIAS = "s1as" ;
5952 public static final String INSTANCE_SECURE_ADMIN_ALIAS = "glassfish-instance" ;
6053 public static final String DEFAULT_MASTER_PASSWORD = "changeit" ;
61- private static final String SKID_EXTENSION_SYSTEM_PROPERTY = "-J-Dsun.security.internal.keytool.skid" ;
6254 private static final String INSTANCE_CN_SUFFIX = "-instance" ;
6355
6456 private static final StringManager _strMgr = StringManager .getManager (KeystoreManager .class );
6557 private PEFileLayout fileLayout ;
6658
6759
68- static {
69- // Byron Nevins, July 2011
70- String nonFinalKeyTool = KEYTOOL_EXE_NAME ; // at the end we set the final
71- String javaroot = new ASenvPropertyReader ().getProps ().get (JAVA_ROOT .getPropertyName ());
72- File keyToolBin = new File (new File (javaroot , "bin" ), KEYTOOL_EXE_NAME );
73-
74- if (keyToolBin .canExecute ()) {
75- nonFinalKeyTool = SmartFile .sanitize (keyToolBin .getPath ());
76- } else {
77- // Can't find it in a JDK. Maybe it is in the PATH?
78- keyToolBin = ProcessUtils .getExe (KEYTOOL_EXE_NAME );
79-
80- if (keyToolBin != null && keyToolBin .canExecute ()) {
81- nonFinalKeyTool = keyToolBin .getPath ();
82- }
83- }
84-
85- KEYTOOL_CMD = nonFinalKeyTool ;
86- }
87-
88- private static class KeytoolExecutor {
89-
90- private ProcessManager process ;
91-
92- public KeytoolExecutor (String [] args , int timeoutInSeconds ) {
93- this .process = createProcessManager (args );
94- process .setTimeout (timeoutInSeconds * 1000 );
95- }
96-
97- public KeytoolExecutor (String [] args , int timeoutInSeconds , String [] inputLines ) {
98- this .process = createProcessManager (args );
99- process .setTimeout (timeoutInSeconds * 1000 );
100- process .setStdinLines (Arrays .asList (inputLines ));
101- }
102-
103- private static ProcessManager createProcessManager (String [] args ) {
104- final String [] command ;
105- if (args [0 ].equals (KEYTOOL_CMD )) {
106- command = Arrays .copyOf (args , args .length );
107- } else {
108- command = new String [args .length + 1 ];
109- command [0 ] = KEYTOOL_CMD ;
110- System .arraycopy (args , 0 , command , 1 , args .length );
111- }
112- return new ProcessManager (command );
113- }
114-
115- public void execute (String keystoreErrorMsg , File keystoreName ) throws RepositoryException {
116- try {
117- if (process .execute () != 0 ) {
118- throw new RepositoryException (_strMgr .getString (keystoreErrorMsg , keystoreName )
119- + process .getStderr () + " " + process .getStdout ());
120- }
121- } catch (ProcessManagerException ex ) {
122- throw new RepositoryException (
123- _strMgr .getString (keystoreErrorMsg , keystoreName ) + process .getStderr () + " " + process .getStdout (),
124- ex );
125- }
126- }
127- }
128-
129-
130-
131- /**
132- * Creates a new instance of RepositoryManager
133- */
134- public KeystoreManager () {
135- }
136-
13760 protected static String getCertificateDN (RepositoryConfig cfg , final String CNSuffix ) {
13861 String cn = getCNFromCfg (cfg );
13962 if (cn == null ) {
@@ -158,26 +81,27 @@ protected PEFileLayout getFileLayout(RepositoryConfig config) {
15881
15982 /**
16083 * Create the default SSL key store using keytool to generate a self signed certificate.
84+ * @param keyStore
16185 *
16286 * @param config
16387 * @param masterPassword
164- * @throws IOException
88+ * @throws DomainException
16589 */
166- protected void createKeyStore (File keystore , RepositoryConfig config , String masterPassword ) throws DomainException {
90+ protected void createKeyStore (File keyStore , RepositoryConfig config , String masterPassword ) throws DomainException {
16791 // Generate a new self signed certificate with s1as as the alias
16892 // Create the default self signed cert
16993 final String dasCertDN = getDASCertDN (config );
17094 System .out .println (_strMgr .getString ("CertificateDN" , dasCertDN ));
17195 try {
172- final KeyTool keyTool = new KeyTool (keystore , masterPassword .toCharArray ());
96+ final KeyTool keyTool = new KeyTool (keyStore , masterPassword .toCharArray ());
17397 keyTool .generateKeyPair (CERTIFICATE_ALIAS , dasCertDN , "RSA" , 3650 );
17498
17599 // Generate a new self signed certificate with glassfish-instance as the alias
176100 // Create the default self-signed cert for instances to use for SSL auth.
177101 final String instanceCertDN = getInstanceCertDN (config );
178102 keyTool .generateKeyPair (INSTANCE_SECURE_ADMIN_ALIAS , instanceCertDN , "RSA" , 3650 );
179103 } catch (IOException e ) {
180- throw new DomainException (_strMgr .getString ("SomeProblemWithKeytool" , e . getMessage () ), e );
104+ throw new DomainException (_strMgr .getString ("SomeProblemWithKeytool" , keyStore ), e );
181105 }
182106 }
183107
@@ -191,7 +115,7 @@ protected void copyCertificatesToTrustStore(File configRoot, DomainConfig config
191115 keyTool .copyCertificate (CERTIFICATE_ALIAS , trustStore );
192116 keyTool .copyCertificate (INSTANCE_SECURE_ADMIN_ALIAS , trustStore );
193117 } catch (IOException e ) {
194- throw new DomainException (_strMgr .getString ("SomeProblemWithKeytool" , e . getMessage () ), e );
118+ throw new DomainException (_strMgr .getString ("SomeProblemWithKeytool" , keyStore ), e );
195119 }
196120 }
197121
@@ -200,18 +124,18 @@ protected void copyCertificatesToTrustStore(File configRoot, DomainConfig config
200124 *
201125 * @param oldPassword the old keystore password
202126 * @param newPassword the new keystore password
203- * @param keystore the keystore whose password is to be changed.
204- * @throws RepositoryException
127+ * @param keyStore the keystore whose password is to be changed.
128+ * @throws DomainException
205129 */
206- protected void changeKeystorePassword (String oldPassword , String newPassword , File keystore ) throws RepositoryException {
207- if (! oldPassword .equals (newPassword )) {
208- // Change truststore password from the default
209- String [] keytoolCmd = {
210- "-storepasswd" ,
211- "-keystore" , keystore . getAbsolutePath (), } ;
212-
213- KeytoolExecutor keytoolExecutor = new KeytoolExecutor ( keytoolCmd , 30 , new String [] { oldPassword , newPassword , newPassword });
214- keytoolExecutor . execute ("keyStorePasswordNotChanged" , keystore );
130+ protected void changeKeystorePassword (String oldPassword , String newPassword , File keyStore ) throws DomainException {
131+ if (oldPassword .equals (newPassword )) {
132+ return ;
133+ }
134+ try {
135+ final KeyTool keyTool = new KeyTool ( keyStore , oldPassword . toCharArray ()) ;
136+ keyTool . changeKeyStorePassword ( newPassword . toCharArray ());
137+ } catch ( IOException e ) {
138+ throw new DomainException ( _strMgr . getString ("keyStorePasswordNotChanged" , keyStore ), e );
215139 }
216140 }
217141
@@ -226,65 +150,39 @@ protected void changeKeystorePassword(String oldPassword, String newPassword, Fi
226150 * @param storePassword the keystore password
227151 * @param oldKeyPassword the old password for the s1as alias
228152 * @param newKeyPassword the new password for the s1as alias
229- * @throws RepositoryException
153+ * @throws DomainException
230154 */
231- protected void changeS1ASAliasPassword (RepositoryConfig config , String storePassword , String oldKeyPassword , String newKeyPassword ) throws RepositoryException {
232- if (!storePassword .equals (oldKeyPassword ) && !oldKeyPassword .equals (newKeyPassword )) {
233- final PEFileLayout layout = getFileLayout (config );
234- final File keystore = layout .getKeyStore ();
235-
236- // First see if the alias exists. The user could have deleted it. Any failure in the
237- // command indicates that the alias does not exist, so we return without error.
238- String keyStoreType = System .getProperty ("javax.net.ssl.keyStoreType" );
239- if (keyStoreType == null ) {
240- keyStoreType = KeyStore .getDefaultType ();
241- }
242-
243- // Add code to change all the aliases that exist rather then change s1as only
244- List <String > aliases = new ArrayList <>();
245- FileInputStream is = null ;
246- try {
247- KeyStore keyStore = KeyStore .getInstance (keyStoreType );
248- is = new FileInputStream (keystore );
249- keyStore .load (is , storePassword .toCharArray ());
250- Enumeration <String > all = keyStore .aliases ();
251- while (all .hasMoreElements ()) {
252- aliases .add (all .nextElement ());
155+ protected void changeKeyPasswords (RepositoryConfig config , String storePassword , String oldKeyPassword ,
156+ String newKeyPassword ) throws DomainException {
157+ if (storePassword .equals (oldKeyPassword ) || oldKeyPassword .equals (newKeyPassword )) {
158+ return ;
159+ }
160+ final PEFileLayout layout = getFileLayout (config );
161+ final File keystore = layout .getKeyStore ();
162+ try {
163+ KeyStore keyStore = KeyStore .getInstance (keystore , storePassword .toCharArray ());
164+ List <String > aliases = Collections .list (keyStore .aliases ());
165+ List <String > keyAliases = new ArrayList <>();
166+ for (String alias : aliases ) {
167+ Key key ;
168+ try {
169+ key = keyStore .getKey (alias , oldKeyPassword .toCharArray ());
170+ } catch (UnrecoverableKeyException e ) {
171+ LOG .log (WARNING ,
172+ "Key entry with alias {0} in a key store {1} could not be recovered with provided key password." ,
173+ alias , keystore );
174+ continue ;
253175 }
254- } catch (Exception e ) {
255- aliases .add (CERTIFICATE_ALIAS );
256- } finally {
257- if (is != null ) {
258- try {
259- is .close ();
260- } catch (IOException ex ) {
261- getLogger ().log (SEVERE , UNHANDLED_EXCEPTION , ex );
262- }
176+ if (key != null ) {
177+ keyAliases .add (alias );
263178 }
264179 }
265-
266- String [] keytoolCmd = {
267- "-list" ,
268- "-keystore" , keystore .getAbsolutePath (),
269- "-alias" , CERTIFICATE_ALIAS , };
270-
271- KeytoolExecutor keytoolExecutor = new KeytoolExecutor (keytoolCmd , 30 , new String [] { storePassword });
272- try {
273- keytoolExecutor .execute ("s1asKeyPasswordNotChanged" , keystore );
274- } catch (RepositoryException ex ) {
275- return ;
276- }
277-
278- // Change truststore password from the default
279- for (String alias : aliases ) {
280- keytoolCmd = new String [] {
281- "-keypasswd" ,
282- "-keystore" , keystore .getAbsolutePath (),
283- "-alias" , alias , };
284-
285- keytoolExecutor = new KeytoolExecutor (keytoolCmd , 30 , new String [] { storePassword , oldKeyPassword , newKeyPassword , newKeyPassword });
286- keytoolExecutor .execute ("s1asKeyPasswordNotChanged" , keystore );
180+ KeyTool keyTool = new KeyTool (keystore , storePassword .toCharArray ());
181+ for (String alias : keyAliases ) {
182+ keyTool .changeKeyPassword (alias , oldKeyPassword .toCharArray (), newKeyPassword .toCharArray ());
287183 }
184+ } catch (Exception e ) {
185+ throw new DomainException (_strMgr .getString ("s1asKeyPasswordNotChanged" , keystore ), e );
288186 }
289187 }
290188
@@ -294,34 +192,18 @@ protected void changeS1ASAliasPassword(RepositoryConfig config, String storePass
294192 * own key/truststore
295193 *
296194 * @param config
297- * @param storePassword
298- * @param oldKeyPassword
299- * @param newKeyPassword
195+ * @param oldPassword
196+ * @param newPassword
300197 */
301- protected void changeSSLCertificateDatabasePassword (RepositoryConfig config , String oldPassword , String newPassword ) throws RepositoryException {
198+ protected void changeSSLCertificateDatabasePassword (RepositoryConfig config , String oldPassword , String newPassword ) throws DomainException {
302199 final PEFileLayout layout = getFileLayout (config );
303200 File keystore = layout .getKeyStore ();
304201 File truststore = layout .getTrustStore ();
305202
306203 if (keystore .exists ()) {
307204 // Change the password on the keystore
308205 changeKeystorePassword (oldPassword , newPassword , keystore );
309-
310- // Change the s1as alias password in the keystore...
311- //
312- // The assumption here is that the keystore password is not the same as the key password.
313- // This is due to the fact that the keystore password should first be changed followed next
314- // by the key password. The end result is that the keystore and s1as key both have
315- // the same passwords. This function will tolerate deletion of the s1as alias, but
316- // it will not tolerate changing the s1as key from something other than the
317- // database password.
318- try {
319- changeS1ASAliasPassword (config , newPassword , oldPassword , newPassword );
320- } catch (Exception ex ) {
321- // For now we eat all exceptions and dump to the log if the password
322- // alias could not be changed.
323- getLogger ().log (SEVERE , UNHANDLED_EXCEPTION , ex );
324- }
206+ changeKeyPasswords (config , newPassword , oldPassword , newPassword );
325207 }
326208
327209 if (truststore .exists ()) {
@@ -372,6 +254,10 @@ private static String getCNFromCfg(RepositoryConfig cfg) {
372254 return value ;
373255 }
374256
257+ private static String getCNFromOption (String option ) {
258+ return getValueFromOptionForName (option , "CN" , true );
259+ }
260+
375261 /**
376262 * Returns CN if valid and non-blank. Returns null otherwise.
377263 *
@@ -397,8 +283,4 @@ private static String getValueFromOptionForName(String option, String name, bool
397283
398284 return null ;
399285 }
400-
401- private static String getCNFromOption (String option ) {
402- return getValueFromOptionForName (option , "CN" , true );
403- }
404286}
0 commit comments