Skip to content

Commit 3870107

Browse files
authored
Merge pull request #2006 from Accelerite/CLOUDSTACK-9833
CLOUDSTACK-9833: Move configuration parameters from Config.java to use configdepot
2 parents 23ac896 + efbb59f commit 3870107

7 files changed

Lines changed: 66 additions & 68 deletions

File tree

api/src/org/apache/cloudstack/api/ApiServerService.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,4 @@ public ResponseObject loginUser(HttpSession session, String username, String pas
4343

4444
public Class<?> getCmdClass(String cmdName);
4545

46-
public String getJSONContentType();
47-
48-
public boolean isSecureSessionCookieEnabled();
4946
}

server/src/com/cloud/api/ApiServer.java

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@
9696
import org.apache.cloudstack.api.response.ListResponse;
9797
import org.apache.cloudstack.api.response.LoginCmdResponse;
9898
import org.apache.cloudstack.context.CallContext;
99+
import org.apache.cloudstack.framework.config.ConfigKey;
100+
import org.apache.cloudstack.framework.config.Configurable;
99101
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
100102
import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
101103
import org.apache.cloudstack.framework.events.EventBus;
@@ -180,13 +182,11 @@
180182
import java.util.regex.Pattern;
181183

182184
@Component
183-
public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiServerService {
185+
public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiServerService, Configurable {
184186
private static final Logger s_logger = Logger.getLogger(ApiServer.class.getName());
185187
private static final Logger s_accessLogger = Logger.getLogger("apiserver." + ApiServer.class.getName());
186188

187189
private static boolean encodeApiResponse = false;
188-
private boolean enableSecureCookie = false;
189-
private String jsonContentType = HttpUtils.JSON_CONTENT_TYPE;
190190

191191
/**
192192
* Non-printable ASCII characters - numbers 0 to 31 and 127 decimal
@@ -227,6 +227,12 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
227227

228228
private static ExecutorService s_executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory(
229229
"ApiServer"));
230+
231+
static final ConfigKey<Boolean> EnableSecureSessionCookie = new ConfigKey<Boolean>("Advanced", Boolean.class, "enable.secure.session.cookie", "false",
232+
"Session cookie is marked as secure if this is enabled. Secure cookies only work when HTTPS is used.", false);
233+
234+
static final ConfigKey<String> JSONcontentType = new ConfigKey<String>(String.class, "json.content.type", "Advanced", "application/json; charset=UTF-8",
235+
"Http response content type for .js files (default is text/javascript)", false, ConfigKey.Scope.Global, null);
230236
@Inject
231237
private MessageBus messageBus;
232238

@@ -366,14 +372,6 @@ public boolean start() {
366372
}
367373

368374
setEncodeApiResponse(Boolean.valueOf(configDao.getValue(Config.EncodeApiResponse.key())));
369-
final String jsonType = configDao.getValue(Config.JSONDefaultContentType.key());
370-
if (jsonType != null) {
371-
jsonContentType = jsonType;
372-
}
373-
final Boolean enableSecureSessionCookie = Boolean.valueOf(configDao.getValue(Config.EnableSecureSessionCookie.key()));
374-
if (enableSecureSessionCookie != null) {
375-
enableSecureCookie = enableSecureSessionCookie;
376-
}
377375

378376
if (apiPort != null) {
379377
final ListenerThread listenerThread = new ListenerThread(this, apiPort);
@@ -1143,7 +1141,7 @@ private void writeResponse(final HttpResponse resp, final String responseText, f
11431141
final BasicHttpEntity body = new BasicHttpEntity();
11441142
if (HttpUtils.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) {
11451143
// JSON response
1146-
body.setContentType(getJSONContentType());
1144+
body.setContentType(JSONcontentType.value());
11471145
if (responseText == null) {
11481146
body.setContent(new ByteArrayInputStream("{ \"error\" : { \"description\" : \"Internal Server Error\" } }".getBytes(HttpUtils.UTF_8)));
11491147
}
@@ -1163,6 +1161,16 @@ private void writeResponse(final HttpResponse resp, final String responseText, f
11631161
}
11641162
}
11651163

1164+
@Override
1165+
public String getConfigComponentName() {
1166+
return ApiServer.class.getSimpleName();
1167+
}
1168+
1169+
@Override
1170+
public ConfigKey<?>[] getConfigKeys() {
1171+
return new ConfigKey<?>[] { EnableSecureSessionCookie, JSONcontentType };
1172+
}
1173+
11661174
// FIXME: the following two threads are copied from
11671175
// http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/httpcore/src/examples/org/apache/http/examples/ElementalHttpServer.java
11681176
// we have to cite a license if we are using this code directly, so we need to add the appropriate citation or
@@ -1366,13 +1374,4 @@ private static void setEncodeApiResponse(final boolean encodeApiResponse) {
13661374
ApiServer.encodeApiResponse = encodeApiResponse;
13671375
}
13681376

1369-
@Override
1370-
public boolean isSecureSessionCookieEnabled() {
1371-
return enableSecureCookie;
1372-
}
1373-
1374-
@Override
1375-
public String getJSONContentType() {
1376-
return jsonContentType;
1377-
}
13781377
}

server/src/com/cloud/api/ApiServlet.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp
158158
try {
159159

160160
if (HttpUtils.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) {
161-
resp.setContentType(apiServer.getJSONContentType());
161+
resp.setContentType(ApiServer.JSONcontentType.value());
162162
} else if (HttpUtils.RESPONSE_TYPE_XML.equalsIgnoreCase(responseType)){
163163
resp.setContentType(HttpUtils.XML_CONTENT_TYPE);
164164
}
@@ -189,12 +189,10 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp
189189
}
190190
}
191191
session = req.getSession(true);
192-
if (apiServer.isSecureSessionCookieEnabled()) {
192+
if (ApiServer.EnableSecureSessionCookie.value()) {
193193
resp.setHeader("SET-COOKIE", String.format("JSESSIONID=%s;Secure;HttpOnly;Path=/client", session.getId()));
194194
if (s_logger.isDebugEnabled()) {
195-
if (s_logger.isDebugEnabled()) {
196-
s_logger.debug("Session cookie is marked secure!");
197-
}
195+
s_logger.debug("Session cookie is marked secure!");
198196
}
199197
}
200198
}
@@ -231,7 +229,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp
231229
sessionKeyCookie.setMaxAge(0);
232230
resp.addCookie(sessionKeyCookie);
233231
}
234-
HttpUtils.writeHttpResponse(resp, responseString, httpResponseCode, responseType, apiServer.getJSONContentType());
232+
HttpUtils.writeHttpResponse(resp, responseString, httpResponseCode, responseType, ApiServer.JSONcontentType.value());
235233
return;
236234
}
237235
}
@@ -256,7 +254,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp
256254
auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials");
257255
final String serializedResponse =
258256
apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType);
259-
HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType());
257+
HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.JSONcontentType.value());
260258
return;
261259
}
262260

@@ -267,7 +265,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp
267265
s_logger.info("missing command, ignoring request...");
268266
auditTrailSb.append(" " + HttpServletResponse.SC_BAD_REQUEST + " " + "no command specified");
269267
final String serializedResponse = apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType);
270-
HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST, responseType, apiServer.getJSONContentType());
268+
HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST, responseType, ApiServer.JSONcontentType.value());
271269
return;
272270
}
273271
final User user = entityMgr.findById(User.class, userId);
@@ -283,7 +281,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp
283281
auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials");
284282
final String serializedResponse =
285283
apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType);
286-
HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType());
284+
HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.JSONcontentType.value());
287285
return;
288286
}
289287
} else {
@@ -297,7 +295,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp
297295
// Add the HTTP method (GET/POST/PUT/DELETE) as well into the params map.
298296
params.put("httpmethod", new String[] {req.getMethod()});
299297
final String response = apiServer.handleRequest(params, responseType, auditTrailSb);
300-
HttpUtils.writeHttpResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType, apiServer.getJSONContentType());
298+
HttpUtils.writeHttpResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType, ApiServer.JSONcontentType.value());
301299
} else {
302300
if (session != null) {
303301
try {
@@ -310,13 +308,13 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp
310308
final String serializedResponse =
311309
apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params,
312310
responseType);
313-
HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType());
311+
HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.JSONcontentType.value());
314312

315313
}
316314
} catch (final ServerApiException se) {
317315
final String serializedResponseText = apiServer.getSerializedApiError(se, params, responseType);
318316
resp.setHeader("X-Description", se.getDescription());
319-
HttpUtils.writeHttpResponse(resp, serializedResponseText, se.getErrorCode().getHttpCode(), responseType, apiServer.getJSONContentType());
317+
HttpUtils.writeHttpResponse(resp, serializedResponseText, se.getErrorCode().getHttpCode(), responseType, ApiServer.JSONcontentType.value());
320318
auditTrailSb.append(" " + se.getErrorCode() + " " + se.getDescription());
321319
} catch (final Exception ex) {
322320
s_logger.error("unknown exception writing api response", ex);

server/src/com/cloud/configuration/Config.java

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -489,10 +489,7 @@ public enum Config {
489489
null),
490490

491491
// Snapshots
492-
SnapshotHourlyMax("Snapshots", SnapshotManager.class, Integer.class, "snapshot.max.hourly", "8", "Maximum hourly snapshots for a volume", null),
493-
SnapshotDailyMax("Snapshots", SnapshotManager.class, Integer.class, "snapshot.max.daily", "8", "Maximum daily snapshots for a volume", null),
494-
SnapshotWeeklyMax("Snapshots", SnapshotManager.class, Integer.class, "snapshot.max.weekly", "8", "Maximum weekly snapshots for a volume", null),
495-
SnapshotMonthlyMax("Snapshots", SnapshotManager.class, Integer.class, "snapshot.max.monthly", "8", "Maximum monthly snapshots for a volume", null),
492+
496493
SnapshotPollInterval(
497494
"Snapshots",
498495
SnapshotManager.class,
@@ -1500,24 +1497,6 @@ public enum Config {
15001497
"Percentage (as a value between 0 and 1) of connected agents after which agent load balancing will start happening",
15011498
null),
15021499

1503-
JSONDefaultContentType(
1504-
"Advanced",
1505-
ManagementServer.class,
1506-
String.class,
1507-
"json.content.type",
1508-
"application/json; charset=UTF-8",
1509-
"Http response content type for JSON",
1510-
null),
1511-
1512-
EnableSecureSessionCookie(
1513-
"Advanced",
1514-
ManagementServer.class,
1515-
Boolean.class,
1516-
"enable.secure.session.cookie",
1517-
"false",
1518-
"Session cookie's secure flag is enabled if true. Use this only when using HTTPS",
1519-
null),
1520-
15211500
DefaultMaxDomainUserVms("Domain Defaults", ManagementServer.class, Long.class, "max.domain.user.vms", "40", "The default maximum number of user VMs that can be deployed for a domain", null),
15221501
DefaultMaxDomainPublicIPs("Domain Defaults", ManagementServer.class, Long.class, "max.domain.public.ips", "40", "The default maximum number of public IPs that can be consumed by a domain", null),
15231502
DefaultMaxDomainTemplates("Domain Defaults", ManagementServer.class, Long.class, "max.domain.templates", "40", "The default maximum number of templates that can be deployed for a domain", null),

server/src/com/cloud/storage/snapshot/SnapshotManager.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,24 @@
2525
import com.cloud.storage.Snapshot;
2626
import com.cloud.storage.SnapshotVO;
2727
import com.cloud.storage.Volume;
28+
import org.apache.cloudstack.framework.config.ConfigKey;
2829

2930
/**
3031
*
3132
*
3233
*/
3334
public interface SnapshotManager {
34-
35-
public static final int HOURLYMAX = 8;
36-
public static final int DAILYMAX = 8;
37-
public static final int WEEKLYMAX = 8;
38-
public static final int MONTHLYMAX = 12;
3935
public static final int DELTAMAX = 16;
4036

37+
static final ConfigKey<Integer> SnapshotHourlyMax = new ConfigKey<Integer>(Integer.class, "snapshot.max.hourly", "Snapshots", "8",
38+
"Maximum recurring hourly snapshots to be retained for a volume. If the limit is reached, early snapshots from the start of the hour are deleted so that newer ones can be saved. This limit does not apply to manual snapshots. If set to 0, recurring hourly snapshots can not be scheduled.", false, ConfigKey.Scope.Global, null);
39+
static final ConfigKey<Integer> SnapshotDailyMax = new ConfigKey<Integer>(Integer.class, "snapshot.max.daily", "Snapshots", "8",
40+
"Maximum recurring daily snapshots to be retained for a volume. If the limit is reached, snapshots from the start of the day are deleted so that newer ones can be saved. This limit does not apply to manual snapshots. If set to 0, recurring daily snapshots can not be scheduled.", false, ConfigKey.Scope.Global, null);
41+
static final ConfigKey<Integer> SnapshotWeeklyMax = new ConfigKey<Integer>(Integer.class, "snapshot.max.weekly", "Snapshots", "8",
42+
"Maximum recurring weekly snapshots to be retained for a volume. If the limit is reached, snapshots from the beginning of the week are deleted so that newer ones can be saved. This limit does not apply to manual snapshots. If set to 0, recurring weekly snapshots can not be scheduled.", false, ConfigKey.Scope.Global, null);
43+
static final ConfigKey<Integer> SnapshotMonthlyMax = new ConfigKey<Integer>(Integer.class, "snapshot.max.monthly", "Snapshots", "8",
44+
"Maximum recurring monthly snapshots to be retained for a volume. If the limit is reached, snapshots from the beginning of the month are deleted so that newer ones can be saved. This limit does not apply to manual snapshots. If set to 0, recurring monthly snapshots can not be scheduled.", false, ConfigKey.Scope.Global, null);
45+
4146
void deletePoliciesForVolume(Long volumeId);
4247

4348
/**

server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@
111111
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
112112
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
113113
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
114+
import org.apache.cloudstack.framework.config.ConfigKey;
115+
import org.apache.cloudstack.framework.config.Configurable;
114116
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
115117
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
116118
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
@@ -128,7 +130,7 @@
128130
import java.util.TimeZone;
129131

130132
@Component
131-
public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements SnapshotManager, SnapshotApiService {
133+
public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements SnapshotManager, SnapshotApiService, Configurable {
132134
private static final Logger s_logger = Logger.getLogger(SnapshotManagerImpl.class);
133135
@Inject
134136
VMTemplateDao _templateDao;
@@ -1176,10 +1178,10 @@ public boolean configure(String name, Map<String, Object> params) throws Configu
11761178

11771179
String value = _configDao.getValue(Config.BackupSnapshotWait.toString());
11781180

1179-
Type.HOURLY.setMax(NumbersUtil.parseInt(_configDao.getValue("snapshot.max.hourly"), HOURLYMAX));
1180-
Type.DAILY.setMax(NumbersUtil.parseInt(_configDao.getValue("snapshot.max.daily"), DAILYMAX));
1181-
Type.WEEKLY.setMax(NumbersUtil.parseInt(_configDao.getValue("snapshot.max.weekly"), WEEKLYMAX));
1182-
Type.MONTHLY.setMax(NumbersUtil.parseInt(_configDao.getValue("snapshot.max.monthly"), MONTHLYMAX));
1181+
Type.HOURLY.setMax(SnapshotHourlyMax.value());
1182+
Type.DAILY.setMax(SnapshotDailyMax.value());
1183+
Type.WEEKLY.setMax(SnapshotWeeklyMax.value());
1184+
Type.MONTHLY.setMax(SnapshotMonthlyMax.value());
11831185
_totalRetries = NumbersUtil.parseInt(_configDao.getValue("total.retries"), 4);
11841186
_pauseInterval = 2 * NumbersUtil.parseInt(_configDao.getValue("ping.interval"), 60);
11851187

@@ -1319,5 +1321,12 @@ public Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName,
13191321
}
13201322

13211323

1324+
@Override
1325+
public String getConfigComponentName() {
1326+
return SnapshotManager.class.getSimpleName();
1327+
}
13221328

1329+
@Override
1330+
public ConfigKey<?>[] getConfigKeys() {
1331+
return new ConfigKey<?>[] { SnapshotHourlyMax, SnapshotDailyMax, SnapshotMonthlyMax, SnapshotWeeklyMax}; }
13231332
}

utils/src/main/java/com/cloud/utils/HttpUtils.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ public static void addSecurityHeaders(final HttpServletResponse resp) {
5050
else {
5151
resp.addHeader("X-XSS-Protection", "1;mode=block");
5252
}
53+
54+
if (resp.containsHeader("content-security-policy")) {
55+
resp.setIntHeader("content-security-policy", 1);
56+
}else {
57+
resp.addIntHeader("content-security-policy", 1);
58+
}
59+
resp.addHeader("content-security-policy","default-src=none");
60+
resp.addHeader("content-security-policy","script-src=self");
61+
resp.addHeader("content-security-policy","connect-src=self");
62+
resp.addHeader("content-security-policy","img-src=self");
63+
resp.addHeader("content-security-policy","style-src=self");
5364
}
5465

5566
public static void writeHttpResponse(final HttpServletResponse resp, final String response,

0 commit comments

Comments
 (0)