alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (PasswordAdapter.java)

This example Glassfish source code file (PasswordAdapter.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

certificateexception, crypto, file, io, ioexception, keystore, keystore, keystoreexception, keystoreexception, nosuchalgorithmexception, nosuchalgorithmexception, passwordadapter, runtimeexception, security, string, string, unrecoverablekeyexception, util

The Glassfish PasswordAdapter.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.enterprise.security.store;

import com.sun.enterprise.util.SystemPropertyConstants;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import java.util.Enumeration;

/**
 * This class implements an adapter for password manipulation a JCEKS.
 ** Note that although it uses locks ('synchronized'), it tends to be created
 ** anew with each use, an inefficient and potentially problematic use that
 ** could create more than one instance accessing the same keystore at a time.
 */
public final class PasswordAdapter {
    public static final String PASSWORD_ALIAS_KEYSTORE = "domain-passwords";

    private KeyStore    _pwdStore;
    private final File  _keyFile;            
    private char[]      _masterPassword;

    private char[] getMasterPassword() {
        return _masterPassword;
    }
    
    private void setMasterPassword(char[] smp) {
        _masterPassword = smp;
    }
    
/*
    private static final boolean DEBUG = true;
    private void //debug( final Object o )
    {
        if ( DEBUG )
        {
            System.out.println( "PasswordAdapter.debug: " + o );
        }
    }
        private void
    debugState( final String when)
    {
        if ( DEBUG )
        {
            final String INDENT = "    ";
            try
            {
                String s = "PasswordAdapter Status: " + when + "\n";
                s = s +INDENT + "Master password: " + new String( getMasterPassword() ) +"\n";
                s = s + INDENT + "Key file: " + _keyFile + "\n";
                s = s +INDENT + "Aliases:\n";
                final Enumeration<String>   aliases = getAliases();
                while ( aliases.hasMoreElements() )
                {
                    final String alias  = aliases.nextElement();
                    s = s +INDENT + INDENT + alias + "=" +
                            new String( getPasswordForAlias(alias) ) + "\n";
                }
                //debug(s);
            }
            catch( Throwable t )
            {
                t.printStackTrace();
            }
        }
    }
*/
    
        private static String
    getDefaultKeyFileName()
    {
        return System.getProperty(SystemPropertyConstants.INSTANCE_ROOT_PROPERTY) +
            File.separator + "config" + File.separator + PASSWORD_ALIAS_KEYSTORE;
    }
    
    /**
     * Construct a PasswordAdapter with given Shared Master Password,
     * SMP using the default keyfile (domain-passwords.jceks)
     * @param smp master password
     * @throws CertificateException
     * @throws IOException
     * @throws KeyStoreException
     * @throws NoSuchAlgorithmException
     */    
    public PasswordAdapter(char[] masterPassword)
            throws CertificateException, IOException,
            KeyStoreException, NoSuchAlgorithmException 
    {
       this( getDefaultKeyFileName(), masterPassword );
    }
    
    /**
     * Construct a PasswordAdapter with given Shared Master Password,
     * SMP.
     * @param keyfileName the jceks key file name
     * @param smp master password
     * @throws CertificateException
     * @throws IOException
     * @throws KeyStoreException
     * @throws NoSuchAlgorithmException
     */    
    public PasswordAdapter(
        final String keyStoreFileName,
        final char[] masterPassword)
            throws CertificateException, IOException,
            KeyStoreException, NoSuchAlgorithmException 
    {
        final File  keyStoreFile    = new File( keyStoreFileName );
        
        _pwdStore   = loadKeyStore( keyStoreFile, masterPassword);
        
        // assign these only once the store is good; no need to keep copies otherwise!
        _keyFile            = keyStoreFile;
        _masterPassword     = masterPassword;
        
        //debugState( "PasswordAdapter constructor" );
    }
    
    /**
     * Construct a PasswordAdapter with given Shared Master Password,
     * SMP.
     * @param keyfileName the jceks key file name
     * @param smp the master password
     * @exception CertificateException
     * @exception IOException
     * @exception KeyStoreException
     * @exception NoSuchAlgorithmException
     */
       private static KeyStore
    loadKeyStore( final File keyStoreFile, final char[] masterPassword )
            throws CertificateException, IOException,
            KeyStoreException, NoSuchAlgorithmException 
    {     
        final KeyStore  keyStore = KeyStore.getInstance("JCEKS");

        if ( keyStoreFile.exists() )
        {
            // don't buffer keystore; it's tiny anyway
            final FileInputStream   input   = new FileInputStream( keyStoreFile );
            try {
                keyStore.load( input, masterPassword );
            }
            finally {
                input.close();
            }
        }
        else
        {
            keyStore.load( null, masterPassword );
        }

        return keyStore;       
    }
    
    /**
     * This methods returns password String for a given alias and SMP.
     * @param alias     
     * @return corresponding password or null if the alias does not exist.
     * @exception KeyStoreException
     * @exception NoSuchAlgorithmException
     * @exception UnrecoverableKeyException
     */
    public synchronized String getPasswordForAlias(final String alias)
            throws KeyStoreException, NoSuchAlgorithmException,
            UnrecoverableKeyException
    {
        String passwordString = null;
        
        final Key key = _pwdStore.getKey( alias, getMasterPassword() );
        if ( key != null )
        {
            passwordString  = new String( key.getEncoded() );
        }
        
        return passwordString;
    }

    /**
     * This methods returns password SecretKey for a given alias and SMP.
     * @param alias     
     * @return corresponding password SecretKey or
     *         null if the alias does not exist.
     * @exception KeyStoreException
     * @exception NoSuchAlgorithmException
     * @exception UnrecoverableKeyException
     */
    public synchronized SecretKey getPasswordSecretKeyForAlias(String alias)
            throws KeyStoreException, NoSuchAlgorithmException,
            UnrecoverableKeyException {

        return (SecretKey)_pwdStore.getKey(alias, getMasterPassword()); 
    }

    /**
     * See if the given alias exists
     * @param alias the alias name 
     * @return true if the alias exists in the keystore
     */    
    public synchronized boolean aliasExists( final String alias) throws KeyStoreException
    {
        return _pwdStore.containsAlias(alias);
    }
    
    /**
     * Remove an alias from the keystore
     * @param alias The name of the alias to remove
     * @throws KeyStoreException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws CertificateException
     */    
    public synchronized void removeAlias( final String alias)
        throws KeyStoreException, IOException,
            NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException
    {
        _pwdStore.deleteEntry(alias);
        writeStore();
    }    
    
    /**
     * Return the aliases from the keystore.
     * @return An enumeration containing all the aliases in the keystore.
     */    
    public synchronized Enumeration<String> getAliases()
        throws KeyStoreException
    {        
        return _pwdStore.aliases();
    }

    /**
     * Writes the keystore to disk
     * @throws KeyStoreException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws CertificateException
     */    
    public void writeStore() throws KeyStoreException, IOException, 
        NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException
    {
        writeKeyStoreSafe( getMasterPassword() );
    }
    
    /**
     * This methods set alias, secretKey into JCEKS keystore.
     * @param alias
     * @param secretKey     
     * @exception CertificateException
     * @exception IOException
     * @exception KeyStoreException
     * @exception NoSuchAlgorithmException
     */
    public synchronized void setPasswordForAlias(
        final String alias, 
        final byte[] keyBytes)
        throws CertificateException, IOException, KeyStoreException, 
            NoSuchAlgorithmException, UnrecoverableKeyException
    {
        //debugState( "BEFORE setPasswordForAlias" );
        final Key key = new SecretKeySpec(keyBytes, "AES");
        _pwdStore.setKeyEntry( alias, key, getMasterPassword(), null);
        writeStore();
        //debugState( "AFTER setPasswordForAlias" );
    }

    
    /**
        Make a new in-memory KeyStore with all the keys secured with
        the new master password.
      */
        private KeyStore
    duplicateKeyStore( final char[] newMasterPassword)
        throws KeyStoreException, IOException, NoSuchAlgorithmException,
            CertificateException, UnrecoverableKeyException
    {
        final char[]    oldMasterPassword       = getMasterPassword();

        final KeyStore oldStore = _pwdStore;
        final KeyStore newKeyStore = KeyStore.getInstance("JCEKS", _pwdStore.getProvider() );
        newKeyStore.load( null, newMasterPassword );

        final Enumeration<String>   aliasesEnum = oldStore.aliases();
        while ( aliasesEnum.hasMoreElements() )
        {
            final String alias  = aliasesEnum.nextElement();

            if ( ! oldStore.isKeyEntry( alias ) )
            {
                throw new IllegalArgumentException( "Expecting keys only" );
            }

            final Key key      = oldStore.getKey( alias, oldMasterPassword );
            newKeyStore.setKeyEntry( alias, key, newMasterPassword, null);
        }

        return newKeyStore;
    }

    /**
        Write the KeyStore to disk.  Calling code should protect against
        overwriting any original file.
        @param keyStore
        @param file
        @param masterPassword
     */
        private static void
    writeKeyStoreToFile(
        final KeyStore  keyStore,
        final File      file,
        final char[]    masterPassword )
           throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
    {
        final FileOutputStream  out = new FileOutputStream(file);
        try
        {
            keyStore.store( out, masterPassword);
        }
        finally
        {
            out.close();
        }
    }


    /**
        Writes the current KeyStore to disk in a manner that preserves its
        on-disk representation from being destroyed if something goes wrong;
        a temporary file is used.
     */
        private synchronized void
    writeKeyStoreSafe( final char[] masterPassword)
        throws KeyStoreException, IOException, NoSuchAlgorithmException,
            CertificateException, UnrecoverableKeyException
     {     
        final boolean keystoreExists = _keyFile.exists();
        
        // if the KeyStore exists, update it in a manner that doesn't destroy
        // the existing store if a failure occurs.
        if ( keystoreExists )
        {
            final KeyStore oldStore = _pwdStore;
            final KeyStore newKeyStore = duplicateKeyStore( masterPassword );   
            
            // 'newKeyStore' is now complete; rename the old KeyStore, the write the new one in its place
            final File  saveOld = new File( _keyFile.toString() + ".save" );

            if ( ! _keyFile.renameTo( saveOld ) )
            {
                final String msg    = "Can't rename " + _keyFile + " to " + saveOld;
                throw new IOException( msg );
            }

            try
            {
                //debug( "Writing KeyStore to " + _keyFile + " using master password = " + new String(masterPassword) );
                writeKeyStoreToFile( newKeyStore, _keyFile, masterPassword );
                _pwdStore   = newKeyStore;
                _masterPassword = masterPassword;
                //debug( "KeyStore written successfully" );
            }
            catch( final Throwable t )
            {
                try
                {
                    saveOld.renameTo( _keyFile );
                }
                catch( final Throwable tt )
                {
                    /* best effort failed */
                    throw new RuntimeException( "Could not write new KeyStore, and " +
                        "cannot restore KeyStore to original state", tt );
                }
                
                throw new RuntimeException( "Can't write new KeyStore", t );
            }

            try
            {
                //debug( "deleting old keystore " + saveOld );
                saveOld.delete();
               // //debug( "done deleting old keystore "  saveOld );
            }
            catch( Throwable t )
            {
                throw new RuntimeException( "Can't remove old KeyStore \"" +  _keyFile  + "\"", t );
            }
        }
        else 
        {
            //debug( "Writing new KeyStore to " + _keyFile + " using master password = " + new String(masterPassword) );
            writeKeyStoreToFile( _pwdStore, _keyFile, masterPassword );
        }

        //debugState( "AFTER changing master password" );

        loadKeyStore( _keyFile, getMasterPassword() );

        //debugState( "AFTER forcing reload from file" );
     }


    /**
        Changes the keystore password, including the encoding of the keys within it.
        <p>
        There are several error conditions that could occur:
        <ul>
            <li>Problem extracting existing alias keys with new ones.
            <li>Problem writing the keystore, including destroying it if an I/O problem occurs.
            <li>
        </ul>
        For these reasons,  make a new KeyStore and write it, then swap it with the old
        one.
        
      * @param newpassword the new keystore password
      * @throws KeyStoreException
      * @throws IOException
      * @throws NoSuchAlgorithmException
      * @throws CertificateException
      */    
    public synchronized void changePassword(char[] newMasterPassword)
        throws KeyStoreException, IOException, NoSuchAlgorithmException,
            CertificateException, UnrecoverableKeyException
     {
        final char[]    oldMasterPassword       = getMasterPassword();
        //debug( "Changing master password from " + new String(oldMasterPassword) + " to "  + new String(newMasterPassword) );
        //debugState( "BEFORE changing master password" );

        writeKeyStoreSafe(newMasterPassword);
        
        //debugState( "AFTER changing master password" );
     }
 }


Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish PasswordAdapter.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.