diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/share/classes/sun/security/provider/IdentityDatabase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/security/provider/IdentityDatabase.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,427 @@ +/* + * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.security.provider; + +import java.io.*; +import java.util.*; +import java.security.*; + +/** + * An implementation of IdentityScope as a persistent identity + * database. + * + * @see Identity + * @see Key + * + * @author Benjamin Renaud + */ +public +class IdentityDatabase extends IdentityScope implements Serializable { + + /** use serialVersionUID from JDK 1.1. for interoperability */ + private static final long serialVersionUID = 4923799573357658384L; + + /* Are we debugging? */ + private static final boolean debug = false; + + /* Are we printing out error messages? */ + private static final boolean error = true; + + /* The source file, if any, for this database.*/ + File sourceFile; + + /* The private representation of the database.*/ + Hashtable identities; + + IdentityDatabase() throws InvalidParameterException { + this("restoring..."); + } + + /** + * Construct a new, empty database with a specified source file. + * + * @param file the source file. + */ + public IdentityDatabase(File file) throws InvalidParameterException { + this(file.getName()); + sourceFile = file; + } + + /** + * Construct a new, empty database. + */ + public IdentityDatabase(String name) throws InvalidParameterException { + super(name); + identities = new Hashtable(); + } + + /** + * Initialize an identity database from a stream. The stream should + * contain data to initialized a serialized IdentityDatabase + * object. + * + * @param is the input stream from which to restore the database. + * + * @exception IOException if a stream IO exception occurs + */ + public static IdentityDatabase fromStream(InputStream is) + throws IOException { + IdentityDatabase db = null; + try { + ObjectInputStream ois = new ObjectInputStream(is); + db = (IdentityDatabase)ois.readObject(); + } catch (ClassNotFoundException e) { + // this can't happen. + debug("This should not be happening.", e); + error( + "The version of the database is obsolete. Cannot initialize."); + + } catch (InvalidClassException e) { + // this may happen in developers workspaces happen. + debug("This should not be happening.", e); + error("Unable to initialize system identity scope: " + + " InvalidClassException. \nThis is most likely due to " + + "a serialization versioning problem: a class used in " + + "key management was obsoleted"); + + } catch (StreamCorruptedException e) { + debug("The serialization stream is corrupted. Unable to load.", e); + error("Unable to initialize system identity scope." + + " StreamCorruptedException."); + } + + if (db == null) { + db = new IdentityDatabase("uninitialized"); + } + + return db; + } + + /** + * Initialize an IdentityDatabase from file. + * + * @param f the filename where the identity database is stored. + * + * @exception IOException a file-related exception occurs (e.g. + * the directory of the file passed does not exists, etc. + * + * @IOException if a file IO exception occurs. + */ + public static IdentityDatabase fromFile(File f) throws IOException { + FileInputStream fis = new FileInputStream(f); + IdentityDatabase edb = fromStream(fis); + edb.sourceFile = f; + return edb; + } + + + + /** + * @return the number of identities in the database. + */ + public int size() { + return identities.size(); + } + + + /** + * @param name the name of the identity to be retrieved. + * + * @return the identity named name, or null if there are + * no identities named name in the database. + */ + public Identity getIdentity(String name) { + Identity id = identities.get(name); + if (id instanceof Signer) { + localCheck("get.signer"); + } + return id; + } + + /** + * Get an identity by key. + * + * @param name the key of the identity to be retrieved. + * + * @return the identity with a given key, or null if there are no + * identities with that key in the database. + */ + public Identity getIdentity(PublicKey key) { + if (key == null) { + return null; + } + Enumeration e = identities(); + while (e.hasMoreElements()) { + Identity i = e.nextElement(); + PublicKey k = i.getPublicKey(); + if (k != null && keyEqual(k, key)) { + if (i instanceof Signer) { + localCheck("get.signer"); + } + return i; + } + } + return null; + } + + private boolean keyEqual(Key key1, Key key2) { + if (key1 == key2) { + return true; + } else { + return MessageDigest.isEqual(key1.getEncoded(), key2.getEncoded()); + } + } + + /** + * Adds an identity to the database. + * + * @param identity the identity to be added. + * + * @exception KeyManagementException if a name or key clash + * occurs, or if another exception occurs. + */ + public void addIdentity(Identity identity) + throws KeyManagementException { + localCheck("add.identity"); + Identity byName = getIdentity(identity.getName()); + Identity byKey = getIdentity(identity.getPublicKey()); + String msg = null; + + if (byName != null) { + msg = "name conflict"; + } + if (byKey != null) { + msg = "key conflict"; + } + if (msg != null) { + throw new KeyManagementException(msg); + } + identities.put(identity.getName(), identity); + } + + /** + * Removes an identity to the database. + */ + public void removeIdentity(Identity identity) + throws KeyManagementException { + localCheck("remove.identity"); + String name = identity.getName(); + if (identities.get(name) == null) { + throw new KeyManagementException("there is no identity named " + + name + " in " + this); + } + identities.remove(name); + } + + /** + * @return an enumeration of all identities in the database. + */ + public Enumeration identities() { + return identities.elements(); + } + + /** + * Set the source file for this database. + */ + void setSourceFile(File f) { + sourceFile = f; + } + + /** + * @return the source file for this database. + */ + File getSourceFile() { + return sourceFile; + } + + /** + * Save the database in its current state to an output stream. + * + * @param os the output stream to which the database should be serialized. + * + * @exception IOException if an IO exception is raised by stream + * operations. + */ + public void save(OutputStream os) throws IOException { + try { + ObjectOutputStream oos = new ObjectOutputStream(os); + oos.writeObject(this); + oos.flush(); + } catch (InvalidClassException e) { + debug("This should not be happening.", e); + return; + } + } + + /** + * Save the database to a file. + * + * @exception IOException if an IO exception is raised by stream + * operations. + */ + void save(File f) throws IOException { + setSourceFile(f); + FileOutputStream fos = new FileOutputStream(f); + save(fos); + } + + /** + * Saves the database to the default source file. + * + * @exception KeyManagementException when there is no default source + * file specified for this database. + */ + public void save() throws IOException { + if (sourceFile == null) { + throw new IOException("this database has no source file"); + } + save(sourceFile); + } + + /** + * This method returns the file from which to initialize the + * system database. + */ + private static File systemDatabaseFile() { + + // First figure out where the identity database is hiding, if anywhere. + String dbPath = Security.getProperty("identity.database"); + // if nowhere, it's the canonical place. + if (dbPath == null) { + dbPath = System.getProperty("user.home") + File.separatorChar + + "identitydb.obj"; + } + return new File(dbPath); + } + + + /* This block initializes the system database, if there is one. */ + static { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + initializeSystem(); + return null; + } + }); + } + + /** + * This method initializes the system's identity database. The + * canonical location is + * /identitydatabase.obj. This is settable through + * the identity.database property. */ + private static void initializeSystem() { + + IdentityDatabase systemDatabase; + File dbFile = systemDatabaseFile(); + + // Second figure out if it's there, and if it isn't, create one. + try { + if (dbFile.exists()) { + debug("loading system database from file: " + dbFile); + systemDatabase = fromFile(dbFile); + } else { + systemDatabase = new IdentityDatabase(dbFile); + } + IdentityScope.setSystemScope(systemDatabase); + debug("System database initialized: " + systemDatabase); + } catch (IOException e) { + debug("Error initializing identity database: " + dbFile, e); + return; + } catch (InvalidParameterException e) { + debug("Error trying to instantiate a system identities db in " + + dbFile, e); + return; + } + } + + /* + private static File securityPropFile(String filename) { + // maybe check for a system property which will specify where to + // look. + String sep = File.separator; + return new File(System.getProperty("java.home") + + sep + "lib" + sep + "security" + + sep + filename); + } + */ + + public String toString() { + return "sun.security.provider.IdentityDatabase, source file: " + + sourceFile; + } + + + private static void debug(String s) { + if (debug) { + System.err.println(s); + } + } + + private static void debug(String s, Throwable t) { + if (debug) { + t.printStackTrace(); + System.err.println(s); + } + } + + private static void error(String s) { + if (error) { + System.err.println(s); + } + } + + void localCheck(String directive) { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + directive = this.getClass().getName() + "." + + directive + "." + localFullName(); + security.checkSecurityAccess(directive); + } + } + + /** + * Returns a parsable name for identity: identityName.scopeName + */ + String localFullName() { + String parsable = getName(); + if (getScope() != null) { + parsable += "." +getScope().getName(); + } + return parsable; + } + + /** + * Serialization write. + */ + private synchronized void writeObject (java.io.ObjectOutputStream stream) + throws IOException { + localCheck("serialize.identity.database"); + stream.writeObject(identities); + stream.writeObject(sourceFile); + } +}