001 /* 002 * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org 003 * Copyright (C) 2011 NightLabs Consulting GmbH 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 package org.cumulus4j.store.crypto.keymanager.messagebroker; 019 020 import java.util.concurrent.TimeoutException; 021 022 import org.cumulus4j.keymanager.back.shared.ErrorResponse; 023 import org.cumulus4j.keymanager.back.shared.GetKeyRequest; 024 import org.cumulus4j.keymanager.back.shared.GetKeyResponse; 025 import org.cumulus4j.keymanager.back.shared.Message; 026 import org.cumulus4j.keymanager.back.shared.NullResponse; 027 import org.cumulus4j.keymanager.back.shared.Request; 028 import org.cumulus4j.keymanager.back.shared.Response; 029 import org.cumulus4j.store.crypto.CryptoSession; 030 import org.cumulus4j.store.crypto.keymanager.rest.ErrorResponseException; 031 032 /** 033 * <p> 034 * Broker transmitting {@link Message messages} between application-server and key-manager. 035 * </p> 036 * <p> 037 * As documented in <a target="_blank" href="http://cumulus4j.org/1.1.1/documentation/deployment-scenarios.html">Deployment scenarios</a>, 038 * TCP connections are always established from the key-manager (i.e. client or key-server) to the application server. 039 * Since this means that the key-exchange-request-response-cycle works opposite the HTTP-request-response-cycle, 040 * we need this <code>MessageBroker</code>. 041 * </p> 042 * <p> 043 * Within every JVM, there is one single {@link MessageBrokerRegistry#getActiveMessageBroker() active MessageBroker}. 044 * This instance must make sure that messages can be exchanged from every cluster-node to every key-manager; i.e. if 045 * the key-manager connects to a different cluster-node than the primary connection (established by the application logic), 046 * the {@link Request}s must be proxied over the right cluster-node to the key-manager. The {@link Response} must 047 * of course be routed appropriately back to the correct cluster-node: 048 * </p> 049 * <p> 050 * <img src="http://cumulus4j.org/1.1.1/images/deployment-scenario/deployment-scenario-without-keyserver-with-cluster.png" /> 051 * </p> 052 * <p> 053 * <b>Important:</b> You should not directly implement this interface but instead subclass {@link AbstractMessageBroker}! 054 * </p> 055 * 056 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de 057 */ 058 public interface MessageBroker 059 { 060 /** 061 * <p> 062 * System property to control the timeout (in milliseconds) for the {@link #query(Class, Request)} method. 063 * </p> 064 * <p> 065 * The <code>query(...)</code> method will throw a {@link TimeoutException}, if no {@link Response} 066 * to a given {@link Request} arrived within this timeout. 067 * </p> 068 * <p> 069 * If the system property is not present or not a valid number, it is up to the <code>MessageBroker</code> 070 * implementation, what default value should be used. See {@link AbstractMessageBroker#getQueryTimeout()} 071 * for the default implemented there. 072 * </p> 073 */ 074 static final String SYSTEM_PROPERTY_QUERY_TIMEOUT = "cumulus4j.MessageBroker.queryTimeout"; 075 076 /** 077 * <p> 078 * System property to control the timeout (in milliseconds) for the {@link #pollRequest(String)} method. 079 * </p> 080 * <p> 081 * The <code>pollRequest(...)</code> method returns <code>null</code>, if no {@link Request} popped up 082 * in the to-do-queue within the timeout. 083 * </p> 084 * <p> 085 * If the system property is not present or not a valid number, it is up to the <code>MessageBroker</code> 086 * implementation, what default value should be used. See {@link AbstractMessageBroker#getPollRequestTimeout()} 087 * for the default implemented there. 088 * </p> 089 */ 090 static final String SYSTEM_PROPERTY_POLL_REQUEST_TIMEOUT = "cumulus4j.MessageBroker.pollRequestTimeout"; 091 092 // ActiveKeyManagerChannelRegistration registerActiveKeyManagerChannel(String cryptoSessionIDPrefix, String internalKeyManagerChannelURL); 093 // 094 // void unregisterActiveKeyManagerChannel(ActiveKeyManagerChannelRegistration registration); 095 096 /** 097 * <p> 098 * Send <code>request</code> to the key-manager (embedded in client or separate in key-server) and return its response. 099 * </p> 100 * <p> 101 * This method is used for example by a {@link CryptoSession} to request keys via a {@link GetKeyRequest}. As soon as 102 * this method entered with the <code>request</code>, it is expected that the {@link #pollRequest(String)} returns 103 * this <code>request</code> to the appropriate key-manager. The <code>query(...)</code> method blocks then until 104 * the key-manager handled the <code>request</code> and sent a {@link GetKeyResponse} back. As soon as the <code>response</code> 105 * was {@link #pushResponse(Response) pushed} into the <code>MessageBroker</code>, <code>query(...)</code> should return it. 106 * </p> 107 * <p> 108 * If the expected {@link Response} does not arrive within the query-timeout (configurable via 109 * system property {@value #SYSTEM_PROPERTY_QUERY_TIMEOUT}), this method should throw 110 * a {@link TimeoutException}. 111 * </p> 112 * 113 * @param responseClass the type of the expected response; can be null, if you expect to receive null (i.e. you pass a "void" request). 114 * @param request the request to be sent to the key-manager. 115 * @return the response from the key-manager. Will be <code>null</code>, if the key-manager replied with a {@link NullResponse}. 116 * @throws TimeoutException if the request was not replied within the {@link #SYSTEM_PROPERTY_QUERY_TIMEOUT query-timeout}. 117 * @throws ErrorResponseException if the key-manager (either running embedded on the remote client or 118 * in a separate key-server) sent an {@link ErrorResponse}. 119 */ 120 <R extends Response> R query(Class<R> responseClass, Request request) 121 throws TimeoutException, ErrorResponseException; 122 123 /** 124 * <p> 125 * Poll the next {@link Request} that is waiting to be processed. 126 * </p> 127 * <p> 128 * This method is - indirectly via a REST web-service - called by the key-manager periodically 129 * in order to receive requests. If there is a request waiting, this method should immediately 130 * return it. If there is no request in the queue, this method should wait for an incoming 131 * request for a short time. If there is still no request available after a short blocking time, 132 * this method should return <code>null</code> (before the remote client would timeout). 133 * </p> 134 * <p> 135 * Usually, blocking about 1 minute is recommended in most situations. However, when 136 * using certain runtimes, it must be much shorter (e.g. the Google App Engine allows 137 * requests not to take longer than 30 sec, thus 20 sec are an appropriate time to stay safe). 138 * </p> 139 * <p> 140 * Additionally, since the remote key-manager must wait at maximum this time, its HTTP-client's 141 * timeout must be longer than this timeout. 142 * </p> 143 * <p> 144 * It should be possible to configure this timeout via the system property 145 * {@value #SYSTEM_PROPERTY_POLL_REQUEST_TIMEOUT}. Implementors should use 146 * {@link #getPollRequestTimeout()} for this purpose. 147 * </p> 148 * @param cryptoSessionIDPrefix usually, every key-manager uses the same prefix for 149 * all crypto-sessions. Thus, this prefix is used to efficiently route requests to 150 * the right key-manager. 151 * @return the next request waiting for processing and fitting to the given <code>cryptoSessionIDPrefix</code> 152 * or <code>null</code>, if no such request pops up in the to-do-queue within the timeout. 153 */ 154 Request pollRequest(String cryptoSessionIDPrefix); 155 156 /** 157 * <p> 158 * Push a {@link Response} in order to reply a previous request. 159 * </p> 160 * <p> 161 * This method is - indirectly via a REST web-service - called by the key-manager after 162 * it successfully handled a {@link Request}. 163 * </p> 164 * @param response the response answering a previous {@link Request} enqueued by {@link #query(Class, Request)}. 165 */ 166 void pushResponse(Response response); 167 168 /** 169 * <p> 170 * Get the {@link MessageBroker#pollRequest(String) pollRequest(....)} timeout in milliseconds. 171 * </p> 172 * <p> 173 * This method takes the system property {@link MessageBroker#SYSTEM_PROPERTY_POLL_REQUEST_TIMEOUT} into account. 174 * If the system property is not present or not a valid number, the default value 60000 (1 minute) is returned. 175 * </p> 176 * <p> 177 * Usually, a value of about 1 minute is recommended in most situations. However, when 178 * using certain runtimes, it must be much shorter (e.g. the Google App Engine allows 179 * requests not to take longer than 30 sec, thus 20 sec are an appropriate time to stay safe). 180 * </p> 181 * <p> 182 * Additionally, since the remote key-manager must wait at maximum this time, its HTTP-client's 183 * timeout must be longer than this timeout. 184 * </p> 185 * 186 * @return the {@link MessageBroker#pollRequest(String) pollRequest(....)} timeout in milliseconds. 187 */ 188 long getPollRequestTimeout(); 189 190 /** 191 * <p> 192 * Get the {@link MessageBroker#query(Class, Request) query} timeout in milliseconds. 193 * </p> 194 * <p> 195 * This method takes the system property {@link MessageBroker#SYSTEM_PROPERTY_QUERY_TIMEOUT} into account. 196 * If the system property is not present or not a valid number, the default value 300000 (5 minutes) is returned. 197 * </p> 198 * 199 * @return the {@link MessageBroker#query(Class, Request) query} timeout in milliseconds. 200 */ 201 long getQueryTimeout(); 202 }