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 }