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.keymanager.front.webapp;
019    
020    import java.io.IOException;
021    
022    import javax.ws.rs.Consumes;
023    import javax.ws.rs.DELETE;
024    import javax.ws.rs.GET;
025    import javax.ws.rs.POST;
026    import javax.ws.rs.PUT;
027    import javax.ws.rs.Path;
028    import javax.ws.rs.PathParam;
029    import javax.ws.rs.Produces;
030    import javax.ws.rs.WebApplicationException;
031    import javax.ws.rs.core.MediaType;
032    import javax.ws.rs.core.Response;
033    import javax.ws.rs.core.Response.Status;
034    
035    import org.cumulus4j.keymanager.AppServerManager;
036    import org.cumulus4j.keymanager.front.shared.AppServer;
037    import org.cumulus4j.keymanager.front.shared.Error;
038    import org.cumulus4j.keymanager.front.shared.PutAppServerResponse;
039    import org.slf4j.Logger;
040    import org.slf4j.LoggerFactory;
041    
042    /**
043     * REST service to manage {@link org.cumulus4j.keymanager.front.shared.AppServer AppServer}s.
044     *
045     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
046     */
047    @Path("AppServer")
048    @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
049    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
050    public class AppServerService extends AbstractService
051    {
052            private static final Logger logger = LoggerFactory.getLogger(AppServerService.class);
053    
054            /**
055             * Create an instance.
056             */
057            public AppServerService() {
058                    logger.debug("logger: instantiated AppServerService");
059            }
060    
061            /**
062             * Get an <code>AppServer</code>.
063             * @param keyStoreID identifier of the key-store to work with.
064             * @param appServerID identifier of app-server to retrieve.
065             * @return the <code>AppServer</code> or <code>null</code>, if no matching <code>AppServer</code> exists.
066             */
067            @GET
068            @Path("{keyStoreID}/{appServerID}")
069            public org.cumulus4j.keymanager.front.shared.AppServer getAppServer(
070                            @PathParam("keyStoreID") String keyStoreID,
071                            @PathParam("appServerID") String appServerID
072            )
073            {
074                    logger.debug("getAppServer: entered");
075                    Auth auth = authenticate(keyStoreID);
076                    try {
077                            AppServerManager appServerManager = keyStoreManager.getAppServerManager(keyStoreID);
078                            org.cumulus4j.keymanager.AppServer appServer = appServerManager.getAppServerForAppServerID(appServerID);
079                            if (appServer == null)
080                                    return null;
081                            else {
082                                    org.cumulus4j.keymanager.front.shared.AppServer as = new org.cumulus4j.keymanager.front.shared.AppServer();
083                                    as.setAppServerID(appServer.getAppServerID());
084                                    as.setAppServerBaseURL(appServer.getAppServerBaseURL());
085                                    return as;
086                            }
087                    } catch (IOException e) {
088                            logger.error("getAppServer: " + e, e);
089                            throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error(e)).build());
090                    } finally {
091                            auth.clear();
092                    }
093            }
094    
095            /**
096             * Get a list of all <code>AppServer</code>s managed by this key-server for the specified key-store.
097             * @param keyStoreID identifier of the key-store to work with.
098             * @return a list of all <code>AppServer</code>s for the specified key-store. Never <code>null</code>, but
099             * it may be an empty list.
100             */
101            @GET
102            @Path("{keyStoreID}")
103            public org.cumulus4j.keymanager.front.shared.AppServerList getAppServers(@PathParam("keyStoreID") String keyStoreID)
104            {
105                    logger.debug("getAppServers: entered");
106                    org.cumulus4j.keymanager.front.shared.AppServerList appServerList = new org.cumulus4j.keymanager.front.shared.AppServerList();
107                    Auth auth = authenticate(keyStoreID);
108                    try {
109                            AppServerManager appServerManager = keyStoreManager.getAppServerManager(keyStoreID);
110                            for (org.cumulus4j.keymanager.AppServer appServer : appServerManager.getAppServers()) {
111                                    org.cumulus4j.keymanager.front.shared.AppServer as = new org.cumulus4j.keymanager.front.shared.AppServer();
112                                    as.setAppServerID(appServer.getAppServerID());
113                                    as.setAppServerBaseURL(appServer.getAppServerBaseURL());
114                                    appServerList.getAppServers().add(as);
115                            }
116                    } catch (IOException e) {
117                            logger.error("getAppServers: " + e, e);
118                            throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error(e)).build());
119                    } finally {
120                            auth.clear();
121                    }
122                    return appServerList;
123            }
124    
125    //      /**
126    //       * Put an <code>AppServer</code>.
127    //       * @param keyStoreID identifier of the key-store to work with.
128    //       * @param appServerID identifier of the <code>AppServer</code> (must match
129    //       * {@link org.cumulus4j.keymanager.front.shared.AppServer#getAppServerID()}).
130    //       * @param appServer the <code>AppServer</code> to be put.
131    //       * @deprecated This service method is not used by the unified key manager API. Shall we remove it?! It exists solely for
132    //       * reasons of REST-ful service consistency. But maybe we should better remove it and provide ONE single way to handle things. Marco :-)
133    //       */
134    //      @Deprecated
135    //      @PUT
136    //      @Path("{keyStoreID}/{appServerID}")
137    //      public void putAppServerWithAppServerIDPath(
138    //                      @PathParam("keyStoreID") String keyStoreID,
139    //                      @PathParam("appServerID") String appServerID,
140    //                      org.cumulus4j.keymanager.front.shared.AppServer appServer
141    //      )
142    //      {
143    //              logger.debug("putAppServerWithAppServerIDPath: entered");
144    //
145    //              if (appServerID == null)
146    //                      throw new IllegalArgumentException("How the hell can appServerID be null?!");
147    //
148    //              if (appServer == null)
149    //                      throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new Error("Missing request-entity!")).build());
150    //
151    //              if (appServer.getAppServerID() == null || appServer.getAppServerID().isEmpty())
152    //                      appServer.setAppServerID(appServerID);
153    //              else if (!appServerID.equals(appServer.getAppServerID()))
154    //                      throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new Error("Path's appServerID='" + appServerID + "' does not match entity's appServerID='" + appServer.getAppServerID() + "'!")).build());
155    //
156    //              putAppServer(keyStoreID, appServer);
157    //      }
158    
159            /**
160             * Compatibility for clients not supporting <code>PUT</code>. This method does the same as (it delegates to)
161             * {@link #putAppServer(String, org.cumulus4j.keymanager.front.shared.AppServer)}. Ajax-Clients (e.g. jQuery in Firefox) seem
162             * not to support <code>PUT</code>.
163             */
164            @POST
165            @Path("{keyStoreID}")
166            public PutAppServerResponse postAppServer(
167                            @PathParam("keyStoreID") String keyStoreID,
168                            org.cumulus4j.keymanager.front.shared.AppServer appServer
169            ) {
170                    return putAppServer(keyStoreID, appServer);
171            }
172    
173            /**
174             * Put an <code>AppServer</code>.
175             * @param keyStoreID identifier of the key-store to work with.
176             * @param appServer the <code>AppServer</code> to be put. Note, that its {@link AppServer#getAppServerID() appServerID}
177             * is ignored! It will be assigned by this method.
178             * @return data that might have been created/changed during the put operation (e.g. the <code>appServerID</code>
179             * is assigned during this method call).
180             */
181            @PUT
182            @Path("{keyStoreID}")
183            public PutAppServerResponse putAppServer(
184                            @PathParam("keyStoreID") String keyStoreID,
185                            org.cumulus4j.keymanager.front.shared.AppServer appServer
186            )
187            {
188                    logger.debug("putAppServer: entered");
189    
190                    if (appServer == null)
191                            throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new Error("Missing request-entity!")).build());
192    
193                    // We do not allow to overwrite an existing AppServer with different data for security & stability reasons.
194                    // Hence the appServerID is always assigned by this service. We enforce it. Marco :-)
195                    appServer.setAppServerID(null);
196    
197                    Auth auth = authenticate(keyStoreID);
198                    try {
199                            AppServerManager appServerManager = keyStoreManager.getAppServerManager(keyStoreID);
200                            org.cumulus4j.keymanager.AppServer as = new org.cumulus4j.keymanager.AppServer(
201                                            appServerManager, appServer.getAppServerID(), appServer.getAppServerBaseURL()
202                            );
203                            appServerManager.putAppServer(as); // This will assign appServer.appServerID, if that property is null.
204    
205                            if (as.getAppServerID() == null) // sanity check.
206                                    throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error(new IllegalStateException("appServer.appServerID is null after registration of appServer!"))).build());
207    
208                            // TODO write AppServers to a file (maybe into the keystore?!)!
209                            return new PutAppServerResponse(as.getAppServerID());
210                    } catch (IOException e) {
211                            logger.error("putAppServer: " + e, e);
212                            throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error(e)).build());
213                    } finally {
214                            // extra safety => overwrite passwords
215                            auth.clear();
216                    }
217            }
218    
219            /**
220             * Delete the AppServer.
221             * @param keyStoreID identifier of the key-store to work with.
222             * @param appServerID identifier of app-server to delete.
223             */
224            @DELETE
225            @Path("{keyStoreID}/{appServerID}")
226            public void deleteAppServer(@PathParam("keyStoreID") String keyStoreID, @PathParam("appServerID") String appServerID)
227            {
228                    logger.debug("deleteAppServer: entered");
229    
230                    Auth auth = authenticate(keyStoreID);
231                    try {
232                            AppServerManager appServerManager = keyStoreManager.getAppServerManager(keyStoreID);
233                            appServerManager.removeAppServer(appServerID);
234                    } catch (IOException e) {
235                            logger.error("deleteAppServer: " + e, e);
236                            throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error(e)).build());
237                    } finally {
238                            // extra safety => overwrite password
239                            auth.clear();
240                    }
241            }
242    }