All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dk.cloudcreate.essentials.components.distributed.fencedlock.springdata.mongo.MongoFencedLockManagerBuilder Maven / Gradle / Ivy

/*
 * Copyright 2021-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dk.cloudcreate.essentials.components.distributed.fencedlock.springdata.mongo;

import dk.cloudcreate.essentials.components.foundation.IOExceptionUtil;
import dk.cloudcreate.essentials.components.foundation.fencedlock.*;
import dk.cloudcreate.essentials.components.foundation.mongo.MongoUtil;
import dk.cloudcreate.essentials.components.foundation.transaction.*;
import dk.cloudcreate.essentials.components.foundation.transaction.mongo.ClientSessionAwareUnitOfWork;
import dk.cloudcreate.essentials.reactive.*;
import org.springframework.data.mongodb.core.MongoTemplate;

import java.time.*;
import java.util.Optional;

/**
 * Security
* It is the responsibility of the user of this component to sanitize the {@link #setFencedLocksCollectionName(String)} * to ensure the security of the resulting MongoDB configuration and associated Queries/Updates/etc. The {@link MongoFencedLockStorage} component, used by the {@link MongoFencedLockManager}, will * call the {@link MongoUtil#checkIsValidCollectionName(String)} method to validate the collection name as a first line of defense.
* The method provided is designed as an initial layer of defense against users providing unsafe collection names, by applying naming conventions intended to reduce the risk of malicious input.
* However, Essentials components as well as {@link MongoUtil#checkIsValidCollectionName(String)} does not offer exhaustive protection, nor does it assure the complete security of the resulting MongoDB configuration and associated Queries/Updates/etc..
* The responsibility for implementing protective measures against malicious input lies exclusively with the users/developers using the Essentials components and its supporting classes.
* Users must ensure thorough sanitization and validation of API input parameters, collection names.
* Insufficient attention to these practices may leave the application vulnerable to attacks, potentially endangering the security and integrity of the database.
*
* It is highly recommended that the {@code fencedLocksCollectionName} value is only derived from a controlled and trusted source.
* To mitigate the risk of malicious input attacks, external or untrusted inputs should never directly provide the {@code fencedLocksCollectionName} value.
* Failure to adequately sanitize and validate this value could expose the application to malicious input attacks, compromising the security and integrity of the database. */ public final class MongoFencedLockManagerBuilder { private MongoTemplate mongoTemplate; private UnitOfWorkFactory unitOfWorkFactory; private Optional lockManagerInstanceId = Optional.empty(); private String fencedLocksCollectionName = MongoFencedLockStorage.DEFAULT_FENCED_LOCKS_COLLECTION_NAME; private Duration lockTimeOut; private Duration lockConfirmationInterval; boolean releaseAcquiredLocksInCaseOfIOExceptionsDuringLockConfirmation = false; private Optional eventBus = Optional.empty(); /** * @param mongoTemplate the mongoTemplate instance * @return this builder instance */ public MongoFencedLockManagerBuilder setMongoTemplate(MongoTemplate mongoTemplate) { this.mongoTemplate = mongoTemplate; return this; } /** * @param unitOfWorkFactory The unit of work factory * @return this builder instance */ public MongoFencedLockManagerBuilder setUnitOfWorkFactory(UnitOfWorkFactory unitOfWorkFactory) { this.unitOfWorkFactory = unitOfWorkFactory; return this; } /** * @param lockManagerInstanceId The unique name for this lock manager instance. If left {@link Optional#empty()} then the machines hostname is used * @return this builder instance */ public MongoFencedLockManagerBuilder setLockManagerInstanceId(Optional lockManagerInstanceId) { this.lockManagerInstanceId = lockManagerInstanceId; return this; } /** * @param releaseAcquiredLocksInCaseOfIOExceptionsDuringLockConfirmation Should {@link FencedLock}'s acquired by this {@link FencedLockManager} be released in case calls to {@link FencedLockStorage#confirmLockInDB(DBFencedLockManager, UnitOfWork, DBFencedLock, OffsetDateTime)} fails * with an exception where {@link IOExceptionUtil#isIOException(Throwable)} returns true - * If releaseAcquiredLocksInCaseOfIOExceptionsDuringLockConfirmation is true, then {@link FencedLock}'s will be released locally, * otherwise we will retain the {@link FencedLock}'s as locked.
* Default value is: false * @return this builder instance */ public MongoFencedLockManagerBuilder setReleaseAcquiredLocksInCaseOfIOExceptionsDuringLockConfirmation(boolean releaseAcquiredLocksInCaseOfIOExceptionsDuringLockConfirmation) { this.releaseAcquiredLocksInCaseOfIOExceptionsDuringLockConfirmation = releaseAcquiredLocksInCaseOfIOExceptionsDuringLockConfirmation; return this; } /** * @param fencedLocksCollectionName The name of the collection where the locks will be stored. * Note:
* To support customization of storage collection name, the {@code fencedLocksCollectionName} will be directly used as Collection name, * which exposes the component to the risk of malicious input.
*
* Security Note:
* It is the responsibility of the user of this component to sanitize the {@code fencedLocksCollectionName} * to ensure the security of the resulting MongoDB configuration and associated Queries/Updates/etc. The {@link MongoFencedLockStorage} component, used by the {@link MongoFencedLockManager}, will * call the {@link MongoUtil#checkIsValidCollectionName(String)} method to validate the collection name as a first line of defense.
* The method provided is designed as an initial layer of defense against users providing unsafe collection names, by applying naming conventions intended to reduce the risk of malicious input.
* However, Essentials components as well as {@link MongoUtil#checkIsValidCollectionName(String)} does not offer exhaustive protection, nor does it assure the complete security of the resulting MongoDB configuration and associated Queries/Updates/etc..
* The responsibility for implementing protective measures against malicious input lies exclusively with the users/developers using the Essentials components and its supporting classes.
* Users must ensure thorough sanitization and validation of API input parameters, collection names.
* Insufficient attention to these practices may leave the application vulnerable to attacks, potentially endangering the security and integrity of the database.
*
* It is highly recommended that the {@code fencedLocksCollectionName} value is only derived from a controlled and trusted source.
* To mitigate the risk of malicious input attacks, external or untrusted inputs should never directly provide the {@code fencedLocksCollectionName} value.
* Failure to adequately sanitize and validate this value could expose the application to malicious input attacks, compromising the security and integrity of the database. * @return this builder instance */ public MongoFencedLockManagerBuilder setFencedLocksCollectionName(String fencedLocksCollectionName) { this.fencedLocksCollectionName = fencedLocksCollectionName; return this; } /** * @param lockManagerInstanceId The unique name for this lock manager instance. If null then the machines hostname is used * @return this builder instance */ public MongoFencedLockManagerBuilder setLockManagerInstanceId(String lockManagerInstanceId) { this.lockManagerInstanceId = Optional.ofNullable(lockManagerInstanceId); return this; } /** * @param lockTimeOut the period between {@link FencedLock#getLockLastConfirmedTimestamp()} and the current time before the lock is marked as timed out * @return this builder instance */ public MongoFencedLockManagerBuilder setLockTimeOut(Duration lockTimeOut) { this.lockTimeOut = lockTimeOut; return this; } /** * @param lockConfirmationInterval how often should the locks be confirmed. MUST is less than the lockTimeOut * @return this builder instance */ public MongoFencedLockManagerBuilder setLockConfirmationInterval(Duration lockConfirmationInterval) { this.lockConfirmationInterval = lockConfirmationInterval; return this; } /** * @param eventBus optional {@link LocalEventBus} where {@link FencedLockEvents} will be published * @return this builder instance */ public MongoFencedLockManagerBuilder setEventBus(Optional eventBus) { this.eventBus = eventBus; return this; } /** * @param eventBus optional {@link LocalEventBus} where {@link FencedLockEvents} will be published * @return this builder instance */ public MongoFencedLockManagerBuilder setEventBus(EventBus eventBus) { this.eventBus = Optional.ofNullable(eventBus); return this; } /** * Create the new {@link MongoFencedLockManager} instance * * @return the new {@link MongoFencedLockManager} instance */ public MongoFencedLockManager build() { return new MongoFencedLockManager(mongoTemplate, unitOfWorkFactory, lockManagerInstanceId, fencedLocksCollectionName, lockTimeOut, lockConfirmationInterval, releaseAcquiredLocksInCaseOfIOExceptionsDuringLockConfirmation, eventBus); } /** * Create the new {@link MongoFencedLockManager} instance and call {@link MongoFencedLockManager#start()} immediately * * @return the new {@link MongoFencedLockManager} instance */ public MongoFencedLockManager buildAndStart() { var instance = build(); instance.start(); return instance; } }