001    package org.cumulus4j.keymanager.api;
002    
003    import java.io.IOException;
004    
005    /**
006     * <p>
007     * A <code>CryptoSession</code> is a session in which key transfers can be performed.
008     * </p><p>
009     * Use {@link KeyManagerAPI#getCryptoSession(String)} to get a <code>CryptoSession</code> instance.
010     * This instance is a proxy which can be kept and never expires (though the underlying real session will expire if
011     * not used for some time). If the underlying real
012     * session expired, a new underlying session with a new <code>cryptoSessionID</code>
013     * will be created and bound to this <code>CryptoSession</code> instance.
014     * </p><p>
015     * <code>CryptoSession</code>s are thread-safe.
016     * </p>
017     *
018     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
019     */
020    public interface CryptoSession
021    {
022            /**
023             * Get the identifier of the application server. This denotes a logical application server, which
024             * can be composed of many physical machines (in a cluster/cloud).
025             * @return the application server's ID; never <code>null</code>.
026             */
027            String getAppServerID();
028    
029            /**
030             * Get the base-url of the app-server-key-manager-channel. This is the part of the URL before the "/KeyManagerChannel" -
031             * e.g. if the REST URL of the KeyManagerChannel-service is
032             * "https://serverUsingCumulus4j.mydomain.org/org.cumulus4j.keymanager.back.webapp/KeyManagerChannel", then this must be
033             * "https://serverUsingCumulus4j.mydomain.org/org.cumulus4j.keymanager.back.webapp".
034             * @return the base-URL before the "/KeyManagerChannel".
035             */
036            String getAppServerBaseURL();
037    
038            /**
039             * <p>
040             * Acquire an unlocked underlying real session.
041             * </p><p>
042             * The application server is only able to request keys from the key manager, while a crypto-session is
043             * acquired. It thus needs to be acquired, first, before it can be used for key transfers.
044             * </p><p>
045             * <b>Important:</b> It is essential that you call {@link #release()} once for every time you called <code>acquire()</code>.
046             * You should therefore use a try-finally-block like this:
047             * </p>
048             * <pre>
049             * String cryptoSessionID = session.acquire();
050             * try {
051             *
052             *      // Do some operation that requires key access. For example
053             *      // call an EJB method or perform a SOAP/REST request which
054             *      // will make your app server read/write data.
055             *
056             * } finally {
057             *      session.release();
058             * }
059             * </pre>
060             * <p>
061             * If multiple threads use the same <code>CryptoSession</code> (recommended!), the underlying real session will be
062             * acquired (unlocked) when the first thread requires it and it will be locked again when the last thread calls
063             * <code>release()</code>.
064             * However, releasing (locking) does not need to happen immediately. Instead it can be deferred a few seconds, in
065             * case a new <code>acquire()</code> would happen quickly again. This
066             * strategy is usually used with a remote key server (when latency makes acquiring/releasing a pretty expensive
067             * operation).
068             * </p>
069             * @return the cryptoSessionID to be used within the acquire-release-block for key-management. This ID must be
070             * passed to your application server in order to allow it perform database operations.
071             * @throws AuthenticationException if the authentication fails. This might happen for example, when
072             * a session was created and then the password was modified by another instance of {@link KeyManagerAPI}.
073             * Calling {@link KeyManagerAPI#putUser(String, char[])} automatically updates the authentication information
074             * of the current <code>KeyManagerAPI</code> if the current user's password was changed. But if the password
075             * is changed by another instance, this instance is locked out due to its outdated password.
076             * @throws IOException if communication with the key-store failed. This might be a socket error between
077             * client and remote key server or it might be a problem when reading/writing data in the local file system.
078             * @see #release()
079             */
080            String acquire() throws AuthenticationException, IOException;
081    
082            /**
083             * <p>
084             * Release the session, after it was previously {@link #acquire() acquired}.
085             * </p><p>
086             * For every call to {@link #acquire()}, there must be exactly one call to {@link #release()}. You should
087             * therefore use a try-finally-block!
088             * </p><p>
089             * See {@link #acquire()} for further details.
090             * </p>
091             *
092             * @throws AuthenticationException if the authentication fails. This might happen for example, when
093             * a session was created and then the password was modified by another instance of {@link KeyManagerAPI}.
094             * Calling {@link KeyManagerAPI#putUser(String, char[])} automatically updates the authentication information
095             * of the current <code>KeyManagerAPI</code> if the current user's password was changed. But if the password
096             * is changed by another instance, this instance is locked out due to its outdated password.
097             * @throws IOException if communication with the key-store failed. This might be a socket error between
098             * client and remote key server or it might be a problem when reading/writing data in the local file system.
099             * @see #acquire()
100             */
101            void release() throws AuthenticationException, IOException;
102    }