Class BindProfileList

java.lang.Object
com.isode.dsapi.profile.BindProfileList
All Implemented Interfaces:
Iterable<BindProfile>

public class BindProfileList extends Object implements Iterable<BindProfile>
This class maintains a collection of BindProfile objects which are stored on disk in between separate invocations of an application. A BindProfileList may be read-only. This has two main effects:
  1. No passphrase is associated with the BindProfileList. When it is loaded from a file, any encrypted passwords in the file are ignored: the corresponding BindProfile objects will have null passwords
  2. While profiles can be added and removed from the list, it is not possible to save the list back to disk
Typically, a read-only BindProfileList is used in order to obtain sufficient information from the saved file to make anonymous connections (using BindProfile.anonymousBind()).

For non read-only objects, a passphrase may be associated with the BindProfileList, in which case sensitive data will be encrypted on the disk. In this case, the data can only be read back using the same password. A null passphrase in this case means that no encryption/decryption will be performed.

When loading encrypted data from disk, an exception will be thrown unless the correct passphrase is used.

When encryption is performed, DEFAULT_ALG and DEFAULT_MDALG specify the algorithms used. When the file is saved, these values will be stored in the file and used by the decryption routines to decrypt data (i.e. the algorithms don't need to be specified for a decrypt operation).

Versioning

Each BindProfileList instance has a version number. The version number determines the format of data stored in the file, and may restrict what functionality is available. The class can manipulate (load, use and save) files of any version up to and including LATEST_VERSION. The version number only needs changing in the event of an incompatible format change to the file, which gives the loadConfiguration() method a chance to fail in this case.

Note that updates to this class which introduce extra tags/data do not count as incompatible changes, since while this class ignores any such information, it preserves it when re-writing the output XML. An example of an incompatible change would be if the <dsa> tag were to be removed altogether, or the way that data is encrypted changed such that earlier versions are unable to decrypt it.

When a file is loaded that has a version number earlier than LATEST_VERSION, that version number will be preserved in the BindProfileList object, and used when the configuration is subsequently saved. This allows callers may safely manipulate "old" files without making them unusable by "old" clients. However, for such BindProfileFile objects, there may be constraints on what happens when you try and save them.

E.g. a BindProfile object which is making use of functionality that only started being supported by "v2" may be added to a "v1" BindProfileList, but an error will occur if an attempt is made to write that BindProfileList to disk without first upgrading it to at least "v2".

Callers should use isFullFeatured() to determine whether a BindProfileList is of an up-to-date format. To convert a BindProfileList from an "old" version, use makeLatestVersion(String). Having done this, subsequent saving of the data to a file will use the latest format. It is not possible to "demote" a BindProfileList to an earlier version.

The idea is that callers can, when loading a BindProfileList, check to see if it's at the latest version, and offer users the ability to update it if they want to, or restrict functionality otherwise.

Author:
nh
  • Field Details

    • EXTRAINFOTAG_LASTUPDATER

      public static final String EXTRAINFOTAG_LASTUPDATER
      See Also:
    • V1_VERSION

      public static final int V1_VERSION
      See Also:
    • V2_VERSION

      public static final int V2_VERSION
      See Also:
    • V3_VERSION

      public static final int V3_VERSION
      See Also:
    • LATEST_VERSION

      public static final int LATEST_VERSION
      Implementation version number. This provides a mechanism for tracking incompatible changes to the content of bind profile files, and should only be changed if a change is made to the way that the files are stored on disk which means that an earlier version would not be able to process the file.

      The initial implementation of BindProfileList had no version number, and so any files written using that will be treated by this implementation as being version "1".

      Whenever a bind profile file is written, this version number is included in the file header. Whenever a bind profile file is loaded, the class makes sure that the file has a version which is no greater than this value.

      See Also:
    • SALT_LENGTH

      public static final int SALT_LENGTH
      Length of salt used when performing encryption. Salted encryption is only used for BindProfileFiles that have a version greater than V1_VERSION. No knowledge of the salt is used when performing decryption, so changing the length here will not result in any risk of "undecryptable" files. The value chosen here is purely arbitrary; larger values may make the encryption slightly more secure.
      See Also:
    • bindList

      protected ArrayList<BindProfile> bindList
    • filename

      protected String filename
    • fw

      protected FileWriter fw
  • Constructor Details

    • BindProfileList

      public BindProfileList(String filename)
      Create a new "read-only" BindProfileList object, used only for reading an existing file, and not making any attempt to decrypt encrypted passwords.
      Parameters:
      filename - filename to be associated with this object. (not null)
      See Also:
    • BindProfileList

      public BindProfileList(String filename, String passphrase)
      Create a new BindProfileList object. After the object has been created, it can be used to load or save a list of BindProfiles to the specified file.
      Parameters:
      filename - filename to be associated with this object. (not null)
      passphrase - the passphrase to be used to encrypt or decrypt sensitive data. If no encryption is required, use null.
      Throws:
      NullPointerException - if filename is null.
      See Also:
  • Method Details

    • setPassphrase

      public void setPassphrase(String passphrase)
      Set the passphrase that will be used to next time this BindProfileList is loaded or saved. This method has no effect for a read-only BindProfileList.
      Parameters:
      passphrase - A passphrase to use. A value of null means no encryption/decryption will be performed.
    • addProfile

      public void addProfile(BindProfile bp) throws OperationFailedException
      Adds a new BindProfile to the list.
      Parameters:
      bp - the BindProfile to add
      Throws:
      OperationFailedException - if a profile already exists with the access point with same DSA DN as in the given bind profile.
    • removeBindProfile

      public boolean removeBindProfile(BindProfile bp, BindProfileList.RemoveMode removeMode)
      Removes a BindProfile from the list.
      Parameters:
      bp - the BindProfile to remove. If bp is not in the list, this method has no effect. Should not be null.
      removeMode - The BindProfileList.RemoveMode to operate in. If BindProfileList.RemoveMode.FAIL then if the bind profile looks like it may be being referred to elsewhere then the removal will fail and the method will return with value false. If null will be treated as BindProfileList.RemoveMode.FORCE
      Returns:
      true unless the removal fails due to the bind profile looking like it is referred to when the BindProfileList.RemoveMode is set to BindProfileList.RemoveMode.FAIL
    • getCount

      public int getCount()
      Determine how many BindProfiles are in the list.
      Returns:
      the number of BindProfiles in the list.
    • getProfile

      public BindProfile getProfile(int index)
      Return a specific BindProfile.
      Parameters:
      index - the BindProfile to return. This must be a value between 0 and one less than the value returned by getCount()
      Returns:
      a BindProfile
      Throws:
      ArrayIndexOutOfBoundsException - if index is not in range.
      See Also:
    • getProfile

      public BindProfile getProfile(String name)
      Return a specific BindProfile by its display-name.
      Parameters:
      name - The name of the BindProfile to return
      Returns:
      The BindProfile, or null if not found
    • getProfile

      public BindProfile getProfile(DN knownDsaDN)
      Return a specific BindProfile by its access point DN.
      Parameters:
      knownDsaDN - The access point DN of the BindProfile to return, (can be null)
      Returns:
      The BindProfile, or 'null' if not found or access point DN was null
    • addExtraInfo

      public void addExtraInfo(String tagName, String value)
      Set the extra info parameters on the bind profile
      Parameters:
      tagName - tag name
      value - value for the tag. Note any whitespace in value will not be preserved.
      Since:
      15.0
    • getExtraInfoForTag

      public String getExtraInfoForTag(String tagName)
      Get the extraInfo value given the tag name
      Parameters:
      tagName - extra info tag name
      Returns:
      extra info value for given tag
      Since:
      15.0
    • setBindProfileModifyWatcher

      public BindProfileModifyWatcher setBindProfileModifyWatcher(BindProfileModifyWatcher bplModifyWatcher)
      Set a watcher that gets notified of changes to bind profile file by an external program when the bind-profile list is saved to disk using the call saveConfiguration(). The watcher is responsible for the action to be taken in such a scenario which could be either overwrite or reload.
      Parameters:
      bplModifyWatcher - Bind Profile List modify Watcher, use null to remove any existing watcher
      Returns:
      old bind profile watcher if any or null
      Since:
      15.0
    • readExtraInfo

      public String readExtraInfo(String tag, String defaultVal)
      Read the extraInfo xml to get the value for the given tag name.
      Parameters:
      tag - tagName to search for in the extra info
      defaultVal - default value to return if the tag is not found in the extra info
      Returns:
      value of the given tag as found in the extraInfo xml tag or the defaultVaL if no such tag is found
      Since:
      15.0
    • isPassphraseModifiedSinceLastLoad

      public boolean isPassphraseModifiedSinceLastLoad()
      This function reads the bind profile file just to get the encryption info to figure out if the bind profile passphrase has been changed or not
      Returns:
      true if the passphrase has been modified since the file was last loaded
      Since:
      15.0
    • saveConfiguration

      public boolean saveConfiguration() throws IOException
      Save the list of BindProfiles to disk, encrypting sensitive data if a passphrase has been set. If a bindprofile modify watcher has been set using the call setBindProfileModifyWatcher(BindProfileModifyWatcher), it will be asked for action to be taken if the bind profile file has been changed externally.

      This method cannot be used for a read-only BindProfileList; attempts to call this method for such an object will result in an IOException.

      The format of the file that is written will be determined by the version number associated with this object as returned from getFileVersion(). If any of the BindProfiles make use of functionality that is not supported by this file format, a IOException will be thrown.

      Returns:
      TRUE if bind profile list was saved to disk, FALSE otherwise (maybe the user decided not to save it if it was simultaneously updated by another application).
      Throws:
      NativeLibraryException - if an unrecoverable error was detected by the native library.
      IOException - if this is a read-only BindProfileList, or if an error occurred when writing to the file (including if one of the BindProfile objects relies on functionality which is not supported for this version of file)
      See Also:
    • getLastModifiedDateOfBindProfile

      public Date getLastModifiedDateOfBindProfile()
      Get the last modified date of the bind profile file.
      Returns:
      last modified date
    • removePrefix

      public static String removePrefix(String decrypted, String expectedPrefix) throws EncryptionException
      Verify that a decrypted String begins with a prefix, and return the String, minus the prefix, if it does. This verifies that the passphrase used to decrypt was correct (since an invalid passphrase would not prevent decryption from working, but would return a String that didn't begin with the correct prefix).
      Parameters:
      decrypted - a String returned from a decryption operation
      expectedPrefix - the prefix which decrypted should begin with assuming it got decrypted properly.
      Returns:
      decrypted with expectedPrefix removed
      Throws:
      EncryptionException - if decrypted didn't begin with expectedPrefix. This means that the passphrase used for decryption was incorrect.
    • addTrustAnchor

      public String addTrustAnchor(SSLCertificate cert) throws IOException
      Add a trust anchor to the bind profile and associated trust store
      Parameters:
      cert - certificate to be added, not null
      Returns:
      key used in bind profile to refer the trust anchor, not null
      Throws:
      IOException - if there was an error while adding the trust anchor
      Since:
      16.3
    • removeTrustAnchor

      public void removeTrustAnchor(String key) throws IOException
      Remove the trust anchor from the bind profile and associated trust store
      Parameters:
      key - key used for referring trust anchor, no action would be taken if null
      Throws:
      IOException - if there was an error while removing the trust anhor
      Since:
      16.3
    • getTrustAnchors

      public Map<String,SSLCertificate> getTrustAnchors()
      Get the trust anchors in the bind profile along with associated keys used to refer them in the bind profile
      Returns:
      trust anchors, not null but can be empty
      Since:
      16.3
    • getTrustAnchorList

      public List<SSLCertificate> getTrustAnchorList()
      Get the trust anchors from the bind profile list
      Returns:
      trust anchors, not null but can be empty
      Since:
      16.3
    • getTrustAnchorsExtraXML

      public List<String> getTrustAnchorsExtraXML()
      Get the list of unparsed XML in the trust anchor section
      Returns:
      list of unparsed XML, can be empty not null
      Since:
      16.3
    • loadConfiguration

      public void loadConfiguration() throws FileNotFoundException, SAXException, EncryptionException
      Load the list of BindProfiles from disk.

      If this is a read-only BindProfileList, then any encrypted passwords in the file will be ignored, and the corresponding BindProfile password set to null.

      In other cases, the passphrase will be used to decrypt any sensitive data in the file, and an EncryptionException will be thrown if the decryption fails.

      Throws:
      FileNotFoundException - if the file does not exist.
      EncryptionException - if the data could not be decrypted and this is not a read-only BindProfileList.
      SAXException - if the XML could not be parsed, or if it has a version number greater than LATEST_VERSION).
      NativeLibraryException - if an unrecoverable error was detected by the native library.
      See Also:
    • toString

      public String toString()
      Returns a user-friendly String representation of this object.
      Overrides:
      toString in class Object
      Returns:
      a String representation of the object.
    • hasPassphrase

      public boolean hasPassphrase()
      Determine whether the BindProfileList has had a passphrase associated with it.
      Returns:
      true if the data will be decrypted when a load is performed, and encrypted when a save is performed; false otherwise.
    • iterator

      public Iterator<BindProfile> iterator()
      Returns an Iterator over the contained BindProfile instances.
      Specified by:
      iterator in interface Iterable<BindProfile>
      Returns:
      Iterator
    • makeLatestVersion

      public void makeLatestVersion(String newFilename)
      Promote this object to one which has the latest functionality, and/or specify the name of the file to which the object should be saved.
      Parameters:
      newFilename - the name of the file that will be used if the object is saved to disk
      Since:
      14.6
      See Also:
    • isFullFeatured

      public boolean isFullFeatured()
      Determine whether this BindProfileList is one which is fully compatible with the latest functionality. Specifically, in the case of V1 BindProfileList files, it may not be possible to store all the data a BindProfile object without risking breaking V1 clients. So callers may use this method to determine whether there is a possibility of data being lost, and provide suitable warnings to users.

      Note that if the method returns false, it doesn't mean that data will be lost, just that it might be.

      Returns:
      true if it's safe to use this object to store any BindProfile data; false if there is a chance that the file format limits the fields in a BindProfile which can be saved.
      Since:
      14.6
      See Also:
    • getFileVersion

      public int getFileVersion()
      Returns the version of the BindProfileFile. For a newly created object, this value will be equal to LATEST_VERSION. This may change if loadConfiguration() is used to read from a file which is of an older format.
      Returns:
      the version of this object, which determines the format of the file that will be written if you call saveConfiguration().
      Since:
      14.6
    • getFileName

      public String getFileName()
      Get the name of the file which holds this BindProfile list
      Returns:
      name of file, which will not be null
      Since:
      16.6
    • getExtraXML

      public String getExtraXML()
      Return a String containing any "extra" XML (tags and contents) that were loaded from the BindProfileFile but not parsed. This data will be re-written to the file if it is saved.
      Returns:
      a String containing all the XML which was not parsed, or null if there was none.
      Since:
      14.6
      See Also:
    • getFileInIdentitiesDirectory

      public static File getFileInIdentitiesDirectory(String s)
      Determine whether a given String represents the absolute pathname of a .p12 file that exists inside the directory that's used to save copies of identities for bind profiles. For example, a String such as "/home/nh/.isode/Identities/a1b7b779e07044e59403bf44a99e90d9.p12" would result in a File object for the corresponding file being returned, assuming the file actually exists. A String such as "a1b7b779e07044e59403bf44a99e90d9.p12" would NOT be resolved, because it's not an absolute file path.
      Parameters:
      s - a String containing the full path of a putative P12 file. May be null.
      Returns:
      File object corresponding to s if s is the name of a file which exists in the Identities directory, null otherwise (including if s is null).
      Since:
      16.0
    • isReadOnly

      public boolean isReadOnly()
      Determine whether this object is "read-only". A BindProfileList will be read-only if it has been loaded without a passphrase having been specified. While it is possible to make changes to the contents of a read-only BindProfileList, any attempt to write it to disk will fail.
      Returns:
      true if this is a read-only BindProfileList, false otherwise.
      Since:
      14.6
      See Also:
    • reLoad

      public void reLoad(String newPassphrase) throws IOException, SAXException, EncryptionException
      Reload the bind profile file from the disk. The list will be restored back in case of failure.
      Parameters:
      newPassphrase - new passphrase with which the file should be reloaded or null if the passphrase is not changed since last load
      Throws:
      IOException - if there is an error reading the file
      SAXException - if the xml is not correct
      EncryptionException - if the bind profile cannot be decrypted with current passphrase. This may happen if the profile's passphrase has changed by external program
      Since:
      15.0
    • makeNameUnique

      public void makeNameUnique(BindProfile bp)
      Make the name of a bind profile unique by appending numbers. This will help in GUIs using bind wizard when users attempt to duplicate a name, rather than sticking up dialogue boxes or whatever. May be used for profiles already present in the BindProfileList, or new profiles about to be added.
      Parameters:
      bp - Bind profile whose display name needs to be made unique
    • makeNameUnique

      public String makeNameUnique(String name)
      Make a bind profile name unique by appending numbers. This will help in GUIs using bind wizard when users attempt to duplicate a name, rather than sticking up dialogue boxes or whatever. May be used for profiles already present in the BindProfileList, or new profiles about to be added.
      Parameters:
      name - Name to make unique
      Returns:
      Either the same name, or a new name if it clashed with an existing bind profile name
    • getProfileWithID

      public Optional<BindProfile> getProfileWithID(String id)
      Get the BindProfile with the given unique id.
      Parameters:
      id - The id to search for a matching bind profile for.
      Returns:
      If there is a BindProfile with the given id value then a Optional containing that BindProfile otherwise an empty Optional