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 }