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                            throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error(e)).build());
089                    } finally {
090                            auth.clear();
091                    }
092            }
093    
094            /**
095             * Get a list of all <code>AppServer</code>s managed by this key-server for the specified key-store.
096             * @param keyStoreID identifier of the key-store to work with.
097             * @return a list of all <code>AppServer</code>s for the specified key-store. Never <code>null</code>, but
098             * it may be an empty list.
099             */
100            @GET
101            @Path("{keyStoreID}")
102            public org.cumulus4j.keymanager.front.shared.AppServerList getAppServers(@PathParam("keyStoreID") String keyStoreID)
103            {
104                    logger.debug("getAppServers: entered");
105                    org.cumulus4j.keymanager.front.shared.AppServerList appServerList = new org.cumulus4j.keymanager.front.shared.AppServerList();
106                    Auth auth = authenticate(keyStoreID);
107                    try {
108                            AppServerManager appServerManager = keyStoreManager.getAppServerManager(keyStoreID);
109                            for (org.cumulus4j.keymanager.AppServer appServer : appServerManager.getAppServers()) {
110                                    org.cumulus4j.keymanager.front.shared.AppServer as = new org.cumulus4j.keymanager.front.shared.AppServer();
111                                    as.setAppServerID(appServer.getAppServerID());
112                                    as.setAppServerBaseURL(appServer.getAppServerBaseURL());
113                                    appServerList.getAppServers().add(as);
114                            }
115                    } catch (IOException e) {
116                            throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error(e)).build());
117                    } finally {
118                            auth.clear();
119                    }
120                    return appServerList;
121            }
122    
123    //      /**
124    //       * Put an <code>AppServer</code>.
125    //       * @param keyStoreID identifier of the key-store to work with.
126    //       * @param appServerID identifier of the <code>AppServer</code> (must match
127    //       * {@link org.cumulus4j.keymanager.front.shared.AppServer#getAppServerID()}).
128    //       * @param appServer the <code>AppServer</code> to be put.
129    //       * @deprecated This service method is not used by the unified key manager API. Shall we remove it?! It exists solely for
130    //       * reasons of REST-ful service consistency. But maybe we should better remove it and provide ONE single way to handle things. Marco :-)
131    //       */
132    //      @Deprecated
133    //      @PUT
134    //      @Path("{keyStoreID}/{appServerID}")
135    //      public void putAppServerWithAppServerIDPath(
136    //                      @PathParam("keyStoreID") String keyStoreID,
137    //                      @PathParam("appServerID") String appServerID,
138    //                      org.cumulus4j.keymanager.front.shared.AppServer appServer
139    //      )
140    //      {
141    //              logger.debug("putAppServerWithAppServerIDPath: entered");
142    //
143    //              if (appServerID == null)
144    //                      throw new IllegalArgumentException("How the hell can appServerID be null?!");
145    //
146    //              if (appServer == null)
147    //                      throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new Error("Missing request-entity!")).build());
148    //
149    //              if (appServer.getAppServerID() == null || appServer.getAppServerID().isEmpty())
150    //                      appServer.setAppServerID(appServerID);
151    //              else if (!appServerID.equals(appServer.getAppServerID()))
152    //                      throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new Error("Path's appServerID='" + appServerID + "' does not match entity's appServerID='" + appServer.getAppServerID() + "'!")).build());
153    //
154    //              putAppServer(keyStoreID, appServer);
155    //      }
156    
157            /**
158             * Compatibility for clients not supporting <code>PUT</code>. This method does the same as (it delegates to)
159             * {@link #putAppServer(String, org.cumulus4j.keymanager.front.shared.AppServer)}. Ajax-Clients (e.g. jQuery in Firefox) seem
160             * not to support <code>PUT</code>.
161             */
162            @POST
163            @Path("{keyStoreID}")
164            public PutAppServerResponse postAppServer(
165                            @PathParam("keyStoreID") String keyStoreID,
166                            org.cumulus4j.keymanager.front.shared.AppServer appServer
167            ) {
168                    return putAppServer(keyStoreID, appServer);
169            }
170    
171            /**
172             * Put an <code>AppServer</code>.
173             * @param keyStoreID identifier of the key-store to work with.
174             * @param appServer the <code>AppServer</code> to be put. Note, that its {@link AppServer#getAppServerID() appServerID}
175             * is ignored! It will be assigned by this method.
176             * @return data that might have been created/changed during the put operation (e.g. the <code>appServerID</code>
177             * is assigned during this method call).
178             */
179            @PUT
180            @Path("{keyStoreID}")
181            public PutAppServerResponse putAppServer(
182                            @PathParam("keyStoreID") String keyStoreID,
183                            org.cumulus4j.keymanager.front.shared.AppServer appServer
184            )
185            {
186                    logger.debug("putAppServer: entered");
187    
188                    if (appServer == null)
189                            throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new Error("Missing request-entity!")).build());
190    
191                    // We do not allow to overwrite an existing AppServer with different data for security & stability reasons.
192                    // Hence the appServerID is always assigned by this service. We enforce it. Marco :-)
193                    appServer.setAppServerID(null);
194    
195                    Auth auth = authenticate(keyStoreID);
196                    try {
197                            AppServerManager appServerManager = keyStoreManager.getAppServerManager(keyStoreID);
198                            org.cumulus4j.keymanager.AppServer as = new org.cumulus4j.keymanager.AppServer(
199                                            appServerManager, appServer.getAppServerID(), appServer.getAppServerBaseURL()
200                            );
201                            appServerManager.putAppServer(as); // This will assign appServer.appServerID, if that property is null.
202    
203                            if (as.getAppServerID() == null) // sanity check.
204                                    throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error(new IllegalStateException("appServer.appServerID is null after registration of appServer!"))).build());
205    
206                            // TODO write AppServers to a file (maybe into the keystore?!)!
207                            return new PutAppServerResponse(as.getAppServerID());
208                    } catch (IOException e) {
209                            throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error(e)).build());
210                    } finally {
211                            // extra safety => overwrite passwords
212                            auth.clear();
213                    }
214            }
215    
216            /**
217             * Delete the AppServer.
218             * @param keyStoreID identifier of the key-store to work with.
219             * @param appServerID identifier of app-server to delete.
220             */
221            @DELETE
222            @Path("{keyStoreID}/{appServerID}")
223            public void deleteAppServer(@PathParam("keyStoreID") String keyStoreID, @PathParam("appServerID") String appServerID)
224            {
225                    logger.debug("deleteAppServer: entered");
226    
227                    Auth auth = authenticate(keyStoreID);
228                    try {
229                            AppServerManager appServerManager = keyStoreManager.getAppServerManager(keyStoreID);
230                            appServerManager.removeAppServer(appServerID);
231                    } catch (IOException e) {
232                            throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new Error(e)).build());
233                    } finally {
234                            // extra safety => overwrite password
235                            auth.clear();
236                    }
237            }
238    }