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 }