New repository quota on messages per ActionStatus (#531)
* New quotaexception for repository quota hit on DDI. Added actionstatus messages quota. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Remove special log handling on the quota exception. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Raise time for slow machines. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Update allure to get rid of log spam in unit tests. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Typos fixed. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -20,8 +20,7 @@ import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException;
|
||||
import org.eclipse.hawkbit.repository.exception.TooManyStatusEntriesException;
|
||||
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
@@ -52,9 +51,9 @@ public interface ControllerManagement {
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if a given entity already exists
|
||||
*
|
||||
* @throws TooManyStatusEntriesException
|
||||
* if more than the allowed number of status entries are
|
||||
* inserted
|
||||
* @throws QuotaExceededException
|
||||
* if more than the allowed number of status entries or messages
|
||||
* per entry are inserted
|
||||
* @throws EntityNotFoundException
|
||||
* if given action does not exist
|
||||
*
|
||||
@@ -87,9 +86,9 @@ public interface ControllerManagement {
|
||||
*
|
||||
* @return created {@link ActionStatus} entity
|
||||
*
|
||||
* @throws TooManyStatusEntriesException
|
||||
* if more than the allowed number of status entries are
|
||||
* inserted
|
||||
* @throws QuotaExceededException
|
||||
* if more than the allowed number of status entries or messages
|
||||
* per entry are inserted
|
||||
* @throws EntityNotFoundException
|
||||
* if given action does not exist
|
||||
*/
|
||||
@@ -106,9 +105,9 @@ public interface ControllerManagement {
|
||||
*
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if a given entity already exists
|
||||
* @throws TooManyStatusEntriesException
|
||||
* if more than the allowed number of status entries are
|
||||
* inserted
|
||||
* @throws QuotaExceededException
|
||||
* if more than the allowed number of status entries or messages
|
||||
* per entry are inserted
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if action status not exist
|
||||
@@ -267,8 +266,8 @@ public interface ControllerManagement {
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if target that has to be updated could not be found
|
||||
* @throws ToManyAttributeEntriesException
|
||||
* if maximum
|
||||
* @throws QuotaExceededException
|
||||
* if maximum number of attribzes per target is exceeded
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map<String, String> attributes);
|
||||
|
||||
@@ -36,4 +36,11 @@ public interface QuotaManagement {
|
||||
*/
|
||||
int getMaxRolloutGroupsPerRollout();
|
||||
|
||||
/**
|
||||
* @return maximum number of
|
||||
* {@link ControllerManagement#getActionHistoryMessages(Long, int)}
|
||||
* for an individual {@link ActionStatus}.
|
||||
*/
|
||||
int getMaxMessagesPerActionStatus();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
|
||||
/**
|
||||
* Thrown if too many entries are added to repository.
|
||||
*
|
||||
*/
|
||||
public final class QuotaExceededException extends AbstractServerRtException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new QuotaExceededException with
|
||||
* {@link SpServerError#SP_QUOTA_EXCEEDED} error.
|
||||
*/
|
||||
public QuotaExceededException() {
|
||||
super(SpServerError.SP_QUOTA_EXCEEDED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public QuotaExceededException(final Throwable cause) {
|
||||
super(SpServerError.SP_QUOTA_EXCEEDED, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* that hit quota
|
||||
* @param inserted
|
||||
* cause for the hit
|
||||
* @param quota
|
||||
* that is defined by the repository
|
||||
*/
|
||||
public QuotaExceededException(final Class<? extends BaseEntity> type, final long inserted, final int quota) {
|
||||
this(type.getSimpleName(), inserted, quota);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
* that hit quota
|
||||
* @param inserted
|
||||
* cause for the hit
|
||||
* @param quota
|
||||
* that is defined by the repository
|
||||
*/
|
||||
public QuotaExceededException(final String type, final long inserted, final int quota) {
|
||||
super("Request contains too many entries of {" + type + "}. {" + inserted + "} is bejond the permitted {"
|
||||
+ quota + "}.", SpServerError.SP_QUOTA_EXCEEDED);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
|
||||
/**
|
||||
* Thrown if too many status entries have been inserted.
|
||||
*/
|
||||
public final class ToManyAttributeEntriesException extends AbstractServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_ATTRIBUTES_TO_MANY_ENTRIES} error.
|
||||
*/
|
||||
public ToManyAttributeEntriesException() {
|
||||
super(SpServerError.SP_ATTRIBUTES_TO_MANY_ENTRIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public ToManyAttributeEntriesException(final Throwable cause) {
|
||||
super(SpServerError.SP_ATTRIBUTES_TO_MANY_ENTRIES, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public ToManyAttributeEntriesException(final String message) {
|
||||
super(message, SpServerError.SP_ATTRIBUTES_TO_MANY_ENTRIES);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
|
||||
/**
|
||||
* Thrown if too many status entries have been inserted.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class TooManyStatusEntriesException extends AbstractServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_REST_BODY_NOT_READABLE} error.
|
||||
*/
|
||||
public TooManyStatusEntriesException() {
|
||||
super(SpServerError.SP_ACTION_STATUS_TO_MANY_ENTRIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public TooManyStatusEntriesException(final Throwable cause) {
|
||||
super(SpServerError.SP_ACTION_STATUS_TO_MANY_ENTRIES, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public TooManyStatusEntriesException(final String message) {
|
||||
super(message, SpServerError.SP_ACTION_STATUS_TO_MANY_ENTRIES);
|
||||
}
|
||||
}
|
||||
@@ -43,4 +43,9 @@ public class PropertiesQuotaManagement implements QuotaManagement {
|
||||
return securityProperties.getDos().getMaxRolloutGroupsPerRollout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxMessagesPerActionStatus() {
|
||||
return securityProperties.getDos().getMaxMessagesPerActionStatus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,7 @@ import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException;
|
||||
import org.eclipse.hawkbit.repository.exception.TooManyStatusEntriesException;
|
||||
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
@@ -79,7 +78,6 @@ import org.springframework.validation.annotation.Validated;
|
||||
@Validated
|
||||
public class JpaControllerManagement implements ControllerManagement {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ControllerManagement.class);
|
||||
private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos");
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
@@ -277,7 +275,8 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
break;
|
||||
default:
|
||||
// information status entry - check for a potential DOS attack
|
||||
checkForToManyStatusEntries(action);
|
||||
checkForTooManyStatusEntries(action);
|
||||
checkForTooManyStatusMessages(actionStatus);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -287,6 +286,14 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
return action;
|
||||
}
|
||||
|
||||
private void checkForTooManyStatusMessages(final JpaActionStatus actionStatus) {
|
||||
if (actionStatus.getMessages().size() > quotaManagement.getMaxMessagesPerActionStatus()) {
|
||||
throw new QuotaExceededException("ActionStatus messages", actionStatus.getMessages().size(),
|
||||
quotaManagement.getMaxStatusEntriesPerAction());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleFinishedCancelation(final JpaActionStatus actionStatus, final JpaAction action) {
|
||||
// in case of successful cancellation we also report the success at
|
||||
// the canceled action itself.
|
||||
@@ -340,7 +347,8 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
break;
|
||||
default:
|
||||
// information status entry - check for a potential DOS attack
|
||||
checkForToManyStatusEntries(action);
|
||||
checkForTooManyStatusEntries(action);
|
||||
checkForTooManyStatusMessages(actionStatus);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -360,16 +368,14 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
targetRepository.save(mergedTarget);
|
||||
}
|
||||
|
||||
private void checkForToManyStatusEntries(final JpaAction action) {
|
||||
private void checkForTooManyStatusEntries(final JpaAction action) {
|
||||
if (quotaManagement.getMaxStatusEntriesPerAction() > 0) {
|
||||
|
||||
final Long statusCount = actionStatusRepository.countByAction(action);
|
||||
|
||||
if (statusCount >= quotaManagement.getMaxStatusEntriesPerAction()) {
|
||||
LOG_DOS.error(
|
||||
"Potential denial of service (DOS) attack identfied. More status entries in the system than permitted ({})!",
|
||||
throw new QuotaExceededException(ActionStatus.class, statusCount,
|
||||
quotaManagement.getMaxStatusEntriesPerAction());
|
||||
throw new TooManyStatusEntriesException(String.valueOf(quotaManagement.getMaxStatusEntriesPerAction()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -406,10 +412,8 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
target.getControllerAttributes().putAll(data);
|
||||
|
||||
if (target.getControllerAttributes().size() > quotaManagement.getMaxAttributeEntriesPerTarget()) {
|
||||
LOG_DOS.info("Target tries to insert more than the allowed number of entries ({}). DOS attack anticipated!",
|
||||
throw new QuotaExceededException("Controller attribues", target.getControllerAttributes().size(),
|
||||
quotaManagement.getMaxAttributeEntriesPerTarget());
|
||||
throw new ToManyAttributeEntriesException(
|
||||
String.valueOf(quotaManagement.getMaxAttributeEntriesPerTarget()));
|
||||
}
|
||||
|
||||
target.setRequestControllerAttributes(false);
|
||||
@@ -488,7 +492,8 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
final JpaActionStatus statusMessage = create.build();
|
||||
statusMessage.setAction(action);
|
||||
|
||||
checkForToManyStatusEntries(action);
|
||||
checkForTooManyStatusEntries(action);
|
||||
checkForTooManyStatusMessages(statusMessage);
|
||||
|
||||
return actionStatusRepository.save(statusMessage);
|
||||
}
|
||||
@@ -533,11 +538,11 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
|
||||
// For negative and large value of messageCount, limit the number of
|
||||
// messages.
|
||||
int limit = messageCount < 0 || messageCount >= RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT
|
||||
final int limit = messageCount < 0 || messageCount >= RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT
|
||||
? RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT : messageCount;
|
||||
|
||||
PageRequest pageable = new PageRequest(0, limit, new Sort(Direction.DESC, "occurredAt"));
|
||||
Page<String> messages = actionStatusRepository.findMessagesByActionIdAndMessageNotLike(pageable, actionId,
|
||||
final PageRequest pageable = new PageRequest(0, limit, new Sort(Direction.DESC, "occurredAt"));
|
||||
final Page<String> messages = actionStatusRepository.findMessagesByActionIdAndMessageNotLike(pageable, actionId,
|
||||
RepositoryConstants.SERVER_MESSAGE_PREFIX + "%");
|
||||
|
||||
LOG.debug("Retrieved {} message(s) from action history for action {}.", messages.getNumberOfElements(),
|
||||
|
||||
Reference in New Issue
Block a user