001: /*
002: * @(#)IdentityDatabase.java 1.48 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package sun.security.provider;
029:
030: import java.io.*;
031: import java.util.*;
032: import java.security.*;
033:
034: /**
035: * An implementation of IdentityScope as a persistent identity
036: * database.
037: *
038: * @see Identity
039: * @see Key
040: *
041: * @version 1.48, 10/10/06
042: * @author Benjamin Renaud
043: */
044: public class IdentityDatabase extends IdentityScope implements
045: Serializable {
046:
047: /** use serialVersionUID from JDK 1.1. for interoperability */
048: private static final long serialVersionUID = 4923799573357658384L;
049:
050: /* Are we debugging? */
051: private static final boolean debug = false;
052:
053: /* Are we printing out error messages? */
054: private static final boolean error = true;
055:
056: /* The source file, if any, for this database.*/
057: File sourceFile;
058:
059: /* The private representation of the database.*/
060: Hashtable identities;
061:
062: IdentityDatabase() throws InvalidParameterException {
063: this ("restoring...");
064: }
065:
066: /**
067: * Construct a new, empty database with a specified source file.
068: *
069: * @param file the source file.
070: */
071: public IdentityDatabase(File file) throws InvalidParameterException {
072: this (file.getName());
073: sourceFile = file;
074: }
075:
076: /**
077: * Construct a new, empty database.
078: */
079: public IdentityDatabase(String name)
080: throws InvalidParameterException {
081: super (name);
082: identities = new Hashtable();
083: }
084:
085: /**
086: * Initialize an identity database from a stream. The stream should
087: * contain data to initialized a serialized IdentityDatabase
088: * object.
089: *
090: * @param is the input stream from which to restore the database.
091: *
092: * @exception IOException if a stream IO exception occurs
093: */
094: public static IdentityDatabase fromStream(InputStream is)
095: throws IOException {
096: IdentityDatabase db = null;
097: try {
098: ObjectInputStream ois = new ObjectInputStream(is);
099: db = (IdentityDatabase) ois.readObject();
100: } catch (ClassNotFoundException e) {
101: // this can't happen.
102: debug("This should not be happening.", e);
103: error("The version of the database is obsolete. Cannot initialize.");
104:
105: } catch (InvalidClassException e) {
106: // this may happen in developers workspaces happen.
107: debug("This should not be happening.", e);
108: error("Unable to initialize system identity scope: "
109: + " InvalidClassException. \nThis is most likely due to "
110: + "a serialization versioning problem: a class used in "
111: + "key management was obsoleted");
112:
113: } catch (StreamCorruptedException e) {
114: debug(
115: "The serialization stream is corrupted. Unable to load.",
116: e);
117: error("Unable to initialize system identity scope."
118: + " StreamCorruptedException.");
119: }
120:
121: if (db == null) {
122: db = new IdentityDatabase("uninitialized");
123: }
124:
125: return db;
126: }
127:
128: /**
129: * Initialize an IdentityDatabase from file.
130: *
131: * @param f the filename where the identity database is stored.
132: *
133: * @exception IOException a file-related exception occurs (e.g.
134: * the directory of the file passed does not exists, etc.
135: *
136: * @IOException if a file IO exception occurs.
137: */
138: public static IdentityDatabase fromFile(File f) throws IOException {
139: InputStream fis = new BufferedInputStream(
140: new FileInputStream(f));
141: IdentityDatabase edb = fromStream(fis);
142: edb.sourceFile = f;
143: return edb;
144: }
145:
146: /**
147: * @return the number of identities in the database.
148: */
149: public int size() {
150: return identities.size();
151: }
152:
153: /**
154: * @param name the name of the identity to be retrieved.
155: *
156: * @return the identity named name, or null if there are
157: * no identities named name in the database.
158: */
159: public Identity getIdentity(String name) {
160: Identity id = (Identity) identities.get(name);
161: if (id instanceof Signer) {
162: localCheck("get.signer");
163: }
164: return id;
165: }
166:
167: /**
168: * Get an identity by key.
169: *
170: * @param name the key of the identity to be retrieved.
171: *
172: * @return the identity with a given key, or null if there are no
173: * identities with that key in the database.
174: */
175: public Identity getIdentity(PublicKey key) {
176: if (key == null) {
177: return null;
178: }
179: Enumeration e = identities();
180: while (e.hasMoreElements()) {
181: Identity i = (Identity) e.nextElement();
182: PublicKey k = i.getPublicKey();
183: if (k != null && keyEqual(k, key)) {
184: if (i instanceof Signer) {
185: localCheck("get.signer");
186: }
187: return i;
188: }
189: }
190: return null;
191: }
192:
193: private boolean keyEqual(Key key1, Key key2) {
194: if (key1 == key2) {
195: return true;
196: } else {
197: return MessageDigest.isEqual(key1.getEncoded(), key2
198: .getEncoded());
199: }
200: }
201:
202: /**
203: * Adds an identity to the database.
204: *
205: * @param identity the identity to be added.
206: *
207: * @exception KeyManagementException if a name or key clash
208: * occurs, or if another exception occurs.
209: */
210: public void addIdentity(Identity identity)
211: throws KeyManagementException {
212: localCheck("add.identity");
213: Identity byName = getIdentity(identity.getName());
214: Identity byKey = getIdentity(identity.getPublicKey());
215: String msg = null;
216:
217: if (byName != null) {
218: msg = "name conflict";
219: }
220: if (byKey != null) {
221: msg = "key conflict";
222: }
223: if (msg != null) {
224: throw new KeyManagementException(msg);
225: }
226: identities.put(identity.getName(), identity);
227: }
228:
229: /**
230: * Removes an identity to the database.
231: */
232: public void removeIdentity(Identity identity)
233: throws KeyManagementException {
234: localCheck("remove.identity");
235: String name = identity.getName();
236: if (identities.get(name) == null) {
237: throw new KeyManagementException(
238: "there is no identity named " + name + " in "
239: + this );
240: }
241: identities.remove(name);
242: }
243:
244: /**
245: * @return an enumeration of all identities in the database.
246: */
247: public Enumeration identities() {
248: return identities.elements();
249: }
250:
251: /**
252: * Set the source file for this database.
253: */
254: void setSourceFile(File f) {
255: sourceFile = f;
256: }
257:
258: /**
259: * @return the source file for this database.
260: */
261: File getSourceFile() {
262: return sourceFile;
263: }
264:
265: /**
266: * Save the database in its current state to an output stream.
267: *
268: * @param os the output stream to which the database should be serialized.
269: *
270: * @exception IOException if an IO exception is raised by stream
271: * operations.
272: */
273: public void save(OutputStream os) throws IOException {
274: try {
275: ObjectOutputStream oos = new ObjectOutputStream(os);
276: oos.writeObject(this );
277: oos.flush();
278: } catch (InvalidClassException e) {
279: debug("This should not be happening.", e);
280: return;
281: }
282: }
283:
284: /**
285: * Save the database to a file.
286: *
287: * @exception IOException if an IO exception is raised by stream
288: * operations.
289: */
290: void save(File f) throws IOException {
291: setSourceFile(f);
292: OutputStream fos = new BufferedOutputStream(
293: new FileOutputStream(f));
294: save(fos);
295: }
296:
297: /**
298: * Saves the database to the default source file.
299: *
300: * @exception KeyManagementException when there is no default source
301: * file specified for this database.
302: */
303: public void save() throws IOException {
304: if (sourceFile == null) {
305: throw new IOException("this database has no source file");
306: }
307: save(sourceFile);
308: }
309:
310: /**
311: * This method returns the file from which to initialize the
312: * system database.
313: */
314: private static File systemDatabaseFile() {
315:
316: // First figure out where the identity database is hiding, if anywhere.
317: String dbPath = Security.getProperty("identity.database");
318: // if nowhere, it's the canonical place.
319: if (dbPath == null) {
320: dbPath = System.getProperty("user.home")
321: + File.separatorChar + "identitydb.obj";
322: }
323: return new File(dbPath);
324: }
325:
326: /* This block initializes the system database, if there is one. */
327: static {
328: java.security.AccessController
329: .doPrivileged(new java.security.PrivilegedAction() {
330: public Object run() {
331: initializeSystem();
332: return null;
333: }
334: });
335: }
336:
337: /**
338: * This method initializes the system's identity database. The
339: * canonical location is
340: * <user.home>/identitydatabase.obj. This is settable through
341: * the identity.database property. */
342: private static void initializeSystem() {
343:
344: IdentityDatabase systemDatabase;
345: File dbFile = systemDatabaseFile();
346:
347: // Second figure out if it's there, and if it isn't, create one.
348: try {
349: if (dbFile.exists()) {
350: debug("loading system database from file: " + dbFile);
351: systemDatabase = fromFile(dbFile);
352: } else {
353: systemDatabase = new IdentityDatabase(dbFile);
354: }
355: IdentityScope.setSystemScope(systemDatabase);
356: debug("System database initialized: " + systemDatabase);
357: } catch (IOException e) {
358: debug("Error initializing identity database: " + dbFile, e);
359: return;
360: } catch (InvalidParameterException e) {
361: debug(
362: "Error trying to instantiate a system identities db in "
363: + dbFile, e);
364: return;
365: }
366: }
367:
368: /*
369: private static File securityPropFile(String filename) {
370: // maybe check for a system property which will specify where to
371: // look.
372: String sep = File.separator;
373: return new File(System.getProperty("java.home") +
374: sep + "lib" + sep + "security" +
375: sep + filename);
376: }
377: */
378:
379: public String toString() {
380: return "sun.security.provider.IdentityDatabase, source file: "
381: + sourceFile;
382: }
383:
384: private static void debug(String s) {
385: if (debug) {
386: System.err.println(s);
387: }
388: }
389:
390: private static void debug(String s, Throwable t) {
391: if (debug) {
392: t.printStackTrace();
393: System.err.println(s);
394: }
395: }
396:
397: private static void error(String s) {
398: if (error) {
399: System.err.println(s);
400: }
401: }
402:
403: void localCheck(String directive) {
404: SecurityManager security = System.getSecurityManager();
405: if (security != null) {
406: directive = this .getClass().getName() + "." + directive
407: + "." + localFullName();
408: security.checkSecurityAccess(directive);
409: }
410: }
411:
412: /**
413: * Returns a parsable name for identity: identityName.scopeName
414: */
415: String localFullName() {
416: String parsable = getName();
417: if (getScope() != null) {
418: parsable += "." + getScope().getName();
419: }
420: return parsable;
421: }
422:
423: /**
424: * Serialization write.
425: */
426: private synchronized void writeObject(
427: java.io.ObjectOutputStream stream) throws IOException {
428: localCheck("serialize.identity.database");
429: stream.writeObject(identities);
430: stream.writeObject(sourceFile);
431: }
432: }
|