package org.eclipse.core.internal.runtime; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import org.eclipse.core.runtime.*; | |
import java.io.*; | |
import java.net.*; | |
import java.util.*; | |
/** | |
* A database that remembers information, such as usernames and | |
* passwords. The information is stored in memory and can be saved | |
* to disk in an encrypted format. While the API is phrased in terms of | |
* URLs, realms and authentication schemes, not all of these must have | |
* significant values. For example, if "realm" is not relevant to a | |
* particular application, it can be left blank (though not | |
* <code>null</code>). | |
*/ | |
public class AuthorizationDatabase { | |
/** | |
* A nested hashtable that stores authorization information. The | |
* table maps server URLs to realms to authentication schemes to | |
* authorization information. | |
*/ | |
private Hashtable authorizationInfo = new Hashtable(5); | |
/** | |
* A hashtable mapping resource URLs to realms. | |
*/ | |
private Hashtable protectionSpace = new Hashtable(5); | |
private File file = null; | |
private String password = null; | |
private boolean needsSaving = true; | |
/** | |
* Creates a new authorization database whose data cannot be saved to | |
* disk. | |
*/ | |
public AuthorizationDatabase() { | |
} | |
/** | |
* Creates a new authorization database, or opens an existing one, whose | |
* data is, or can be, saved to a file with the given filename. A | |
* password must be given to create a new database and an existing | |
* database is opened by supplying the password that was given to create | |
* it. | |
* | |
* @param filename the location of the database on disk. For example, | |
* "c:/temp/database" | |
* @param password the password to access the database. For example, | |
* "secret" | |
* @exception Exception if there are problems creating the database. | |
* Reasons include: | |
* <ul> | |
* <li>The database could not be opened because the wrong password was given. | |
* <li>The database could not be opened because the specified file is corrupt. | |
* </ul> | |
*/ | |
public AuthorizationDatabase(String filename, String password) throws CoreException { | |
Assert.isNotNull(filename); | |
Assert.isNotNull(password); | |
this.password = password; | |
file = new File(filename); | |
load(); | |
} | |
/** | |
* Adds the given authorization information to the database. The | |
* information is relevant for the specified protection space and the | |
* given authorization scheme. The protection space is defined by the | |
* combination of the given server URL and realm. The authorization | |
* scheme determines what the authorization information contains and how | |
* it should be used. The authorization information is a <code>Map</code> | |
* of <code>String</code> to <code>String</code> and typically | |
* contain information such as usernames and passwords. | |
* | |
* @param serverUrl the URL identifying the server for this authorization | |
* information. For example, "http://www.hostname.com/". | |
* @param realm the subsection of the given server to which this | |
* authorization information applies. For example, | |
* "realm1@hostname.com" or "" for no realm. | |
* @param authScheme the scheme for which this authorization information | |
* applies. For example, "Basic" or "" for no authorization scheme | |
* @param info a <code>Map</code> containing authorization information | |
* such as usernames and passwords | |
*/ | |
public void addAuthorizationInfo(URL serverUrl, String realm, String authScheme, Map info){ | |
Assert.isNotNull(serverUrl); | |
Assert.isNotNull(realm); | |
Assert.isNotNull(authScheme); | |
Assert.isNotNull(info); | |
String url = serverUrl.toString(); | |
Hashtable realmToAuthScheme = (Hashtable)authorizationInfo.get(url); | |
if(realmToAuthScheme == null){ | |
realmToAuthScheme = new Hashtable(5); | |
authorizationInfo.put(url, realmToAuthScheme); | |
} | |
Hashtable authSchemeToInfo = (Hashtable)realmToAuthScheme.get(realm); | |
if(authSchemeToInfo == null){ | |
authSchemeToInfo = new Hashtable(5); | |
realmToAuthScheme.put(realm, authSchemeToInfo); | |
} | |
authSchemeToInfo.put(authScheme.toLowerCase(), info); | |
needsSaving = true; | |
} | |
/** | |
* Adds the specified resource to the protection space specified by the | |
* given realm. All resources at or deeper than the depth of the last | |
* symbolic element in the path of the given resource URL are assumed to | |
* be in the same protection space. | |
* | |
* @param resourceUrl the URL identifying the resources to be added to | |
* the specified protection space. For example, | |
* "http://www.hostname.com/folder/". | |
* @param realm the name of the protection space. For example, | |
* "realm1@hostname.com" | |
*/ | |
public void addProtectionSpace(URL resourceUrl, String realm){ | |
Assert.isNotNull(resourceUrl); | |
Assert.isNotNull(realm); | |
String file = resourceUrl.getFile(); | |
if(!file.endsWith("/")){ | |
resourceUrl = URLTool.getParent(resourceUrl); | |
} | |
String oldRealm = getProtectionSpace(resourceUrl); | |
if(oldRealm != null && oldRealm.equals(realm)){ | |
return; | |
} | |
String url1 = resourceUrl.toString(); | |
Enumeration urls = protectionSpace.keys(); | |
while(urls.hasMoreElements()){ | |
String url2 = (String)urls.nextElement(); | |
if(url1.startsWith(url2) || url2.startsWith(url1)){ | |
protectionSpace.remove(url2); | |
break; | |
} | |
} | |
protectionSpace.put(url1, realm); | |
needsSaving = true; | |
} | |
/** | |
* Removes the authorization information for the specified protection | |
* space and given authorization scheme. The protection space is defined | |
* by the given server URL and realm. | |
* | |
* @param serverUrl the URL identifying the server to remove the | |
* authorization information for. For example, | |
* "http://www.hostname.com/". | |
* @param realm the subsection of the given server to remove the | |
* authorization information for. For example, | |
* "realm1@hostname.com" or "" for no realm. | |
* @param authScheme the scheme for which the authorization information | |
* to remove applies. For example, "Basic" or "" for no | |
* authorization scheme. | |
*/ | |
public void flushAuthorizationInfo(URL serverUrl, String realm, String authScheme) { | |
Hashtable realmToAuthScheme = (Hashtable)authorizationInfo.get(serverUrl.toString()); | |
if(realmToAuthScheme == null){ | |
return; | |
} | |
Hashtable authSchemeToInfo = (Hashtable)realmToAuthScheme.get(realm); | |
if(authSchemeToInfo == null){ | |
return; | |
} | |
authSchemeToInfo.remove(authScheme.toLowerCase()); | |
needsSaving = true; | |
} | |
/** | |
* Returns the authorization information for the specified protection | |
* space and given authorization scheme. The protection space is defined | |
* by the given server URL and realm. Returns <code>null</code> if no | |
* such information exists. | |
* | |
* @param serverUrl the URL identifying the server for the authorization | |
* information. For example, "http://www.hostname.com/". | |
* @param realm the subsection of the given server to which the | |
* authorization information applies. For example, | |
* "realm1@hostname.com" or "" for no realm. | |
* @param authScheme the scheme for which the authorization information | |
* applies. For example, "Basic" or "" for no authorization scheme | |
* @return the authorization information for the specified protection | |
* space and given authorization scheme, or <code>null</code> if no | |
* such information exists | |
*/ | |
public Map getAuthorizationInfo(URL serverUrl, String realm, String authScheme){ | |
Hashtable realmToAuthScheme = (Hashtable)authorizationInfo.get(serverUrl.toString()); | |
if(realmToAuthScheme == null){ | |
return null; | |
} | |
Hashtable authSchemeToInfo = (Hashtable)realmToAuthScheme.get(realm); | |
if(authSchemeToInfo == null){ | |
return null; | |
} | |
return (Map)authSchemeToInfo.get(authScheme.toLowerCase()); | |
} | |
/** | |
* Returns the protection space (realm) for the specified resource, or | |
* <code>null</code> if the realm is unknown. | |
* | |
* @param resourceUrl the URL of the resource whose protection space is | |
* returned. For example, "http://www.hostname.com/folder/". | |
* @return the protection space (realm) for the specified resource, or | |
* <code>null</code> if the realm is unknown | |
*/ | |
public String getProtectionSpace(URL resourceUrl){ | |
while(resourceUrl != null){ | |
String realm = (String)protectionSpace.get(resourceUrl.toString()); | |
if(realm != null){ | |
return realm; | |
} | |
resourceUrl = URLTool.getParent(resourceUrl); | |
} | |
return null; | |
} | |
private void load() throws CoreException { | |
if (file == null) | |
return; | |
if (!file.exists()) { | |
save(); | |
return; | |
} | |
try { | |
InputStream input = new FileInputStream(file); | |
try { | |
load(input); | |
} finally { | |
input.close(); | |
} | |
} catch (IOException e) { | |
throw new CoreException(new Status(IStatus.ERROR,Platform.PI_RUNTIME,13,Policy.bind("meta.unableToReadAuthorization",file.toString()),e)); | |
} catch (ClassNotFoundException e) { | |
throw new CoreException(new Status(IStatus.ERROR,Platform.PI_RUNTIME,13,Policy.bind("meta.unableToReadAuthorization",file.toString()),e)); | |
} | |
} | |
private void load(InputStream is) throws IOException, ClassNotFoundException { | |
CipherInputStream cis = new CipherInputStream(is, password); | |
ObjectInputStream ois = new ObjectInputStream(cis); | |
authorizationInfo = (Hashtable) ois.readObject(); | |
protectionSpace = (Hashtable) ois.readObject(); | |
ois.close(); | |
} | |
/** | |
* Saves the authorization database to disk. | |
*/ | |
public void save() throws CoreException { | |
if (!needsSaving || file == null) | |
return; | |
try { | |
file.delete(); | |
file.createNewFile(); | |
save(new FileOutputStream(file)); | |
} catch (IOException e) { | |
throw new CoreException(new Status(IStatus.ERROR,Platform.PI_RUNTIME,13,Policy.bind("meta.unableToWriteAuthorization",file.toString()),e)); | |
} | |
needsSaving = false; | |
} | |
private void save(OutputStream os) throws IOException { | |
CipherOutputStream cos = new CipherOutputStream(os, password); | |
ObjectOutputStream oos = new ObjectOutputStream(cos); | |
oos.writeObject(authorizationInfo); | |
oos.writeObject(protectionSpace); | |
oos.close(); | |
} | |
/** | |
* Sets the password to use for accessing this database. If the database | |
* is subsequently saved, this new password is used. | |
*/ | |
public boolean setPassword(String oldValue, String newValue) { | |
if (!oldValue.equals(password)) | |
return false; | |
password = newValue; | |
needsSaving = true; | |
return true; | |
} | |
} |