KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > runtime > AuthorizationDatabase


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.runtime;
12
13 import java.io.*;
14 import java.net.URL JavaDoc;
15 import java.util.*;
16 import org.eclipse.core.runtime.*;
17 import org.eclipse.osgi.util.NLS;
18
19 /**
20  * A database that remembers information, such as usernames and
21  * passwords. The information is stored in memory and can be saved
22  * to disk in an encrypted format. While the API is phrased in terms of
23  * URLs, realms and authentication schemes, not all of these must have
24  * significant values. For example, if "realm" is not relevant to a
25  * particular application, it can be left blank (though not
26  * <code>null</code>).
27  */

28 public class AuthorizationDatabase {
29     /**
30      * Version number for the format of the keyring file.
31      */

32     private static final int KEYRING_FILE_VERSION = 1;
33     /**
34      * A nested hashtable that stores authorization information. The
35      * table maps server URLs to realms to authentication schemes to
36      * authorization information.
37      */

38     private Hashtable authorizationInfo = new Hashtable(5);
39
40     /**
41      * A hashtable mapping resource URLs to realms.
42      */

43     private Hashtable protectionSpace = new Hashtable(5);
44
45     private File file = null;
46     private String JavaDoc password = null;
47     private boolean needsSaving = true;
48
49     /**
50      * Creates a new authorization database whose data cannot be saved to
51      * disk.
52      */

53     public AuthorizationDatabase() {
54         super();
55     }
56
57     /**
58      * Creates a new authorization database, or opens an existing one, whose
59      * data is, or can be, saved to a file with the given filename. A
60      * password must be given to create a new database and an existing
61      * database is opened by supplying the password that was given to create
62      * it.
63      *
64      * @param filename the location of the database on disk. For example,
65      * "c:/temp/database"
66      * @param password the password to access the database. For example,
67      * "secret"
68      * @exception CoreException if there are problems creating the database.
69      * Reasons include:
70      * <ul>
71      * <li>The database could not be opened because the wrong password was given.
72      * <li>The database could not be opened because the specified file is corrupt.
73      * </ul>
74      */

75     public AuthorizationDatabase(String JavaDoc filename, String JavaDoc password) throws CoreException {
76         Assert.isNotNull(filename);
77         Assert.isNotNull(password);
78         this.password = password;
79         file = new File(filename);
80         load();
81     }
82
83     /**
84      * Adds the given authorization information to the database. The
85      * information is relevant for the specified protection space and the
86      * given authorization scheme. The protection space is defined by the
87      * combination of the given server URL and realm. The authorization
88      * scheme determines what the authorization information contains and how
89      * it should be used. The authorization information is a <code>Map</code>
90      * of <code>String</code> to <code>String</code> and typically
91      * contain information such as usernames and passwords.
92      *
93      * @param serverUrl the URL identifying the server for this authorization
94      * information. For example, "http://www.hostname.com/".
95      * @param realm the subsection of the given server to which this
96      * authorization information applies. For example,
97      * "realm1@hostname.com" or "" for no realm.
98      * @param authScheme the scheme for which this authorization information
99      * applies. For example, "Basic" or "" for no authorization scheme
100      * @param info a <code>Map</code> containing authorization information
101      * such as usernames and passwords
102      */

103     public void addAuthorizationInfo(URL JavaDoc serverUrl, String JavaDoc realm, String JavaDoc authScheme, Map info) {
104         Assert.isNotNull(serverUrl);
105         Assert.isNotNull(realm);
106         Assert.isNotNull(authScheme);
107         Assert.isNotNull(info);
108
109         String JavaDoc url = serverUrl.toString();
110         Hashtable realmToAuthScheme = (Hashtable) authorizationInfo.get(url);
111         if (realmToAuthScheme == null) {
112             realmToAuthScheme = new Hashtable(5);
113             authorizationInfo.put(url, realmToAuthScheme);
114         }
115
116         Hashtable authSchemeToInfo = (Hashtable) realmToAuthScheme.get(realm);
117         if (authSchemeToInfo == null) {
118             authSchemeToInfo = new Hashtable(5);
119             realmToAuthScheme.put(realm, authSchemeToInfo);
120         }
121
122         authSchemeToInfo.put(authScheme.toLowerCase(), info);
123         needsSaving = true;
124     }
125
126     /**
127      * Adds the specified resource to the protection space specified by the
128      * given realm. All resources at or deeper than the depth of the last
129      * symbolic element in the path of the given resource URL are assumed to
130      * be in the same protection space.
131      *
132      * @param resourceUrl the URL identifying the resources to be added to
133      * the specified protection space. For example,
134      * "http://www.hostname.com/folder/".
135      * @param realm the name of the protection space. For example,
136      * "realm1@hostname.com"
137      */

138     public void addProtectionSpace(URL JavaDoc resourceUrl, String JavaDoc realm) {
139         Assert.isNotNull(resourceUrl);
140         Assert.isNotNull(realm);
141
142         if (!resourceUrl.getFile().endsWith("/")) { //$NON-NLS-1$
143
resourceUrl = URLTool.getParent(resourceUrl);
144         }
145
146         String JavaDoc oldRealm = getProtectionSpace(resourceUrl);
147         if (oldRealm != null && oldRealm.equals(realm)) {
148             return;
149         }
150
151         String JavaDoc url1 = resourceUrl.toString();
152         Enumeration urls = protectionSpace.keys();
153         while (urls.hasMoreElements()) {
154             String JavaDoc url2 = (String JavaDoc) urls.nextElement();
155             if (url1.startsWith(url2) || url2.startsWith(url1)) {
156                 protectionSpace.remove(url2);
157                 break;
158             }
159         }
160
161         protectionSpace.put(url1, realm);
162         needsSaving = true;
163     }
164
165     /**
166      * Removes the authorization information for the specified protection
167      * space and given authorization scheme. The protection space is defined
168      * by the given server URL and realm.
169      *
170      * @param serverUrl the URL identifying the server to remove the
171      * authorization information for. For example,
172      * "http://www.hostname.com/".
173      * @param realm the subsection of the given server to remove the
174      * authorization information for. For example,
175      * "realm1@hostname.com" or "" for no realm.
176      * @param authScheme the scheme for which the authorization information
177      * to remove applies. For example, "Basic" or "" for no
178      * authorization scheme.
179      */

180     public void flushAuthorizationInfo(URL JavaDoc serverUrl, String JavaDoc realm, String JavaDoc authScheme) {
181         Hashtable realmToAuthScheme = (Hashtable) authorizationInfo.get(serverUrl.toString());
182
183         if (realmToAuthScheme == null) {
184             return;
185         }
186
187         Hashtable authSchemeToInfo = (Hashtable) realmToAuthScheme.get(realm);
188
189         if (authSchemeToInfo == null) {
190             return;
191         }
192
193         authSchemeToInfo.remove(authScheme.toLowerCase());
194
195         needsSaving = true;
196     }
197
198     /**
199      * Returns the authorization information for the specified protection
200      * space and given authorization scheme. The protection space is defined
201      * by the given server URL and realm. Returns <code>null</code> if no
202      * such information exists.
203      *
204      * @param serverUrl the URL identifying the server for the authorization
205      * information. For example, "http://www.hostname.com/".
206      * @param realm the subsection of the given server to which the
207      * authorization information applies. For example,
208      * "realm1@hostname.com" or "" for no realm.
209      * @param authScheme the scheme for which the authorization information
210      * applies. For example, "Basic" or "" for no authorization scheme
211      * @return the authorization information for the specified protection
212      * space and given authorization scheme, or <code>null</code> if no
213      * such information exists
214      */

215     public Map getAuthorizationInfo(URL JavaDoc serverUrl, String JavaDoc realm, String JavaDoc authScheme) {
216         Hashtable realmToAuthScheme = (Hashtable) authorizationInfo.get(serverUrl.toString());
217         if (realmToAuthScheme == null) {
218             return null;
219         }
220
221         Hashtable authSchemeToInfo = (Hashtable) realmToAuthScheme.get(realm);
222         if (authSchemeToInfo == null) {
223             return null;
224         }
225
226         return (Map) authSchemeToInfo.get(authScheme.toLowerCase());
227     }
228
229     /**
230      * Returns the protection space (realm) for the specified resource, or
231      * <code>null</code> if the realm is unknown.
232      *
233      * @param resourceUrl the URL of the resource whose protection space is
234      * returned. For example, "http://www.hostname.com/folder/".
235      * @return the protection space (realm) for the specified resource, or
236      * <code>null</code> if the realm is unknown
237      */

238     public String JavaDoc getProtectionSpace(URL JavaDoc resourceUrl) {
239         while (resourceUrl != null) {
240             String JavaDoc realm = (String JavaDoc) protectionSpace.get(resourceUrl.toString());
241             if (realm != null) {
242                 return realm;
243             }
244             resourceUrl = URLTool.getParent(resourceUrl);
245         }
246
247         return null;
248     }
249
250     private void load() throws CoreException {
251         if (file == null)
252             return;
253         if (!file.exists()) {
254             save();
255             return;
256         }
257         try {
258             InputStream input = new FileInputStream(file);
259             try {
260                 load(input);
261             } finally {
262                 input.close();
263             }
264         } catch (IOException e) {
265             throw new CoreException(new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.FAILED_READ_METADATA, NLS.bind(Messages.meta_unableToReadAuthorization, file), e));
266         } catch (ClassNotFoundException JavaDoc e) {
267             throw new CoreException(new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.FAILED_READ_METADATA, NLS.bind(Messages.meta_unableToReadAuthorization, file), e));
268         }
269     }
270
271     private void load(InputStream is) throws IOException, ClassNotFoundException JavaDoc, CoreException {
272         //try to read the file version number. Pre 2.0 versions had no number
273
int version = is.read();
274         if (version == KEYRING_FILE_VERSION) {
275             //read the authorization data
276
CipherInputStream cis = new CipherInputStream(is, password);
277             ObjectInputStream ois = new ObjectInputStream(cis);
278             try {
279                 authorizationInfo = (Hashtable) ois.readObject();
280                 protectionSpace = (Hashtable) ois.readObject();
281             } finally {
282                 ois.close();
283             }
284         } else {
285             //the format has changed, just log a warning
286
InternalPlatform.getDefault().log(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.FAILED_READ_METADATA, Messages.meta_authFormatChanged, null));
287             //close the stream and save a new file in the correct format
288
try {
289                 is.close();
290             } catch (IOException e) {
291                 //ignore failure to close
292
}
293             needsSaving = true;
294             save();
295         }
296     }
297
298     /**
299      * Saves the authorization database to disk.
300      */

301     public void save() throws CoreException {
302         if (!needsSaving || file == null)
303             return;
304         try {
305             file.delete();
306             if ((!file.getParentFile().exists() && !file.getParentFile().mkdirs()) || !canWrite(file.getParentFile()))
307                 throw new CoreException(new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.FAILED_WRITE_METADATA, NLS.bind(Messages.meta_unableToWriteAuthorization, file), null));
308             file.createNewFile();
309             FileOutputStream out = new FileOutputStream(file);
310             try {
311                 save(out);
312             } finally {
313                 out.close();
314             }
315         } catch (IOException e) {
316             throw new CoreException(new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.FAILED_WRITE_METADATA, NLS.bind(Messages.meta_unableToWriteAuthorization, file), e));
317         }
318         needsSaving = false;
319     }
320
321     private static boolean canWrite(File installDir) {
322         if (!installDir.canWrite())
323             return false;
324
325         if (!installDir.isDirectory())
326             return false;
327
328         File fileTest = null;
329         try {
330             fileTest = File.createTempFile("writtableArea", null, installDir); //$NON-NLS-1$
331
} catch (IOException e) {
332             //If an exception occured while trying to create the file, it means that it is not writtable
333
return false;
334         } finally {
335             if (fileTest != null)
336                 fileTest.delete();
337         }
338         return true;
339     }
340
341     private void save(FileOutputStream os) throws IOException {
342         //write the version number
343
os.write(KEYRING_FILE_VERSION);
344
345         CipherOutputStream cos = new CipherOutputStream(os, password);
346         ObjectOutputStream oos = new ObjectOutputStream(cos);
347         //write the data
348
try {
349             oos.writeObject(authorizationInfo);
350             oos.writeObject(protectionSpace);
351             os.flush();
352             os.getFD().sync();
353         } finally {
354             oos.close();
355         }
356     }
357
358     /**
359      * Sets the password to use for accessing this database. If the database
360      * is subsequently saved, this new password is used.
361      */

362     public boolean setPassword(String JavaDoc oldValue, String JavaDoc newValue) {
363         if (!oldValue.equals(password))
364             return false;
365         password = newValue;
366         needsSaving = true;
367         return true;
368     }
369 }
370
Popular Tags