blob: d99ddda21d8f6d289d075adcf0d4cbbb15dc82f0 [file] [log] [blame]
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;
}
}