KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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.auth;
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 user-names 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     public static final String JavaDoc PI_RUNTIME_AUTH = "org.eclipse.core.runtime.auth.compatibility"; //$NON-NLS-1$
30

31     /**
32      * Status code constant (value 4) indicating the platform could not read
33      * some of its metadata.
34      */

35     public static final int FAILED_READ_METADATA = 4;
36
37     /**
38      * Status code constant (value 5) indicating the platform could not write
39      * some of its metadata.
40      */

41     public static final int FAILED_WRITE_METADATA = 5;
42
43     /**
44      * Version number for the format of the key-ring file.
45      */

46     private static final int KEYRING_FILE_VERSION = 1;
47
48     /**
49      * A nested hashtable that stores authorization information. The
50      * table maps server URLs to realms to authentication schemes to
51      * authorization information.
52      */

53     private Hashtable authorizationInfo = new Hashtable(5);
54
55     /**
56      * A hashtable mapping resource URLs to realms.
57      */

58     private Hashtable protectionSpace = new Hashtable(5);
59
60     private File file = null;
61     private String JavaDoc password = null;
62     private boolean needsSaving = true;
63
64     /**
65      * Creates a new authorization database whose data cannot be saved to
66      * disk.
67      */

68     public AuthorizationDatabase() {
69         super();
70     }
71
72     /**
73      * Creates a new authorization database, or opens an existing one, whose
74      * data is, or can be, saved to a file with the given filename. A
75      * password must be given to create a new database and an existing
76      * database is opened by supplying the password that was given to create
77      * it.
78      *
79      * @param filename the location of the database on disk. For example,
80      * "c:/temp/database"
81      * @param password the password to access the database. For example,
82      * "secret"
83      * @exception CoreException if there are problems creating the database.
84      * Reasons include:
85      * <ul>
86      * <li>The database could not be opened because the wrong password was given.
87      * <li>The database could not be opened because the specified file is corrupt.
88      * </ul>
89      */

90     public AuthorizationDatabase(String JavaDoc filename, String JavaDoc password) throws CoreException {
91         Assert.isNotNull(filename);
92         Assert.isNotNull(password);
93         this.password = password;
94         file = new File(filename);
95         load();
96     }
97
98     /**
99      * Adds the given authorization information to the database. The
100      * information is relevant for the specified protection space and the
101      * given authorization scheme. The protection space is defined by the
102      * combination of the given server URL and realm. The authorization
103      * scheme determines what the authorization information contains and how
104      * it should be used. The authorization information is a <code>Map</code>
105      * of <code>String</code> to <code>String</code> and typically
106      * contain information such as usernames and passwords.
107      *
108      * @param serverUrl the URL identifying the server for this authorization
109      * information. For example, "http://www.hostname.com/".
110      * @param realm the subsection of the given server to which this
111      * authorization information applies. For example,
112      * "realm1@hostname.com" or "" for no realm.
113      * @param authScheme the scheme for which this authorization information
114      * applies. For example, "Basic" or "" for no authorization scheme
115      * @param info a <code>Map</code> containing authorization information
116      * such as usernames and passwords
117      */

118     public void addAuthorizationInfo(URL JavaDoc serverUrl, String JavaDoc realm, String JavaDoc authScheme, Map info) {
119         Assert.isNotNull(serverUrl);
120         Assert.isNotNull(realm);
121         Assert.isNotNull(authScheme);
122         Assert.isNotNull(info);
123
124         String JavaDoc url = serverUrl.toString();
125         Hashtable realmToAuthScheme = (Hashtable) authorizationInfo.get(url);
126         if (realmToAuthScheme == null) {
127             realmToAuthScheme = new Hashtable(5);
128             authorizationInfo.put(url, realmToAuthScheme);
129         }
130
131         Hashtable authSchemeToInfo = (Hashtable) realmToAuthScheme.get(realm);
132         if (authSchemeToInfo == null) {
133             authSchemeToInfo = new Hashtable(5);
134             realmToAuthScheme.put(realm, authSchemeToInfo);
135         }
136
137         authSchemeToInfo.put(authScheme.toLowerCase(), info);
138         needsSaving = true;
139     }
140
141     /**
142      * Adds the specified resource to the protection space specified by the
143      * given realm. All resources at or deeper than the depth of the last
144      * symbolic element in the path of the given resource URL are assumed to
145      * be in the same protection space.
146      *
147      * @param resourceUrl the URL identifying the resources to be added to
148      * the specified protection space. For example,
149      * "http://www.hostname.com/folder/".
150      * @param realm the name of the protection space. For example,
151      * "realm1@hostname.com"
152      */

153     public void addProtectionSpace(URL JavaDoc resourceUrl, String JavaDoc realm) {
154         Assert.isNotNull(resourceUrl);
155         Assert.isNotNull(realm);
156
157         if (!resourceUrl.getFile().endsWith("/")) { //$NON-NLS-1$
158
resourceUrl = URLTool.getParent(resourceUrl);
159         }
160
161         String JavaDoc oldRealm = getProtectionSpace(resourceUrl);
162         if (oldRealm != null && oldRealm.equals(realm)) {
163             return;
164         }
165
166         String JavaDoc url1 = resourceUrl.toString();
167         Enumeration urls = protectionSpace.keys();
168         while (urls.hasMoreElements()) {
169             String JavaDoc url2 = (String JavaDoc) urls.nextElement();
170             if (url1.startsWith(url2) || url2.startsWith(url1)) {
171                 protectionSpace.remove(url2);
172                 break;
173             }
174         }
175
176         protectionSpace.put(url1, realm);
177         needsSaving = true;
178     }
179
180     /**
181      * Removes the authorization information for the specified protection
182      * space and given authorization scheme. The protection space is defined
183      * by the given server URL and realm.
184      *
185      * @param serverUrl the URL identifying the server to remove the
186      * authorization information for. For example,
187      * "http://www.hostname.com/".
188      * @param realm the subsection of the given server to remove the
189      * authorization information for. For example,
190      * "realm1@hostname.com" or "" for no realm.
191      * @param authScheme the scheme for which the authorization information
192      * to remove applies. For example, "Basic" or "" for no
193      * authorization scheme.
194      */

195     public void flushAuthorizationInfo(URL JavaDoc serverUrl, String JavaDoc realm, String JavaDoc authScheme) {
196         Hashtable realmToAuthScheme = (Hashtable) authorizationInfo.get(serverUrl.toString());
197
198         if (realmToAuthScheme == null) {
199             return;
200         }
201
202         Hashtable authSchemeToInfo = (Hashtable) realmToAuthScheme.get(realm);
203
204         if (authSchemeToInfo == null) {
205             return;
206         }
207
208         authSchemeToInfo.remove(authScheme.toLowerCase());
209
210         needsSaving = true;
211     }
212
213     /**
214      * Returns the authorization information for the specified protection
215      * space and given authorization scheme. The protection space is defined
216      * by the given server URL and realm. Returns <code>null</code> if no
217      * such information exists.
218      *
219      * @param serverUrl the URL identifying the server for the authorization
220      * information. For example, "http://www.hostname.com/".
221      * @param realm the subsection of the given server to which the
222      * authorization information applies. For example,
223      * "realm1@hostname.com" or "" for no realm.
224      * @param authScheme the scheme for which the authorization information
225      * applies. For example, "Basic" or "" for no authorization scheme
226      * @return the authorization information for the specified protection
227      * space and given authorization scheme, or <code>null</code> if no
228      * such information exists
229      */

230     public Map getAuthorizationInfo(URL JavaDoc serverUrl, String JavaDoc realm, String JavaDoc authScheme) {
231         Hashtable realmToAuthScheme = (Hashtable) authorizationInfo.get(serverUrl.toString());
232         if (realmToAuthScheme == null) {
233             return null;
234         }
235
236         Hashtable authSchemeToInfo = (Hashtable) realmToAuthScheme.get(realm);
237         if (authSchemeToInfo == null) {
238             return null;
239         }
240
241         return (Map) authSchemeToInfo.get(authScheme.toLowerCase());
242     }
243
244     /**
245      * Returns the protection space (realm) for the specified resource, or
246      * <code>null</code> if the realm is unknown.
247      *
248      * @param resourceUrl the URL of the resource whose protection space is
249      * returned. For example, "http://www.hostname.com/folder/".
250      * @return the protection space (realm) for the specified resource, or
251      * <code>null</code> if the realm is unknown
252      */

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

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

377     public boolean setPassword(String JavaDoc oldValue, String JavaDoc newValue) {
378         if (!oldValue.equals(password))
379             return false;
380         password = newValue;
381         needsSaving = true;
382         return true;
383     }
384 }
385
Popular Tags