jdk/src/share/classes/sun/security/provider/IdentityDatabase.java
changeset 4422 ade55a65b0f2
parent 4421 fcbbd4d49581
parent 4408 80dcc8ac5696
child 4423 4061c66ba1af
equal deleted inserted replaced
4421:fcbbd4d49581 4422:ade55a65b0f2
     1 /*
       
     2  * Copyright 1996-2006 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.security.provider;
       
    27 
       
    28 import java.io.*;
       
    29 import java.util.*;
       
    30 import java.security.*;
       
    31 
       
    32 /**
       
    33  * An implementation of IdentityScope as a persistent identity
       
    34  * database.
       
    35  *
       
    36  * @see Identity
       
    37  * @see Key
       
    38  *
       
    39  * @author Benjamin Renaud
       
    40  */
       
    41 public
       
    42 class IdentityDatabase extends IdentityScope implements Serializable {
       
    43 
       
    44     /** use serialVersionUID from JDK 1.1. for interoperability */
       
    45     private static final long serialVersionUID = 4923799573357658384L;
       
    46 
       
    47     /* Are we debugging? */
       
    48     private static final boolean debug = false;
       
    49 
       
    50     /* Are we printing out error messages? */
       
    51     private static final boolean error = true;
       
    52 
       
    53     /* The source file, if any, for this database.*/
       
    54     File sourceFile;
       
    55 
       
    56     /* The private representation of the database.*/
       
    57     Hashtable<String, Identity> identities;
       
    58 
       
    59     IdentityDatabase() throws InvalidParameterException {
       
    60         this("restoring...");
       
    61     }
       
    62 
       
    63     /**
       
    64      * Construct a new, empty database with a specified source file.
       
    65      *
       
    66      * @param file the source file.
       
    67      */
       
    68     public IdentityDatabase(File file) throws InvalidParameterException {
       
    69         this(file.getName());
       
    70         sourceFile = file;
       
    71     }
       
    72 
       
    73     /**
       
    74      * Construct a new, empty database.
       
    75      */
       
    76     public IdentityDatabase(String name) throws InvalidParameterException {
       
    77         super(name);
       
    78         identities = new Hashtable<String, Identity>();
       
    79     }
       
    80 
       
    81     /**
       
    82      * Initialize an identity database from a stream. The stream should
       
    83      * contain data to initialized a serialized IdentityDatabase
       
    84      * object.
       
    85      *
       
    86      * @param is the input stream from which to restore the database.
       
    87      *
       
    88      * @exception IOException if a stream IO exception occurs
       
    89      */
       
    90     public static IdentityDatabase fromStream(InputStream is)
       
    91     throws IOException {
       
    92         IdentityDatabase db = null;
       
    93         try {
       
    94             ObjectInputStream ois = new ObjectInputStream(is);
       
    95             db = (IdentityDatabase)ois.readObject();
       
    96         } catch (ClassNotFoundException e) {
       
    97             // this can't happen.
       
    98             debug("This should not be happening.", e);
       
    99             error(
       
   100                 "The version of the database is obsolete. Cannot initialize.");
       
   101 
       
   102         } catch (InvalidClassException e) {
       
   103             // this may happen in developers workspaces happen.
       
   104             debug("This should not be happening.", e);
       
   105             error("Unable to initialize system identity scope: " +
       
   106                   " InvalidClassException. \nThis is most likely due to " +
       
   107                   "a serialization versioning problem: a class used in " +
       
   108                   "key management was obsoleted");
       
   109 
       
   110         } catch (StreamCorruptedException e) {
       
   111             debug("The serialization stream is corrupted. Unable to load.", e);
       
   112             error("Unable to initialize system identity scope." +
       
   113                   " StreamCorruptedException.");
       
   114         }
       
   115 
       
   116         if (db == null) {
       
   117             db = new IdentityDatabase("uninitialized");
       
   118         }
       
   119 
       
   120         return db;
       
   121     }
       
   122 
       
   123     /**
       
   124      * Initialize an IdentityDatabase from file.
       
   125      *
       
   126      * @param f the filename where the identity database is stored.
       
   127      *
       
   128      * @exception IOException a file-related exception occurs (e.g.
       
   129      * the directory of the file passed does not exists, etc.
       
   130      *
       
   131      * @IOException if a file IO exception occurs.
       
   132      */
       
   133     public static IdentityDatabase fromFile(File f) throws IOException {
       
   134         FileInputStream fis = new FileInputStream(f);
       
   135         IdentityDatabase edb = fromStream(fis);
       
   136         edb.sourceFile = f;
       
   137         return edb;
       
   138     }
       
   139 
       
   140 
       
   141 
       
   142     /**
       
   143      * @return the number of identities in the database.
       
   144      */
       
   145    public int size() {
       
   146        return identities.size();
       
   147    }
       
   148 
       
   149 
       
   150     /**
       
   151      * @param name the name of the identity to be retrieved.
       
   152      *
       
   153      * @return the identity named name, or null if there are
       
   154      * no identities named name in the database.
       
   155      */
       
   156     public Identity getIdentity(String name) {
       
   157         Identity id = identities.get(name);
       
   158         if (id instanceof Signer) {
       
   159             localCheck("get.signer");
       
   160         }
       
   161         return id;
       
   162     }
       
   163 
       
   164     /**
       
   165      * Get an identity by key.
       
   166      *
       
   167      * @param name the key of the identity to be retrieved.
       
   168      *
       
   169      * @return the identity with a given key, or null if there are no
       
   170      * identities with that key in the database.
       
   171      */
       
   172     public Identity getIdentity(PublicKey key) {
       
   173         if (key == null) {
       
   174             return null;
       
   175         }
       
   176         Enumeration<Identity> e = identities();
       
   177         while (e.hasMoreElements()) {
       
   178             Identity i = e.nextElement();
       
   179             PublicKey k = i.getPublicKey();
       
   180             if (k != null && keyEqual(k, key)) {
       
   181                 if (i instanceof Signer) {
       
   182                     localCheck("get.signer");
       
   183                 }
       
   184                 return i;
       
   185             }
       
   186         }
       
   187         return null;
       
   188     }
       
   189 
       
   190     private boolean keyEqual(Key key1, Key key2) {
       
   191         if (key1 == key2) {
       
   192             return true;
       
   193         } else {
       
   194             return MessageDigest.isEqual(key1.getEncoded(), key2.getEncoded());
       
   195         }
       
   196     }
       
   197 
       
   198     /**
       
   199      * Adds an identity to the database.
       
   200      *
       
   201      * @param identity the identity to be added.
       
   202      *
       
   203      * @exception KeyManagementException if a name or key clash
       
   204      * occurs, or if another exception occurs.
       
   205      */
       
   206     public void addIdentity(Identity identity)
       
   207     throws KeyManagementException {
       
   208         localCheck("add.identity");
       
   209         Identity byName = getIdentity(identity.getName());
       
   210         Identity byKey = getIdentity(identity.getPublicKey());
       
   211         String msg = null;
       
   212 
       
   213         if (byName != null) {
       
   214             msg = "name conflict";
       
   215         }
       
   216         if (byKey != null) {
       
   217             msg = "key conflict";
       
   218         }
       
   219         if (msg != null) {
       
   220             throw new KeyManagementException(msg);
       
   221         }
       
   222         identities.put(identity.getName(), identity);
       
   223     }
       
   224 
       
   225     /**
       
   226      * Removes an identity to the database.
       
   227      */
       
   228     public void removeIdentity(Identity identity)
       
   229     throws KeyManagementException {
       
   230         localCheck("remove.identity");
       
   231         String name = identity.getName();
       
   232         if (identities.get(name) == null) {
       
   233             throw new KeyManagementException("there is no identity named " +
       
   234                                              name + " in " + this);
       
   235         }
       
   236         identities.remove(name);
       
   237     }
       
   238 
       
   239     /**
       
   240      * @return an enumeration of all identities in the database.
       
   241      */
       
   242     public Enumeration<Identity> identities() {
       
   243         return identities.elements();
       
   244     }
       
   245 
       
   246     /**
       
   247      * Set the source file for this database.
       
   248      */
       
   249     void setSourceFile(File f) {
       
   250         sourceFile = f;
       
   251     }
       
   252 
       
   253     /**
       
   254      * @return the source file for this database.
       
   255      */
       
   256     File getSourceFile() {
       
   257         return sourceFile;
       
   258     }
       
   259 
       
   260     /**
       
   261      * Save the database in its current state to an output stream.
       
   262      *
       
   263      * @param os the output stream to which the database should be serialized.
       
   264      *
       
   265      * @exception IOException if an IO exception is raised by stream
       
   266      * operations.
       
   267      */
       
   268     public void save(OutputStream os) throws IOException {
       
   269         try {
       
   270             ObjectOutputStream oos = new ObjectOutputStream(os);
       
   271             oos.writeObject(this);
       
   272             oos.flush();
       
   273         } catch (InvalidClassException e) {
       
   274             debug("This should not be happening.", e);
       
   275             return;
       
   276         }
       
   277     }
       
   278 
       
   279     /**
       
   280      * Save the database to a file.
       
   281      *
       
   282      * @exception IOException if an IO exception is raised by stream
       
   283      * operations.
       
   284      */
       
   285     void save(File f) throws IOException {
       
   286         setSourceFile(f);
       
   287         FileOutputStream fos = new FileOutputStream(f);
       
   288         save(fos);
       
   289     }
       
   290 
       
   291     /**
       
   292      * Saves the database to the default source file.
       
   293      *
       
   294      * @exception KeyManagementException when there is no default source
       
   295      * file specified for this database.
       
   296      */
       
   297     public void save() throws IOException {
       
   298         if (sourceFile == null) {
       
   299             throw new IOException("this database has no source file");
       
   300         }
       
   301         save(sourceFile);
       
   302     }
       
   303 
       
   304     /**
       
   305      * This method returns the file from which to initialize the
       
   306      * system database.
       
   307      */
       
   308     private static File systemDatabaseFile() {
       
   309 
       
   310         // First figure out where the identity database is hiding, if anywhere.
       
   311         String dbPath = Security.getProperty("identity.database");
       
   312         // if nowhere, it's the canonical place.
       
   313         if (dbPath == null) {
       
   314             dbPath = System.getProperty("user.home") + File.separatorChar +
       
   315                 "identitydb.obj";
       
   316         }
       
   317         return new File(dbPath);
       
   318     }
       
   319 
       
   320 
       
   321     /* This block initializes the system database, if there is one. */
       
   322     static {
       
   323         java.security.AccessController.doPrivileged(
       
   324             new java.security.PrivilegedAction<Void>() {
       
   325             public Void run() {
       
   326                 initializeSystem();
       
   327                 return null;
       
   328             }
       
   329         });
       
   330     }
       
   331 
       
   332     /**
       
   333      * This method initializes the system's identity database. The
       
   334      * canonical location is
       
   335      * <user.home>/identitydatabase.obj. This is settable through
       
   336      * the identity.database property.  */
       
   337     private static void initializeSystem() {
       
   338 
       
   339         IdentityDatabase systemDatabase;
       
   340         File dbFile = systemDatabaseFile();
       
   341 
       
   342         // Second figure out if it's there, and if it isn't, create one.
       
   343         try {
       
   344             if (dbFile.exists()) {
       
   345                 debug("loading system database from file: " + dbFile);
       
   346                 systemDatabase = fromFile(dbFile);
       
   347             } else {
       
   348                 systemDatabase = new IdentityDatabase(dbFile);
       
   349             }
       
   350             IdentityScope.setSystemScope(systemDatabase);
       
   351             debug("System database initialized: " + systemDatabase);
       
   352         } catch (IOException e) {
       
   353             debug("Error initializing identity database: " + dbFile, e);
       
   354             return;
       
   355         } catch (InvalidParameterException e) {
       
   356             debug("Error trying to instantiate a system identities db in " +
       
   357                                dbFile, e);
       
   358             return;
       
   359         }
       
   360     }
       
   361 
       
   362     /*
       
   363     private static File securityPropFile(String filename) {
       
   364         // maybe check for a system property which will specify where to
       
   365         // look.
       
   366         String sep = File.separator;
       
   367         return new File(System.getProperty("java.home") +
       
   368                         sep + "lib" + sep + "security" +
       
   369                         sep + filename);
       
   370     }
       
   371     */
       
   372 
       
   373     public String toString() {
       
   374         return "sun.security.provider.IdentityDatabase, source file: " +
       
   375             sourceFile;
       
   376     }
       
   377 
       
   378 
       
   379     private static void debug(String s) {
       
   380         if (debug) {
       
   381             System.err.println(s);
       
   382         }
       
   383     }
       
   384 
       
   385     private static void debug(String s, Throwable t) {
       
   386         if (debug) {
       
   387             t.printStackTrace();
       
   388             System.err.println(s);
       
   389         }
       
   390     }
       
   391 
       
   392     private static void error(String s) {
       
   393         if (error) {
       
   394             System.err.println(s);
       
   395         }
       
   396     }
       
   397 
       
   398     void localCheck(String directive) {
       
   399         SecurityManager security = System.getSecurityManager();
       
   400         if (security != null) {
       
   401             directive = this.getClass().getName() + "." +
       
   402                 directive + "." + localFullName();
       
   403             security.checkSecurityAccess(directive);
       
   404         }
       
   405     }
       
   406 
       
   407     /**
       
   408      * Returns a parsable name for identity: identityName.scopeName
       
   409      */
       
   410     String localFullName() {
       
   411         String parsable = getName();
       
   412         if (getScope() != null) {
       
   413             parsable += "." +getScope().getName();
       
   414         }
       
   415         return parsable;
       
   416     }
       
   417 
       
   418     /**
       
   419      * Serialization write.
       
   420      */
       
   421     private synchronized void writeObject (java.io.ObjectOutputStream stream)
       
   422     throws IOException {
       
   423         localCheck("serialize.identity.database");
       
   424         stream.writeObject(identities);
       
   425         stream.writeObject(sourceFile);
       
   426     }
       
   427 }