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    }