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 }