001    package org.cumulus4j.keymanager.api.internal.remote;
002    
003    import java.io.IOException;
004    import java.util.Date;
005    
006    import javax.ws.rs.core.MediaType;
007    
008    import org.cumulus4j.keymanager.api.AuthenticationException;
009    import org.cumulus4j.keymanager.api.CryptoSession;
010    import org.cumulus4j.keymanager.front.shared.AcquireCryptoSessionResponse;
011    import org.cumulus4j.keymanager.front.shared.AppServer;
012    
013    import com.sun.jersey.api.client.Client;
014    import com.sun.jersey.api.client.UniformInterface;
015    import com.sun.jersey.api.client.UniformInterfaceException;
016    
017    /**
018     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
019     */
020    public class RemoteCryptoSession implements CryptoSession
021    {
022            private RemoteKeyManagerAPI remoteKeyManagerAPI;
023    
024            private AppServer appServer;
025    
026            public RemoteCryptoSession(RemoteKeyManagerAPI remoteKeyManagerAPI, AppServer appServer)
027            {
028                    if (remoteKeyManagerAPI == null)
029                            throw new IllegalArgumentException("remoteKeyManagerAPI == null");
030    
031                    if (appServer == null)
032                            throw new IllegalArgumentException("appServer == null");
033    
034                    this.remoteKeyManagerAPI = remoteKeyManagerAPI;
035                    this.appServer = appServer;
036            }
037    
038            // BEGIN some convenience methods
039            private final Client getClient() { return remoteKeyManagerAPI.getClient(); }
040            private final String getKeyManagerBaseURL() { return remoteKeyManagerAPI.getKeyManagerBaseURL(); }
041            private final String getKeyStoreID() { return remoteKeyManagerAPI.getKeyStoreID(); }
042            private static final String appendFinalSlash(String url) { return RemoteKeyManagerAPI.appendFinalSlash(url); }
043            // END some convenience methods
044    
045            @Override
046            public String getAppServerID() {
047                    return appServer.getAppServerID();
048            }
049    
050            @Override
051            public String getAppServerBaseURL() {
052                    return appServer.getAppServerBaseURL();
053            }
054    
055            private Date acquireSessionResponseLocalTimestamp;
056            private AcquireCryptoSessionResponse acquireCryptoSessionResponse;
057    
058    //      @Override
059    //      public synchronized String getCryptoSessionID() throws AuthenticationException, IOException
060    //      {
061    //              if (
062    //                              acquireSessionResponseLocalTimestamp != null &&
063    //                              acquireSessionResponseLocalTimestamp.after(new Date(System.currentTimeMillis() - 10000)) // TODO make time configurable!
064    //              )
065    //                      return acquireCryptoSessionResponse.getCryptoSessionID();
066    //
067    //              try {
068    //                      Date now = new Date();
069    //                      AcquireCryptoSessionResponse response = getClient().resource(appendFinalSlash(getKeyManagerBaseURL()) + "CryptoSession/" + getKeyStoreID() + '/' + appServer.getAppServerID() + "/open")
070    //                      .accept(MediaType.APPLICATION_XML_TYPE)
071    //                      .post(AcquireCryptoSessionResponse.class);
072    //
073    //                      if (response == null)
074    //                              throw new IllegalStateException("Key server returned null instead of an AcquireCryptoSessionResponse when opening a session!"); // TODO nice exceptions for this API!
075    //
076    //                      this.lastOpenSessionResponseLocalTimestamp = now;
077    //                      this.acquireSessionResponse = response;
078    //
079    //                      return response.getCryptoSessionID();
080    //              } catch (UniformInterfaceException x) {
081    //                      RemoteKeyManagerAPI.throwUniformInterfaceExceptionAsAuthenticationException(x);
082    //                      RemoteKeyManagerAPI.throwUniformInterfaceExceptionAsIOException(x);
083    //                      throw new IOException(x);
084    //              }
085    //      }
086    
087            private int unlockCounter;
088    
089            @Override
090            public synchronized void release() throws AuthenticationException, IOException
091            {
092                    if (--unlockCounter < 0)
093                            throw new IllegalStateException("release() called more often than acquire()!!!");
094    
095                    if (unlockCounter == 0) // TODO don't immediately lock, but use a separate thread that locks with a delay (in case a new unlock comes in the next few seconds).
096                            doRelease();
097            }
098    
099            private void doRelease() throws AuthenticationException, IOException
100            {
101                    if (acquireCryptoSessionResponse == null)
102                            throw new IllegalStateException("acquireCryptoSessionResponse == null");
103    
104                    String cryptoSessionID = acquireCryptoSessionResponse.getCryptoSessionID();
105    
106                    try {
107                            String url = (
108                                            appendFinalSlash(getKeyManagerBaseURL())
109                                            + "CryptoSession/" + getKeyStoreID() + '/' + appServer.getAppServerID() + '/' + cryptoSessionID + "/release"
110                            );
111    
112                            UniformInterface jui = getClient().resource(url);
113                            jui.post();
114    
115                    } catch (UniformInterfaceException x) {
116                            RemoteKeyManagerAPI.throwUniformInterfaceExceptionAsAuthenticationException(x);
117                            RemoteKeyManagerAPI.throwUniformInterfaceExceptionAsIOException(x);
118                            throw new IOException(x);
119                    }
120    
121                    acquireCryptoSessionResponse = null;
122                    acquireSessionResponseLocalTimestamp = null;
123            }
124    
125            @Override
126            public synchronized String acquire() throws AuthenticationException, IOException
127            {
128                    if (0 == unlockCounter++)
129                            doAcquire();
130                    else if (acquireSessionResponseLocalTimestamp.getTime() + 10000L < System.currentTimeMillis()) // TODO make configurable!
131                            doReacquire();
132    
133                    return acquireCryptoSessionResponse.getCryptoSessionID();
134            }
135    
136            private void doAcquire() throws AuthenticationException, IOException
137            {
138                    try {
139                            Date now = new Date();
140                            String url = (
141                                            appendFinalSlash(getKeyManagerBaseURL())
142                                            + "CryptoSession/" + getKeyStoreID() + '/' + appServer.getAppServerID() + "/acquire"
143                            );
144    
145                            UniformInterface jui = getClient().resource(url).accept(MediaType.APPLICATION_XML_TYPE);
146                            AcquireCryptoSessionResponse response = jui.post(AcquireCryptoSessionResponse.class);
147    
148                            if (response == null)
149                                    throw new IllegalStateException("Key server returned null instead of an AcquireCryptoSessionResponse when opening a session!"); // TODO nice exceptions for this API!
150    
151                            this.acquireSessionResponseLocalTimestamp = now;
152                            this.acquireCryptoSessionResponse = response;
153                    } catch (UniformInterfaceException x) {
154                            RemoteKeyManagerAPI.throwUniformInterfaceExceptionAsAuthenticationException(x);
155                            RemoteKeyManagerAPI.throwUniformInterfaceExceptionAsIOException(x);
156                            throw new IOException(x);
157                    }
158            }
159    
160            private void doReacquire() throws AuthenticationException, IOException
161            {
162                    if (acquireCryptoSessionResponse == null)
163                            throw new IllegalStateException("acquireCryptoSessionResponse == null");
164    
165                    String cryptoSessionID = acquireCryptoSessionResponse.getCryptoSessionID();
166    
167                    try {
168                            Date now = new Date();
169                            String url = (
170                                            appendFinalSlash(getKeyManagerBaseURL())
171                                            + "CryptoSession/" + getKeyStoreID() + '/' + appServer.getAppServerID() + '/' + cryptoSessionID + "/reacquire"
172                            );
173    
174                            UniformInterface jui = getClient().resource(url).accept(MediaType.APPLICATION_XML_TYPE);
175                            AcquireCryptoSessionResponse response = jui.post(AcquireCryptoSessionResponse.class);
176    
177                            if (response == null)
178                                    throw new IllegalStateException("Key server returned null instead of an AcquireCryptoSessionResponse when opening a session!"); // TODO nice exceptions for this API!
179    
180                            this.acquireSessionResponseLocalTimestamp = now;
181                            this.acquireCryptoSessionResponse = response;
182                    } catch (UniformInterfaceException x) {
183                            RemoteKeyManagerAPI.throwUniformInterfaceExceptionAsAuthenticationException(x);
184                            RemoteKeyManagerAPI.throwUniformInterfaceExceptionAsIOException(x);
185                            throw new IOException(x);
186                    }
187            }
188    
189    //      @Override
190    //      public synchronized void close()
191    //      {
192    //              if (acquireCryptoSessionResponse == null)
193    //                      return; // there's nothing to be closed, yet
194    //
195    //              String cryptoSessionID = acquireCryptoSessionResponse.getCryptoSessionID();
196    //              getClient().resource(appendFinalSlash(getKeyManagerBaseURL()) + "CryptoSession/" + getKeyStoreID() + '/' + appServer.getAppServerID() + '/' + cryptoSessionID)
197    //              .delete();
198    //
199    //              acquireCryptoSessionResponse = null;
200    //              acquireSessionResponseLocalTimestamp = null;
201    //      }
202    
203    }