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 }