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.rest;
019
020 import javax.ws.rs.Consumes;
021 import javax.ws.rs.GET;
022 import javax.ws.rs.POST;
023 import javax.ws.rs.Path;
024 import javax.ws.rs.PathParam;
025 import javax.ws.rs.Produces;
026 import javax.ws.rs.core.MediaType;
027
028 import org.cumulus4j.keymanager.back.shared.NullResponse;
029 import org.cumulus4j.keymanager.back.shared.Request;
030 import org.cumulus4j.keymanager.back.shared.Response;
031 import org.cumulus4j.store.crypto.keymanager.messagebroker.ActiveKeyManagerChannelRegistration;
032 import org.cumulus4j.store.crypto.keymanager.messagebroker.MessageBroker;
033 import org.cumulus4j.store.crypto.keymanager.messagebroker.MessageBrokerRegistry;
034
035 /**
036 * REST service for the communication channel between key-manager and app-server.
037 *
038 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
039 */
040 @Path("KeyManagerChannel")
041 @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
042 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
043 public class KeyManagerChannelService
044 {
045 // private static final Logger logger = LoggerFactory.getLogger(KeyManagerChannelService.class);
046 private MessageBroker messageBroker = MessageBrokerRegistry.sharedInstance().getActiveMessageBroker();
047
048 // @Context
049 // private HttpServletRequest httpServletRequest;
050
051 private ActiveKeyManagerChannelRegistration registerActiveKeyManagerChannel(String cryptoSessionIDPrefix)
052 {
053 return null;
054 // if (logger.isDebugEnabled()) {
055 // logger.debug("registerKeyManagerChannelUrl: httpServletRequest.getRequestURL() = {}", httpServletRequest.getRequestURL());
056 // logger.debug("registerKeyManagerChannelUrl: httpServletRequest.getRequestURI() = {}", httpServletRequest.getRequestURI());
057 // logger.debug("registerKeyManagerChannelUrl: httpServletRequest.getLocalName() = {}", httpServletRequest.getLocalName());
058 // logger.debug("registerKeyManagerChannelUrl: httpServletRequest.getLocalAddr() = {}", httpServletRequest.getLocalAddr());
059 // logger.debug("registerKeyManagerChannelUrl: httpServletRequest.getLocalPort() = {}", httpServletRequest.getLocalPort());
060 // }
061 //
062 // String keyManagerChannelURLPart = "/KeyManagerChannel/";
063 // String requestURI = httpServletRequest.getRequestURI();
064 // int idx = requestURI.indexOf(keyManagerChannelURLPart);
065 // if (idx < 0)
066 // throw new IllegalStateException("\"" + keyManagerChannelURLPart + "\" does not occur in requestURI: " + requestURI);
067 //
068 // String keyManagerChannelURI = requestURI.substring(0, idx + keyManagerChannelURLPart.length());
069 //
070 // String internalKeyManagerChannelProtocol = "http"; // TODO make configurable via system property
071 // String internalKeyManagerChannelHost = httpServletRequest.getLocalName(); // TODO allow overriding (instead of auto-detection) via system property
072 // int internalKeyManagerChannelPort = httpServletRequest.getLocalPort(); // TODO allow overriding (instead of auto-detection) via system property
073 //
074 // String internalKeyManagerChannelURL = (
075 // internalKeyManagerChannelProtocol + "://"
076 // + internalKeyManagerChannelHost + ':' + internalKeyManagerChannelPort
077 // + keyManagerChannelURI
078 // );
079 //
080 // ActiveKeyManagerChannelRegistration registration = messageBroker.registerActiveKeyManagerChannel(cryptoSessionIDPrefix, internalKeyManagerChannelURL);
081 // return registration;
082 }
083
084 private void unregisterActiveKeyManagerChannel(ActiveKeyManagerChannelRegistration registration)
085 {
086 // if (registration != null)
087 // messageBroker.unregisterActiveKeyManagerChannel(registration);
088 }
089
090 /**
091 * Test method to allow an administrator to verify the URL in a browser.
092 * @return a string beginning with "OK:".
093 */
094 @Path("test")
095 @GET
096 @Produces(MediaType.TEXT_PLAIN)
097 public String testGet()
098 {
099 ActiveKeyManagerChannelRegistration registration = registerActiveKeyManagerChannel("test");
100 unregisterActiveKeyManagerChannel(registration);
101
102 return "OK: " + this.getClass().getName();
103 }
104
105 // @Path("pushResponse")
106 // @POST
107 // public void pushResponse(Response response)
108 // {
109 // registerLocalClusterNodeKeyManagerChannelUrl();
110 //
111 // if (response == null)
112 // return;
113 //
114 // // The NullResponse can either be a filler without request and thus needs to be discarded here,
115 // // or it can be a response to a specific request. Hence, we check whether the NullResponse.requestID is null.
116 // if ((response instanceof NullResponse) && response.getRequestID() == null)
117 // return;
118 //
119 // messageBroker.pushResponse(response);
120 // }
121
122 /**
123 * Upload a {@link Response} and fetch the next {@link Request}. If there is no <code>Response</code>, yet,
124 * the key-manager must upload a {@link NullResponse}. This method forwards the <code>response</code>
125 * to {@link MessageBroker#pushResponse(Response)} and then {@link MessageBroker#pollRequest(String)
126 * polls the next request}.
127 * @param cryptoSessionIDPrefix the prefix used by the key-manager, i.e. the unique identifier of the key-manager.
128 * This is used for efficient routing of requests, i.e. by {@link MessageBroker#pollRequest(String)}.
129 * @param response the last response or an instance of {@link NullResponse} (without <code>requestID</code>)
130 * if there is no last request to be replied.
131 * @return the next polled request or <code>null</code> if none popped up before the timeout.
132 */
133 @Path("nextRequest/{cryptoSessionIDPrefix}")
134 @POST
135 public Request nextRequest(@PathParam("cryptoSessionIDPrefix") String cryptoSessionIDPrefix, Response response)
136 {
137 if (cryptoSessionIDPrefix == null)
138 throw new IllegalArgumentException("cryptoSessionIDPrefix == null");
139
140 ActiveKeyManagerChannelRegistration registration = registerActiveKeyManagerChannel(cryptoSessionIDPrefix);
141 try {
142 if (response != null && response.getRequestID() != null) {
143 // The NullResponse can either be a filler without request and thus needs to be discarded here,
144 // or it can be a response to a specific request. Hence, we check whether the Response.requestID is null
145 // and don't care about the type at all. If it has a requestID, it must be pushed, no matter what type
146 // it is. Marco :-)
147 messageBroker.pushResponse(response);
148 }
149
150 Request request = messageBroker.pollRequest(cryptoSessionIDPrefix);
151 return request;
152 } finally {
153 unregisterActiveKeyManagerChannel(registration);
154 }
155 }
156
157 }