/******************************************************************************* * Copyright (c) 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.equinox.security.storage; import java.io.IOException; /** * This interface describes functionality provided by secure preferences. Secure * preferences can be used to persist sensitive information in an encrypted form. * <p> * Logically, secure preferences combine functionality of a keyring (keystore) and * {@link org.osgi.service.prefs.Preferences}. * </p><p> * For an excellent detailed description of the preferences functionality see * {@link org.osgi.service.prefs.Preferences}. To recap in a short form, preferences * provide a tree. Nodes on that tree can be used to specify context. For instance, * root node could have a child node called "cvs" to store information related to CVS * integration. * </p><p> * Each node can have a map of keys with associated values. For instance, to store * password for the CVS repository located on eclipse.org we could use the following * code: * </p> * <pre> * ISecurePreferences root = SecurePreferencesFactory.getDefault(); * ISecurePreferences node = root.node("cvs/eclipse.org"); * node.put("password", myPassword, true); * </pre> * <p> * This interface has the following differences from the {@link org.osgi.service.prefs.Preferences}: * <ul> * <li>get...() and put...() methods throw StorageException</li> * <li>put...() methods have an extra argument bEncrypt</li> * <li>Methods that used to throw BackingStoreException will be throwing more detailed StorageException</li> * <li>Navigation on preferences tree will return ISecurePreferences, as opposing to Preferences</li> * <li>flush() throws IOException</li> * <li>sync() method is removed</li> * </ul> * </p><p> * On the keyring side, when adding a key to the node, you can ask framework to encrypt it. Framework * will lazily acquire password from password provider and use it to encrypt all new entries added * to the secure preferences tree in this session. * </p><p> * It is worthwhile to reiterate that same limitations as {@link org.osgi.service.prefs.Preferences} * apply to the node names. One non-trivial limitation is that node names can not contain forward * slashes. For convenience, utility methods {@link EncodingUtils#encodeSlashes(String)} and * {@link EncodingUtils#decodeSlashes(String)} are provided to work around this limitation. * </p><p> * Also note that secure preferences only intended to store relatively small size data, such as * passwords. If you need to securely store large objects, consider encrypting such objects in * a symmetric way using randomly generated password and use secure preferences to store the password. * </p><p> * If secure preferences were modified, the framework will automatically save them on shutdown. * </p><p> * This interface is not intended to be implemented or extended by clients. * </p> * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ public interface ISecurePreferences { /** * Stores a value associated with the key in this node. * @param key key with which the value is going to be associated * @param value value to store * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value * does not need to be encrypted * @throws StorageException if exception occurred during encryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. * @throws NullPointerException if <code>key</code> is <code>null</code>. */ public void put(String key, String value, boolean encrypt) throws StorageException; /** * Retrieves a value associated with the key in this node. If the value was encrypted, * it is decrypted. * @param key key with this the value is associated * @param def default value to return if the key is not associated with any value * @return value associated the key. If value was stored in an encrypted form, it will be decrypted * @throws StorageException if exception occurred during decryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public String get(String key, String def) throws StorageException; /** * Removes value associated with the key. * @param key key with which a value is associated * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public void remove(String key); /** * Removes all values from this node. * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public void clear(); /** * Returns keys that have associated values. * @return keys that have associated values * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public String[] keys(); /** * Returns names of children nodes * @return names of children nodes * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public String[] childrenNames(); /** * Returns parent of this node * @return parent of this node * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public ISecurePreferences parent(); /** * Returns node corresponding to the path specified. If such node does not * exist, a new node is created. * <p> * If the node path is invalid, an {@link IllegalArgumentException} will be thrown * by this method. The valid node path: * <ul> * <li>contains only ASCII characters between 32 and 126 (ASCII alphanumeric and printable * characters);</li> * <li>can not contain two or more consecutive forward slashes;</li> * <li>can not end with a trailing forward slash.</li> * </ul> * </p> * @see org.osgi.service.prefs.Preferences * @see org.osgi.service.prefs.Preferences#node(String) * @param pathName absolute or relative path to the node * @return node corresponding to the path * @throws IllegalArgumentException if the path name is invalid. * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public ISecurePreferences node(String pathName); /** * Checks if the node corresponding to the specified path exists in this tree * of secure preferences. * <p> * If the node path is invalid, an {@link IllegalArgumentException} will be thrown * by this method. See {@link #node(String)} for the description of what is considered * to be a valid path. * </p> * @see org.osgi.service.prefs.Preferences * @see org.osgi.service.prefs.Preferences#node(String) * @param pathName absolute or relative path to the node * @return <code>true</code> if node corresponding to the path exists, <code>false</code> otherwise * @throws IllegalArgumentException if the path name is invalid. * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public boolean nodeExists(String pathName); /** * Removes this node from the tree of secure preferences. * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public void removeNode(); /** * Returns name of this node. * @return name of this node * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public String name(); /** * Returns absolute path to this node. * @return absolute path to this node * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public String absolutePath(); /** * Saves the tree of secure preferences to the persistent storage. This method can be called * on any node in the secure preference tree. * @throws IOException if error occurred while saving secure preferences */ public void flush() throws IOException; /** * Stores a value associated with the key in this node. * @param key key with which the value is going to be associated * @param value value to store * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value * does not need to be encrypted * @throws StorageException if exception occurred during encryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. * @throws NullPointerException if <code>key</code> is <code>null</code>. */ public void putInt(String key, int value, boolean encrypt) throws StorageException; /** * Retrieves a value associated with the key in this node. If the value was encrypted, * it is decrypted. * @param key key with this the value is associated * @param def default value to return if the key is not associated with any value * @return value associated the key. If value was stored in an encrypted form, it will be decrypted * @throws StorageException if exception occurred during decryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public int getInt(String key, int def) throws StorageException; /** * Stores a value associated with the key in this node. * @param key key with which the value is going to be associated * @param value value to store * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value * does not need to be encrypted * @throws StorageException if exception occurred during encryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. * @throws NullPointerException if <code>key</code> is <code>null</code>. */ public void putLong(String key, long value, boolean encrypt) throws StorageException; /** * Retrieves a value associated with the key in this node. If the value was encrypted, * it is decrypted. * @param key key with this the value is associated * @param def default value to return if the key is not associated with any value * @return value associated the key. If value was stored in an encrypted form, it will be decrypted * @throws StorageException if exception occurred during decryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public long getLong(String key, long def) throws StorageException; /** * Stores a value associated with the key in this node. * @param key key with which the value is going to be associated * @param value value to store * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value * does not need to be encrypted * @throws StorageException if exception occurred during encryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. * @throws NullPointerException if <code>key</code> is <code>null</code>. */ public void putBoolean(String key, boolean value, boolean encrypt) throws StorageException; /** * Retrieves a value associated with the key in this node. If the value was encrypted, * it is decrypted. * @param key key with this the value is associated * @param def default value to return if the key is not associated with any value * @return value associated the key. If value was stored in an encrypted form, it will be decrypted * @throws StorageException if exception occurred during decryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public boolean getBoolean(String key, boolean def) throws StorageException; /** * Stores a value associated with the key in this node. * @param key key with which the value is going to be associated * @param value value to store * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value * does not need to be encrypted * @throws StorageException if exception occurred during encryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. * @throws NullPointerException if <code>key</code> is <code>null</code>. */ public void putFloat(String key, float value, boolean encrypt) throws StorageException; /** * Retrieves a value associated with the key in this node. If the value was encrypted, * it is decrypted. * @param key key with this the value is associated * @param def default value to return if the key is not associated with any value * @return value associated the key. If value was stored in an encrypted form, it will be decrypted * @throws StorageException if exception occurred during decryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public float getFloat(String key, float def) throws StorageException; /** * Stores a value associated with the key in this node. * @param key key with which the value is going to be associated * @param value value to store * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value * does not need to be encrypted * @throws StorageException if exception occurred during encryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. * @throws NullPointerException if <code>key</code> is <code>null</code>. */ public void putDouble(String key, double value, boolean encrypt) throws StorageException; /** * Retrieves a value associated with the key in this node. If the value was encrypted, * it is decrypted. * @param key key with this the value is associated * @param def default value to return if the key is not associated with any value * @return value associated the key. If value was stored in an encrypted form, it will be decrypted * @throws StorageException if exception occurred during decryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public double getDouble(String key, double def) throws StorageException; /** * Stores a value associated with the key in this node. * @param key key with which the value is going to be associated * @param value value to store * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value * does not need to be encrypted * @throws StorageException if exception occurred during encryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. * @throws NullPointerException if <code>key</code> is <code>null</code>. */ public void putByteArray(String key, byte[] value, boolean encrypt) throws StorageException; /** * Retrieves a value associated with the key in this node. If the value was encrypted, * it is decrypted. * @param key key with this the value is associated * @param def default value to return if the key is not associated with any value * @return value associated the key. If value was stored in an encrypted form, it will be decrypted * @throws StorageException if exception occurred during decryption * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public byte[] getByteArray(String key, byte[] def) throws StorageException; /** * Specifies if value associated with the key is encrypted. * @param key key with which a value is associated * @return <code>true</code> if value is encrypted, <code>false</code> otherwise * @throws StorageException if stored data is invalid * @throws IllegalStateException if this node (or an ancestor) has been removed with * the {@link #removeNode()} method. */ public boolean isEncrypted(String key) throws StorageException; }