From 9b5e37d28527d629db1829d679b967f63a68a015 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Tue, 24 Oct 2023 23:20:09 +1100 Subject: [PATCH 01/58] Begin work on authenticator framework for allowing global auth (RESTRICTED) mode, or intermediate (HYBRID) mode that applies authentication on only select sub queues. --- .../authentication/AuthenticationMatrix.kt | 53 ++++++++ .../AuthenticationMatrixDocument.kt | 34 +++++ .../MultiQueueAuthenticationType.kt | 30 +++++ .../authenticator/MultiQueueAuthenticator.kt | 78 ++++++++++++ .../cache/redis/RedisAuthenticator.kt | 41 +++++++ .../inmemory/InMemoryAuthenticator.kt | 32 +++++ .../MongoAuthenticationMatrixRepository.kt | 15 +++ .../nosql/mongo/MongoAuthenticator.kt | 41 +++++++ .../sql/SqlAuthenticationMatrixRepository.kt | 18 +++ .../authenticator/sql/SqlAuthenticator.kt | 40 ++++++ .../configuration/QueueConfiguration.kt | 57 ++++++++- .../cache/redis/RedisConfiguration.kt | 20 ++- .../filter/CorrelationIdFilter.kt | 2 +- .../filter/JwtAuthenticationFilter.kt | 116 ++++++++++++++++++ .../repository/MongoQueueMessageRepository.kt | 1 - .../messagequeue/queue/sql/SqlMultiQueue.kt | 5 +- ...sitory.kt => SqlQueueMessageRepository.kt} | 2 +- .../settings/MessageQueueSettings.kt | 21 ++++ 18 files changed, 597 insertions(+), 9 deletions(-) create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/MultiQueueAuthenticationType.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticationMatrixRepository.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticationMatrixRepository.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt rename src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/{SQLQueueMessageRepository.kt => SqlQueueMessageRepository.kt} (98%) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt new file mode 100644 index 0000000..cc58a22 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt @@ -0,0 +1,53 @@ +package au.kilemon.messagequeue.authentication + +import au.kilemon.messagequeue.message.QueueMessage +import com.fasterxml.jackson.annotation.JsonIgnore +import javax.persistence.* + +/** + * + * + * @author github.com/Kilemonn + */ +@Entity +@Table(name = AuthenticationMatrix.TABLE_NAME) +class AuthenticationMatrix(@Column(name = "subqueue", nullable = false) var subQueue: String) +{ + companion object + { + const val TABLE_NAME: String = "multiqueueauthenticationmatrix" + } + + @JsonIgnore + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + + /** + * Required for JSON deserialisation. + */ + constructor() : this("") + + /** + * Overriding to only include specific properties when checking if messages are equal. + * This checks the following are equal in order to return `true`: + * - subQueue + */ + override fun equals(other: Any?): Boolean + { + if (other == null || other !is AuthenticationMatrix) + { + return false + } + + return other.subQueue == this.subQueue + } + + /** + * Only performs a hashcode on the properties checked in [AuthenticationMatrix.equals]. + */ + override fun hashCode(): Int + { + return subQueue.hashCode() + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt new file mode 100644 index 0000000..051ab5f --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt @@ -0,0 +1,34 @@ +package au.kilemon.messagequeue.authentication + +import com.fasterxml.jackson.annotation.JsonIgnore +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.mapping.Document + +/** + * + * + * @author github.com/Kilemonn + */ +@Document(value = AuthenticationMatrixDocument.DOCUMENT_NAME) +class AuthenticationMatrixDocument(var subQueue: String) +{ + companion object + { + const val DOCUMENT_NAME: String = "multiqueueauthenticationmatrix" + } + + @JsonIgnore + @Id + var id: Long? = null + + /** + * Required for JSON deserialisation. + */ + constructor() : this("") + + constructor(authenticationMatrix: AuthenticationMatrix) : this() + { + this.id = authenticationMatrix.id + this.subQueue = authenticationMatrix.subQueue + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/MultiQueueAuthenticationType.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/MultiQueueAuthenticationType.kt new file mode 100644 index 0000000..d571c90 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/MultiQueueAuthenticationType.kt @@ -0,0 +1,30 @@ +package au.kilemon.messagequeue.authentication + +/** + * An enum class used to represent the different types of `MultiQueueAuthentication`. + * This will drive whether authentication is available and for which sub queues. + * + * @author github.com/Kilemonn + */ +enum class MultiQueueAuthenticationType +{ + /** + * This is the default, which enforces no authentication on any sub queue, messages can be enqueued and dequeued + * as required by any called without any form of authentication. + */ + NONE, + + /** + * This is a hybrid mode where sub queues can be created without authentication, but other sub queues can + * be created with it (if they do not already exist). + * Any sub queue created with authentication will not be accessible without a token, sub queues created without a + * token will continue to be accessible without one. + */ + HYBRID, + + /** + * This is a restricted mode that forces any sub queue to be pre-created and a token will be given before messages + * can be stored or accessed in any sub queue. + */ + RESTRICTED; +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt new file mode 100644 index 0000000..d31df42 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt @@ -0,0 +1,78 @@ +package au.kilemon.messagequeue.authentication.authenticator + +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.logging.HasLogger +import org.slf4j.Logger +import org.springframework.beans.factory.annotation.Autowired + +/** + * + * + * @author github.com/Kilemonn + */ +abstract class MultiQueueAuthenticator: HasLogger +{ + abstract override val LOG: Logger + + @Autowired + protected lateinit var multiQueueAuthenticationType: MultiQueueAuthenticationType + + /** + * + */ + fun isRestricted(subQueue: String): Boolean + { + return if (multiQueueAuthenticationType == MultiQueueAuthenticationType.NONE) + { + false + } + else + { + isRestrictedInternal(subQueue) + } + } + + /** + * + */ + abstract fun isRestrictedInternal(subQueue: String): Boolean + + + /** + * + */ + fun addRestrictedEntry(subQueue: String) + { + if (multiQueueAuthenticationType != MultiQueueAuthenticationType.NONE) + { + LOG.debug("Adding restriction level [{}] to sub queue [{}].", multiQueueAuthenticationType, subQueue) + addRestrictedEntryInternal(subQueue) + } + else + { + LOG.trace("Bypassing adding restricted entry for [{}] since the authentication type is set to [{}].", subQueue, multiQueueAuthenticationType) + } + } + + /** + * + */ + abstract fun addRestrictedEntryInternal(subQueue: String) + + /** + * + */ + fun removeRestriction(subQueue: String): Boolean + { + if (multiQueueAuthenticationType != MultiQueueAuthenticationType.NONE) + { + return removeRestrictionInternal(subQueue) + } + return false + } + + /** + * + */ + abstract fun removeRestrictionInternal(subQueue: String): Boolean +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt new file mode 100644 index 0000000..36ed465 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt @@ -0,0 +1,41 @@ +package au.kilemon.messagequeue.authentication.authenticator.cache.redis + +import au.kilemon.messagequeue.authentication.AuthenticationMatrix +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import org.slf4j.Logger +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.redis.core.RedisTemplate + +/** + * + * + * @author github.com/Kilemonn + */ +class RedisAuthenticator: MultiQueueAuthenticator() +{ + companion object + { + // TODO - Completely black list this key as its used for special purpose for redis + const val RESTRICTED_KEY = AuthenticationMatrix.TABLE_NAME + "_restricted" + } + + override val LOG: Logger = initialiseLogger() + + @Autowired + lateinit var redisTemplate: RedisTemplate + + override fun isRestrictedInternal(subQueue: String): Boolean + { + return redisTemplate.opsForSet().members(RESTRICTED_KEY)?.contains(AuthenticationMatrix(subQueue)) ?: false + } + + override fun addRestrictedEntryInternal(subQueue: String) + { + redisTemplate.opsForSet().add(RESTRICTED_KEY, AuthenticationMatrix(subQueue)) + } + + override fun removeRestrictionInternal(subQueue: String): Boolean + { + return redisTemplate.opsForSet().remove(RESTRICTED_KEY, subQueue) != null + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt new file mode 100644 index 0000000..1c79363 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt @@ -0,0 +1,32 @@ +package au.kilemon.messagequeue.authentication.authenticator.inmemory + +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import org.slf4j.Logger + +/** + * + * + * @author github.com/Kilemonn + */ +class InMemoryAuthenticator: MultiQueueAuthenticator() +{ + override val LOG: Logger = initialiseLogger() + + private val authMap = HashSet() + + override fun isRestrictedInternal(subQueue: String): Boolean + { + return authMap.contains(subQueue) + } + + override fun addRestrictedEntryInternal(subQueue: String) + { + authMap.add(subQueue) + } + + override fun removeRestrictionInternal(subQueue: String): Boolean + { + return authMap.remove(subQueue) + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticationMatrixRepository.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticationMatrixRepository.kt new file mode 100644 index 0000000..a1c7641 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticationMatrixRepository.kt @@ -0,0 +1,15 @@ +package au.kilemon.messagequeue.authentication.authenticator.nosql.mongo + +import au.kilemon.messagequeue.authentication.AuthenticationMatrix +import au.kilemon.messagequeue.authentication.AuthenticationMatrixDocument +import org.springframework.data.mongodb.repository.MongoRepository + +/** + * + * + * @author github.com/Kilemonn + */ +interface MongoAuthenticationMatrixRepository: MongoRepository +{ + fun findBySubQueue(subQueue: String): List +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt new file mode 100644 index 0000000..c4ae31f --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt @@ -0,0 +1,41 @@ +package au.kilemon.messagequeue.authentication.authenticator.nosql.mongo + +import au.kilemon.messagequeue.authentication.AuthenticationMatrix +import au.kilemon.messagequeue.authentication.AuthenticationMatrixDocument +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import org.slf4j.Logger +import org.springframework.beans.factory.annotation.Autowired + +/** + * + * + * @author github.com/Kilemonn + */ +class MongoAuthenticator: MultiQueueAuthenticator() +{ + override val LOG: Logger = initialiseLogger() + + @Autowired + lateinit var authenticationMatrixRepository: MongoAuthenticationMatrixRepository + + override fun isRestrictedInternal(subQueue: String): Boolean + { + val entries = authenticationMatrixRepository.findBySubQueue(subQueue) + return entries.isNotEmpty() + } + + override fun addRestrictedEntryInternal(subQueue: String) + { + val authMatrix = AuthenticationMatrixDocument(subQueue) + authenticationMatrixRepository.save(authMatrix) + } + + override fun removeRestrictionInternal(subQueue: String): Boolean + { + val entries = authenticationMatrixRepository.findBySubQueue(subQueue) + val entriesExist = entries.isNotEmpty() + entries.forEach { entry -> authenticationMatrixRepository.delete(entry) } + + return entriesExist + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticationMatrixRepository.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticationMatrixRepository.kt new file mode 100644 index 0000000..d1035d5 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticationMatrixRepository.kt @@ -0,0 +1,18 @@ +package au.kilemon.messagequeue.authentication.authenticator.sql + +import au.kilemon.messagequeue.authentication.AuthenticationMatrix +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +/** + * A [JpaRepository] specific for [AuthenticationMatrix] and queries made against them. + * + * Reference: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation + * + * @author github.com/Kilemonn + */ +@Repository +interface SqlAuthenticationMatrixRepository: JpaRepository +{ + fun findBySubQueue(subQueue: String): List +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt new file mode 100644 index 0000000..6cd3140 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt @@ -0,0 +1,40 @@ +package au.kilemon.messagequeue.authentication.authenticator.sql + +import au.kilemon.messagequeue.authentication.AuthenticationMatrix +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import org.slf4j.Logger +import org.springframework.beans.factory.annotation.Autowired + +/** + * + * + * @author github.com/Kilemonn + */ +class SqlAuthenticator: MultiQueueAuthenticator() +{ + override val LOG: Logger = initialiseLogger() + + @Autowired + lateinit var authenticationMatrixRepository: SqlAuthenticationMatrixRepository + + override fun isRestrictedInternal(subQueue: String): Boolean + { + val entries = authenticationMatrixRepository.findBySubQueue(subQueue) + return entries.isNotEmpty() + } + + override fun addRestrictedEntryInternal(subQueue: String) + { + val authMatrix = AuthenticationMatrix(subQueue) + authenticationMatrixRepository.save(authMatrix) + } + + override fun removeRestrictionInternal(subQueue: String): Boolean + { + val entries = authenticationMatrixRepository.findBySubQueue(subQueue) + val entriesExist = entries.isNotEmpty() + entries.forEach { entry -> authenticationMatrixRepository.delete(entry) } + + return entriesExist + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt index 7641f06..0c19d2a 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt @@ -10,6 +10,12 @@ import au.kilemon.messagequeue.queue.inmemory.InMemoryMultiQueue import au.kilemon.messagequeue.queue.nosql.mongo.MongoMultiQueue import au.kilemon.messagequeue.queue.sql.SqlMultiQueue import au.kilemon.messagequeue.settings.MessageQueueSettings +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.cache.redis.RedisAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.inmemory.InMemoryAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.nosql.mongo.MongoAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.sql.SqlAuthenticator import au.kilemon.messagequeue.settings.MultiQueueType import lombok.Generated import org.slf4j.Logger @@ -58,7 +64,7 @@ class QueueConfiguration : HasLogger // Default to in-memory var queue: MultiQueue = InMemoryMultiQueue() - when (messageQueueSettings.multiQueueType) { + when (messageQueueSettings.multiQueueType.uppercase()) { MultiQueueType.REDIS.toString() -> { queue = RedisMultiQueue(messageQueueSettings.redisPrefix, redisTemplate) } @@ -74,4 +80,53 @@ class QueueConfiguration : HasLogger return queue } + + /** + * Initialise the [MultiQueueAuthenticationType] which drives how sub queues are accessed and created. + */ + @Bean + open fun getMultiQueueAuthenticationType(): MultiQueueAuthenticationType + { + var authenticationType = MultiQueueAuthenticationType.NONE + + if (messageQueueSettings.multiQueueAuthentication.isNotBlank()) + { + try + { + authenticationType = MultiQueueAuthenticationType.valueOf(messageQueueSettings.multiQueueAuthentication.uppercase()) + } + catch (ex: Exception) + { + LOG.warn("Unable to initialise appropriate authentication type with provided value [{}], falling back to default [{}].", messageQueueSettings.multiQueueAuthentication, MultiQueueAuthenticationType.NONE, ex) + } + } + + LOG.info("Using [{}] authentication as the [{}] is set to [{}].", authenticationType, MessageQueueSettings.MULTI_QUEUE_AUTHENTICATION, messageQueueSettings.multiQueueAuthentication) + + return authenticationType + } + + /** + * Initialise the [MultiQueueAuthenticator] [Bean] based on the [MessageQueueSettings.multiQueueType]. + */ + @Bean + open fun getMultiQueueAuthenticator(): MultiQueueAuthenticator + { + var authenticator: MultiQueueAuthenticator = InMemoryAuthenticator() + when (messageQueueSettings.multiQueueType.uppercase()) { + MultiQueueType.REDIS.toString() -> { + authenticator = RedisAuthenticator() + } + MultiQueueType.SQL.toString() -> { + authenticator = SqlAuthenticator() + } + MultiQueueType.MONGO.toString() -> { + authenticator = MongoAuthenticator() + } + } + + LOG.info("Initialising [{}] authenticator as the [{}] is set to [{}].", authenticator::class.java.name, MessageQueueSettings.MULTI_QUEUE_TYPE, messageQueueSettings.multiQueueType) + + return authenticator + } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt index d45e39b..c6a6087 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt @@ -1,5 +1,6 @@ package au.kilemon.messagequeue.configuration.cache.redis +import au.kilemon.messagequeue.authentication.AuthenticationMatrix import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.settings.MessageQueueSettings @@ -156,17 +157,32 @@ class RedisConfiguration: HasLogger } /** - * Create the [RedisTemplate] from [getConnectionFactory]. + * Create a [RedisTemplate] to interact with [QueueMessage] from the [getConnectionFactory]. * * @return the [RedisTemplate] used to interface with the [RedisTemplate] cache. */ @Bean @ConditionalOnProperty(name=[MessageQueueSettings.MULTI_QUEUE_TYPE], havingValue="REDIS") - fun getRedisTemplate(): RedisTemplate + fun getQueueRedisTemplate(): RedisTemplate { val template = RedisTemplate() template.connectionFactory = getConnectionFactory() template.keySerializer = StringRedisSerializer() return template } + + /** + * Create a [RedisTemplate] to interact with [AuthenticationMatrix] from the [getConnectionFactory]. + * + * @return the [RedisTemplate] used to interface with the [RedisTemplate] cache. + */ + @Bean + @ConditionalOnProperty(name=[MessageQueueSettings.MULTI_QUEUE_TYPE], havingValue="REDIS") + fun getAuthMatrixRedisTemplate(): RedisTemplate + { + val template = RedisTemplate() + template.connectionFactory = getConnectionFactory() + template.keySerializer = StringRedisSerializer() + return template + } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/CorrelationIdFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/CorrelationIdFilter.kt index 6647cf5..4f0a3e2 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/CorrelationIdFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/CorrelationIdFilter.kt @@ -42,7 +42,7 @@ class CorrelationIdFilter: OncePerRequestFilter(), HasLogger } finally { - MDC.clear() + MDC.remove(CORRELATION_ID) } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt new file mode 100644 index 0000000..577be0d --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -0,0 +1,116 @@ +package au.kilemon.messagequeue.filter + +import au.kilemon.messagequeue.logging.HasLogger +import au.kilemon.messagequeue.queue.MultiQueue +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import org.slf4j.Logger +import org.slf4j.MDC +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.core.annotation.Order +import org.springframework.stereotype.Component +import org.springframework.web.filter.OncePerRequestFilter +import java.util.* +import javax.servlet.FilterChain +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse + +/** + * + * + * @author github.com/Kilemonn + */ +@Component +@Order(2) +class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger +{ + companion object + { + const val AUTHORIZATION_HEADER = "Authorization" + + const val SUB_QUEUE = "Sub-Queue" + } + + override val LOG: Logger = this.initialiseLogger() + + @Autowired + lateinit var authenticationType: MultiQueueAuthenticationType + + @Autowired + lateinit var authenticator: MultiQueueAuthenticator + + /** + * + */ + override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) + { + try + { + val subQueue = getSubQueueInToken(request) + setSubQueue(subQueue) + + if (authenticationType == MultiQueueAuthenticationType.NONE) + { + LOG.trace("Allowed access as authentication is set to [{}].", MultiQueueAuthenticationType.NONE) + filterChain.doFilter(request, response) + } + else if (authenticationType == MultiQueueAuthenticationType.HYBRID) + { + LOG.trace("Allowing request through for lower layer to check as authentication is set to [{}].", MultiQueueAuthenticationType.NONE) + filterChain.doFilter(request, response) + } + else if (authenticationType == MultiQueueAuthenticationType.RESTRICTED) + { + if (subQueue.isPresent && authenticator.isRestricted(subQueue.get())) + { + LOG.trace("Accepted request for sub queue [{}].", subQueue.get()) + filterChain.doFilter(request, response) + } + else + { + LOG.error("Failed to manipulate sub queue [{}] with provided token as the authentication level is set to [{}].", subQueue.get(), authenticationType) + // TODO throw here + } + } + } + finally + { + MDC.remove(SUB_QUEUE) + } + } + + /** + * Set the provided [Optional][String] into the [MDC] as [JwtAuthenticationFilter.SUB_QUEUE] if it is not [Optional.empty]. + * + * @param subQueue an optional sub queue identifier, if it is not [Optional.empty] it will be placed into the [MDC] + */ + fun setSubQueue(subQueue: Optional) + { + if (subQueue.isPresent) + { + LOG.trace("Setting resolved sub queue from token into request context [{}].", subQueue.get()) + MDC.put(SUB_QUEUE, subQueue.get()) + } + } + + /** + * + */ + fun getSubQueueInToken(request: HttpServletRequest): Optional + { + val authHeader = request.getHeader(AUTHORIZATION_HEADER) + if (authHeader != null) + { + return isValidJwtToken(authHeader) + } + return Optional.empty() + } + + /** + * + */ + fun isValidJwtToken(jwtToken: String): Optional + { + return Optional.ofNullable(null) + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/repository/MongoQueueMessageRepository.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/repository/MongoQueueMessageRepository.kt index 5091fb3..8d5e674 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/repository/MongoQueueMessageRepository.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/repository/MongoQueueMessageRepository.kt @@ -1,6 +1,5 @@ package au.kilemon.messagequeue.queue.nosql.mongo.repository -import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.message.QueueMessageDocument import org.springframework.data.jpa.repository.Modifying import org.springframework.data.mongodb.repository.Aggregation diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt index d65229d..8457cde 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt @@ -4,13 +4,12 @@ import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.MultiQueue import au.kilemon.messagequeue.queue.exception.MessageUpdateException -import au.kilemon.messagequeue.queue.sql.repository.SQLQueueMessageRepository +import au.kilemon.messagequeue.queue.sql.repository.SqlQueueMessageRepository import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Lazy import java.util.* import java.util.concurrent.ConcurrentLinkedQueue -import java.util.concurrent.atomic.AtomicLong /** * A database backed [MultiQueue]. All operations are performed directly on the database it is the complete source of truth. @@ -24,7 +23,7 @@ class SqlMultiQueue : MultiQueue(), HasLogger @Lazy @Autowired - private lateinit var queueMessageRepository: SQLQueueMessageRepository + private lateinit var queueMessageRepository: SqlQueueMessageRepository override fun getQueueForType(queueType: String): Queue { diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/SQLQueueMessageRepository.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/SqlQueueMessageRepository.kt similarity index 98% rename from src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/SQLQueueMessageRepository.kt rename to src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/SqlQueueMessageRepository.kt index 9f06a4c..295c9c6 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/SQLQueueMessageRepository.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/SqlQueueMessageRepository.kt @@ -17,7 +17,7 @@ import java.util.* * @author github.com/Kilemonn */ @Repository -interface SQLQueueMessageRepository: JpaRepository +interface SqlQueueMessageRepository: JpaRepository { /** * Delete a [QueueMessage] by the provided [QueueMessage.type] [String]. diff --git a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt index b26d63a..4c7e57a 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt @@ -65,6 +65,15 @@ class MessageQueueSettings */ const val SQL_SCHEMA: String = "SQL_SCHEMA" const val SQL_SCHEMA_DEFAULT: String = "public" + + /** + * Start authenticated sub queue properties. + */ + /** + * Indicates what authentication mode the `MultiQueue` should be in. + */ + const val MULTI_QUEUE_AUTHENTICATION: String = "MULTI_QUEUE_AUTHENTICATION" + const val MULTI_QUEUE_AUTHENTICATION_DEFAULT: String = "" } /** @@ -79,6 +88,18 @@ class MessageQueueSettings @set:Generated lateinit var multiQueueType: String + /** + * `Optional` uses the [MULTI_QUEUE_AUTHENTICATION] environment variable to determine whether specific sub-queues + * will require authentication or not to create or access. It can be any value of [MultiQueueType]. + * Defaults to [MultiQueueType.IN_MEMORY] ([MULTI_QUEUE_AUTHENTICATION_DEFAULT]). + */ + @SerializedName(MULTI_QUEUE_AUTHENTICATION) + @JsonProperty(MULTI_QUEUE_AUTHENTICATION) + @Value("\${$MULTI_QUEUE_AUTHENTICATION:$MULTI_QUEUE_AUTHENTICATION_DEFAULT}") + @get:Generated + @set:Generated + lateinit var multiQueueAuthentication: String + /** * `Optional` when [MULTI_QUEUE_TYPE] is set to [MultiQueueType.REDIS]. From 62bbdb66aef6817f8b7c448eb0e6c9fcde30b61c Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Wed, 25 Oct 2023 18:19:33 +1100 Subject: [PATCH 02/58] Add MultiQueueAuthenticationException --- .../exception/MultiQueueAuthenticationException.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt new file mode 100644 index 0000000..d6709d7 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt @@ -0,0 +1,9 @@ +package au.kilemon.messagequeue.authentication.exception + +/** + * An authentication exception used when the `MultiQueueAuthenticator` does not allow the caller to perform the + * requested action on the requested sub-queue. + * + * @author github.com/Kilemonn + */ +class MultiQueueAuthenticationException(subQueue: String) : Exception("Unable to access sub-queue [$subQueue].") From 1864660a37460ca293fd98a3e254ade60f47bb35 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Thu, 26 Oct 2023 18:47:08 +1100 Subject: [PATCH 03/58] Add handling in RestResponseExceptionHandler for MultiQueueAuthenticationException and add test. --- .../MultiQueueAuthenticationException.kt | 8 +++++- .../response/RestResponseExceptionHandler.kt | 8 ++++++ .../RestResponseExceptionHandlerTest.kt | 28 +++++++++++++++++-- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt index d6709d7..9d8d289 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt @@ -6,4 +6,10 @@ package au.kilemon.messagequeue.authentication.exception * * @author github.com/Kilemonn */ -class MultiQueueAuthenticationException(subQueue: String) : Exception("Unable to access sub-queue [$subQueue].") +class MultiQueueAuthenticationException(subQueue: String) : Exception(String.format(MESSAGE_FORMAT, subQueue)) +{ + companion object + { + const val MESSAGE_FORMAT = "Unable to access sub-queue [%s]." + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt index 1ed3e3e..177106f 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt @@ -1,5 +1,7 @@ package au.kilemon.messagequeue.rest.response +import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException +import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler @@ -19,4 +21,10 @@ class RestResponseExceptionHandler: ResponseEntityExceptionHandler() { return ResponseEntity(ErrorResponse(ex.reason), ex.status) } + + @ExceptionHandler(MultiQueueAuthenticationException::class) + fun handleMultiQueueAuthenticationException(ex: MultiQueueAuthenticationException): ResponseEntity + { + return ResponseEntity(ErrorResponse(ex.message), HttpStatus.FORBIDDEN) + } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt index beda368..e6c395f 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt @@ -1,5 +1,6 @@ package au.kilemon.messagequeue.rest.response +import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException import au.kilemon.messagequeue.filter.CorrelationIdFilter import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions @@ -17,6 +18,8 @@ import java.util.* */ class RestResponseExceptionHandlerTest { + private val responseHandler = RestResponseExceptionHandler() + @BeforeEach fun setUp() { @@ -33,16 +36,16 @@ class RestResponseExceptionHandlerTest } /** - * Ensure all the properties required to create an [ErrorResponse] are correctly extracted from the [ResponseStatusException]. + * Ensure [RestResponseExceptionHandler#handleResponseStatusException] sets all the properties required to create an + * [ErrorResponse] are correctly extracted from the [ResponseStatusException]. */ @Test fun testHandleResponseStatusException() { val correlationId = UUID.randomUUID().toString() MDC.put(CorrelationIdFilter.CORRELATION_ID, correlationId) - val responseHandler = RestResponseExceptionHandler() val message = "Bad error message" - val statusCode = HttpStatus.FORBIDDEN + val statusCode = HttpStatus.I_AM_A_TEAPOT val exception = ResponseStatusException(statusCode, message) val response = responseHandler.handleResponseStatusException(exception) @@ -51,4 +54,23 @@ class RestResponseExceptionHandlerTest Assertions.assertEquals(message, response.body!!.message) Assertions.assertEquals(correlationId, response.body!!.correlationId) } + + /** + * Ensure the [RestResponseExceptionHandler#handleMultiQueueAuthenticationException] returns the appropriate + * response code and message on error. + */ + @Test + fun testHandleMultiQueueAuthenticationException() + { + val correlationId = UUID.randomUUID().toString() + MDC.put(CorrelationIdFilter.CORRELATION_ID, correlationId) + val message = "testHandleMultiQueueAuthenticationException" + val exception = MultiQueueAuthenticationException(message) + val response = responseHandler.handleMultiQueueAuthenticationException(exception) + + Assertions.assertEquals(HttpStatus.FORBIDDEN, response.statusCode) + Assertions.assertNotNull(response.body) + Assertions.assertEquals(String.format(MultiQueueAuthenticationException.MESSAGE_FORMAT, message), response.body!!.message) + Assertions.assertEquals(correlationId, response.body!!.correlationId) + } } From 0e579f258ed92040c475a898923a8908fd1d7d3b Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Thu, 26 Oct 2023 19:00:30 +1100 Subject: [PATCH 04/58] Update docs. --- .../rest/response/RestResponseExceptionHandlerTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt index e6c395f..53daa40 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt @@ -36,7 +36,7 @@ class RestResponseExceptionHandlerTest } /** - * Ensure [RestResponseExceptionHandler#handleResponseStatusException] sets all the properties required to create an + * Ensure [RestResponseExceptionHandler.handleResponseStatusException] sets all the properties required to create an * [ErrorResponse] are correctly extracted from the [ResponseStatusException]. */ @Test @@ -56,7 +56,7 @@ class RestResponseExceptionHandlerTest } /** - * Ensure the [RestResponseExceptionHandler#handleMultiQueueAuthenticationException] returns the appropriate + * Ensure the [RestResponseExceptionHandler.handleMultiQueueAuthenticationException] returns the appropriate * response code and message on error. */ @Test From 36344c7880ac4ae978039fa433b9919e9f5ed0be Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 27 Oct 2023 18:31:55 +1100 Subject: [PATCH 05/58] Refactor to authorisation exception, create new auth exception. Create method to verify incoming subqueue. --- .../authenticator/MultiQueueAuthenticator.kt | 77 ++++++++++++++++++- .../MultiQueueAuthenticationException.kt | 8 +- .../MultiQueueAuthorisationException.kt | 18 +++++ .../filter/JwtAuthenticationFilter.kt | 25 +++--- .../kilemon/messagequeue/queue/MultiQueue.kt | 9 ++- .../response/RestResponseExceptionHandler.kt | 9 ++- .../MessageQueueControllerMockTest.kt | 17 +++- .../rest/controller/SettingsControllerTest.kt | 16 ++++ .../RestResponseExceptionHandlerTest.kt | 28 ++++++- 9 files changed, 183 insertions(+), 24 deletions(-) create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt index d31df42..0661413 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt @@ -1,9 +1,12 @@ package au.kilemon.messagequeue.authentication.authenticator import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException +import au.kilemon.messagequeue.filter.JwtAuthenticationFilter import au.kilemon.messagequeue.logging.HasLogger import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired +import kotlin.jvm.Throws /** * @@ -17,12 +20,80 @@ abstract class MultiQueueAuthenticator: HasLogger @Autowired protected lateinit var multiQueueAuthenticationType: MultiQueueAuthenticationType + /** + * @return [multiQueueAuthenticationType] + */ + fun getAuthenticationType(): MultiQueueAuthenticationType + { + return multiQueueAuthenticationType + } + + /** + * + */ + @Throws(MultiQueueAuthorisationException::class) + fun canAccessSubQueue(subQueue: String) + { + if (isInNoneMode()) + { + return + } + else if (isInHybridMode()) + { + if (isRestricted(subQueue)) + { + if (JwtAuthenticationFilter.getSubQueue() == subQueue) + { + return + } + } + else + { + // If we are in hybrid mode and the sub queue is not restricted we should let it pass + return + } + } + else if (isInRestrictedMode()) + { + if (isRestricted(subQueue) && JwtAuthenticationFilter.getSubQueue() == subQueue) + { + return + } + } + + throw MultiQueueAuthorisationException(subQueue, multiQueueAuthenticationType) + } + + /** + * Indicates whether [multiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. + */ + fun isInNoneMode(): Boolean + { + return multiQueueAuthenticationType == MultiQueueAuthenticationType.NONE + } + + /** + * Indicates whether [multiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.HYBRID]. + */ + fun isInHybridMode(): Boolean + { + return multiQueueAuthenticationType == MultiQueueAuthenticationType.HYBRID + } + + /** + * Indicates whether [multiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.RESTRICTED]. + */ + fun isInRestrictedMode(): Boolean + { + return multiQueueAuthenticationType == MultiQueueAuthenticationType.RESTRICTED + } + /** * */ fun isRestricted(subQueue: String): Boolean { - return if (multiQueueAuthenticationType == MultiQueueAuthenticationType.NONE) + return if (isInNoneMode()) { false } @@ -43,7 +114,7 @@ abstract class MultiQueueAuthenticator: HasLogger */ fun addRestrictedEntry(subQueue: String) { - if (multiQueueAuthenticationType != MultiQueueAuthenticationType.NONE) + if (isInNoneMode()) { LOG.debug("Adding restriction level [{}] to sub queue [{}].", multiQueueAuthenticationType, subQueue) addRestrictedEntryInternal(subQueue) @@ -64,7 +135,7 @@ abstract class MultiQueueAuthenticator: HasLogger */ fun removeRestriction(subQueue: String): Boolean { - if (multiQueueAuthenticationType != MultiQueueAuthenticationType.NONE) + if (isInNoneMode()) { return removeRestrictionInternal(subQueue) } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt index 9d8d289..b56fe91 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationException.kt @@ -1,15 +1,15 @@ package au.kilemon.messagequeue.authentication.exception /** - * An authentication exception used when the `MultiQueueAuthenticator` does not allow the caller to perform the - * requested action on the requested sub-queue. + * An authentication exception used when the provided token is invalid when an action is requested to be performed on a + * sub-queue. * * @author github.com/Kilemonn */ -class MultiQueueAuthenticationException(subQueue: String) : Exception(String.format(MESSAGE_FORMAT, subQueue)) +class MultiQueueAuthenticationException : Exception(ERROR_MESSAGE) { companion object { - const val MESSAGE_FORMAT = "Unable to access sub-queue [%s]." + const val ERROR_MESSAGE = "Invalid token provided." } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt new file mode 100644 index 0000000..ad066f7 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt @@ -0,0 +1,18 @@ +package au.kilemon.messagequeue.authentication.exception + +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType + +/** + * An authorisation exception used when the `MultiQueueAuthenticator` does not allow the caller to perform the + * requested action on the requested sub-queue. Due to either due to a mismatch of the provided token and the sub-queue + * that is being request OR in hybrid mode if a token is required but not provided. + * + * @author github.com/Kilemonn + */ +class MultiQueueAuthorisationException(subQueue: String, authenticationType: MultiQueueAuthenticationType) : Exception(String.format(MESSAGE_FORMAT, subQueue, authenticationType)) +{ + companion object + { + const val MESSAGE_FORMAT = "Unable to access sub-queue [%s]. Using mode [%s]." + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index 577be0d..22595d5 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -1,9 +1,9 @@ package au.kilemon.messagequeue.filter import au.kilemon.messagequeue.logging.HasLogger -import au.kilemon.messagequeue.queue.MultiQueue import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException import org.slf4j.Logger import org.slf4j.MDC import org.springframework.beans.factory.annotation.Autowired @@ -29,13 +29,19 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger const val AUTHORIZATION_HEADER = "Authorization" const val SUB_QUEUE = "Sub-Queue" + + /** + * Gets the stored [SUB_QUEUE] from the [MDC]. + * This can be null if no valid token is provided. + */ + fun getSubQueue(): String? + { + return MDC.get(SUB_QUEUE) + } } override val LOG: Logger = this.initialiseLogger() - @Autowired - lateinit var authenticationType: MultiQueueAuthenticationType - @Autowired lateinit var authenticator: MultiQueueAuthenticator @@ -49,17 +55,17 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger val subQueue = getSubQueueInToken(request) setSubQueue(subQueue) - if (authenticationType == MultiQueueAuthenticationType.NONE) + if (authenticator.isInNoneMode()) { LOG.trace("Allowed access as authentication is set to [{}].", MultiQueueAuthenticationType.NONE) filterChain.doFilter(request, response) } - else if (authenticationType == MultiQueueAuthenticationType.HYBRID) + else if (authenticator.isInHybridMode()) { LOG.trace("Allowing request through for lower layer to check as authentication is set to [{}].", MultiQueueAuthenticationType.NONE) filterChain.doFilter(request, response) } - else if (authenticationType == MultiQueueAuthenticationType.RESTRICTED) + else if (authenticator.isInRestrictedMode()) { if (subQueue.isPresent && authenticator.isRestricted(subQueue.get())) { @@ -68,8 +74,8 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger } else { - LOG.error("Failed to manipulate sub queue [{}] with provided token as the authentication level is set to [{}].", subQueue.get(), authenticationType) - // TODO throw here + LOG.error("Failed to manipulate sub queue [{}] with provided token as the authentication level is set to [{}].", subQueue.get(), authenticator.getAuthenticationType()) + throw MultiQueueAuthenticationException() } } } @@ -109,6 +115,7 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger /** * */ + @Throws(MultiQueueAuthenticationException::class) fun isValidJwtToken(jwtToken: String): Optional { return Optional.ofNullable(null) diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt index d54d12d..915acec 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt @@ -1,16 +1,18 @@ package au.kilemon.messagequeue.queue +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.queue.exception.DuplicateMessageException import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.exception.HealthCheckFailureException import au.kilemon.messagequeue.queue.exception.MessageUpdateException import org.slf4j.Logger +import org.springframework.beans.factory.annotation.Autowired import java.util.* -import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedQueue import java.util.stream.Collectors import kotlin.collections.HashMap +import kotlin.collections.HashSet import kotlin.jvm.Throws /** @@ -29,6 +31,9 @@ abstract class MultiQueue: Queue, HasLogger abstract override val LOG: Logger + @Autowired + protected lateinit var multiQueueAuthenticator: MultiQueueAuthenticator + /** * Get the underlying size of the [MultiQueue]. * This is done by summing the length of each [getQueueForType] for each key in [keys]. @@ -92,7 +97,7 @@ abstract class MultiQueue: Queue, HasLogger /** * Retrieves or creates a new [Queue] of type [QueueMessage] for the provided [String]. * If the underlying [Queue] does not exist for the provided [String] then a new [Queue] will - * be created and stored in the [ConcurrentHashMap] under the provided [String]. + * be created. * * @param queueType the identifier of the sub-queue [Queue] * @return the [Queue] matching the provided [String] diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt index 177106f..ea70716 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt @@ -1,6 +1,7 @@ package au.kilemon.messagequeue.rest.response import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException +import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice @@ -22,9 +23,15 @@ class RestResponseExceptionHandler: ResponseEntityExceptionHandler() return ResponseEntity(ErrorResponse(ex.reason), ex.status) } + @ExceptionHandler(MultiQueueAuthorisationException::class) + fun handleMultiQueueAuthorisationException(ex: MultiQueueAuthorisationException): ResponseEntity + { + return ResponseEntity(ErrorResponse(ex.message), HttpStatus.FORBIDDEN) + } + @ExceptionHandler(MultiQueueAuthenticationException::class) fun handleMultiQueueAuthenticationException(ex: MultiQueueAuthenticationException): ResponseEntity { - return ResponseEntity(ErrorResponse(ex.message), HttpStatus.FORBIDDEN) + return ResponseEntity(ErrorResponse(ex.message), HttpStatus.UNAUTHORIZED) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt index 7e654da..69c704f 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt @@ -1,5 +1,8 @@ package au.kilemon.messagequeue.rest.controller +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.inmemory.InMemoryAuthenticator import au.kilemon.messagequeue.logging.LoggingConfiguration import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.MultiQueue @@ -45,13 +48,25 @@ class MessageQueueControllerMockTest { return Mockito.spy(InMemoryMultiQueue::class.java) } + + @Bean + open fun getMultiQueueAuthenticator(): MultiQueueAuthenticator + { + return Mockito.spy(InMemoryAuthenticator::class.java) + } + + @Bean + open fun getMultiQueueAuthenticationType(): MultiQueueAuthenticationType + { + return MultiQueueAuthenticationType.NONE + } } @Autowired private lateinit var mockMvc: MockMvc @Autowired - lateinit var multiQueue: MultiQueue + private lateinit var multiQueue: MultiQueue private val gson: Gson = Gson() diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt index 4a2fd76..9c70ce0 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt @@ -1,5 +1,8 @@ package au.kilemon.messagequeue.rest.controller +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.inmemory.InMemoryAuthenticator import au.kilemon.messagequeue.logging.LoggingConfiguration import au.kilemon.messagequeue.settings.MessageQueueSettings import au.kilemon.messagequeue.settings.MultiQueueType @@ -7,6 +10,7 @@ import com.google.gson.Gson import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mockito import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.boot.test.context.SpringBootTest @@ -48,6 +52,18 @@ class SettingsControllerTest { return MessageQueueSettings() } + + @Bean + open fun getMultiQueueAuthenticator(): MultiQueueAuthenticator + { + return Mockito.spy(InMemoryAuthenticator::class.java) + } + + @Bean + open fun getMultiQueueAuthenticationType(): MultiQueueAuthenticationType + { + return MultiQueueAuthenticationType.NONE + } } @Autowired diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt index 53daa40..179ed31 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt @@ -1,6 +1,8 @@ package au.kilemon.messagequeue.rest.response +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException +import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException import au.kilemon.messagequeue.filter.CorrelationIdFilter import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions @@ -55,6 +57,25 @@ class RestResponseExceptionHandlerTest Assertions.assertEquals(correlationId, response.body!!.correlationId) } + /** + * Ensure the [RestResponseExceptionHandler.handleMultiQueueAuthorisationException] returns the appropriate + * response code and message on error. + */ + @Test + fun testHandleMultiQueueAuthorisationException() + { + val correlationId = UUID.randomUUID().toString() + MDC.put(CorrelationIdFilter.CORRELATION_ID, correlationId) + val message = "testHandleMultiQueueAuthorisationException" + val exception = MultiQueueAuthorisationException(message, MultiQueueAuthenticationType.NONE) + val response = responseHandler.handleMultiQueueAuthorisationException(exception) + + Assertions.assertEquals(HttpStatus.FORBIDDEN, response.statusCode) + Assertions.assertNotNull(response.body) + Assertions.assertEquals(String.format(MultiQueueAuthorisationException.MESSAGE_FORMAT, message, MultiQueueAuthenticationType.NONE), response.body!!.message) + Assertions.assertEquals(correlationId, response.body!!.correlationId) + } + /** * Ensure the [RestResponseExceptionHandler.handleMultiQueueAuthenticationException] returns the appropriate * response code and message on error. @@ -64,13 +85,12 @@ class RestResponseExceptionHandlerTest { val correlationId = UUID.randomUUID().toString() MDC.put(CorrelationIdFilter.CORRELATION_ID, correlationId) - val message = "testHandleMultiQueueAuthenticationException" - val exception = MultiQueueAuthenticationException(message) + val exception = MultiQueueAuthenticationException() val response = responseHandler.handleMultiQueueAuthenticationException(exception) - Assertions.assertEquals(HttpStatus.FORBIDDEN, response.statusCode) + Assertions.assertEquals(HttpStatus.UNAUTHORIZED, response.statusCode) Assertions.assertNotNull(response.body) - Assertions.assertEquals(String.format(MultiQueueAuthenticationException.MESSAGE_FORMAT, message), response.body!!.message) + Assertions.assertEquals(MultiQueueAuthenticationException.ERROR_MESSAGE, response.body!!.message) Assertions.assertEquals(correlationId, response.body!!.correlationId) } } From 0f2e6fdae94f66faf2b062d25f0e0178f8c1408c Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 27 Oct 2023 19:37:37 +1100 Subject: [PATCH 06/58] Add tests for JwtAuthenticationFilter. --- .../filter/JwtAuthenticationFilter.kt | 19 ++- .../filter/JwtAuthenticationFilterTest.kt | 152 ++++++++++++++++++ 2 files changed, 167 insertions(+), 4 deletions(-) create mode 100644 src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index 22595d5..9ac1fa1 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -52,7 +52,7 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger { try { - val subQueue = getSubQueueInToken(request) + val subQueue = getSubQueueInTokenFromHeaders(request) setSubQueue(subQueue) if (authenticator.isInNoneMode()) @@ -67,7 +67,7 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger } else if (authenticator.isInRestrictedMode()) { - if (subQueue.isPresent && authenticator.isRestricted(subQueue.get())) + if (tokenIsPresentAndQueueIsRestricted(subQueue, authenticator)) { LOG.trace("Accepted request for sub queue [{}].", subQueue.get()) filterChain.doFilter(request, response) @@ -85,6 +85,14 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger } } + /** + * + */ + fun tokenIsPresentAndQueueIsRestricted(subQueue: Optional, multiQueueAuthenticator: MultiQueueAuthenticator): Boolean + { + return subQueue.isPresent && multiQueueAuthenticator.isRestricted(subQueue.get()) + } + /** * Set the provided [Optional][String] into the [MDC] as [JwtAuthenticationFilter.SUB_QUEUE] if it is not [Optional.empty]. * @@ -100,9 +108,12 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger } /** + * Get the value of the provided [request] for the [AUTHORIZATION_HEADER] header. * + * @param request the request to retrieve the [AUTHORIZATION_HEADER] from + * @return the [AUTHORIZATION_HEADER] header value wrapped as an [Optional], otherwise [Optional.empty] */ - fun getSubQueueInToken(request: HttpServletRequest): Optional + fun getSubQueueInTokenFromHeaders(request: HttpServletRequest): Optional { val authHeader = request.getHeader(AUTHORIZATION_HEADER) if (authHeader != null) @@ -118,6 +129,6 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger @Throws(MultiQueueAuthenticationException::class) fun isValidJwtToken(jwtToken: String): Optional { - return Optional.ofNullable(null) + return Optional.ofNullable(jwtToken) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt new file mode 100644 index 0000000..3f0e350 --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt @@ -0,0 +1,152 @@ +package au.kilemon.messagequeue.filter + +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito +import org.slf4j.MDC +import java.util.* +import javax.servlet.http.HttpServletRequest + +/** + * + * @author github.com/Kilemonn + */ +class JwtAuthenticationFilterTest +{ + private val jwtAuthenticationFilter = JwtAuthenticationFilter() + + @BeforeEach + fun setUp() + { + MDC.clear() + } + + /** + * This should be afterclass but works better here. + */ + @AfterEach + fun tearDown() + { + MDC.clear() + } + + /** + * Ensure that [JwtAuthenticationFilter.setSubQueue] does set the [MDC] [JwtAuthenticationFilter.SUB_QUEUE] property + * if the provided [Optional] is [Optional.isPresent]. + */ + @Test + fun testSetSubQueue_valuePresent() + { + val subQueue = Optional.of("testSetSubQueue_valuePresent") + Assertions.assertTrue(subQueue.isPresent) + Assertions.assertNull(MDC.get(JwtAuthenticationFilter.SUB_QUEUE)) + + jwtAuthenticationFilter.setSubQueue(subQueue) + + Assertions.assertEquals(subQueue.get(), MDC.get(JwtAuthenticationFilter.SUB_QUEUE)) + } + + /** + * Ensure that [JwtAuthenticationFilter.setSubQueue] does not set the [MDC] [JwtAuthenticationFilter.SUB_QUEUE] + * property if the provided [Optional] is [Optional.isEmpty]. + */ + @Test + fun testSetSubQueue_valueEmpty() + { + val subQueue = Optional.empty() + Assertions.assertTrue(subQueue.isEmpty) + Assertions.assertNull(MDC.get(JwtAuthenticationFilter.SUB_QUEUE)) + + jwtAuthenticationFilter.setSubQueue(subQueue) + + Assertions.assertNull(MDC.get(JwtAuthenticationFilter.SUB_QUEUE)) + } + + /** + * Ensure that [JwtAuthenticationFilter.getSubQueueInTokenFromHeaders] will retrieve the value correctly from the + * [JwtAuthenticationFilter.AUTHORIZATION_HEADER] and return it. + */ + @Test + fun testGetSubQueueInTokenFromHeaders_headerExists() + { + val request = Mockito.mock(HttpServletRequest::class.java) + val authHeaderValue = "testGetSubQueueInTokenFromHeaders_headerExists" + Mockito.`when`(request.getHeader(JwtAuthenticationFilter.AUTHORIZATION_HEADER)).thenReturn(authHeaderValue) + + val subQueue = jwtAuthenticationFilter.getSubQueueInTokenFromHeaders(request) + Assertions.assertTrue(subQueue.isPresent) + Assertions.assertEquals(authHeaderValue, subQueue.get()) + } + + /** + * Ensure that [JwtAuthenticationFilter.getSubQueueInTokenFromHeaders] will return an [Optional.empty] when the + * [JwtAuthenticationFilter.AUTHORIZATION_HEADER] header value is `null`. + */ + @Test + fun testGetSubQueueInTokenFromHeaders_headerDoesNotExists() + { + val request = Mockito.mock(HttpServletRequest::class.java) + Mockito.`when`(request.getHeader(JwtAuthenticationFilter.AUTHORIZATION_HEADER)).thenReturn(null) + + val subQueue = jwtAuthenticationFilter.getSubQueueInTokenFromHeaders(request) + Assertions.assertTrue(subQueue.isEmpty) + } + + /** + * Ensure the [JwtAuthenticationFilter.getSubQueue] retrieves the stored [JwtAuthenticationFilter.SUB_QUEUE] + * property from the [MDC]. + */ + @Test + fun testGetSubQueue() + { + val subQueue = "testGetSubQueue" + Assertions.assertNull(JwtAuthenticationFilter.getSubQueue()) + + jwtAuthenticationFilter.setSubQueue(Optional.of(subQueue)) + Assertions.assertEquals(subQueue, JwtAuthenticationFilter.getSubQueue()) + } + + /** + * Ensure that [JwtAuthenticationFilter.tokenIsPresentAndQueueIsRestricted] returns `true` when the provided + * token is present and the queue is restricted. + */ + @Test + fun testTokenIsPresentAndQueueIsRestricted_TokenPresentAndQueueRestricted() + { + val subQueue = Optional.of("testTokenIsPresentAndQueueIsRestricted_TokenPresentAndQueueRestricted") + val authenticator = Mockito.mock(MultiQueueAuthenticator::class.java) + Mockito.`when`(authenticator.isRestricted(subQueue.get())).thenReturn(true) + + Assertions.assertTrue(jwtAuthenticationFilter.tokenIsPresentAndQueueIsRestricted(subQueue, authenticator)) + } + + /** + * Ensure that [JwtAuthenticationFilter.tokenIsPresentAndQueueIsRestricted] returns `false` when the provided + * token is present and the queue is NOT restricted. + */ + @Test + fun testTokenIsPresentAndQueueIsRestricted_TokenPresentAndQueueNotRestricted() + { + val subQueue = Optional.of("testTokenIsPresentAndQueueIsRestricted_TokenPresentAndQueueNotRestricted") + val authenticator = Mockito.mock(MultiQueueAuthenticator::class.java) + Mockito.`when`(authenticator.isRestricted(subQueue.get())).thenReturn(false) + + Assertions.assertFalse(jwtAuthenticationFilter.tokenIsPresentAndQueueIsRestricted(subQueue, authenticator)) + } + + /** + * Ensure that [JwtAuthenticationFilter.tokenIsPresentAndQueueIsRestricted] returns `false` when the provided + * token is empty. + */ + @Test + fun testTokenIsPresentAndQueueIsRestricted_TokenNotPresent() + { + val subQueue = Optional.empty() + val authenticator = Mockito.mock(MultiQueueAuthenticator::class.java) + + Assertions.assertFalse(jwtAuthenticationFilter.tokenIsPresentAndQueueIsRestricted(subQueue, authenticator)) + } +} From 075ed7b5cf8c7a45afa4c724d98f1eb51e558bdd Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 27 Oct 2023 19:37:48 +1100 Subject: [PATCH 07/58] Make authentication type completely private and use getter. --- .../authenticator/MultiQueueAuthenticator.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt index 0661413..d8a8335 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt @@ -18,7 +18,7 @@ abstract class MultiQueueAuthenticator: HasLogger abstract override val LOG: Logger @Autowired - protected lateinit var multiQueueAuthenticationType: MultiQueueAuthenticationType + private lateinit var multiQueueAuthenticationType: MultiQueueAuthenticationType /** * @return [multiQueueAuthenticationType] @@ -61,7 +61,7 @@ abstract class MultiQueueAuthenticator: HasLogger } } - throw MultiQueueAuthorisationException(subQueue, multiQueueAuthenticationType) + throw MultiQueueAuthorisationException(subQueue, getAuthenticationType()) } /** @@ -69,7 +69,7 @@ abstract class MultiQueueAuthenticator: HasLogger */ fun isInNoneMode(): Boolean { - return multiQueueAuthenticationType == MultiQueueAuthenticationType.NONE + return getAuthenticationType() == MultiQueueAuthenticationType.NONE } /** @@ -77,7 +77,7 @@ abstract class MultiQueueAuthenticator: HasLogger */ fun isInHybridMode(): Boolean { - return multiQueueAuthenticationType == MultiQueueAuthenticationType.HYBRID + return getAuthenticationType() == MultiQueueAuthenticationType.HYBRID } /** @@ -85,7 +85,7 @@ abstract class MultiQueueAuthenticator: HasLogger */ fun isInRestrictedMode(): Boolean { - return multiQueueAuthenticationType == MultiQueueAuthenticationType.RESTRICTED + return getAuthenticationType() == MultiQueueAuthenticationType.RESTRICTED } /** @@ -116,12 +116,12 @@ abstract class MultiQueueAuthenticator: HasLogger { if (isInNoneMode()) { - LOG.debug("Adding restriction level [{}] to sub queue [{}].", multiQueueAuthenticationType, subQueue) + LOG.debug("Adding restriction level [{}] to sub queue [{}].", getAuthenticationType(), subQueue) addRestrictedEntryInternal(subQueue) } else { - LOG.trace("Bypassing adding restricted entry for [{}] since the authentication type is set to [{}].", subQueue, multiQueueAuthenticationType) + LOG.trace("Bypassing adding restricted entry for [{}] since the authentication type is set to [{}].", subQueue, getAuthenticationType()) } } From 45b98c55558abcb09aa7a33dccd6595478d42a07 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 27 Oct 2023 19:47:18 +1100 Subject: [PATCH 08/58] Add tests for AuthenticationMatrix and the AuthN and AuthZ exceptions. --- .../authentication/AuthenticationMatrix.kt | 6 ++-- .../AuthenticationMatrixDocument.kt | 3 +- .../AuthenticationMatrixTest.kt | 35 +++++++++++++++++++ .../MultiQueueAuthenticationExceptionTest.kt | 25 +++++++++++++ .../MultiQueueAuthorisationExceptionTest.kt | 25 +++++++++++++ 5 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixTest.kt create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationExceptionTest.kt create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt index cc58a22..1697ece 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt @@ -1,11 +1,13 @@ package au.kilemon.messagequeue.authentication -import au.kilemon.messagequeue.message.QueueMessage import com.fasterxml.jackson.annotation.JsonIgnore import javax.persistence.* /** - * + * An object that holds subqueue authentication information. + * If a specific sub queue is in restricted mode it will have a matching [AuthenticationMatrix] created which will + * be checked to verify if a specific sub queue can be operated on. + * This object is used for `In-memory`, `SQL` and `Redis`. * * @author github.com/Kilemonn */ diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt index 051ab5f..a5d80fc 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt @@ -5,7 +5,8 @@ import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.mapping.Document /** - * + * A holder object for the restricted sub queues. Refer to [AuthenticationMatrix]. + * This is used only for `Mongo`. * * @author github.com/Kilemonn */ diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixTest.kt new file mode 100644 index 0000000..d8c8452 --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixTest.kt @@ -0,0 +1,35 @@ +package au.kilemon.messagequeue.authentication + +import au.kilemon.messagequeue.message.QueueMessage +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import java.util.* + +/** + * A test class for the [AuthenticationMatrix]. + * Specifically to verify the [equals] method. + * + * @author github.com/Kilemonn + */ +class AuthenticationMatrixTest +{ + /** + * Ensure that two [AuthenticationMatrix] with the same appropriate properties are `equal` when the [equals] + * method is called on them. + */ + @Test + fun testEquals() + { + val authMatrix1 = AuthenticationMatrix("authMatrix") + val authMatrix2 = AuthenticationMatrix("authMatrix") + val authMatrix3 = AuthenticationMatrix("authMatrix3") + + Assertions.assertEquals(authMatrix1, authMatrix1) + Assertions.assertEquals(authMatrix1, authMatrix2) + Assertions.assertEquals(authMatrix2, authMatrix1) + Assertions.assertEquals(authMatrix2, authMatrix2) + + Assertions.assertNotEquals(authMatrix1, authMatrix3) + Assertions.assertNotEquals(authMatrix2, authMatrix3) + } +} diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationExceptionTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationExceptionTest.kt new file mode 100644 index 0000000..432fb26 --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthenticationExceptionTest.kt @@ -0,0 +1,25 @@ +package au.kilemon.messagequeue.authentication.exception + +import au.kilemon.messagequeue.queue.exception.DuplicateMessageException +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +/** + * A unit test class for the [MultiQueueAuthenticationException] for any specific tests related to this exception. + * + * @author github.com/Kilemonn + */ +class MultiQueueAuthenticationExceptionTest +{ + /** + * Ensure that [MultiQueueAuthenticationException] is a type of [Exception] and not [RuntimeException]. + * Incase this is changed in future. + */ + @Test + fun testTypeOfException() + { + val e = MultiQueueAuthenticationException() + Assertions.assertTrue(Exception::class.isInstance(e)) + Assertions.assertFalse(RuntimeException::class.isInstance(e)) + } +} diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt new file mode 100644 index 0000000..01f808e --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt @@ -0,0 +1,25 @@ +package au.kilemon.messagequeue.authentication.exception + +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +/** + * A unit test class for the [MultiQueueAuthorisationException] for any specific tests related to this exception. + * + * @author github.com/Kilemonn + */ +class MultiQueueAuthorisationExceptionTest +{ + /** + * Ensure that [MultiQueueAuthorisationException] is a type of [Exception] and not [RuntimeException]. + * Incase this is changed in future. + */ + @Test + fun testTypeOfException() + { + val e = MultiQueueAuthorisationException("Sub queue", MultiQueueAuthenticationType.NONE) + Assertions.assertTrue(Exception::class.isInstance(e)) + Assertions.assertFalse(RuntimeException::class.isInstance(e)) + } +} From 1d69713f0effd77e57d3b6319949d5b088ce9312 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 28 Oct 2023 00:18:04 +1100 Subject: [PATCH 09/58] Work on Authenticator tests. Rename base MultiQueueTest. --- .../authenticator/MultiQueueAuthenticator.kt | 52 +++++-- .../cache/redis/RedisAuthenticator.kt | 20 ++- .../inmemory/InMemoryAuthenticator.kt | 21 ++- .../nosql/mongo/MongoAuthenticator.kt | 13 +- .../authenticator/sql/SqlAuthenticator.kt | 12 ++ .../MultiQueueAuthenticatorTest.kt | 132 ++++++++++++++++++ .../inmemory/InMemoryAuthenticatorTest.kt | 81 +++++++++++ ...actMultiQueueTest.kt => MultiQueueTest.kt} | 11 +- .../redis/RedisSentinelMultiQueueTest.kt | 13 +- .../redis/RedisStandAloneMultiQueueTest.kt | 12 +- .../queue/inmemory/InMemoryMultiQueueTest.kt | 11 +- .../queue/nosql/mongo/MongoMultiQueueTest.kt | 6 +- .../queue/sql/AbstractSqlMultiQueueTest.kt | 12 +- .../queue/sql/MySqlMultiQueueTest.kt | 4 +- .../queue/sql/PostgreSqlMultiQueueTest.kt | 4 +- 15 files changed, 340 insertions(+), 64 deletions(-) create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt rename src/test/kotlin/au/kilemon/messagequeue/queue/{AbstractMultiQueueTest.kt => MultiQueueTest.kt} (99%) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt index d8a8335..230ba26 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt @@ -110,18 +110,29 @@ abstract class MultiQueueAuthenticator: HasLogger /** - * + * @return `true` if the sub queue identifier was added to the restriction set, otherwise `false` if there was + * no underlying change made */ - fun addRestrictedEntry(subQueue: String) + fun addRestrictedEntry(subQueue: String): Boolean { if (isInNoneMode()) { - LOG.debug("Adding restriction level [{}] to sub queue [{}].", getAuthenticationType(), subQueue) - addRestrictedEntryInternal(subQueue) + LOG.trace("Skipping adding restricted entry for [{}] since the authentication type is set to [{}].", subQueue, getAuthenticationType()) + return false } else { - LOG.trace("Bypassing adding restricted entry for [{}] since the authentication type is set to [{}].", subQueue, getAuthenticationType()) + return if (isRestricted(subQueue)) + { + LOG.trace("Restriction for sub queue [{}] was not increased as it is already restricted.", subQueue) + false + } + else + { + LOG.info("Adding restriction to sub queue [{}].", subQueue) + addRestrictedEntryInternal(subQueue) + true + } } } @@ -131,19 +142,42 @@ abstract class MultiQueueAuthenticator: HasLogger abstract fun addRestrictedEntryInternal(subQueue: String) /** - * + * @return `true` if there was a restriction that was removed because of this call, otherwise `false` */ fun removeRestriction(subQueue: String): Boolean { - if (isInNoneMode()) + return if (isInNoneMode()) + { + LOG.trace("Skipping removing restricted entry for [{}] since the authentication type is set to [{}].", subQueue, getAuthenticationType()) + false + } + else { - return removeRestrictionInternal(subQueue) + return if (isRestricted(subQueue)) + { + LOG.info("Removing restriction to sub queue [{}].", subQueue) + removeRestrictionInternal(subQueue) + } + else + { + LOG.trace("Restriction for sub queue [{}] was not removed as it is currently unrestricted.", subQueue) + false + } + } - return false } /** * */ abstract fun removeRestrictionInternal(subQueue: String): Boolean + + abstract fun getRestrictedSubQueueIdentifiers(): Set + + /** + * Clear the underlying restriction storage entries. (This is mainly used for testing). + * + * @return the amount of sub queue restrictions that were cleared + */ + abstract fun clearRestrictedSubQueues(): Long } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt index 36ed465..448e393 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt @@ -24,9 +24,14 @@ class RedisAuthenticator: MultiQueueAuthenticator() @Autowired lateinit var redisTemplate: RedisTemplate + private fun getMembersSet(): Set + { + return redisTemplate.opsForSet().members(RESTRICTED_KEY) ?: HashSet() + } + override fun isRestrictedInternal(subQueue: String): Boolean { - return redisTemplate.opsForSet().members(RESTRICTED_KEY)?.contains(AuthenticationMatrix(subQueue)) ?: false + return getMembersSet().contains(AuthenticationMatrix(subQueue)) ?: false } override fun addRestrictedEntryInternal(subQueue: String) @@ -38,4 +43,17 @@ class RedisAuthenticator: MultiQueueAuthenticator() { return redisTemplate.opsForSet().remove(RESTRICTED_KEY, subQueue) != null } + + override fun getRestrictedSubQueueIdentifiers(): Set + { + return getMembersSet().map { authMatrix -> authMatrix.subQueue }.toList().toSet() + } + + override fun clearRestrictedSubQueues(): Long + { + val members = getMembersSet() + val existingMembersSize = members.size.toLong() + redisTemplate.opsForSet().remove(RESTRICTED_KEY, members) + return existingMembersSize + } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt index 1c79363..5c516ce 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt @@ -1,6 +1,5 @@ package au.kilemon.messagequeue.authentication.authenticator.inmemory -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import org.slf4j.Logger @@ -13,20 +12,32 @@ class InMemoryAuthenticator: MultiQueueAuthenticator() { override val LOG: Logger = initialiseLogger() - private val authMap = HashSet() + private val restrictedSubQueues = HashSet() override fun isRestrictedInternal(subQueue: String): Boolean { - return authMap.contains(subQueue) + return restrictedSubQueues.contains(subQueue) } override fun addRestrictedEntryInternal(subQueue: String) { - authMap.add(subQueue) + restrictedSubQueues.add(subQueue) } override fun removeRestrictionInternal(subQueue: String): Boolean { - return authMap.remove(subQueue) + return restrictedSubQueues.remove(subQueue) + } + + override fun getRestrictedSubQueueIdentifiers(): Set + { + return restrictedSubQueues.toSet() + } + + override fun clearRestrictedSubQueues(): Long + { + val existingEntriesSize = restrictedSubQueues.size.toLong() + restrictedSubQueues.clear() + return existingEntriesSize } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt index c4ae31f..23bf904 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt @@ -1,6 +1,5 @@ package au.kilemon.messagequeue.authentication.authenticator.nosql.mongo -import au.kilemon.messagequeue.authentication.AuthenticationMatrix import au.kilemon.messagequeue.authentication.AuthenticationMatrixDocument import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import org.slf4j.Logger @@ -38,4 +37,16 @@ class MongoAuthenticator: MultiQueueAuthenticator() return entriesExist } + + override fun getRestrictedSubQueueIdentifiers(): Set + { + TODO("Not yet implemented") + } + + override fun clearRestrictedSubQueues(): Long + { + val existingEntriesCount = authenticationMatrixRepository.count() + authenticationMatrixRepository.deleteAll() + return existingEntriesCount + } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt index 6cd3140..83c9a5d 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt @@ -37,4 +37,16 @@ class SqlAuthenticator: MultiQueueAuthenticator() return entriesExist } + + override fun getRestrictedSubQueueIdentifiers(): Set + { + TODO("Not yet implemented") + } + + override fun clearRestrictedSubQueues(): Long + { + val existingEntriesCount = authenticationMatrixRepository.count() + authenticationMatrixRepository.deleteAll() + return existingEntriesCount + } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt new file mode 100644 index 0000000..29e600b --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt @@ -0,0 +1,132 @@ +package au.kilemon.messagequeue.authentication.authenticator + +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.mockito.Mockito +import org.springframework.boot.test.mock.mockito.SpyBean + +/** + * An abstract test class for the [MultiQueueAuthenticator] class. + * This class can be extended, and the [MultiQueueAuthenticator] member overridden to easily ensure that the different + * [MultiQueueAuthenticator] implementations all operate as expected in the same test cases. + * + * @author github.com/Kilemonn + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +abstract class MultiQueueAuthenticatorTest +{ + @SpyBean + protected lateinit var multiQueueAuthenticator: MultiQueueAuthenticator + + @BeforeEach + fun setUp() + { + multiQueueAuthenticator.clearRestrictedSubQueues() + } + + /** + * Ensure [MultiQueueAuthenticator.addRestrictedEntry] always returns and does not add an entry if the + * [MultiQueueAuthenticator.getAuthenticationType] is [MultiQueueAuthenticationType.NONE]. + */ + @Test + fun testAddRestrictedEntry_WithNoneMode() + { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + val subQueue = "testAddRestrictedEntry_WithNoneMode" + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) + Assertions.assertFalse(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) + } + + /** + * Ensure [MultiQueueAuthenticator.addRestrictedEntry] will add the request sub queue identifier when the + * [MultiQueueAuthenticator.getAuthenticationType] is NOT [MultiQueueAuthenticationType.NONE]. + * Also tests [MultiQueueAuthenticator.isRestricted] can determine the sub queue is restricted after its been added. + */ + @Test + fun testAddRestrictedEntry_WithARestrictedNoneMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + val subQueue = "testAddRestrictedEntry_WithARestrictedNoneMode" + + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) + } + + /** + * Ensure that [MultiQueueAuthenticator.removeRestriction] will not be able to remove a restriction if the + * [MultiQueueAuthenticator.getAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. + */ + @Test + fun testRemoveRestriction_WithNoneMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + val subQueue = "testRemoveRestriction_WithNoneMode" + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) + + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) + + Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + Assertions.assertFalse(multiQueueAuthenticator.removeRestriction(subQueue)) + } + + /** + * Ensure that [MultiQueueAuthenticator.addRestrictedEntry] returns `false` when an existing sub queue identifier + * is attempting to be added. + */ + @Test + fun testRemoveRestriction_AddExistingSubQueueIdentifier() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + val subQueue = "testRemoveRestriction_AddExistingSubQueueIdentifier" + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) + + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) + + Assertions.assertFalse(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) + } + + /** + * Ensure that [MultiQueueAuthenticator.removeRestriction] will not be able to remove a restriction if the + * [MultiQueueAuthenticator.getAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. + */ + @Test + fun testRemoveRestriction_WithARestrictedNoneMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + val subQueue = "testRemoveRestriction_WithARestrictedNoneMode" + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) + + multiQueueAuthenticator.addRestrictedEntry(subQueue) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) + + Assertions.assertTrue(multiQueueAuthenticator.removeRestriction(subQueue)) + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) + } + + /** + * Ensure that [MultiQueueAuthenticator.removeRestriction] returns `false` when you attempt to remove a sub queue + * identifier that does not exist. + */ + @Test + fun testRemoveRestriction_DoesNotExist() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + val subQueue = "testRemoveRestriction_DoesNotExist" + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) + Assertions.assertFalse(multiQueueAuthenticator.removeRestriction(subQueue)) + } +} diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt new file mode 100644 index 0000000..04b25a3 --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt @@ -0,0 +1,81 @@ +package au.kilemon.messagequeue.authentication.authenticator.inmemory + +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticatorTest +import au.kilemon.messagequeue.configuration.QueueConfiguration +import au.kilemon.messagequeue.logging.LoggingConfiguration +import au.kilemon.messagequeue.queue.MultiQueueTest +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mockito +import org.springframework.context.annotation.Import +import org.springframework.test.context.junit.jupiter.SpringExtension + +/** + * A test class for the [InMemoryAuthenticator] class. + * + * This class also does mock testing for the different types of [MultiQueueAuthenticationType] since they don't + * rely on the backing mechanism. + * + * @author github.com/Kilemonn + */ +@ExtendWith(SpringExtension::class) +@Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) +class InMemoryAuthenticatorTest: MultiQueueAuthenticatorTest() +{ + /** + * Ensure that [MultiQueueAuthenticator.isInNoneMode] returns the correct value based on the stored + * [MultiQueueAuthenticationType]. + */ + @Test + fun testIsInNoneMode() + { + val authenticator = Mockito.spy(MultiQueueAuthenticator::class.java) + Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(authenticator).getAuthenticationType() + Assertions.assertTrue(authenticator.isInNoneMode()) + + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertFalse(authenticator.isInNoneMode()) + + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() + Assertions.assertFalse(authenticator.isInNoneMode()) + } + + /** + * Ensure that [MultiQueueAuthenticator.isInHybridMode] returns the correct value based on the stored + * [MultiQueueAuthenticationType]. + */ + @Test + fun testIsInHybridMode() + { + val authenticator = Mockito.spy(MultiQueueAuthenticator::class.java) + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertTrue(authenticator.isInHybridMode()) + + Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(authenticator).getAuthenticationType() + Assertions.assertFalse(authenticator.isInHybridMode()) + + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() + Assertions.assertFalse(authenticator.isInHybridMode()) + } + + /** + * Ensure that [MultiQueueAuthenticator.isInRestrictedMode] returns the correct value based on the stored + * [MultiQueueAuthenticationType]. + */ + @Test + fun testIsInRestrictedMode() + { + val authenticator = Mockito.spy(MultiQueueAuthenticator::class.java) + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() + Assertions.assertTrue(authenticator.isInRestrictedMode()) + + Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(authenticator).getAuthenticationType() + Assertions.assertFalse(authenticator.isInRestrictedMode()) + + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertFalse(authenticator.isInRestrictedMode()) + } +} diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/AbstractMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt similarity index 99% rename from src/test/kotlin/au/kilemon/messagequeue/queue/AbstractMultiQueueTest.kt rename to src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt index c536f12..fea3213 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/AbstractMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt @@ -9,7 +9,10 @@ import au.kilemon.messagequeue.queue.sql.SqlMultiQueue import au.kilemon.messagequeue.rest.model.Payload import au.kilemon.messagequeue.rest.model.PayloadEnum import au.kilemon.messagequeue.settings.MessageQueueSettings -import org.junit.jupiter.api.* +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.assertAll import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource @@ -30,7 +33,7 @@ import java.util.stream.Stream * @author github.com/Kilemonn */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) -abstract class AbstractMultiQueueTest +abstract class MultiQueueTest { /** * A Spring configuration that is used for this test class. @@ -38,7 +41,7 @@ abstract class AbstractMultiQueueTest * @author github.com/Kilemonn */ @TestConfiguration - class AbstractMultiQueueTestConfiguration + class MultiQueueTestConfiguration { /** * The bean initialise here will have all its properties overridden by environment variables. @@ -89,7 +92,7 @@ abstract class AbstractMultiQueueTest } /** - * An argument provider for the [AbstractMultiQueueTest.testAdd] method. + * An argument provider for the [MultiQueueTest.testAdd] method. */ private fun parameters_testAdd(): Stream { diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt index a3101f0..5b3756c 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt @@ -3,23 +3,16 @@ package au.kilemon.messagequeue.queue.cache.redis import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.configuration.cache.redis.RedisConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration -import au.kilemon.messagequeue.queue.AbstractMultiQueueTest +import au.kilemon.messagequeue.queue.MultiQueueTest import au.kilemon.messagequeue.settings.MessageQueueSettings import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest -import org.springframework.boot.test.context.TestConfiguration import org.springframework.boot.test.util.TestPropertyValues import org.springframework.context.ApplicationContextInitializer import org.springframework.context.ConfigurableApplicationContext -import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import -import org.springframework.context.annotation.Lazy -import org.springframework.data.redis.connection.RedisConnectionFactory -import org.springframework.data.redis.connection.RedisSentinelConfiguration import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit.jupiter.SpringExtension @@ -39,8 +32,8 @@ import java.util.* @TestPropertySource(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS"]) @Testcontainers @ContextConfiguration(initializers = [RedisSentinelMultiQueueTest.Initializer::class]) -@Import(*[LoggingConfiguration::class, RedisConfiguration::class, QueueConfiguration::class, AbstractMultiQueueTest.AbstractMultiQueueTestConfiguration::class]) -class RedisSentinelMultiQueueTest: AbstractMultiQueueTest() +@Import(*[LoggingConfiguration::class, RedisConfiguration::class, QueueConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class]) +class RedisSentinelMultiQueueTest: MultiQueueTest() { companion object { diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt index d736ab8..f031730 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt @@ -3,31 +3,25 @@ package au.kilemon.messagequeue.queue.cache.redis import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.configuration.cache.redis.RedisConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration -import au.kilemon.messagequeue.queue.AbstractMultiQueueTest +import au.kilemon.messagequeue.queue.MultiQueueTest import au.kilemon.messagequeue.settings.MessageQueueSettings import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.boot.test.context.TestConfiguration import org.springframework.boot.test.util.TestPropertyValues import org.springframework.context.ApplicationContextInitializer import org.springframework.context.ConfigurableApplicationContext -import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import import org.springframework.context.annotation.Lazy -import org.springframework.data.redis.connection.RedisConnectionFactory -import org.springframework.data.redis.connection.RedisStandaloneConfiguration import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit.jupiter.SpringExtension import org.testcontainers.containers.GenericContainer import org.testcontainers.junit.jupiter.Testcontainers import org.testcontainers.utility.DockerImageName -import java.util.* /** @@ -48,8 +42,8 @@ import java.util.* @TestPropertySource(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS", "${MessageQueueSettings.REDIS_PREFIX}=test"]) @Testcontainers @ContextConfiguration(initializers = [RedisStandAloneMultiQueueTest.Initializer::class]) -@Import(*[QueueConfiguration::class, LoggingConfiguration::class, RedisConfiguration::class, AbstractMultiQueueTest.AbstractMultiQueueTestConfiguration::class]) -class RedisStandAloneMultiQueueTest: AbstractMultiQueueTest() +@Import(*[QueueConfiguration::class, LoggingConfiguration::class, RedisConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class]) +class RedisStandAloneMultiQueueTest: MultiQueueTest() { companion object { diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueueTest.kt index ce5ae0a..852955b 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueueTest.kt @@ -2,16 +2,11 @@ package au.kilemon.messagequeue.queue.inmemory import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration -import au.kilemon.messagequeue.queue.AbstractMultiQueueTest +import au.kilemon.messagequeue.queue.MultiQueueTest import au.kilemon.messagequeue.queue.MultiQueue -import au.kilemon.messagequeue.settings.MessageQueueSettings import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest -import org.springframework.boot.test.context.TestConfiguration -import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import -import org.springframework.context.annotation.Lazy import org.springframework.test.context.junit.jupiter.SpringExtension @@ -21,8 +16,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension * @author github.com/Kilemonn */ @ExtendWith(SpringExtension::class) -@Import( *[QueueConfiguration::class, LoggingConfiguration::class, AbstractMultiQueueTest.AbstractMultiQueueTestConfiguration::class] ) -class InMemoryMultiQueueTest: AbstractMultiQueueTest() +@Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) +class InMemoryMultiQueueTest: MultiQueueTest() { /** * Ensure the [MultiQueue] is cleared before each test. diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt index e9ddd6f..ebfb2df 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt @@ -2,7 +2,7 @@ package au.kilemon.messagequeue.queue.nosql.mongo import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration -import au.kilemon.messagequeue.queue.AbstractMultiQueueTest +import au.kilemon.messagequeue.queue.MultiQueueTest import au.kilemon.messagequeue.queue.nosql.mongo.MongoMultiQueueTest.Companion.MONGO_CONTAINER import au.kilemon.messagequeue.settings.MessageQueueSettings import org.junit.jupiter.api.AfterAll @@ -31,8 +31,8 @@ import org.testcontainers.utility.DockerImageName @DataMongoTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=MONGO"]) @ContextConfiguration(initializers = [MongoMultiQueueTest.Initializer::class]) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -@Import( *[QueueConfiguration::class, LoggingConfiguration::class, AbstractMultiQueueTest.AbstractMultiQueueTestConfiguration::class] ) -class MongoMultiQueueTest: AbstractMultiQueueTest() +@Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) +class MongoMultiQueueTest: MultiQueueTest() { companion object { diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/AbstractSqlMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/AbstractSqlMultiQueueTest.kt index a0b5889..ad61ac5 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/AbstractSqlMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/AbstractSqlMultiQueueTest.kt @@ -1,19 +1,11 @@ package au.kilemon.messagequeue.queue.sql -import au.kilemon.messagequeue.configuration.QueueConfiguration -import au.kilemon.messagequeue.configuration.cache.redis.RedisConfiguration -import au.kilemon.messagequeue.logging.LoggingConfiguration -import au.kilemon.messagequeue.queue.AbstractMultiQueueTest +import au.kilemon.messagequeue.queue.MultiQueueTest import au.kilemon.messagequeue.settings.MessageQueueSettings import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.boot.test.context.TestConfiguration -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Import -import org.springframework.context.annotation.Lazy import org.springframework.test.context.junit.jupiter.SpringExtension import org.testcontainers.junit.jupiter.Testcontainers @@ -35,4 +27,4 @@ import org.testcontainers.junit.jupiter.Testcontainers @Testcontainers @DataJpaTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=SQL", "spring.jpa.hibernate.ddl-auto=create", "spring.autoconfigure.exclude="]) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -abstract class AbstractSqlMultiQueueTest: AbstractMultiQueueTest() +abstract class AbstractSqlMultiQueueTest: MultiQueueTest() diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt index b90a587..1a49969 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt @@ -2,7 +2,7 @@ package au.kilemon.messagequeue.queue.sql import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration -import au.kilemon.messagequeue.queue.AbstractMultiQueueTest +import au.kilemon.messagequeue.queue.MultiQueueTest import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach @@ -21,7 +21,7 @@ import java.util.HashMap * @author github.com/Kilemonn */ @ContextConfiguration(initializers = [MySqlMultiQueueTest.Initializer::class]) -@Import( *[QueueConfiguration::class, LoggingConfiguration::class, AbstractMultiQueueTest.AbstractMultiQueueTestConfiguration::class] ) +@Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) class MySqlMultiQueueTest : AbstractSqlMultiQueueTest() { companion object diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt index 8e5dcc1..230e951 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt @@ -2,7 +2,7 @@ package au.kilemon.messagequeue.queue.sql import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration -import au.kilemon.messagequeue.queue.AbstractMultiQueueTest +import au.kilemon.messagequeue.queue.MultiQueueTest import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach @@ -22,7 +22,7 @@ import java.util.* * @author github.com/Kilemonn */ @ContextConfiguration(initializers = [PostgreSqlMultiQueueTest.Initializer::class]) -@Import( *[QueueConfiguration::class, LoggingConfiguration::class, AbstractMultiQueueTest.AbstractMultiQueueTestConfiguration::class] ) +@Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) class PostgreSqlMultiQueueTest: AbstractSqlMultiQueueTest() { companion object From 99304ad1979287842c83ac04f8453772c8052931 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 28 Oct 2023 11:37:06 +1100 Subject: [PATCH 10/58] Finish off generalise tests for the MultiQueueAuthenticator and add docs. --- .../authenticator/MultiQueueAuthenticator.kt | 37 ++- .../MultiQueueAuthenticatorTest.kt | 210 ++++++++++++++++++ 2 files changed, 243 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt index 230ba26..56baaeb 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt @@ -6,10 +6,10 @@ import au.kilemon.messagequeue.filter.JwtAuthenticationFilter import au.kilemon.messagequeue.logging.HasLogger import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired -import kotlin.jvm.Throws /** - * + * The base Authenticator class. This is responsible to tracking which sub queues are marked as restricted and + * maintaining this underlying collection within the specified storage medium. * * @author github.com/Kilemonn */ @@ -29,7 +29,12 @@ abstract class MultiQueueAuthenticator: HasLogger } /** + * Determines whether based on the currently set [getAuthenticationType] and the provided [subQueue] and + * [JwtAuthenticationFilter.getSubQueue] to determine if the user is able to interact with the requested sub queue. * + * @param subQueue the sub-queue identifier that is being requested access to + * @throws MultiQueueAuthorisationException if there is a mis-matching token OR no token provided. Or the sub-queue + * is not in restricted mode when it should be */ @Throws(MultiQueueAuthorisationException::class) fun canAccessSubQueue(subQueue: String) @@ -89,7 +94,10 @@ abstract class MultiQueueAuthenticator: HasLogger } /** + * Will determine if the requested [subQueue] identifier is being treated as a restricted queue or not. * + * @param subQueue the sub-queue to check whether it is restricted or not + * @return if [isInNoneMode] will always return `false`, otherwise delegates to [isRestrictedInternal] */ fun isRestricted(subQueue: String): Boolean { @@ -104,14 +112,22 @@ abstract class MultiQueueAuthenticator: HasLogger } /** + * Defers to the child class to implement this. It should look up in the appropriate storage medium to determine + * whether the provided [subQueue] is restricted or not. * + * @param subQueue the sub-queue to check whether it is restricted or not + * @return `true` if this sub-queue is in restricted mode, otherwise `false` */ abstract fun isRestrictedInternal(subQueue: String): Boolean /** + * Add the provided [subQueue] identifier as a restricted sub-queue. + * This will delegate to [addRestrictedEntryInternal]. + * + * @param subQueue the sub-queue identifier to make restricted * @return `true` if the sub queue identifier was added to the restriction set, otherwise `false` if there was - * no underlying change made + * no underlying change made. If [isInNoneMode] is set this will always return `false`. */ fun addRestrictedEntry(subQueue: String): Boolean { @@ -137,12 +153,19 @@ abstract class MultiQueueAuthenticator: HasLogger } /** + * Add the provided [subQueue] identifier as a restricted sub-queue. * + * @param subQueue the sub-queue identifier to make restricted */ abstract fun addRestrictedEntryInternal(subQueue: String) /** - * @return `true` if there was a restriction that was removed because of this call, otherwise `false` + * Remove the provided [subQueue] from being a restricted sub-queue. + * This will delegate to [removeRestrictionInternal]. + * + * @param subQueue the sub-queue identifier that will no longer be treated as restricted + * @return `true` if there was a restriction that was removed because of this call, otherwise `false`. If + * [isInNoneMode] this will always return `false` */ fun removeRestriction(subQueue: String): Boolean { @@ -168,10 +191,16 @@ abstract class MultiQueueAuthenticator: HasLogger } /** + * Remove the provided [subQueue] from being a restricted sub-queue. * + * @param subQueue the sub-queue identifier that will no longer be treated as restricted + * @return `true` if the identifier is no longer marked as restricted, otherwise `false` */ abstract fun removeRestrictionInternal(subQueue: String): Boolean + /** + * @return the underlying [Set] of sub-queue identifiers that are marked as restricted + */ abstract fun getRestrictedSubQueueIdentifiers(): Set /** diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt index 29e600b..6e3efcc 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt @@ -1,11 +1,14 @@ package au.kilemon.messagequeue.authentication.authenticator import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException +import au.kilemon.messagequeue.filter.JwtAuthenticationFilter import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import org.mockito.Mockito +import org.slf4j.MDC import org.springframework.boot.test.mock.mockito.SpyBean /** @@ -129,4 +132,211 @@ abstract class MultiQueueAuthenticatorTest Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) Assertions.assertFalse(multiQueueAuthenticator.removeRestriction(subQueue)) } + + /** + * Ensure that [MultiQueueAuthenticator.canAccessSubQueue] never throws when its in + * [MultiQueueAuthenticator.isInNoneMode]. + */ + @Test + fun testCanAccessSubQueue_WithNoneMode() + { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + val subQueue = "testCanAccessSubQueue_WithNoneMode" + multiQueueAuthenticator.canAccessSubQueue(subQueue) + } + + /** + * Ensure that [MultiQueueAuthenticator.canAccessSubQueue] never throws when its in + * [MultiQueueAuthenticator.isInHybridMode] and the sub-queue identifier is not marked as restricted. + */ + @Test + fun testCanAccessSubQueue_WithHybridMode_isNotRestricted() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val subQueue = "testCanAccessSubQueue_WithHybridMode_isNotRestricted" + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) + + multiQueueAuthenticator.canAccessSubQueue(subQueue) + } + + /** + * Ensure that [MultiQueueAuthenticator.canAccessSubQueue] never throws when its in + * [MultiQueueAuthenticator.isInHybridMode] and the sub-queue identifier is marked as restricted AND matches + * the stored sub-queue identifier from the auth token. + */ + @Test + fun testCanAccessSubQueue_WithHybridMode_isRestricted_matchesStoredSubQueue() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val subQueue = "testCanAccessSubQueue_WithHybridMode_isRestricted_matchesStoredSubQueue" + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) + + try + { + MDC.put(JwtAuthenticationFilter.SUB_QUEUE, subQueue) + multiQueueAuthenticator.canAccessSubQueue(subQueue) + } + finally + { + MDC.clear() + } + } + + /** + * Ensure that [MultiQueueAuthenticator.canAccessSubQueue] DOES throw a [MultiQueueAuthorisationException] when its + * in [MultiQueueAuthenticator.isInHybridMode] and the sub-queue identifier is marked as restricted AND does NOT + * match the stored sub-queue identifier from the auth token. + */ + @Test + fun testCanAccessSubQueue_WithHybridMode_isRestricted_doesNotMatchStoredSubQueue() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val subQueue = "testCanAccessSubQueue_WithHybridMode_isRestricted_matchesStoredSubQueue" + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) + + try + { + MDC.put(JwtAuthenticationFilter.SUB_QUEUE, "does not match sub-queue") + Assertions.assertThrows(MultiQueueAuthorisationException::class.java) { + multiQueueAuthenticator.canAccessSubQueue(subQueue) + } + } + finally + { + MDC.clear() + } + } + + /** + * Ensure that [MultiQueueAuthenticator.canAccessSubQueue] DOES throw a [MultiQueueAuthorisationException] when its + * in [MultiQueueAuthenticator.isInRestrictedMode] and the sub-queue identifier is NOT marked as restricted. + */ + @Test + fun testCanAccessSubQueue_WithRestrictedMode_isNotRestricted() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + + val subQueue = "testCanAccessSubQueue_WithRestrictedMode_isNotRestricted" + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) + Assertions.assertThrows(MultiQueueAuthorisationException::class.java) { + multiQueueAuthenticator.canAccessSubQueue(subQueue) + } + } + + /** + * Ensure that [MultiQueueAuthenticator.canAccessSubQueue] does NOT throw when its + * in [MultiQueueAuthenticator.isInRestrictedMode] and the sub-queue identifier is marked as restricted AND the + * stored sub-queue identifier from the token matches the requested token. + */ + @Test + fun testCanAccessSubQueue_WithRestrictedMode_isRestricted_matchesStoredSubQueue() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + + val subQueue = "testCanAccessSubQueue_WithRestrictedMode_isRestricted_matchesStoredSubQueue" + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) + + try + { + MDC.put(JwtAuthenticationFilter.SUB_QUEUE, subQueue) + multiQueueAuthenticator.canAccessSubQueue(subQueue) + } + finally + { + MDC.clear() + } + } + + /** + * Ensure that [MultiQueueAuthenticator.canAccessSubQueue] DOES throw a [MultiQueueAuthorisationException] when its + * in [MultiQueueAuthenticator.isInRestrictedMode] and the sub-queue identifier is marked as restricted and the + * provided sub-queue identifier does NOT match the identifier provided in the auth token. + */ + @Test + fun testCanAccessSubQueue_WithRestrictedMode_isRestricted_doesNotMatchStoredSubQueue() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + + val subQueue = "testCanAccessSubQueue_WithRestrictedMode_isRestricted_doesNotMatchStoredSubQueue" + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) + + try + { + MDC.put(JwtAuthenticationFilter.SUB_QUEUE, "does not match sub-queue") + Assertions.assertThrows(MultiQueueAuthorisationException::class.java) { + multiQueueAuthenticator.canAccessSubQueue(subQueue) + } + } + finally + { + MDC.clear() + } + } + + /** + * Ensure that [MultiQueueAuthenticator.clearRestrictedSubQueues] will clear all sub-queue restrictions. + */ + @Test + fun testClearRestrictedSubQueues() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + + val subQueues = listOf("testClearRestrictedSubQueues1", "testClearRestrictedSubQueues2", "testClearRestrictedSubQueues3", + "testClearRestrictedSubQueues4", "testClearRestrictedSubQueues5", "testClearRestrictedSubQueues6") + + subQueues.forEach { subQueue -> Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) } + subQueues.forEach { subQueue -> Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) } + subQueues.forEach { subQueue -> Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) } + multiQueueAuthenticator.clearRestrictedSubQueues() + subQueues.forEach { subQueue -> Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) } + } + + /** + * Ensure that [MultiQueueAuthenticator.getRestrictedSubQueueIdentifiers] will retrieve the restrict sub-queue + * identifiers even when new entries are added/removed and cleared. + */ + @Test + fun testGetRestrictedSubQueueIdentifiers() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + + val subQueues = listOf("testGetRestrictedSubQueueIdentifiers1", "testGetRestrictedSubQueueIdentifiers2", + "testGetRestrictedSubQueueIdentifiers3", "testGetRestrictedSubQueueIdentifiers4", + "testGetRestrictedSubQueueIdentifiers5", "testGetRestrictedSubQueueIdentifiers6") + + subQueues.forEach { subQueue -> Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) } + subQueues.forEach { subQueue -> + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + } + subQueues.forEach { subQueue -> Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) } + + val restrictedIdentifiers = multiQueueAuthenticator.getRestrictedSubQueueIdentifiers() + restrictedIdentifiers.forEach { identifier -> Assertions.assertTrue(multiQueueAuthenticator.isRestricted(identifier)) } + + Assertions.assertEquals(subQueues.size, restrictedIdentifiers.size) + + Assertions.assertTrue(multiQueueAuthenticator.removeRestriction(restrictedIdentifiers.elementAt(0))) + val updatedIdentifiers = multiQueueAuthenticator.getRestrictedSubQueueIdentifiers() + Assertions.assertEquals(restrictedIdentifiers.size - 1, updatedIdentifiers.size) + Assertions.assertFalse(updatedIdentifiers.contains(restrictedIdentifiers.elementAt(0))) + + multiQueueAuthenticator.clearRestrictedSubQueues() + val emptyIdentifiers = multiQueueAuthenticator.getRestrictedSubQueueIdentifiers() + Assertions.assertTrue(emptyIdentifiers.isEmpty()) + } } From 221c405f98f1a4f62d523ff5e76004398ba15eb8 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 28 Oct 2023 15:53:43 +1100 Subject: [PATCH 11/58] Implement redis tests. Fix entry clearing issue. --- .../authentication/AuthenticationMatrix.kt | 3 +- .../cache/redis/RedisAuthenticator.kt | 5 +- .../MultiQueueAuthenticatorTest.kt | 13 +-- .../redis/RedisSentinelAuthenticatorTest.kt | 93 +++++++++++++++++++ .../redis/RedisStandAloneAuthenticatorTest.kt | 79 ++++++++++++++++ .../inmemory/InMemoryAuthenticatorTest.kt | 7 ++ .../redis/RedisSentinelMultiQueueTest.kt | 2 - 7 files changed, 187 insertions(+), 15 deletions(-) create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt index 1697ece..c454f2f 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt @@ -1,6 +1,7 @@ package au.kilemon.messagequeue.authentication import com.fasterxml.jackson.annotation.JsonIgnore +import java.io.Serializable import javax.persistence.* /** @@ -13,7 +14,7 @@ import javax.persistence.* */ @Entity @Table(name = AuthenticationMatrix.TABLE_NAME) -class AuthenticationMatrix(@Column(name = "subqueue", nullable = false) var subQueue: String) +class AuthenticationMatrix(@Column(name = "subqueue", nullable = false) var subQueue: String): Serializable { companion object { diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt index 448e393..159b20d 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt @@ -41,7 +41,8 @@ class RedisAuthenticator: MultiQueueAuthenticator() override fun removeRestrictionInternal(subQueue: String): Boolean { - return redisTemplate.opsForSet().remove(RESTRICTED_KEY, subQueue) != null + val result = redisTemplate.opsForSet().remove(RESTRICTED_KEY, AuthenticationMatrix(subQueue)) + return result != null && result > 0 } override fun getRestrictedSubQueueIdentifiers(): Set @@ -53,7 +54,7 @@ class RedisAuthenticator: MultiQueueAuthenticator() { val members = getMembersSet() val existingMembersSize = members.size.toLong() - redisTemplate.opsForSet().remove(RESTRICTED_KEY, members) + redisTemplate.delete(RESTRICTED_KEY) return existingMembersSize } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt index 6e3efcc..6b206a1 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt @@ -24,12 +24,6 @@ abstract class MultiQueueAuthenticatorTest @SpyBean protected lateinit var multiQueueAuthenticator: MultiQueueAuthenticator - @BeforeEach - fun setUp() - { - multiQueueAuthenticator.clearRestrictedSubQueues() - } - /** * Ensure [MultiQueueAuthenticator.addRestrictedEntry] always returns and does not add an entry if the * [MultiQueueAuthenticator.getAuthenticationType] is [MultiQueueAuthenticationType.NONE]. @@ -198,7 +192,7 @@ abstract class MultiQueueAuthenticatorTest Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) - val subQueue = "testCanAccessSubQueue_WithHybridMode_isRestricted_matchesStoredSubQueue" + val subQueue = "testCanAccessSubQueue_WithHybridMode_isRestricted_doesNotMatchStoredSubQueue" Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) @@ -303,6 +297,7 @@ abstract class MultiQueueAuthenticatorTest subQueues.forEach { subQueue -> Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) } multiQueueAuthenticator.clearRestrictedSubQueues() subQueues.forEach { subQueue -> Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) } + Assertions.assertTrue(multiQueueAuthenticator.getRestrictedSubQueueIdentifiers().isEmpty()) } /** @@ -320,9 +315,7 @@ abstract class MultiQueueAuthenticatorTest "testGetRestrictedSubQueueIdentifiers5", "testGetRestrictedSubQueueIdentifiers6") subQueues.forEach { subQueue -> Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) } - subQueues.forEach { subQueue -> - Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) - } + subQueues.forEach { subQueue -> Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) } subQueues.forEach { subQueue -> Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) } val restrictedIdentifiers = multiQueueAuthenticator.getRestrictedSubQueueIdentifiers() diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt new file mode 100644 index 0000000..f91221e --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt @@ -0,0 +1,93 @@ +package au.kilemon.messagequeue.authentication.authenticator.cache.redis + +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticatorTest +import au.kilemon.messagequeue.configuration.QueueConfiguration +import au.kilemon.messagequeue.configuration.cache.redis.RedisConfiguration +import au.kilemon.messagequeue.logging.LoggingConfiguration +import au.kilemon.messagequeue.queue.MultiQueueTest +import au.kilemon.messagequeue.settings.MessageQueueSettings +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.boot.test.util.TestPropertyValues +import org.springframework.context.ApplicationContextInitializer +import org.springframework.context.ConfigurableApplicationContext +import org.springframework.context.annotation.Import +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.testcontainers.containers.GenericContainer +import org.testcontainers.junit.jupiter.Testcontainers +import org.testcontainers.utility.DockerImageName + +@ExtendWith(SpringExtension::class) +@TestPropertySource(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS"]) +@Testcontainers +@ContextConfiguration(initializers = [RedisSentinelAuthenticatorTest.Initializer::class]) +@Import(*[LoggingConfiguration::class, RedisConfiguration::class, QueueConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class]) +class RedisSentinelAuthenticatorTest: MultiQueueAuthenticatorTest() +{ + companion object + { + private const val REDIS_CONTAINER: String = "redis:7.0.5-alpine" + private const val REDIS_SENTINEL_CONTAINER: String = "s7anley/redis-sentinel-docker:3.2.12" + + lateinit var redis: GenericContainer<*> + lateinit var sentinel: GenericContainer<*> + + /** + * Stop the container at the end of all the tests. + */ + @AfterAll + @JvmStatic + fun afterClass() + { + sentinel.stop() + redis.stop() + } + } + + /** + * The test initialiser for [RedisSentinelAuthenticatorTest] to initialise the container and test properties. + * + * @author github.com/Kilemonn + */ + internal class Initializer : ApplicationContextInitializer + { + /** + * Force start the container, so we can place its host and dynamic ports into the system properties. + * + * Set the environment variables before any of the beans are initialised. + */ + override fun initialize(configurableApplicationContext: ConfigurableApplicationContext) + { + redis = GenericContainer(DockerImageName.parse(REDIS_CONTAINER)) + .withExposedPorts(RedisConfiguration.REDIS_DEFAULT_PORT.toInt()).withReuse(false) + redis.start() + + val envMap = HashMap() + // For the sentinel container to determine where the master node is accessible from + envMap["MASTER"] = redis.host + envMap["REDIS_PORT"] = redis.getMappedPort(RedisConfiguration.REDIS_DEFAULT_PORT.toInt()).toString() + envMap["MASTER_NAME"] = MessageQueueSettings.REDIS_MASTER_NAME_DEFAULT + sentinel = GenericContainer(DockerImageName.parse(REDIS_SENTINEL_CONTAINER)) + .withExposedPorts(RedisConfiguration.REDIS_SENTINEL_DEFAULT_PORT.toInt()).withReuse(false) + .withEnv(envMap) + sentinel.start() + + TestPropertyValues.of( + "${MessageQueueSettings.REDIS_ENDPOINT}=${sentinel.host}:${sentinel.getMappedPort(RedisConfiguration.REDIS_SENTINEL_DEFAULT_PORT.toInt())}", + "${MessageQueueSettings.REDIS_USE_SENTINELS}=true" + ).applyTo(configurableApplicationContext.environment) + } + } + + @BeforeEach + fun beforeEach() + { + Assertions.assertTrue(redis.isRunning) + Assertions.assertTrue(sentinel.isRunning) + multiQueueAuthenticator.clearRestrictedSubQueues() + } +} diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt new file mode 100644 index 0000000..4347fd3 --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt @@ -0,0 +1,79 @@ +package au.kilemon.messagequeue.authentication.authenticator.cache.redis + +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticatorTest +import au.kilemon.messagequeue.configuration.QueueConfiguration +import au.kilemon.messagequeue.configuration.cache.redis.RedisConfiguration +import au.kilemon.messagequeue.logging.LoggingConfiguration +import au.kilemon.messagequeue.queue.MultiQueueTest +import au.kilemon.messagequeue.settings.MessageQueueSettings +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.boot.test.util.TestPropertyValues +import org.springframework.context.ApplicationContextInitializer +import org.springframework.context.ConfigurableApplicationContext +import org.springframework.context.annotation.Import +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.testcontainers.containers.GenericContainer +import org.testcontainers.junit.jupiter.Testcontainers +import org.testcontainers.utility.DockerImageName + +@ExtendWith(SpringExtension::class) +@TestPropertySource(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS", "${MessageQueueSettings.REDIS_PREFIX}=test"]) +@Testcontainers +@ContextConfiguration(initializers = [RedisStandAloneAuthenticatorTest.Initializer::class]) +@Import(*[QueueConfiguration::class, LoggingConfiguration::class, RedisConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class]) +class RedisStandAloneAuthenticatorTest: MultiQueueAuthenticatorTest() +{ + companion object + { + private const val REDIS_PORT: Int = 6379 + private const val REDIS_CONTAINER: String = "redis:7.0.5-alpine" + + lateinit var redis: GenericContainer<*> + + /** + * Stop the container at the end of all the tests. + */ + @AfterAll + @JvmStatic + fun afterClass() + { + redis.stop() + } + } + + /** + * The test initialiser for [RedisStandAloneAuthenticatorTest] to initialise the container and test properties. + * + * @author github.com/Kilemonn + */ + internal class Initializer : ApplicationContextInitializer + { + /** + * Force start the container, so we can place its host and dynamic ports into the system properties. + * + * Set the environment variables before any of the beans are initialised. + */ + override fun initialize(configurableApplicationContext: ConfigurableApplicationContext) + { + redis = GenericContainer(DockerImageName.parse(REDIS_CONTAINER)) + .withExposedPorts(REDIS_PORT).withReuse(false) + redis.start() + + TestPropertyValues.of( + "${MessageQueueSettings.REDIS_ENDPOINT}=${redis.host}:${redis.getMappedPort(REDIS_PORT)}" + ).applyTo(configurableApplicationContext.environment) + } + } + + @BeforeEach + fun beforeEach() + { + Assertions.assertTrue(redis.isRunning) + multiQueueAuthenticator.clearRestrictedSubQueues() + } +} diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt index 04b25a3..1d14f83 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt @@ -7,6 +7,7 @@ import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration import au.kilemon.messagequeue.queue.MultiQueueTest import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Mockito @@ -25,6 +26,12 @@ import org.springframework.test.context.junit.jupiter.SpringExtension @Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) class InMemoryAuthenticatorTest: MultiQueueAuthenticatorTest() { + @BeforeEach + fun setUp() + { + multiQueueAuthenticator.clearRestrictedSubQueues() + } + /** * Ensure that [MultiQueueAuthenticator.isInNoneMode] returns the correct value based on the stored * [MultiQueueAuthenticationType]. diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt index 5b3756c..2a2e52d 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt @@ -38,11 +38,9 @@ class RedisSentinelMultiQueueTest: MultiQueueTest() companion object { private const val REDIS_CONTAINER: String = "redis:7.0.5-alpine" - private const val REDIS_SENTINEL_CONTAINER: String = "s7anley/redis-sentinel-docker:3.2.12" lateinit var redis: GenericContainer<*> - lateinit var sentinel: GenericContainer<*> /** From 252a2652ea27789ada870ab32a172812a47163dc Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 28 Oct 2023 17:08:13 +1100 Subject: [PATCH 12/58] Add get all for mongo and sql repos. Add mechanism to handle reserved sub-queue identifiers. --- .../authenticator/MultiQueueAuthenticator.kt | 16 ++++++++++++++++ .../cache/redis/RedisAuthenticator.kt | 9 ++++++++- .../nosql/mongo/MongoAuthenticator.kt | 3 ++- .../authenticator/sql/SqlAuthenticator.kt | 3 ++- .../redis/RedisStandAloneAuthenticatorTest.kt | 16 ++++++++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt index 56baaeb..d5de4d6 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt @@ -28,6 +28,17 @@ abstract class MultiQueueAuthenticator: HasLogger return multiQueueAuthenticationType } + /** + * Used to return a list of completed reserved sub-queue identifiers that can never be used. Even when + * [MultiQueueAuthenticationType.NONE] is being used. + * + * @return list of sub-queue identifiers that cannot be used + */ + open fun getReservedSubQueues(): Set + { + return setOf() + } + /** * Determines whether based on the currently set [getAuthenticationType] and the provided [subQueue] and * [JwtAuthenticationFilter.getSubQueue] to determine if the user is able to interact with the requested sub queue. @@ -39,6 +50,11 @@ abstract class MultiQueueAuthenticator: HasLogger @Throws(MultiQueueAuthorisationException::class) fun canAccessSubQueue(subQueue: String) { + if (getReservedSubQueues().contains(subQueue)) + { + throw MultiQueueAuthorisationException(subQueue, getAuthenticationType()) + } + if (isInNoneMode()) { return diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt index 159b20d..38d1322 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt @@ -15,7 +15,6 @@ class RedisAuthenticator: MultiQueueAuthenticator() { companion object { - // TODO - Completely black list this key as its used for special purpose for redis const val RESTRICTED_KEY = AuthenticationMatrix.TABLE_NAME + "_restricted" } @@ -24,6 +23,14 @@ class RedisAuthenticator: MultiQueueAuthenticator() @Autowired lateinit var redisTemplate: RedisTemplate + /** + * Overriding to completely remove all access to the [RESTRICTED_KEY]. + */ + override fun getReservedSubQueues(): Set + { + return setOf(RESTRICTED_KEY) + } + private fun getMembersSet(): Set { return redisTemplate.opsForSet().members(RESTRICTED_KEY) ?: HashSet() diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt index 23bf904..dff0e1b 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt @@ -40,7 +40,8 @@ class MongoAuthenticator: MultiQueueAuthenticator() override fun getRestrictedSubQueueIdentifiers(): Set { - TODO("Not yet implemented") + return authenticationMatrixRepository.findAll().stream().map { authMatrix -> authMatrix.subQueue } + .toList().toSet() } override fun clearRestrictedSubQueues(): Long diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt index 83c9a5d..4d7846f 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt @@ -40,7 +40,8 @@ class SqlAuthenticator: MultiQueueAuthenticator() override fun getRestrictedSubQueueIdentifiers(): Set { - TODO("Not yet implemented") + return authenticationMatrixRepository.findAll().stream().map { authMatrix -> authMatrix.subQueue } + .toList().toSet() } override fun clearRestrictedSubQueues(): Long diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt index 4347fd3..322a845 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt @@ -1,6 +1,7 @@ package au.kilemon.messagequeue.authentication.authenticator.cache.redis import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticatorTest +import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.configuration.cache.redis.RedisConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration @@ -9,6 +10,7 @@ import au.kilemon.messagequeue.settings.MessageQueueSettings import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.springframework.boot.test.util.TestPropertyValues import org.springframework.context.ApplicationContextInitializer @@ -76,4 +78,18 @@ class RedisStandAloneAuthenticatorTest: MultiQueueAuthenticatorTest() Assertions.assertTrue(redis.isRunning) multiQueueAuthenticator.clearRestrictedSubQueues() } + + /** + * Ensure that the [RedisAuthenticator.getReservedSubQueues] always contains [RedisAuthenticator.RESTRICTED_KEY] and + * that calls to [MultiQueueAuthenticator.canAccessSubQueue] will throw a [MultiQueueAuthorisationException]. + */ + @Test + fun testGetReservedSubQueues() + { + Assertions.assertTrue(multiQueueAuthenticator.getReservedSubQueues().contains(RedisAuthenticator.RESTRICTED_KEY)) + Assertions.assertThrows(MultiQueueAuthorisationException::class.java) { + multiQueueAuthenticator.canAccessSubQueue(RedisAuthenticator.RESTRICTED_KEY) + } + } + } From 94f465ac0de041218eeceb10afa2fafa42efd129 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 28 Oct 2023 19:37:56 +1100 Subject: [PATCH 13/58] Add remaining test classes for SQL and MongoDB. --- .../authentication/AuthenticationMatrix.kt | 2 +- .../AuthenticationMatrixDocument.kt | 11 -- .../cache/redis/RedisAuthenticator.kt | 3 +- .../inmemory/InMemoryAuthenticator.kt | 3 +- .../MongoAuthenticationMatrixRepository.kt | 11 +- .../nosql/mongo/MongoAuthenticator.kt | 20 +++- .../authenticator/sql/SqlAuthenticator.kt | 3 +- .../queue/nosql/mongo/MongoMultiQueue.kt | 2 +- .../AuthenticationMatrixTest.kt | 23 +++- .../redis/RedisSentinelAuthenticatorTest.kt | 5 + .../redis/RedisStandAloneAuthenticatorTest.kt | 5 + .../mongo/MongoMultiAuthenticatorTest.kt | 104 ++++++++++++++++++ .../sql/MySqlAuthenticatorTest.kt | 94 ++++++++++++++++ .../sql/PostgreSqlAuthenticatorTest.kt | 94 ++++++++++++++++ .../queue/sql/MySqlMultiQueueTest.kt | 2 +- .../queue/sql/PostgreSqlMultiQueueTest.kt | 2 +- ...MultiQueueTest.kt => SqlMultiQueueTest.kt} | 2 +- 17 files changed, 362 insertions(+), 24 deletions(-) create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoMultiAuthenticatorTest.kt create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt rename src/test/kotlin/au/kilemon/messagequeue/queue/sql/{AbstractSqlMultiQueueTest.kt => SqlMultiQueueTest.kt} (95%) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt index c454f2f..1a48fda 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt @@ -27,7 +27,7 @@ class AuthenticationMatrix(@Column(name = "subqueue", nullable = false) var subQ var id: Long? = null /** - * Required for JSON deserialisation. + * Required for MySQL. */ constructor() : this("") diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt index a5d80fc..4559df8 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt @@ -21,15 +21,4 @@ class AuthenticationMatrixDocument(var subQueue: String) @JsonIgnore @Id var id: Long? = null - - /** - * Required for JSON deserialisation. - */ - constructor() : this("") - - constructor(authenticationMatrix: AuthenticationMatrix) : this() - { - this.id = authenticationMatrix.id - this.subQueue = authenticationMatrix.subQueue - } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt index 38d1322..8d50b61 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt @@ -7,7 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.data.redis.core.RedisTemplate /** - * + * A [MultiQueueAuthenticator] implementation using Redis as the storage mechanism for the restricted + * sub-queue identifiers. * * @author github.com/Kilemonn */ diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt index 5c516ce..0316d52 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt @@ -4,7 +4,8 @@ import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthentica import org.slf4j.Logger /** - * + * A [MultiQueueAuthenticator] implementation using an in-memory set as the storage mechanism for the restricted + * sub-queue identifiers. * * @author github.com/Kilemonn */ diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticationMatrixRepository.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticationMatrixRepository.kt index a1c7641..f852b30 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticationMatrixRepository.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticationMatrixRepository.kt @@ -1,15 +1,22 @@ package au.kilemon.messagequeue.authentication.authenticator.nosql.mongo -import au.kilemon.messagequeue.authentication.AuthenticationMatrix import au.kilemon.messagequeue.authentication.AuthenticationMatrixDocument import org.springframework.data.mongodb.repository.MongoRepository +import java.util.* /** - * + * A [MongoRepository] for [AuthenticationMatrixDocument] which stores which sub-queues are under restricted access. * * @author github.com/Kilemonn */ interface MongoAuthenticationMatrixRepository: MongoRepository { fun findBySubQueue(subQueue: String): List + + /** + * Get the entry with the largest ID. + * + * @return the [AuthenticationMatrixDocument] with the largest ID, otherwise [Optional.empty] + */ + fun findTopByOrderByIdDesc(): Optional } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt index dff0e1b..ed26b83 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt @@ -6,7 +6,8 @@ import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired /** - * + * A [MultiQueueAuthenticator] implementation using MongoDB as the storage mechanism for the restricted sub-queue + * identifiers. * * @author github.com/Kilemonn */ @@ -23,9 +24,26 @@ class MongoAuthenticator: MultiQueueAuthenticator() return entries.isNotEmpty() } + /** + * Since mongodb does not manage self generated IDs we need to generate the ID ourselves when creating a new entry. + */ + private fun getNextQueueIndex(): Long + { + val largestIdMessage = authenticationMatrixRepository.findTopByOrderByIdDesc() + return if (largestIdMessage.isPresent) + { + largestIdMessage.get().id?.plus(1) ?: 1 + } + else + { + 1 + } + } + override fun addRestrictedEntryInternal(subQueue: String) { val authMatrix = AuthenticationMatrixDocument(subQueue) + authMatrix.id = getNextQueueIndex() authenticationMatrixRepository.save(authMatrix) } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt index 4d7846f..353584c 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt @@ -6,7 +6,8 @@ import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired /** - * + * A [MultiQueueAuthenticator] implementation using SQL as the storage mechanism for the restricted sub-queue + * identifiers. * * @author github.com/Kilemonn */ diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt index 0299d18..e1fb803 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt @@ -168,7 +168,7 @@ class MongoMultiQueue : MultiQueue(), HasLogger val largestIdMessage = queueMessageRepository.findTopByOrderByIdDesc() return if (largestIdMessage.isPresent) { - Optional.ofNullable(largestIdMessage.get().id?.plus(1) ?: 1) + Optional.of(largestIdMessage.get().id?.plus(1) ?: 1) } else { diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixTest.kt index d8c8452..92f4dc8 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixTest.kt @@ -1,9 +1,7 @@ package au.kilemon.messagequeue.authentication -import au.kilemon.messagequeue.message.QueueMessage import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test -import java.util.* /** * A test class for the [AuthenticationMatrix]. @@ -32,4 +30,25 @@ class AuthenticationMatrixTest Assertions.assertNotEquals(authMatrix1, authMatrix3) Assertions.assertNotEquals(authMatrix2, authMatrix3) } + + /** + * Ensure [AuthenticationMatrix.equals] returns `false` when `null` is passed in. + */ + @Test + fun testEquals_nullArg() + { + val authMatrix = AuthenticationMatrix("authMatrix") + Assertions.assertNotEquals(authMatrix, null) + } + + /** + * Ensure [AuthenticationMatrix.equals] returns `false` when a non-[AuthenticationMatrix] object is passed in. + */ + @Test + fun testEquals_differentObject() + { + val authMatrix = AuthenticationMatrix("authMatrix") + val string = "test" + Assertions.assertNotEquals(authMatrix, string) + } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt index f91221e..8fad6c5 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt @@ -21,6 +21,11 @@ import org.testcontainers.containers.GenericContainer import org.testcontainers.junit.jupiter.Testcontainers import org.testcontainers.utility.DockerImageName +/** + * A test class for [RedisAuthenticator] running in a sentinel configuration. + * + * @author github.com/Kilemonn + */ @ExtendWith(SpringExtension::class) @TestPropertySource(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS"]) @Testcontainers diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt index 322a845..a0f518f 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt @@ -23,6 +23,11 @@ import org.testcontainers.containers.GenericContainer import org.testcontainers.junit.jupiter.Testcontainers import org.testcontainers.utility.DockerImageName +/** + * A test class for [RedisAuthenticator] running in a standalone configuration. + * + * @author github.com/Kilemonn + */ @ExtendWith(SpringExtension::class) @TestPropertySource(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS", "${MessageQueueSettings.REDIS_PREFIX}=test"]) @Testcontainers diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoMultiAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoMultiAuthenticatorTest.kt new file mode 100644 index 0000000..9c4111d --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoMultiAuthenticatorTest.kt @@ -0,0 +1,104 @@ +package au.kilemon.messagequeue.authentication.authenticator.nosql.mongo + +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticatorTest +import au.kilemon.messagequeue.authentication.authenticator.nosql.mongo.MongoMultiAuthenticatorTest.Companion.MONGO_CONTAINER +import au.kilemon.messagequeue.configuration.QueueConfiguration +import au.kilemon.messagequeue.logging.LoggingConfiguration +import au.kilemon.messagequeue.queue.MultiQueueTest +import au.kilemon.messagequeue.settings.MessageQueueSettings +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase +import org.springframework.boot.test.util.TestPropertyValues +import org.springframework.context.ApplicationContextInitializer +import org.springframework.context.ConfigurableApplicationContext +import org.springframework.context.annotation.Import +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.testcontainers.containers.GenericContainer +import org.testcontainers.junit.jupiter.Testcontainers +import org.testcontainers.utility.DockerImageName + +/** + * A test class for the [MONGO_CONTAINER] to ensure the [MongoAuthenticator] works as expected with this underlying data + * storage DB. + * + * @author github.com/Kilemonn + */ +@ExtendWith(SpringExtension::class) +@Testcontainers +@DataMongoTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=MONGO"]) +@ContextConfiguration(initializers = [MongoMultiAuthenticatorTest.Initializer::class]) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) +class MongoMultiAuthenticatorTest: MultiQueueAuthenticatorTest() +{ + companion object + { + lateinit var mongoDb: GenericContainer<*> + + private const val MONGO_CONTAINER = "mongo:7.0.0" + private const val MONGO_PORT = 27017 + + /** + * Stop the container at the end of all the tests. + */ + @AfterAll + @JvmStatic + fun afterClass() + { + mongoDb.stop() + } + } + + /** + * The test initialiser for [MongoMultiAuthenticatorTest] to initialise the container and test properties. + * + * @author github.com/Kilemonn + */ + internal class Initializer : ApplicationContextInitializer + { + /** + * Force start the container, so we can place its host and dynamic ports into the system properties. + * + * Set the environment variables before any of the beans are initialised. + * + * The following properties can also be used: + * - "spring.data.mongodb.host=${mongoDb.host}" + * - "spring.data.mongodb.database=$databaseName" + * - "spring.data.mongodb.username=$username" + * - "spring.data.mongodb.password=$password" + * - "spring.data.mongodb.port=${mongoDb.getMappedPort(MONGO_PORT)}" + */ + override fun initialize(configurableApplicationContext: ConfigurableApplicationContext) + { + val password = "password" + val username = "root" + val envMap = HashMap() + envMap["MONGO_INITDB_ROOT_PASSWORD"] = password + envMap["MONGO_INITDB_ROOT_USERNAME"] = username + + mongoDb = GenericContainer(DockerImageName.parse(MONGO_CONTAINER)) + .withExposedPorts(MONGO_PORT).withReuse(false).withEnv(envMap) + mongoDb.start() + + val databaseName = "MultiQueue" + // mongodb://:@:/ + val endpoint = "mongodb://$username:$password@${mongoDb.host}:${mongoDb.getMappedPort(MONGO_PORT)}/$databaseName?authSource=admin" + + TestPropertyValues.of( + "spring.data.mongodb.uri=$endpoint" + ).applyTo(configurableApplicationContext.environment) + } + } + + @BeforeEach + fun beforeEach() + { + Assertions.assertTrue(mongoDb.isRunning) + multiQueueAuthenticator.clearRestrictedSubQueues() + } +} diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt new file mode 100644 index 0000000..35ac6f8 --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt @@ -0,0 +1,94 @@ +package au.kilemon.messagequeue.authentication.authenticator.sql + +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticatorTest +import au.kilemon.messagequeue.configuration.QueueConfiguration +import au.kilemon.messagequeue.logging.LoggingConfiguration +import au.kilemon.messagequeue.queue.MultiQueueTest +import au.kilemon.messagequeue.settings.MessageQueueSettings +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.boot.test.util.TestPropertyValues +import org.springframework.context.ApplicationContextInitializer +import org.springframework.context.ConfigurableApplicationContext +import org.springframework.context.annotation.Import +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.testcontainers.containers.GenericContainer +import org.testcontainers.junit.jupiter.Testcontainers +import org.testcontainers.utility.DockerImageName + +/** + * A test class for [SqlAuthenticator] using MySQL as the backing database. + * + * @author github.com/Kilemonn + */ +@ExtendWith(SpringExtension::class) +@Testcontainers +@DataJpaTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=SQL", "spring.jpa.hibernate.ddl-auto=create", "spring.autoconfigure.exclude="]) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@ContextConfiguration(initializers = [MySqlAuthenticatorTest.Initializer::class]) +@Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) +class MySqlAuthenticatorTest: MultiQueueAuthenticatorTest() +{ + companion object + { + lateinit var database: GenericContainer<*> + + private const val MYSQL_CONTAINER = "mysql:8.0.31" + private const val MYSQL_PORT = 3306 + + /** + * Stop the container at the end of all the tests. + */ + @AfterAll + @JvmStatic + fun afterClass() + { + database.stop() + } + } + + /** + * The test initialiser for [MySqlAuthenticatorTest] to initialise the container and test properties. + * + * @author github.com/Kilemonn + */ + internal class Initializer : ApplicationContextInitializer + { + /** + * Force start the container, so we can place its host and dynamic ports into the system properties. + * + * Set the environment variables before any of the beans are initialised. + */ + override fun initialize(configurableApplicationContext: ConfigurableApplicationContext) + { + val password = "password" + val envMap = HashMap() + envMap["MYSQL_ROOT_PASSWORD"] = password + + database = GenericContainer(DockerImageName.parse(MYSQL_CONTAINER)) + .withExposedPorts(MYSQL_PORT).withReuse(false).withEnv(envMap) + database.start() + + val endpoint = "jdbc:mysql://${database.host}:${database.getMappedPort(MYSQL_PORT)}/mysql" + val username = "root" + + TestPropertyValues.of( + "spring.datasource.url=$endpoint", + "spring.datasource.username=$username", + "spring.datasource.password=$password", + ).applyTo(configurableApplicationContext.environment) + } + } + + @BeforeEach + fun beforeEach() + { + Assertions.assertTrue(database.isRunning) + multiQueueAuthenticator.clearRestrictedSubQueues() + } +} diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt new file mode 100644 index 0000000..c7286c2 --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt @@ -0,0 +1,94 @@ +package au.kilemon.messagequeue.authentication.authenticator.sql + +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticatorTest +import au.kilemon.messagequeue.configuration.QueueConfiguration +import au.kilemon.messagequeue.logging.LoggingConfiguration +import au.kilemon.messagequeue.queue.MultiQueueTest +import au.kilemon.messagequeue.settings.MessageQueueSettings +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.boot.test.util.TestPropertyValues +import org.springframework.context.ApplicationContextInitializer +import org.springframework.context.ConfigurableApplicationContext +import org.springframework.context.annotation.Import +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.testcontainers.containers.GenericContainer +import org.testcontainers.junit.jupiter.Testcontainers +import org.testcontainers.utility.DockerImageName + +/** + * A test class for [SqlAuthenticator] using PostgreSQL as the backing database. + * + * @author github.com/Kilemonn + */ +@ExtendWith(SpringExtension::class) +@Testcontainers +@DataJpaTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=SQL", "spring.jpa.hibernate.ddl-auto=create", "spring.autoconfigure.exclude="]) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@ContextConfiguration(initializers = [PostgreSqlAuthenticatorTest.Initializer::class]) +@Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) +class PostgreSqlAuthenticatorTest: MultiQueueAuthenticatorTest() +{ + companion object + { + lateinit var database: GenericContainer<*> + + private const val POSTGRES_CONTAINER = "postgres:14.5" + private const val POSTGRES_PORT = 5432 + + /** + * Stop the container at the end of all the tests. + */ + @AfterAll + @JvmStatic + fun afterClass() + { + database.stop() + } + } + + /** + * The test initialiser for [PostgreSqlAuthenticatorTest] to initialise the container and test properties. + * + * @author github.com/Kilemonn + */ + internal class Initializer : ApplicationContextInitializer + { + /** + * Force start the container, so we can place its host and dynamic ports into the system properties. + * + * Set the environment variables before any of the beans are initialised. + */ + override fun initialize(configurableApplicationContext: ConfigurableApplicationContext) + { + val password = "password" + val envMap = HashMap() + envMap["POSTGRES_PASSWORD"] = password + + database = GenericContainer(DockerImageName.parse(POSTGRES_CONTAINER)) + .withExposedPorts(POSTGRES_PORT).withReuse(false).withEnv(envMap) + database.start() + + val endpoint = "jdbc:postgresql://${database.host}:${database.getMappedPort(POSTGRES_PORT)}/postgres" + val username = "postgres" + + TestPropertyValues.of( + "spring.datasource.url=$endpoint", + "spring.datasource.username=$username", + "spring.datasource.password=$password", + ).applyTo(configurableApplicationContext.environment) + } + } + + @BeforeEach + fun beforeEach() + { + Assertions.assertTrue(database.isRunning) + multiQueueAuthenticator.clearRestrictedSubQueues() + } +} diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt index 1a49969..5719d9a 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt @@ -22,7 +22,7 @@ import java.util.HashMap */ @ContextConfiguration(initializers = [MySqlMultiQueueTest.Initializer::class]) @Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) -class MySqlMultiQueueTest : AbstractSqlMultiQueueTest() +class MySqlMultiQueueTest : SqlMultiQueueTest() { companion object { diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt index 230e951..a01b4fb 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt @@ -23,7 +23,7 @@ import java.util.* */ @ContextConfiguration(initializers = [PostgreSqlMultiQueueTest.Initializer::class]) @Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) -class PostgreSqlMultiQueueTest: AbstractSqlMultiQueueTest() +class PostgreSqlMultiQueueTest: SqlMultiQueueTest() { companion object { diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/AbstractSqlMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueueTest.kt similarity index 95% rename from src/test/kotlin/au/kilemon/messagequeue/queue/sql/AbstractSqlMultiQueueTest.kt rename to src/test/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueueTest.kt index ad61ac5..aee2255 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/AbstractSqlMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueueTest.kt @@ -27,4 +27,4 @@ import org.testcontainers.junit.jupiter.Testcontainers @Testcontainers @DataJpaTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=SQL", "spring.jpa.hibernate.ddl-auto=create", "spring.autoconfigure.exclude="]) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -abstract class AbstractSqlMultiQueueTest: MultiQueueTest() +abstract class SqlMultiQueueTest: MultiQueueTest() From e6ec3261874b5fdbba53aafddb0867e5d990ffc5 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 28 Oct 2023 22:20:25 +1100 Subject: [PATCH 14/58] Add JWT lib and creation/verification functions. --- build.gradle.kts | 4 + .../authentication/token/JwtTokenProvider.kt | 112 ++++++++++++++++++ .../configuration/QueueConfiguration.kt | 7 ++ .../filter/JwtAuthenticationFilter.kt | 36 +++++- .../token/JwtTokenProviderTest.kt | 102 ++++++++++++++++ .../filter/JwtAuthenticationFilterTest.kt | 18 ++- 6 files changed, 275 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt create mode 100644 src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index ba346ef..55e2028 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -46,6 +46,10 @@ dependencies { // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb implementation("org.springframework.boot:spring-boot-starter-data-mongodb:3.1.3") + // JWT token + // https://mvnrepository.com/artifact/com.auth0/java-jwt + implementation("com.auth0:java-jwt:4.4.0") + // Test dependencies testImplementation("org.springframework.boot:spring-boot-starter-test:3.0.6") // Required to mock MultiQueue objects since they apparently override a final 'remove(Object)' method. diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt new file mode 100644 index 0000000..73eeed9 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt @@ -0,0 +1,112 @@ +package au.kilemon.messagequeue.authentication.token + +import au.kilemon.messagequeue.logging.HasLogger +import com.auth0.jwt.JWT +import com.auth0.jwt.JWTVerifier +import com.auth0.jwt.algorithms.Algorithm +import com.auth0.jwt.exceptions.JWTCreationException +import com.auth0.jwt.exceptions.JWTVerificationException +import com.auth0.jwt.interfaces.DecodedJWT +import org.slf4j.Logger +import java.security.SecureRandom +import java.util.* + +/** + * A class to handle Jwt token creation and verification. + */ +class JwtTokenProvider: HasLogger +{ + companion object + { + const val ISSUER = "kilemon/message-queue" + + const val SUB_QUEUE_CLAIM = "Sub-Queue-Identifier" + } + + override val LOG: Logger = this.initialiseLogger() + + private var jwtVerifier: JWTVerifier? = null + + private var algorithm: Algorithm? = null + + /** + * Lazily initialise and get the [Algorithm] using [Algorithm.HMAC512] and a random key. + * + * @return the shared [Algorithm] instance + */ + private fun getAlgorithm(): Algorithm + { + if (algorithm == null) + { + val random = SecureRandom() + val bytes = ByteArray(128) + random.nextBytes(bytes) + algorithm = Algorithm.HMAC512(bytes) + } + return algorithm!! + } + + /** + * Lazily initialise and get the [JWTVerifier]. + * + * @return the shared [JWTVerifier] instance + */ + private fun getVerifier(): JWTVerifier + { + if (jwtVerifier == null) + { + jwtVerifier = JWT.require(getAlgorithm()).withIssuer(ISSUER).build() + } + return jwtVerifier!! + } + + /** + * Verify the provided [String] token and decode it and return it as a [DecodedJWT]. + * + * @param token the token to parse and decode + * @return the [DecodedJWT] from the provided [String] token, otherwise [Optional.empty] + */ + fun verifyTokenForSubQueue(token: String): Optional + { + try + { + return Optional.ofNullable(getVerifier().verify(token)) + } + catch (ex: JWTVerificationException) + { + // Invalid signature/claims + LOG.error("Failed to verify provided token.", ex) + } + return Optional.empty() + } + + /** + * Create a new token. + * + * @param subQueue will be embedded in the generated token as a claim with key [SUB_QUEUE_CLAIM] + * @param expiryInMinutes the generated token expiry in minutes, if `null` this is not added the token will be valid + * indefinitely + * @return the generated token as a [String] otherwise [Optional.empty] if there was a problem generating the token + */ + fun createTokenForSubQueue(subQueue: String, expiryInMinutes: Long? = null): Optional + { + try + { + val builder = JWT.create().withIssuer(ISSUER).withClaim(SUB_QUEUE_CLAIM, subQueue) + if (expiryInMinutes != null) + { + builder.withExpiresAt(Date(Date().time + (expiryInMinutes * 60 * 1000))) + } + val token = builder.sign(getAlgorithm()) + + LOG.info("Creating new token for sub-queue [{}] with expiry of [{}] minutes.", subQueue, expiryInMinutes) + return Optional.ofNullable(token) + } + catch (ex: JWTCreationException) + { + // Invalid Signing configuration / Couldn't convert Claims. + LOG.error(String.format("Failed to create requested token for sub-queue identifier [%s].", subQueue), ex) + } + return Optional.empty() + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt index 0c19d2a..401ec7f 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt @@ -16,6 +16,7 @@ import au.kilemon.messagequeue.authentication.authenticator.cache.redis.RedisAut import au.kilemon.messagequeue.authentication.authenticator.inmemory.InMemoryAuthenticator import au.kilemon.messagequeue.authentication.authenticator.nosql.mongo.MongoAuthenticator import au.kilemon.messagequeue.authentication.authenticator.sql.SqlAuthenticator +import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.settings.MultiQueueType import lombok.Generated import org.slf4j.Logger @@ -129,4 +130,10 @@ class QueueConfiguration : HasLogger return authenticator } + + @Bean + open fun getJwtTokenProvider(): JwtTokenProvider + { + return JwtTokenProvider() + } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index 9ac1fa1..183e4be 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -4,6 +4,7 @@ import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException +import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import org.slf4j.Logger import org.slf4j.MDC import org.springframework.beans.factory.annotation.Autowired @@ -16,7 +17,7 @@ import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse /** - * + * A filter responsible for verifying provided Jwt tokens when sub-queues are being accessed. * * @author github.com/Kilemonn */ @@ -27,6 +28,7 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger companion object { const val AUTHORIZATION_HEADER = "Authorization" + const val BEARER_HEADER_VALUE = "Bearer " const val SUB_QUEUE = "Sub-Queue" @@ -45,6 +47,9 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger @Autowired lateinit var authenticator: MultiQueueAuthenticator + @Autowired + lateinit var jwtTokenProvider: JwtTokenProvider + /** * */ @@ -86,7 +91,10 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger } /** + * Check if the token is set and it is restricted sub-queue identifier. * + * @return `true` if the provided [Optional.isPresent] and the call to [MultiQueueAuthenticator.isRestricted] is + * `true` using the provided [Optional] value. Otherwise, returns `false` */ fun tokenIsPresentAndQueueIsRestricted(subQueue: Optional, multiQueueAuthenticator: MultiQueueAuthenticator): Boolean { @@ -118,17 +126,39 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger val authHeader = request.getHeader(AUTHORIZATION_HEADER) if (authHeader != null) { - return isValidJwtToken(authHeader) + return if (authHeader.startsWith(BEARER_HEADER_VALUE)) + { + val removeBearer = authHeader.substring(BEARER_HEADER_VALUE.length) + isValidJwtToken(removeBearer) + } + else + { + LOG.error("Provided [{}] header did not have prefix [{}].", AUTHORIZATION_HEADER, BEARER_HEADER_VALUE) + Optional.empty() + } } return Optional.empty() } /** + * Delegate to the [JwtTokenProvider] to determine if the provided token is valid. * + * @param jwtToken the token to verify + * @return the [String] for the sub-queue that this token is able to access, otherwise [Optional.empty] if there was + * a problem with parsing the claim + * @throws [MultiQueueAuthenticationException] if there is an issue verifying the token */ @Throws(MultiQueueAuthenticationException::class) fun isValidJwtToken(jwtToken: String): Optional { - return Optional.ofNullable(jwtToken) + val result = jwtTokenProvider.verifyTokenForSubQueue(jwtToken) + if (result.isPresent) + { + return Optional.ofNullable(result.get().getClaim(JwtTokenProvider.SUB_QUEUE_CLAIM).asString()) + } + else + { + throw MultiQueueAuthenticationException() + } } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt new file mode 100644 index 0000000..c6d27ce --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt @@ -0,0 +1,102 @@ +package au.kilemon.messagequeue.authentication.token + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import java.util.* + +/** + * A test class for [JwtTokenProvider] and different token issuing and verification scenarios. + */ +class JwtTokenProviderTest +{ + private val jwtTokenProvider = JwtTokenProvider() + + /** + * Ensure [JwtTokenProvider.createTokenForSubQueue] can successfully provision a token for a sub-queue. + */ + @Test + fun testCreateTokenForSubQueue() + { + val subQueue = "testCreateTokenForSubQueue" + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) + + Assertions.assertNotNull(token) + Assertions.assertTrue(token.isPresent) + } + + /** + * Ensure [JwtTokenProvider.verifyTokenForSubQueue] correctly parses out the token's properties + * and that the issuer and claim are set correctly. And expiry is not set. + */ + @Test + fun testVerifyTokenForSubQueue_withoutExpiry() + { + val subQueue = "testVerifyTokenForSubQueue" + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) + Assertions.assertNotNull(token) + Assertions.assertTrue(token.isPresent) + + val decodedJwt = jwtTokenProvider.verifyTokenForSubQueue(token.get()) + Assertions.assertNotNull(decodedJwt) + Assertions.assertTrue(decodedJwt.isPresent) + + val jwt = decodedJwt.get() + Assertions.assertEquals(subQueue, jwt.getClaim(JwtTokenProvider.SUB_QUEUE_CLAIM).asString()) + Assertions.assertEquals(JwtTokenProvider.ISSUER, jwt.issuer) + Assertions.assertNull(jwt.expiresAt) + } + + /** + * Ensure [JwtTokenProvider.verifyTokenForSubQueue] correctly parses out the token's properties + * and that the issuer, claim and expiry are set correctly. + */ + @Test + fun testVerifyTokenForSubQueue_withExpiringToken() + { + val subQueue = "testVerifyTokenForSubQueue_withExpiringToken" + val expiryInMinutes = 60L + val date = Date() + val token = jwtTokenProvider.createTokenForSubQueue(subQueue, expiryInMinutes) + Assertions.assertNotNull(token) + Assertions.assertTrue(token.isPresent) + + val decodedJwt = jwtTokenProvider.verifyTokenForSubQueue(token.get()) + Assertions.assertNotNull(decodedJwt) + Assertions.assertTrue(decodedJwt.isPresent) + + val jwt = decodedJwt.get() + Assertions.assertEquals(subQueue, jwt.getClaim(JwtTokenProvider.SUB_QUEUE_CLAIM).asString()) + Assertions.assertEquals(JwtTokenProvider.ISSUER, jwt.issuer) + Assertions.assertNotNull(jwt.expiresAt) + Assertions.assertTrue(jwt.expiresAt >= Date(date.time + (expiryInMinutes * 60 * 1000))) + Assertions.assertTrue(jwt.expiresAt < Date(date.time + ((expiryInMinutes + 1) * 60 * 1000))) + } + + /** + * Ensure [JwtTokenProvider.verifyTokenForSubQueue] fails to decode a token that has an expiry date that is in the + * past (expired token). + */ + @Test + fun testVerifyTokenForSubQueue_withExpiredToken() + { + val subQueue = "testVerifyTokenForSubQueue_withExpiringToken" + val expiryInMinutes = -10L + val token = jwtTokenProvider.createTokenForSubQueue(subQueue, expiryInMinutes) + + val decodedJwt = jwtTokenProvider.verifyTokenForSubQueue(token.get()) + Assertions.assertNotNull(decodedJwt) + Assertions.assertTrue(decodedJwt.isEmpty) + } + + /** + * Ensure [JwtTokenProvider.verifyTokenForSubQueue] fails to parse the provided token if it's not a valid JWT token. + */ + @Test + fun testVerifyTokenForSubQueue_invalidToken() + { + val token = "testVerifyTokenForSubQueue_invalidToken" + val decodedJwt = jwtTokenProvider.verifyTokenForSubQueue(token) + Assertions.assertNotNull(decodedJwt) + Assertions.assertTrue(decodedJwt.isEmpty) + } +} diff --git a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt index 3f0e350..5524316 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt @@ -11,6 +11,7 @@ import java.util.* import javax.servlet.http.HttpServletRequest /** + * A test class for the [JwtAuthenticationFilter]. * * @author github.com/Kilemonn */ @@ -73,7 +74,7 @@ class JwtAuthenticationFilterTest fun testGetSubQueueInTokenFromHeaders_headerExists() { val request = Mockito.mock(HttpServletRequest::class.java) - val authHeaderValue = "testGetSubQueueInTokenFromHeaders_headerExists" + val authHeaderValue = "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}testGetSubQueueInTokenFromHeaders_headerExists" Mockito.`when`(request.getHeader(JwtAuthenticationFilter.AUTHORIZATION_HEADER)).thenReturn(authHeaderValue) val subQueue = jwtAuthenticationFilter.getSubQueueInTokenFromHeaders(request) @@ -81,6 +82,21 @@ class JwtAuthenticationFilterTest Assertions.assertEquals(authHeaderValue, subQueue.get()) } + /** + * Ensure that [JwtAuthenticationFilter.getSubQueueInTokenFromHeaders] will fail to retrieve and verify the token + * when it does not have the [JwtAuthenticationFilter.BEARER_HEADER_VALUE] prefix. + */ + @Test + fun testGetSubQueueInTokenFromHeaders_withoutBearerPrefix() + { + val request = Mockito.mock(HttpServletRequest::class.java) + val authHeaderValue = "testGetSubQueueInTokenFromHeaders_withoutBearerPrefix" + Mockito.`when`(request.getHeader(JwtAuthenticationFilter.AUTHORIZATION_HEADER)).thenReturn(authHeaderValue) + + val subQueue = jwtAuthenticationFilter.getSubQueueInTokenFromHeaders(request) + Assertions.assertTrue(subQueue.isEmpty) + } + /** * Ensure that [JwtAuthenticationFilter.getSubQueueInTokenFromHeaders] will return an [Optional.empty] when the * [JwtAuthenticationFilter.AUTHORIZATION_HEADER] header value is `null`. From 8f558443da5fd57e2909ee1f7f163d672363da88 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sun, 29 Oct 2023 19:21:32 +1100 Subject: [PATCH 15/58] Make test more consistent with a sleep. --- .../messagequeue/authentication/token/JwtTokenProviderTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt index c6d27ce..7f27783 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt @@ -56,6 +56,7 @@ class JwtTokenProviderTest val subQueue = "testVerifyTokenForSubQueue_withExpiringToken" val expiryInMinutes = 60L val date = Date() + Thread.sleep(1000) // Forcing a sleep here to make sure the token is generated AFTER the current time val token = jwtTokenProvider.createTokenForSubQueue(subQueue, expiryInMinutes) Assertions.assertNotNull(token) Assertions.assertTrue(token.isPresent) From 97a8f07e9530922b84c80e4c69de6af7ce67797e Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Mon, 30 Oct 2023 23:10:03 +1100 Subject: [PATCH 16/58] Fix last filter test. --- .../filter/JwtAuthenticationFilterTest.kt | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt index 5524316..18a5110 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt @@ -1,12 +1,22 @@ package au.kilemon.messagequeue.filter import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.token.JwtTokenProvider +import au.kilemon.messagequeue.configuration.QueueConfiguration +import au.kilemon.messagequeue.logging.LoggingConfiguration +import au.kilemon.messagequeue.queue.MultiQueueTest import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Mockito import org.slf4j.MDC +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.context.annotation.Import +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.junit.jupiter.SpringExtension import java.util.* import javax.servlet.http.HttpServletRequest @@ -15,9 +25,16 @@ import javax.servlet.http.HttpServletRequest * * @author github.com/Kilemonn */ +@ExtendWith(SpringExtension::class) +@ContextConfiguration(classes = [JwtAuthenticationFilter::class]) +@Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) class JwtAuthenticationFilterTest { - private val jwtAuthenticationFilter = JwtAuthenticationFilter() + @Autowired + private lateinit var jwtAuthenticationFilter: JwtAuthenticationFilter + + @Autowired + private lateinit var jwtTokenProvider: JwtTokenProvider @BeforeEach fun setUp() @@ -74,12 +91,15 @@ class JwtAuthenticationFilterTest fun testGetSubQueueInTokenFromHeaders_headerExists() { val request = Mockito.mock(HttpServletRequest::class.java) - val authHeaderValue = "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}testGetSubQueueInTokenFromHeaders_headerExists" + val initialSubQueue = "testGetSubQueueInTokenFromHeaders_headerExists" + val token = jwtTokenProvider.createTokenForSubQueue(initialSubQueue) + Assertions.assertTrue(token.isPresent) + val authHeaderValue = "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}" Mockito.`when`(request.getHeader(JwtAuthenticationFilter.AUTHORIZATION_HEADER)).thenReturn(authHeaderValue) val subQueue = jwtAuthenticationFilter.getSubQueueInTokenFromHeaders(request) Assertions.assertTrue(subQueue.isPresent) - Assertions.assertEquals(authHeaderValue, subQueue.get()) + Assertions.assertEquals(initialSubQueue, subQueue.get()) } /** From 918679528168749e5b6ec7be5d78657df3b9492c Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Mon, 30 Oct 2023 23:15:40 +1100 Subject: [PATCH 17/58] Add docs for filter method. --- .../messagequeue/filter/JwtAuthenticationFilter.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index 183e4be..488fe71 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -51,7 +51,17 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger lateinit var jwtTokenProvider: JwtTokenProvider /** + * Perform appropriate validation of the [AUTHORIZATION_HEADER] if it is provided. + * Depending on the set [MultiQueueAuthenticationType] will determine how this filter handles a request. + * - [MultiQueueAuthenticationType.NONE] all requests will be allowed, whether they provide a valid token or not. + * - [MultiQueueAuthenticationType.HYBRID] all requests will be allowed and the provided token [SUB_QUEUE] parameter + * will be set if a token is provided. It's up to the lower level controllers to determine how they need to react + * in accordance with the active [MultiQueueAuthenticator]. + * - [MultiQueueAuthenticationType.RESTRICTED] a token is required and if not valid the request will be rejected + * here and a [MultiQueueAuthenticationException] will be thrown * + * @throws MultiQueueAuthenticationException if [MultiQueueAuthenticationType] is set to + * [MultiQueueAuthenticationType.RESTRICTED] and an invalid token OR NO token is provided */ override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) { From ae7e45bca1a9897735767205178653410a10f465 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Mon, 30 Oct 2023 23:45:49 +1100 Subject: [PATCH 18/58] Create auth controller and work on creation and deletion of sub-queue restrictions. --- .../rest/controller/AuthController.kt | 146 ++++++++++++++++++ .../rest/controller/MessageQueueController.kt | 4 +- .../rest/controller/RestParameters.kt | 2 + .../rest/response/AuthResponse.kt | 13 ++ 4 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt create mode 100644 src/main/kotlin/au/kilemon/messagequeue/rest/response/AuthResponse.kt diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt new file mode 100644 index 0000000..bf74369 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt @@ -0,0 +1,146 @@ +package au.kilemon.messagequeue.rest.controller + +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.token.JwtTokenProvider +import au.kilemon.messagequeue.filter.JwtAuthenticationFilter +import au.kilemon.messagequeue.logging.HasLogger +import au.kilemon.messagequeue.rest.response.AuthResponse +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import io.swagger.v3.oas.annotations.tags.Tag +import lombok.Generated +import org.slf4j.Logger +import org.slf4j.MDC +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* + +@Tag(name = AuthController.AUTH_TAG) +@RestController +@RequestMapping(AuthController.AUTH_PATH) +open class AuthController : HasLogger +{ + companion object + { + /** + * The [Tag] for the [AuthController] endpoints. + */ + const val AUTH_TAG: String = "Auth" + + /** + * The base path for the [AuthController]. + */ + const val AUTH_PATH = "/auth" + } + + override val LOG: Logger = this.initialiseLogger() + + @Autowired + @get:Generated + @set:Generated + lateinit var multiQueueAuthenticator: MultiQueueAuthenticator + + @Autowired + @get:Generated + @set:Generated + lateinit var jwtTokenProvider: JwtTokenProvider + + @Operation(summary = "Create restriction on sub-queue.", description = "Create restriction a specific sub-queue to require authentication for future interactions and retrieve a token used to interact with this sub-queue.") + @PostMapping("${AUTH_PATH}/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) + @ApiResponses( + ApiResponse(responseCode = "200", description = "Successfully registered the sub-queue identifier and returns an appropriate token for future access to the sub-queue."), + ApiResponse(responseCode = "204", description = "The MultiQueue is in a no-auth mode and tokens cannot be generated.", content = [Content()]), // Add empty Content() to remove duplicate responses in swagger docsApiResponse(responseCode = "204", description = "No queue messages match the provided UUID.", content = [Content()]) + ApiResponse(responseCode = "409", description = "A sub-queue with the provided identifier is already authorised.", content = [Content()]), + ApiResponse(responseCode = "500", description = "There was an error generating the auth token for the sub-queue.", content = [Content()]) + ) + fun restrictSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "") + @PathVariable(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, + @Parameter(`in` = ParameterIn.QUERY, required = false, description = "The generated token's expiry in minutes.") + @RequestParam(required = false, name = RestParameters.EXPIRY) expiry: Long?): ResponseEntity + { + if (multiQueueAuthenticator.isInNoneMode()) + { + LOG.trace("Requested token for sub-queue [{}] is not provided as queue is in mode [{}].", queueType, + multiQueueAuthenticator.getAuthenticationType()) + return ResponseEntity.noContent().build() + } + + if (multiQueueAuthenticator.isRestricted(queueType)) + { + return ResponseEntity.status(HttpStatus.CONFLICT).build() + } + else + { + multiQueueAuthenticator.addRestrictedEntry(queueType) + val token = jwtTokenProvider.createTokenForSubQueue(queueType, expiry) + return if (token.isEmpty) + { + LOG.error("Failed to generated token for sub-queue [{}].", queueType) + ResponseEntity.internalServerError().build() + } + else + { + LOG.info("Successfully generated token for sub-queue [{}] with expiry [{}] minutes.", queueType, expiry) + ResponseEntity.ok(AuthResponse(token.get(), queueType)) + } + } + } + + @Operation(summary = "Remove restriction from sub-queue.", description = "Remove restriction from sub-queue so it can be accessed without restriction.") + @DeleteMapping("${AUTH_PATH}/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) + @ApiResponses( + ApiResponse(responseCode = "200", description = "Successfully removed restriction for the sub-queue identifier."), + ApiResponse(responseCode = "204", description = "The MultiQueue is in a no-auth mode and sub-queue restrictions are disabled.", content = [Content()]), // Add empty Content() to remove duplicate responses in swagger docsApiResponse(responseCode = "204", description = "No queue messages match the provided UUID.", content = [Content()]) + ApiResponse(responseCode = "403", description = "Invalid token provided to remove restriction from requested sub-queue.", content = [Content()]), + ApiResponse(responseCode = "404", description = "The requested sub-queue is not currently restricted.", content = [Content()]), + ApiResponse(responseCode = "500", description = "There was an error releasing restriction from the sub-queue.", content = [Content()]) + ) + fun removeRestrictionFromSubQueue(queueType: String, clearQueue: Boolean = false): ResponseEntity + { + if (multiQueueAuthenticator.isInNoneMode()) + { + LOG.trace("Requested to release authentication for sub-queue [{}] but queue is in mode [{}].", queueType, + multiQueueAuthenticator.getAuthenticationType()) + return ResponseEntity.noContent().build() + } + + val authedToken = JwtAuthenticationFilter.getSubQueue() + if (authedToken == queueType) + { + if (multiQueueAuthenticator.isRestricted(queueType)) + { + return if (multiQueueAuthenticator.removeRestriction(queueType)) + { + LOG.info("Removed restriction from sub-queue [{}].", queueType) + ResponseEntity.ok().build() + } + else + { + LOG.error("Failed to remove restriction for sub-queue [{}].", queueType) + ResponseEntity.internalServerError().build() + } + } + else + { + LOG.info("Cannot remove restriction from a sub-queue [{}] that is not restricted.", queueType) + return ResponseEntity.notFound().build() + } + } + else + { + LOG.error("Failed to release authentication for sub-queue [{}] since provided token [{}] is not for the requested sub-queue.", queueType, authedToken) + return ResponseEntity.status(HttpStatus.FORBIDDEN).build() + } + } + + fun refreshToken() + { + + } +} diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt index c549cd9..486d235 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt @@ -157,7 +157,7 @@ open class MessageQueueController : HasLogger } catch(ex: HealthCheckFailureException) { - LOG.error("Health check failed.") + LOG.error("Health check failed.", ex) ResponseEntity.internalServerError().build() } } @@ -337,7 +337,7 @@ open class MessageQueueController : HasLogger @PutMapping("$ENDPOINT_ASSIGN/{${RestParameters.UUID}}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( ApiResponse(responseCode = "200", description = "Successfully assigned the message to the provided identifier. The message was not previously assigned."), - ApiResponse(responseCode = "202", description = "The message was already assigned to the provided identifier."), + ApiResponse(responseCode = "202", description = "The message was already assigned to the provided identifier.", content = [Content()]), ApiResponse(responseCode = "204", description = "No queue messages match the provided UUID.", content = [Content()]), ApiResponse(responseCode = "409", description = "The message is already assigned to another identifier.", content = [Content()]) ) diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt index 079c5ba..a92fce1 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt @@ -19,4 +19,6 @@ object RestParameters const val UUID = "uuid" const val INCLUDE_EMPTY = "includeEmpty" + + const val EXPIRY = "expiry" } diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/response/AuthResponse.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/response/AuthResponse.kt new file mode 100644 index 0000000..f06333c --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/response/AuthResponse.kt @@ -0,0 +1,13 @@ +package au.kilemon.messagequeue.rest.response + +import au.kilemon.messagequeue.filter.CorrelationIdFilter +import com.fasterxml.jackson.annotation.JsonPropertyOrder +import org.slf4j.MDC + +/** + * A response object which wraps the response jwt token. + * + * @author github.com/Kilemonn + */ +@JsonPropertyOrder("correlationId", "subQueue", "token") +class AuthResponse(val token: String, val subQueue: String, val correlationId: String? = MDC.get(CorrelationIdFilter.CORRELATION_ID)) From 6934690e976547fbed732968b79ff26120ac2766 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Thu, 2 Nov 2023 18:41:30 +1100 Subject: [PATCH 19/58] Fix failing test. Fix and updating settings test. --- .../settings/MessageQueueSettings.kt | 2 +- .../MessageQueueControllerMockTest.kt | 7 +++++++ .../rest/controller/SettingsControllerTest.kt | 21 +++---------------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt index 4c7e57a..1c17580 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt @@ -73,7 +73,7 @@ class MessageQueueSettings * Indicates what authentication mode the `MultiQueue` should be in. */ const val MULTI_QUEUE_AUTHENTICATION: String = "MULTI_QUEUE_AUTHENTICATION" - const val MULTI_QUEUE_AUTHENTICATION_DEFAULT: String = "" + const val MULTI_QUEUE_AUTHENTICATION_DEFAULT: String = "NONE" } /** diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt index 69c704f..e162580 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt @@ -3,6 +3,7 @@ package au.kilemon.messagequeue.rest.controller import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.authentication.authenticator.inmemory.InMemoryAuthenticator +import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.logging.LoggingConfiguration import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.MultiQueue @@ -60,6 +61,12 @@ class MessageQueueControllerMockTest { return MultiQueueAuthenticationType.NONE } + + @Bean + open fun getJwtTokenProvider(): JwtTokenProvider + { + return JwtTokenProvider() + } } @Autowired diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt index 9c70ce0..d88f3cb 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt @@ -1,8 +1,7 @@ package au.kilemon.messagequeue.rest.controller import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType -import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator -import au.kilemon.messagequeue.authentication.authenticator.inmemory.InMemoryAuthenticator +import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration import au.kilemon.messagequeue.settings.MessageQueueSettings import au.kilemon.messagequeue.settings.MultiQueueType @@ -10,15 +9,12 @@ import com.google.gson.Gson import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.Mockito import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest -import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.context.TestConfiguration import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import import org.springframework.http.MediaType -import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.junit.jupiter.SpringExtension import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.MvcResult @@ -32,7 +28,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers */ @ExtendWith(SpringExtension::class) @WebMvcTest(controllers = [SettingsController::class], properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=IN_MEMORY"]) -@Import(LoggingConfiguration::class) +@Import(*[QueueConfiguration::class, LoggingConfiguration::class]) class SettingsControllerTest { /** @@ -52,18 +48,6 @@ class SettingsControllerTest { return MessageQueueSettings() } - - @Bean - open fun getMultiQueueAuthenticator(): MultiQueueAuthenticator - { - return Mockito.spy(InMemoryAuthenticator::class.java) - } - - @Bean - open fun getMultiQueueAuthenticationType(): MultiQueueAuthenticationType - { - return MultiQueueAuthenticationType.NONE - } } @Autowired @@ -84,6 +68,7 @@ class SettingsControllerTest val settings = gson.fromJson(mvcResult.response.contentAsString, MessageQueueSettings::class.java) Assertions.assertEquals(MultiQueueType.IN_MEMORY.toString(), settings.multiQueueType) + Assertions.assertEquals(MultiQueueAuthenticationType.NONE.toString(), settings.multiQueueAuthentication) Assertions.assertTrue(settings.redisPrefix.isEmpty()) Assertions.assertEquals(MessageQueueSettings.REDIS_ENDPOINT_DEFAULT, settings.redisEndpoint) From f4a8e437de669fe05faed527d5e5ffe03bfdd68b Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Thu, 2 Nov 2023 19:20:50 +1100 Subject: [PATCH 20/58] Add AuthControllerTest and tests for restrictSubQueue(). --- .../rest/controller/AuthController.kt | 11 +- .../rest/controller/AuthControllerTest.kt | 184 ++++++++++++++++++ 2 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt index bf74369..7a45c3e 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt @@ -52,7 +52,7 @@ open class AuthController : HasLogger lateinit var jwtTokenProvider: JwtTokenProvider @Operation(summary = "Create restriction on sub-queue.", description = "Create restriction a specific sub-queue to require authentication for future interactions and retrieve a token used to interact with this sub-queue.") - @PostMapping("${AUTH_PATH}/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) + @PostMapping("/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( ApiResponse(responseCode = "200", description = "Successfully registered the sub-queue identifier and returns an appropriate token for future access to the sub-queue."), ApiResponse(responseCode = "204", description = "The MultiQueue is in a no-auth mode and tokens cannot be generated.", content = [Content()]), // Add empty Content() to remove duplicate responses in swagger docsApiResponse(responseCode = "204", description = "No queue messages match the provided UUID.", content = [Content()]) @@ -77,9 +77,9 @@ open class AuthController : HasLogger } else { - multiQueueAuthenticator.addRestrictedEntry(queueType) + val wasAdded = multiQueueAuthenticator.addRestrictedEntry(queueType) val token = jwtTokenProvider.createTokenForSubQueue(queueType, expiry) - return if (token.isEmpty) + return if (token.isEmpty || !wasAdded) { LOG.error("Failed to generated token for sub-queue [{}].", queueType) ResponseEntity.internalServerError().build() @@ -93,7 +93,7 @@ open class AuthController : HasLogger } @Operation(summary = "Remove restriction from sub-queue.", description = "Remove restriction from sub-queue so it can be accessed without restriction.") - @DeleteMapping("${AUTH_PATH}/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) + @DeleteMapping("/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( ApiResponse(responseCode = "200", description = "Successfully removed restriction for the sub-queue identifier."), ApiResponse(responseCode = "204", description = "The MultiQueue is in a no-auth mode and sub-queue restrictions are disabled.", content = [Content()]), // Add empty Content() to remove duplicate responses in swagger docsApiResponse(responseCode = "204", description = "No queue messages match the provided UUID.", content = [Content()]) @@ -101,7 +101,8 @@ open class AuthController : HasLogger ApiResponse(responseCode = "404", description = "The requested sub-queue is not currently restricted.", content = [Content()]), ApiResponse(responseCode = "500", description = "There was an error releasing restriction from the sub-queue.", content = [Content()]) ) - fun removeRestrictionFromSubQueue(queueType: String, clearQueue: Boolean = false): ResponseEntity + fun removeRestrictionFromSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "") + @PathVariable(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, clearQueue: Boolean = false): ResponseEntity { if (multiQueueAuthenticator.isInNoneMode()) { diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt new file mode 100644 index 0000000..883112b --- /dev/null +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -0,0 +1,184 @@ +package au.kilemon.messagequeue.rest.controller + +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.token.JwtTokenProvider +import au.kilemon.messagequeue.configuration.QueueConfiguration +import au.kilemon.messagequeue.logging.LoggingConfiguration +import au.kilemon.messagequeue.rest.response.AuthResponse +import au.kilemon.messagequeue.settings.MessageQueueSettings +import com.google.gson.Gson +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mockito +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.boot.test.mock.mockito.SpyBean +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Import +import org.springframework.http.MediaType +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.MvcResult +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import java.util.* + +/** + * A test class for the [AuthController]. + * Providing tests of the context and endpoint validation/handling itself. + * + * @author github.com/Kilemonn + */ +@ExtendWith(SpringExtension::class) +@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD) +@WebMvcTest(controllers = [AuthController::class], properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=IN_MEMORY"]) +@Import(*[QueueConfiguration::class, LoggingConfiguration::class]) +class AuthControllerTest +{ + /** + * A [TestConfiguration] for the outer class. + * + * @author github.com/Kilemonn + */ + @TestConfiguration + open class TestConfig + { + @Bean + open fun getSettings(): MessageQueueSettings + { + return MessageQueueSettings() + } + } + + // Setting as a Spy to override it to replicate different scenarios + @SpyBean + private lateinit var multiQueueAuthenticator: MultiQueueAuthenticator + + // Setting as a Spy to override it to replicate different scenarios + @SpyBean + private lateinit var jwtTokenProvider: JwtTokenProvider + + @Autowired + private lateinit var mockMvc: MockMvc + + private val gson: Gson = Gson() + + /** + * Ensure [AuthController.restrictSubQueue] returns [org.springframework.http.HttpStatus.NO_CONTENT] when the + * [MultiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. + */ + @Test + fun testRestrictSubQueue_inNoneMode() + { + val queueType = "testRestrictSubQueue_inNoneMode" + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + mockMvc.perform( + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNoContent) + } + + /** + * Ensure [AuthController.restrictSubQueue] returns [org.springframework.http.HttpStatus.CONFLICT] when the + * requested queue type requested is already restricted. + */ + @Test + fun testRestrictSubQueue_alreadyRestricted() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRestrictSubQueue_alreadyRestricted" + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(queueType)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(queueType)) + + mockMvc.perform( + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isConflict) + } + + /** + * Ensure [AuthController.restrictSubQueue] returns [org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR] + * when the requested queue type fails to be restricted. + */ + @Test + fun testRestrictSubQueue_wasNotAdded() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRestrictSubQueue_wasNotAdded" + Mockito.doReturn(false).`when`(multiQueueAuthenticator).addRestrictedEntry(queueType) + + mockMvc.perform( + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isInternalServerError) + } + + /** + * Ensure [AuthController.restrictSubQueue] returns [org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR] + * when the token fails to generate. + */ + @Test + fun testRestrictSubQueue_tokenGenerationFailure() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRestrictSubQueue_tokenGenerationFailure" + Mockito.doReturn(Optional.empty()).`when`(jwtTokenProvider).createTokenForSubQueue(queueType) + + mockMvc.perform( + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isInternalServerError) + } + + /** + * Ensure [AuthController.restrictSubQueue] returns [org.springframework.http.HttpStatus.OK] and a valid + * [AuthResponse] when the requested queue type is restricted successfully. + */ + @Test + fun testRestrictSubQueue_tokenGenerated() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRestrictSubQueue_tokenGenerated" + + val mvcResult: MvcResult = mockMvc.perform( + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val authResponse = gson.fromJson(mvcResult.response.contentAsString, AuthResponse::class.java) + Assertions.assertNotNull(authResponse.token) + Assertions.assertNotNull(authResponse.correlationId) + Assertions.assertEquals(queueType, authResponse.subQueue) + } + + /** + * Ensure [AuthController.removeRestrictionFromSubQueue] returns [org.springframework.http.HttpStatus.NO_CONTENT] + * when the [MultiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. + */ + @Test + fun testRemoveRestrictionFromSubQueue_inNoneMode() + { + val queueType = "testRemoveRestrictionFromSubQueue_inNoneMode" + + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + mockMvc.perform( + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNoContent) + } + +} From 41e878749a2c39c592ecafd3dcd371b0beb9aafa Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Thu, 2 Nov 2023 19:26:47 +1100 Subject: [PATCH 21/58] Add urlRequiresAuthentication() check to the JwtAuthenticationFilter. Add tests. --- .../filter/JwtAuthenticationFilter.kt | 22 ++++++++++++++ .../filter/JwtAuthenticationFilterTest.kt | 29 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index 488fe71..364b87a 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -5,6 +5,7 @@ import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException import au.kilemon.messagequeue.authentication.token.JwtTokenProvider +import au.kilemon.messagequeue.rest.controller.MessageQueueController import org.slf4j.Logger import org.slf4j.MDC import org.springframework.beans.factory.annotation.Autowired @@ -70,6 +71,13 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger val subQueue = getSubQueueInTokenFromHeaders(request) setSubQueue(subQueue) + if (!urlRequiresAuthentication(request)) + { + LOG.trace("Allowed access to path [{}] as it does not require authentication.", request.requestURI) + filterChain.doFilter(request, response) + return + } + if (authenticator.isInNoneMode()) { LOG.trace("Allowed access as authentication is set to [{}].", MultiQueueAuthenticationType.NONE) @@ -100,6 +108,20 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger } } + /** + * Verify the requested URI requires authentication or not. + * + * @param request the incoming request to verify the path of + * @return `true` if the provided path starts with an auth required prefix, otherwise `false` + */ + fun urlRequiresAuthentication(request: HttpServletRequest): Boolean + { + val requestString = request.requestURI + val authRequiredUrlPrefixes = listOf(MessageQueueController.MESSAGE_QUEUE_BASE_PATH) + + return authRequiredUrlPrefixes.any { authRequiredUrlPrefix -> requestString.startsWith(authRequiredUrlPrefix) } + } + /** * Check if the token is set and it is restricted sub-queue identifier. * diff --git a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt index 18a5110..8812028 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt @@ -5,6 +5,7 @@ import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration import au.kilemon.messagequeue.queue.MultiQueueTest +import au.kilemon.messagequeue.rest.controller.MessageQueueController import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach @@ -185,4 +186,32 @@ class JwtAuthenticationFilterTest Assertions.assertFalse(jwtAuthenticationFilter.tokenIsPresentAndQueueIsRestricted(subQueue, authenticator)) } + + /** + * Ensure [JwtAuthenticationFilter.urlRequiresAuthentication] returns `false` when the provided URI does not + * start with an authorised path prefix. + */ + @Test + fun testUrlRequiresAuthentication_noAuthRequiredURL() + { + val request = Mockito.mock(HttpServletRequest::class.java) + val uriPath = "/another/test/endpoint/${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}" + Mockito.`when`(request.requestURI).thenReturn(uriPath) + + Assertions.assertFalse(jwtAuthenticationFilter.urlRequiresAuthentication(request)) + } + + /** + * Ensure [JwtAuthenticationFilter.urlRequiresAuthentication] returns `true` when the provided URI does + * start with an authorised path prefix. + */ + @Test + fun testUrlRequiresAuthentication_authRequiredURL() + { + val request = Mockito.mock(HttpServletRequest::class.java) + val uriPath = "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}/test/endpoint" + Mockito.`when`(request.requestURI).thenReturn(uriPath) + + Assertions.assertTrue(jwtAuthenticationFilter.urlRequiresAuthentication(request)) + } } From be8ecf66ec0f4dcb2a46f43deff1098870fd8684 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Thu, 2 Nov 2023 19:46:40 +1100 Subject: [PATCH 22/58] Add missing coverage for JwtAuthenticationFilterTest. --- .../filter/JwtAuthenticationFilterTest.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt index 8812028..862f4a8 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt @@ -1,6 +1,7 @@ package au.kilemon.messagequeue.filter import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration @@ -214,4 +215,33 @@ class JwtAuthenticationFilterTest Assertions.assertTrue(jwtAuthenticationFilter.urlRequiresAuthentication(request)) } + + /** + * Ensure that [JwtAuthenticationFilter.isValidJwtToken] returns a valid [Optional] with the correct sub-queue + * value when a valid token is provided. + */ + @Test + fun testIsValidJwtToken_validToken() + { + val subQueue = "testIsValidJwtToken_validToken" + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) + Assertions.assertTrue(token.isPresent) + + val embeddedSubQueue = jwtAuthenticationFilter.isValidJwtToken(token.get()) + Assertions.assertTrue(embeddedSubQueue.isPresent) + Assertions.assertEquals(subQueue, embeddedSubQueue.get()) + } + + /** + * Ensure that [JwtAuthenticationFilter.isValidJwtToken] throws a [MultiQueueAuthenticationException] when the + * provided token is invalid. + */ + @Test + fun testIsValidJwtToken_throws() + { + val token = "testIsValidJwtToken_throws" + Assertions.assertThrows(MultiQueueAuthenticationException::class.java) { + jwtAuthenticationFilter.isValidJwtToken(token) + } + } } From e2694a35590330f5f90ca9aa092d88690dbbb7f4 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Thu, 2 Nov 2023 19:52:39 +1100 Subject: [PATCH 23/58] Add generated annotations. --- src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt index 915acec..9d5649e 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt @@ -6,6 +6,7 @@ import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.exception.HealthCheckFailureException import au.kilemon.messagequeue.queue.exception.MessageUpdateException +import lombok.Generated import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired import java.util.* @@ -32,6 +33,8 @@ abstract class MultiQueue: Queue, HasLogger abstract override val LOG: Logger @Autowired + @get:Generated + @set:Generated protected lateinit var multiQueueAuthenticator: MultiQueueAuthenticator /** From b7b34b061c7e5da20f49605d527862b171e13880 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 3 Nov 2023 19:34:27 +1100 Subject: [PATCH 24/58] Add changes to URL auth check method. Add remaining tests for auth controller. --- .../filter/JwtAuthenticationFilter.kt | 32 +++- .../rest/controller/AuthController.kt | 26 ++- .../rest/controller/RestParameters.kt | 2 + .../filter/JwtAuthenticationFilterTest.kt | 25 ++- .../rest/controller/AuthControllerTest.kt | 157 ++++++++++++++++++ 5 files changed, 225 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index 364b87a..f0cb001 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -5,13 +5,18 @@ import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException import au.kilemon.messagequeue.authentication.token.JwtTokenProvider +import au.kilemon.messagequeue.rest.controller.AuthController import au.kilemon.messagequeue.rest.controller.MessageQueueController +import au.kilemon.messagequeue.rest.response.RestResponseExceptionHandler import org.slf4j.Logger import org.slf4j.MDC import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Lazy import org.springframework.core.annotation.Order +import org.springframework.http.HttpMethod import org.springframework.stereotype.Component import org.springframework.web.filter.OncePerRequestFilter +import org.springframework.web.servlet.HandlerExceptionResolver import java.util.* import javax.servlet.FilterChain import javax.servlet.http.HttpServletRequest @@ -46,10 +51,14 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger override val LOG: Logger = this.initialiseLogger() @Autowired - lateinit var authenticator: MultiQueueAuthenticator + private lateinit var authenticator: MultiQueueAuthenticator @Autowired - lateinit var jwtTokenProvider: JwtTokenProvider + private lateinit var jwtTokenProvider: JwtTokenProvider + + @Autowired + @Lazy + private lateinit var handlerExceptionResolver: HandlerExceptionResolver /** * Perform appropriate validation of the [AUTHORIZATION_HEADER] if it is provided. @@ -97,8 +106,10 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger } else { - LOG.error("Failed to manipulate sub queue [{}] with provided token as the authentication level is set to [{}].", subQueue.get(), authenticator.getAuthenticationType()) - throw MultiQueueAuthenticationException() + val token = if (subQueue.isPresent) subQueue.get() else "null" + LOG.error("Failed to manipulate sub queue [{}] with provided token as the authentication level is set to [{}].", token, authenticator.getAuthenticationType()) + handlerExceptionResolver.resolveException(request, response, null, MultiQueueAuthenticationException()) + return } } } @@ -117,9 +128,16 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger fun urlRequiresAuthentication(request: HttpServletRequest): Boolean { val requestString = request.requestURI - val authRequiredUrlPrefixes = listOf(MessageQueueController.MESSAGE_QUEUE_BASE_PATH) - - return authRequiredUrlPrefixes.any { authRequiredUrlPrefix -> requestString.startsWith(authRequiredUrlPrefix) } + val authRequiredUrlPrefixes = listOf( + Pair(HttpMethod.GET, MessageQueueController.MESSAGE_QUEUE_BASE_PATH), + Pair(HttpMethod.POST, MessageQueueController.MESSAGE_QUEUE_BASE_PATH), + Pair(HttpMethod.PUT, MessageQueueController.MESSAGE_QUEUE_BASE_PATH), + Pair(HttpMethod.DELETE, MessageQueueController.MESSAGE_QUEUE_BASE_PATH), + Pair(HttpMethod.DELETE, AuthController.AUTH_PATH) + ) + + return authRequiredUrlPrefixes.filter { authRequiredUrlPrefix -> authRequiredUrlPrefix.first.toString() == request.method } + .any { authRequiredUrlPrefix -> requestString.startsWith(authRequiredUrlPrefix.second) } } /** diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt index 7a45c3e..417fd26 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt @@ -4,6 +4,7 @@ import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthentica import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.filter.JwtAuthenticationFilter import au.kilemon.messagequeue.logging.HasLogger +import au.kilemon.messagequeue.queue.MultiQueue import au.kilemon.messagequeue.rest.response.AuthResponse import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter @@ -14,7 +15,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses import io.swagger.v3.oas.annotations.tags.Tag import lombok.Generated import org.slf4j.Logger -import org.slf4j.MDC import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.HttpStatus import org.springframework.http.MediaType @@ -46,6 +46,11 @@ open class AuthController : HasLogger @set:Generated lateinit var multiQueueAuthenticator: MultiQueueAuthenticator + @Autowired + @get:Generated + @set:Generated + lateinit var multiQueue: MultiQueue + @Autowired @get:Generated @set:Generated @@ -101,8 +106,8 @@ open class AuthController : HasLogger ApiResponse(responseCode = "404", description = "The requested sub-queue is not currently restricted.", content = [Content()]), ApiResponse(responseCode = "500", description = "There was an error releasing restriction from the sub-queue.", content = [Content()]) ) - fun removeRestrictionFromSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "") - @PathVariable(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, clearQueue: Boolean = false): ResponseEntity + fun removeRestrictionFromSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "The sub-queue identifier to remove restriction for.") @PathVariable(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, + @Parameter(`in` = ParameterIn.QUERY, required = false, description = "If restriction is removed successfully indicate whether the sub-queue should be cleared now that it is accessible without a token.") @RequestParam(required = false, name = RestParameters.CLEAR_QUEUE) clearQueue: Boolean?): ResponseEntity { if (multiQueueAuthenticator.isInNoneMode()) { @@ -118,7 +123,15 @@ open class AuthController : HasLogger { return if (multiQueueAuthenticator.removeRestriction(queueType)) { - LOG.info("Removed restriction from sub-queue [{}].", queueType) + if (clearQueue == true) + { + LOG.info("Restriction removed and clearing sub-queue [{}].", queueType) + multiQueue.clearForType(queueType) + } + else + { + LOG.info("Removed restriction from sub-queue [{}] without clearing stored messages.", queueType) + } ResponseEntity.ok().build() } else @@ -139,9 +152,4 @@ open class AuthController : HasLogger return ResponseEntity.status(HttpStatus.FORBIDDEN).build() } } - - fun refreshToken() - { - - } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt index a92fce1..033209e 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt @@ -21,4 +21,6 @@ object RestParameters const val INCLUDE_EMPTY = "includeEmpty" const val EXPIRY = "expiry" + + const val CLEAR_QUEUE = "clearQueue" } diff --git a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt index 862f4a8..9086306 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt @@ -15,10 +15,14 @@ import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Mockito import org.slf4j.MDC import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import +import org.springframework.http.HttpMethod import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.web.servlet.HandlerExceptionResolver +import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite import java.util.* import javax.servlet.http.HttpServletRequest @@ -32,12 +36,29 @@ import javax.servlet.http.HttpServletRequest @Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) class JwtAuthenticationFilterTest { + /** + * A [TestConfiguration] for the outer class. + * + * @author github.com/Kilemonn + */ + @TestConfiguration + open class TestConfig + { + @Bean + open fun getHandlerExceptionResolver(): HandlerExceptionResolver + { + return HandlerExceptionResolverComposite() + } + } + @Autowired private lateinit var jwtAuthenticationFilter: JwtAuthenticationFilter @Autowired private lateinit var jwtTokenProvider: JwtTokenProvider + + @BeforeEach fun setUp() { @@ -198,6 +219,7 @@ class JwtAuthenticationFilterTest val request = Mockito.mock(HttpServletRequest::class.java) val uriPath = "/another/test/endpoint/${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}" Mockito.`when`(request.requestURI).thenReturn(uriPath) + Mockito.`when`(request.method).thenReturn(HttpMethod.POST.toString()) Assertions.assertFalse(jwtAuthenticationFilter.urlRequiresAuthentication(request)) } @@ -212,6 +234,7 @@ class JwtAuthenticationFilterTest val request = Mockito.mock(HttpServletRequest::class.java) val uriPath = "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}/test/endpoint" Mockito.`when`(request.requestURI).thenReturn(uriPath) + Mockito.`when`(request.method).thenReturn(HttpMethod.GET.toString()) Assertions.assertTrue(jwtAuthenticationFilter.urlRequiresAuthentication(request)) } diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index 883112b..a114b04 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -4,7 +4,10 @@ import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.configuration.QueueConfiguration +import au.kilemon.messagequeue.filter.JwtAuthenticationFilter import au.kilemon.messagequeue.logging.LoggingConfiguration +import au.kilemon.messagequeue.message.QueueMessage +import au.kilemon.messagequeue.queue.MultiQueue import au.kilemon.messagequeue.rest.response.AuthResponse import au.kilemon.messagequeue.settings.MessageQueueSettings import com.google.gson.Gson @@ -63,11 +66,21 @@ class AuthControllerTest @SpyBean private lateinit var jwtTokenProvider: JwtTokenProvider + @Autowired + private lateinit var multiQueue: MultiQueue + @Autowired private lateinit var mockMvc: MockMvc private val gson: Gson = Gson() + @BeforeEach + fun setUp() + { + multiQueueAuthenticator.clearRestrictedSubQueues() + multiQueue.clear() + } + /** * Ensure [AuthController.restrictSubQueue] returns [org.springframework.http.HttpStatus.NO_CONTENT] when the * [MultiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. @@ -181,4 +194,148 @@ class AuthControllerTest .andExpect(MockMvcResultMatchers.status().isNoContent) } + /** + * Ensure [AuthController.removeRestrictionFromSubQueue] returns [org.springframework.http.HttpStatus.FORBIDDEN] + * when the provided token does not + */ + @Test + fun testRemoveRestrictionFromSubQueue_invalidToken() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRemoveRestrictionFromSubQueue_invalidToken" + val invalidQueueType = "invalidQueueType" + val token = jwtTokenProvider.createTokenForSubQueue(queueType) + Assertions.assertTrue(token.isPresent) + + mockMvc.perform( + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${invalidQueueType}") + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isForbidden) + } + + @Test + fun testRemoveRestrictionFromSubQueue_withoutAuthToken() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRemoveRestrictionFromSubQueue_withoutAuthToken" + + mockMvc.perform( + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized) + } + + @Test + fun testRemoveRestrictionFromSubQueue_validTokenButNotRestricted() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRemoveRestrictionFromSubQueue_validToken" + val token = jwtTokenProvider.createTokenForSubQueue(queueType) + Assertions.assertTrue(token.isPresent) + + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(queueType)) + + mockMvc.perform( + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound) + } + + @Test + fun testRemoveRestrictionFromSubQueue_failedToRemoveRestriction() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRemoveRestrictionFromSubQueue_failedToRemoveRestriction" + val token = jwtTokenProvider.createTokenForSubQueue(queueType) + Assertions.assertTrue(token.isPresent) + + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(queueType)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(queueType)) + + Mockito.doReturn(false).`when`(multiQueueAuthenticator).removeRestriction(queueType) + + mockMvc.perform( + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isInternalServerError) + } + + @Test + fun testRemoveRestrictionFromSubQueue_removeButDontClearQueue() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRemoveRestrictionFromSubQueue_removeButDontClearQueue" + val token = jwtTokenProvider.createTokenForSubQueue(queueType) + Assertions.assertTrue(token.isPresent) + + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(queueType)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(queueType)) + + multiQueue.clear() + try + { + Assertions.assertTrue(multiQueue.add(QueueMessage("a payload", queueType))) + Assertions.assertEquals(1, multiQueue.size) + + mockMvc.perform( + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + + Assertions.assertEquals(1, multiQueue.size) + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(queueType)) + } + finally + { + multiQueue.clear() + } + } + + @Test + fun testRemoveRestrictionFromSubQueue_removeAndClearQueue() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRemoveRestrictionFromSubQueue_removeAndClearQueue" + val token = jwtTokenProvider.createTokenForSubQueue(queueType) + Assertions.assertTrue(token.isPresent) + + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(queueType)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(queueType)) + + multiQueue.clear() + try + { + Assertions.assertTrue(multiQueue.add(QueueMessage("a payload", queueType))) + Assertions.assertEquals(1, multiQueue.size) + + mockMvc.perform( + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}?${RestParameters.CLEAR_QUEUE}=true") + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + + Assertions.assertEquals(0, multiQueue.size) + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(queueType)) + } + finally + { + multiQueue.clear() + } + } } From 0911c0f6d833ebfba097796e224f49c2bf5b475f Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 3 Nov 2023 22:08:16 +1100 Subject: [PATCH 25/58] Add calls to the authenticator from the multiqueue. Add option to not throw. --- .../authenticator/MultiQueueAuthenticator.kt | 25 ++++++++--- .../kilemon/messagequeue/queue/MultiQueue.kt | 4 +- .../rest/controller/MessageQueueController.kt | 45 ++++++++++++++----- .../rest/controller/SettingsController.kt | 5 +-- .../MultiQueueAuthenticatorTest.kt | 10 +++-- 5 files changed, 63 insertions(+), 26 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt index d5de4d6..6c4bde0 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt @@ -44,20 +44,27 @@ abstract class MultiQueueAuthenticator: HasLogger * [JwtAuthenticationFilter.getSubQueue] to determine if the user is able to interact with the requested sub queue. * * @param subQueue the sub-queue identifier that is being requested access to + * @param throwException `true` to throw an exception if the [subQueue] cannot be accessed, otherwise the return + * value can be used + * @return returns `true` if the [subQueue] can be accessed, otherwise `false` * @throws MultiQueueAuthorisationException if there is a mis-matching token OR no token provided. Or the sub-queue * is not in restricted mode when it should be */ @Throws(MultiQueueAuthorisationException::class) - fun canAccessSubQueue(subQueue: String) + fun canAccessSubQueue(subQueue: String, throwException: Boolean = true): Boolean { if (getReservedSubQueues().contains(subQueue)) { - throw MultiQueueAuthorisationException(subQueue, getAuthenticationType()) + if (throwException) + { + throw MultiQueueAuthorisationException(subQueue, getAuthenticationType()) + } + return false } if (isInNoneMode()) { - return + return true } else if (isInHybridMode()) { @@ -65,24 +72,28 @@ abstract class MultiQueueAuthenticator: HasLogger { if (JwtAuthenticationFilter.getSubQueue() == subQueue) { - return + return true } } else { // If we are in hybrid mode and the sub queue is not restricted we should let it pass - return + return true } } else if (isInRestrictedMode()) { if (isRestricted(subQueue) && JwtAuthenticationFilter.getSubQueue() == subQueue) { - return + return true } } - throw MultiQueueAuthorisationException(subQueue, getAuthenticationType()) + if (throwException) + { + throw MultiQueueAuthorisationException(subQueue, getAuthenticationType()) + } + return false } /** diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt index 9d5649e..a26da4d 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt @@ -159,7 +159,7 @@ abstract class MultiQueue: Queue, HasLogger fun getOwnersAndKeysMap(queueType: String?): Map> { val responseMap = HashMap>() - if (queueType != null) + if (queueType != null && multiQueueAuthenticator.canAccessSubQueue(queueType, false)) { LOG.debug("Getting owners map for sub-queue with identifier [{}].", queueType) getOwnersAndKeysMapForType(queueType, responseMap) @@ -168,7 +168,7 @@ abstract class MultiQueue: Queue, HasLogger { LOG.debug("Getting owners map for all sub-queues.") val keys = keys(false) - keys.forEach { key -> + keys.filter { key -> multiQueueAuthenticator.canAccessSubQueue(key, false) }.forEach { key -> getOwnersAndKeysMapForType(key, responseMap) } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt index 486d235..5d9dc50 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt @@ -1,9 +1,10 @@ package au.kilemon.messagequeue.rest.controller -import au.kilemon.messagequeue.queue.exception.DuplicateMessageException +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.MultiQueue +import au.kilemon.messagequeue.queue.exception.DuplicateMessageException import au.kilemon.messagequeue.queue.exception.HealthCheckFailureException import au.kilemon.messagequeue.rest.response.MessageResponse import io.swagger.v3.oas.annotations.Hidden @@ -14,7 +15,6 @@ import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses import io.swagger.v3.oas.annotations.tags.Tag -import lombok.Generated import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.HttpStatus @@ -25,7 +25,6 @@ import org.springframework.web.server.ResponseStatusException import java.util.* import java.util.stream.Collectors import javax.validation.Valid -import kotlin.collections.HashMap /** * The REST controller for the [MultiQueue]. It exposes endpoints to access and manipulate the queue and the messages inside it. @@ -104,9 +103,10 @@ open class MessageQueueController : HasLogger } @Autowired - @get:Generated - @set:Generated - lateinit var messageQueue: MultiQueue + private lateinit var messageQueue: MultiQueue + + @Autowired + private lateinit var authenticator: MultiQueueAuthenticator /** * Retrieve information about the whole [MultiQueue]. Specifically data related information. @@ -132,6 +132,8 @@ open class MessageQueueController : HasLogger fun getQueueTypeInfo(@Parameter(`in` = ParameterIn.PATH, required = true, description = "The queueType to retrieve information about.") @PathVariable(name = RestParameters.QUEUE_TYPE) queueType: String): ResponseEntity { + authenticator.canAccessSubQueue(queueType) + val queueForType = messageQueue.getQueueForType(queueType) LOG.debug("Returning size [{}] for queue with type [{}].", queueForType.size, queueType) return ResponseEntity.ok(queueForType.size.toString()) @@ -182,6 +184,7 @@ open class MessageQueueController : HasLogger if (entry.isPresent) { val foundEntry = entry.get() + authenticator.canAccessSubQueue(foundEntry.type) LOG.debug("Found message with UUID [{}] in queue with type [{}].", foundEntry.uuid, foundEntry.type) return ResponseEntity.ok(MessageResponse(foundEntry)) } @@ -215,6 +218,9 @@ open class MessageQueueController : HasLogger { queueMessage.assignedTo = null } + + authenticator.canAccessSubQueue(queueMessage.type) + val wasAdded = messageQueue.add(queueMessage) if (wasAdded) { @@ -259,6 +265,7 @@ open class MessageQueueController : HasLogger { if (queueType != null) { + authenticator.canAccessSubQueue(queueType) messageQueue.clearForType(queueType) } else @@ -285,6 +292,7 @@ open class MessageQueueController : HasLogger if ( !queueType.isNullOrBlank()) { LOG.debug("Retrieving all entry details from queue with type [{}].", queueType) + authenticator.canAccessSubQueue(queueType) val queueForType: Queue = messageQueue.getQueueForType(queueType) val queueDetails = queueForType.stream().map { message -> message.removePayload(detailed) }.collect(Collectors.toList()) responseMap[queueType] = queueDetails @@ -294,10 +302,13 @@ open class MessageQueueController : HasLogger LOG.debug("Retrieving all entry details from all queue types.") for (key: String in messageQueue.keys(false)) { - // No need to empty check since we passed `false` to `keys()` above - val queueForType: Queue = messageQueue.getQueueForType(key) - val queueDetails = queueForType.stream().map { message -> message.removePayload(detailed) }.collect(Collectors.toList()) - responseMap[key] = queueDetails + if (authenticator.canAccessSubQueue(key, false)) + { + // No need to empty check since we passed `false` to `keys()` above + val queueForType: Queue = messageQueue.getQueueForType(key) + val queueDetails = queueForType.stream().map { message -> message.removePayload(detailed) }.collect(Collectors.toList()) + responseMap[key] = queueDetails + } } } return ResponseEntity.ok(responseMap) @@ -316,6 +327,8 @@ open class MessageQueueController : HasLogger fun getOwned(@Parameter(`in` = ParameterIn.QUERY, required = true, description = "The identifier that must match the message's `assigned` property in order to be returned.") @RequestParam(required = true, name = RestParameters.ASSIGNED_TO) assignedTo: String, @Parameter(`in` = ParameterIn.QUERY, required = true, description = "The sub queue to search for the assigned messages.") @RequestParam(required = true, name = RestParameters.QUEUE_TYPE) queueType: String): ResponseEntity> { + authenticator.canAccessSubQueue(queueType) + val assignedMessages: Queue = messageQueue.getAssignedMessagesForType(queueType, assignedTo) val ownedMessages = assignedMessages.stream().map { message -> MessageResponse(message) }.collect(Collectors.toList()) LOG.debug("Found [{}] owned entries within queue with type [{}] for user with identifier [{}].", ownedMessages.size, queueType, assignedTo) @@ -348,6 +361,8 @@ open class MessageQueueController : HasLogger if (message.isPresent) { val messageToAssign = message.get() + authenticator.canAccessSubQueue(messageToAssign.type + ) if (!messageToAssign.assignedTo.isNullOrBlank()) { if (messageToAssign.assignedTo == assignedTo) @@ -390,6 +405,8 @@ open class MessageQueueController : HasLogger fun getNext(@Parameter(`in` = ParameterIn.QUERY, required = true, description = "The sub queue identifier to query the next available message from.") @RequestParam(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, @Parameter(`in` = ParameterIn.QUERY, required = true, description = "The identifier to assign the next available message to if one exists.") @RequestParam(required = true, name = RestParameters.ASSIGNED_TO) assignedTo: String): ResponseEntity { + authenticator.canAccessSubQueue(queueType) + val queueForType: Queue = messageQueue.getUnassignedMessagesForType(queueType) return if (queueForType.iterator().hasNext()) { @@ -432,6 +449,8 @@ open class MessageQueueController : HasLogger if (message.isPresent) { val messageToRelease = message.get() + authenticator.canAccessSubQueue(messageToRelease.type) + if (messageToRelease.assignedTo == null) { // The message is already in this state, returning 202 to tell the client that it is accepted but no action was done @@ -482,6 +501,7 @@ open class MessageQueueController : HasLogger if (message.isPresent) { val messageToRemove = message.get() + authenticator.canAccessSubQueue(messageToRemove.type) if ( !assignedTo.isNullOrBlank() && messageToRemove.assignedTo != assignedTo) { val errorMessage = "Unable to remove message with UUID [$uuid] in Queue [${messageToRemove.type}] because the provided assignee identifier: [$assignedTo] does not match the message's assignee identifier: [${messageToRemove.assignedTo}]" @@ -514,6 +534,11 @@ open class MessageQueueController : HasLogger @ApiResponse(responseCode = "200", description = "Successfully returns the map of owner identifiers mapped to all the sub-queues that they have one or more assigned messages in.") fun getOwners(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "The sub queue to search for the owner identifiers.") @RequestParam(required = false, name = RestParameters.QUEUE_TYPE) queueType: String?): ResponseEntity>> { + if (queueType != null) + { + authenticator.canAccessSubQueue(queueType) + } + return ResponseEntity.ok(messageQueue.getOwnersAndKeysMap(queueType)) } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/SettingsController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/SettingsController.kt index 785d76d..55a946a 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/SettingsController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/SettingsController.kt @@ -4,7 +4,6 @@ import au.kilemon.messagequeue.settings.MessageQueueSettings import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.tags.Tag -import lombok.Generated import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.http.ResponseEntity @@ -36,9 +35,7 @@ open class SettingsController } @Autowired - @get:Generated - @set:Generated - lateinit var queueSettings: MessageQueueSettings + private lateinit var queueSettings: MessageQueueSettings /** * Get and return the [MessageQueueSettings] singleton for the user to view configuration. diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt index 6b206a1..193e0a3 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt @@ -136,7 +136,7 @@ abstract class MultiQueueAuthenticatorTest { Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testCanAccessSubQueue_WithNoneMode" - multiQueueAuthenticator.canAccessSubQueue(subQueue) + Assertions.assertTrue(multiQueueAuthenticator.canAccessSubQueue(subQueue)) } /** @@ -152,7 +152,7 @@ abstract class MultiQueueAuthenticatorTest val subQueue = "testCanAccessSubQueue_WithHybridMode_isNotRestricted" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) - multiQueueAuthenticator.canAccessSubQueue(subQueue) + Assertions.assertTrue(multiQueueAuthenticator.canAccessSubQueue(subQueue)) } /** @@ -173,7 +173,7 @@ abstract class MultiQueueAuthenticatorTest try { MDC.put(JwtAuthenticationFilter.SUB_QUEUE, subQueue) - multiQueueAuthenticator.canAccessSubQueue(subQueue) + Assertions.assertTrue(multiQueueAuthenticator.canAccessSubQueue(subQueue)) } finally { @@ -202,6 +202,7 @@ abstract class MultiQueueAuthenticatorTest Assertions.assertThrows(MultiQueueAuthorisationException::class.java) { multiQueueAuthenticator.canAccessSubQueue(subQueue) } + Assertions.assertFalse(multiQueueAuthenticator.canAccessSubQueue(subQueue, false)) } finally { @@ -224,6 +225,7 @@ abstract class MultiQueueAuthenticatorTest Assertions.assertThrows(MultiQueueAuthorisationException::class.java) { multiQueueAuthenticator.canAccessSubQueue(subQueue) } + Assertions.assertFalse(multiQueueAuthenticator.canAccessSubQueue(subQueue, false)) } /** @@ -245,6 +247,7 @@ abstract class MultiQueueAuthenticatorTest { MDC.put(JwtAuthenticationFilter.SUB_QUEUE, subQueue) multiQueueAuthenticator.canAccessSubQueue(subQueue) + Assertions.assertTrue(multiQueueAuthenticator.canAccessSubQueue(subQueue)) } finally { @@ -273,6 +276,7 @@ abstract class MultiQueueAuthenticatorTest Assertions.assertThrows(MultiQueueAuthorisationException::class.java) { multiQueueAuthenticator.canAccessSubQueue(subQueue) } + Assertions.assertFalse(multiQueueAuthenticator.canAccessSubQueue(subQueue, false)) } finally { From 8ea313ca5b3d9c8bd0af294b3ade3ca4ee05a786 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 3 Nov 2023 22:17:59 +1100 Subject: [PATCH 26/58] Merge mock tests into existing MessageQueueControllerTest class. --- .../MessageQueueControllerMockTest.kt | 111 ------------------ .../controller/MessageQueueControllerTest.kt | 38 +++++- 2 files changed, 37 insertions(+), 112 deletions(-) delete mode 100644 src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt deleted file mode 100644 index e162580..0000000 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerMockTest.kt +++ /dev/null @@ -1,111 +0,0 @@ -package au.kilemon.messagequeue.rest.controller - -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType -import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator -import au.kilemon.messagequeue.authentication.authenticator.inmemory.InMemoryAuthenticator -import au.kilemon.messagequeue.authentication.token.JwtTokenProvider -import au.kilemon.messagequeue.logging.LoggingConfiguration -import au.kilemon.messagequeue.message.QueueMessage -import au.kilemon.messagequeue.queue.MultiQueue -import au.kilemon.messagequeue.queue.inmemory.InMemoryMultiQueue -import au.kilemon.messagequeue.settings.MessageQueueSettings -import com.google.gson.Gson -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.Mockito -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest -import org.springframework.boot.test.context.TestConfiguration -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Import -import org.springframework.http.HttpStatus -import org.springframework.http.MediaType -import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders -import org.springframework.test.web.servlet.result.MockMvcResultMatchers - -/** - * A test class for the [MessageQueueController]. - * Specifically mocking scenarios that are hard to replicate. - * - * @author github.com/Kilemonn - */ -@ExtendWith(SpringExtension::class) -@WebMvcTest(controllers = [MessageQueueController::class], properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=IN_MEMORY"]) -@Import(*[LoggingConfiguration::class]) -class MessageQueueControllerMockTest -{ - /** - * A [TestConfiguration] for the outer [MessageQueueControllerTest] class. - * - * @author github.com/Kilemonn - */ - @TestConfiguration - open class TestConfig - { - @Bean - open fun getMultiQueue(): MultiQueue - { - return Mockito.spy(InMemoryMultiQueue::class.java) - } - - @Bean - open fun getMultiQueueAuthenticator(): MultiQueueAuthenticator - { - return Mockito.spy(InMemoryAuthenticator::class.java) - } - - @Bean - open fun getMultiQueueAuthenticationType(): MultiQueueAuthenticationType - { - return MultiQueueAuthenticationType.NONE - } - - @Bean - open fun getJwtTokenProvider(): JwtTokenProvider - { - return JwtTokenProvider() - } - } - - @Autowired - private lateinit var mockMvc: MockMvc - - @Autowired - private lateinit var multiQueue: MultiQueue - - private val gson: Gson = Gson() - - /** - * Perform a health check call on the [MessageQueueController] to ensure a [HttpStatus.INTERNAL_SERVER_ERROR] is returned when the health check fails. - */ - @Test - fun testGetPerformHealthCheck_failureResponse() - { - Mockito.`when`(multiQueue.performHealthCheckInternal()).thenThrow(RuntimeException("Failed to perform health check.")) - - mockMvc.perform( - MockMvcRequestBuilders.get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_HEALTH_CHECK) - .contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().isInternalServerError) - .andReturn() - } - - /** - * Test [MessageQueueController.createMessage] to ensure that an internal server error is returned when [MultiQueue.add] returns `false`. - */ - @Test - fun testCreateMessage_addFails() - { - val message = QueueMessage("payload", "type") - - Mockito.`when`(multiQueue.add(message)).thenReturn(false) - - mockMvc.perform( - MockMvcRequestBuilders.post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .content(gson.toJson(message))) - .andExpect(MockMvcResultMatchers.status().isInternalServerError) - } -} diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt index 6f65aee..43dcded 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt @@ -15,9 +15,11 @@ import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mockito import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.boot.test.context.TestConfiguration +import org.springframework.boot.test.mock.mockito.SpyBean import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import import org.springframework.http.HttpStatus @@ -58,7 +60,7 @@ class MessageQueueControllerTest @Autowired private lateinit var mockMvc: MockMvc - @Autowired + @SpyBean private lateinit var multiQueue: MultiQueue private val gson: Gson = Gson() @@ -980,6 +982,40 @@ class MessageQueueControllerTest types.forEach { type -> Assertions.assertFalse(multiQueue.keys().contains(type)) } } + /** + * `Mock Test`. + * + * Perform a health check call on the [MessageQueueController] to ensure a [HttpStatus.INTERNAL_SERVER_ERROR] is returned when the health check fails. + */ + @Test + fun testGetPerformHealthCheck_failureResponse() + { + Mockito.doThrow(RuntimeException("Failed to perform health check.")).`when`(multiQueue).performHealthCheckInternal() + + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_HEALTH_CHECK) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isInternalServerError) + .andReturn() + } + + /** + * `Mock Test`. + * + * Test [MessageQueueController.createMessage] to ensure that an internal server error is returned when [MultiQueue.add] returns `false`. + */ + @Test + fun testCreateMessage_addFails() + { + val message = QueueMessage("payload", "type") + + Mockito.doReturn(false).`when`(multiQueue).add(message) + + mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(gson.toJson(message))) + .andExpect(MockMvcResultMatchers.status().isInternalServerError) + } + /** * A helper method which creates `4` [QueueMessage] objects and inserts them into the [MultiQueue]. * From ac511d253675cc8af1b01c5f6201bd45cbd506c7 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 3 Nov 2023 23:02:47 +1100 Subject: [PATCH 27/58] Add environment property to pass through the HMAC512 key. Remove unnecessary uses of the @Generated annotations. --- .../authentication/token/JwtTokenProvider.kt | 56 ++++++++++++++++--- .../configuration/QueueConfiguration.kt | 12 +--- .../cache/redis/RedisConfiguration.kt | 4 +- .../rest/controller/AuthController.kt | 12 +--- .../settings/MessageQueueSettings.kt | 7 +++ .../redis/RedisStandAloneAuthenticatorTest.kt | 1 + .../token/JwtTokenProviderTest.kt | 20 +++++++ .../cache/redis/RedisConfigurationTest.kt | 20 +++---- 8 files changed, 92 insertions(+), 40 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt index 73eeed9..5d3dc27 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt @@ -1,6 +1,7 @@ package au.kilemon.messagequeue.authentication.token import au.kilemon.messagequeue.logging.HasLogger +import au.kilemon.messagequeue.settings.MessageQueueSettings import com.auth0.jwt.JWT import com.auth0.jwt.JWTVerifier import com.auth0.jwt.algorithms.Algorithm @@ -8,6 +9,7 @@ import com.auth0.jwt.exceptions.JWTCreationException import com.auth0.jwt.exceptions.JWTVerificationException import com.auth0.jwt.interfaces.DecodedJWT import org.slf4j.Logger +import org.springframework.beans.factory.annotation.Value import java.security.SecureRandom import java.util.* @@ -29,6 +31,9 @@ class JwtTokenProvider: HasLogger private var algorithm: Algorithm? = null + @Value("\${${MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY}:\"\"}") + private var tokenKey: String = "" + /** * Lazily initialise and get the [Algorithm] using [Algorithm.HMAC512] and a random key. * @@ -38,12 +43,32 @@ class JwtTokenProvider: HasLogger { if (algorithm == null) { + algorithm = Algorithm.HMAC512(getKey()) + } + return algorithm!! + } + + /** + * Get the key to be used for Jwt token generation and verification. + * + * @return If a value is provided via [MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY] then we will use it if it is + * not blank. Otherwise, a randomly generated a byte array is returned + */ + private fun getKey(): ByteArray + { + return if (tokenKey.isNotBlank()) + { + LOG.info("Using provided key in property [{}] as the HMAC512 token generation and verification key.", MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY) + tokenKey.toByteArray() + } + else + { + LOG.info("No HMAC512 key provided in property [{}] for token generation and verification key. Generating a new random key.", MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY) val random = SecureRandom() val bytes = ByteArray(128) random.nextBytes(bytes) - algorithm = Algorithm.HMAC512(bytes) + bytes } - return algorithm!! } /** @@ -92,12 +117,7 @@ class JwtTokenProvider: HasLogger { try { - val builder = JWT.create().withIssuer(ISSUER).withClaim(SUB_QUEUE_CLAIM, subQueue) - if (expiryInMinutes != null) - { - builder.withExpiresAt(Date(Date().time + (expiryInMinutes * 60 * 1000))) - } - val token = builder.sign(getAlgorithm()) + val token = createTokenInternal(subQueue, expiryInMinutes) LOG.info("Creating new token for sub-queue [{}] with expiry of [{}] minutes.", subQueue, expiryInMinutes) return Optional.ofNullable(token) @@ -109,4 +129,24 @@ class JwtTokenProvider: HasLogger } return Optional.empty() } + + /** + * The internal method for creating the token. + * This is needed for tests instead of using PowerMock or something. + * + * @param subQueue will be embedded in the generated token as a claim with key [SUB_QUEUE_CLAIM] + * @param expiryInMinutes the generated token expiry in minutes, if `null` this is not added the token will be valid + * indefinitely + * @return the generated token as a [String] + * @throws JWTCreationException if there is a problem creating the token + */ + fun createTokenInternal(subQueue: String, expiryInMinutes: Long? = null): String + { + val builder = JWT.create().withIssuer(ISSUER).withClaim(SUB_QUEUE_CLAIM, subQueue) + if (expiryInMinutes != null) + { + builder.withExpiresAt(Date(Date().time + (expiryInMinutes * 60 * 1000))) + } + return builder.sign(getAlgorithm()) + } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt index 401ec7f..5c7baf6 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt @@ -40,20 +40,14 @@ class QueueConfiguration : HasLogger override val LOG: Logger = initialiseLogger() @Autowired - @get:Generated - @set:Generated - lateinit var messageQueueSettings: MessageQueueSettings + private lateinit var messageQueueSettings: MessageQueueSettings @Autowired - @get:Generated - @set:Generated - lateinit var messageSource: ReloadableResourceBundleMessageSource + private lateinit var messageSource: ReloadableResourceBundleMessageSource @Autowired @Lazy - @get:Generated - @set:Generated - lateinit var redisTemplate: RedisTemplate + private lateinit var redisTemplate: RedisTemplate /** * Initialise the [MultiQueue] [Bean] based on the [MessageQueueSettings.multiQueueType]. diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt index c6a6087..8f34cb1 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt @@ -80,9 +80,7 @@ class RedisConfiguration: HasLogger } @Autowired - @get:Generated - @set:Generated - lateinit var messageQueueSettings: MessageQueueSettings + private lateinit var messageQueueSettings: MessageQueueSettings /** * Create the [RedisConnectionFactory] based on the loaded configuration. diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt index 417fd26..81646e1 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt @@ -42,19 +42,13 @@ open class AuthController : HasLogger override val LOG: Logger = this.initialiseLogger() @Autowired - @get:Generated - @set:Generated - lateinit var multiQueueAuthenticator: MultiQueueAuthenticator + private lateinit var multiQueueAuthenticator: MultiQueueAuthenticator @Autowired - @get:Generated - @set:Generated - lateinit var multiQueue: MultiQueue + private lateinit var multiQueue: MultiQueue @Autowired - @get:Generated - @set:Generated - lateinit var jwtTokenProvider: JwtTokenProvider + private lateinit var jwtTokenProvider: JwtTokenProvider @Operation(summary = "Create restriction on sub-queue.", description = "Create restriction a specific sub-queue to require authentication for future interactions and retrieve a token used to interact with this sub-queue.") @PostMapping("/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) diff --git a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt index 1c17580..aab6803 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt @@ -74,6 +74,13 @@ class MessageQueueSettings */ const val MULTI_QUEUE_AUTHENTICATION: String = "MULTI_QUEUE_AUTHENTICATION" const val MULTI_QUEUE_AUTHENTICATION_DEFAULT: String = "NONE" + + /** + * A property that is passed through to the [au.kilemon.messagequeue.authentication.token.JwtTokenProvider] and + * used as the token generation and verification key. If this is not provided, a new key will be generated each + * time the application starts. + */ + const val MULTI_QUEUE_TOKEN_KEY: String = "MULTI_QUEUE_TOKEN_KEY" } /** diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt index a0f518f..994949a 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt @@ -95,6 +95,7 @@ class RedisStandAloneAuthenticatorTest: MultiQueueAuthenticatorTest() Assertions.assertThrows(MultiQueueAuthorisationException::class.java) { multiQueueAuthenticator.canAccessSubQueue(RedisAuthenticator.RESTRICTED_KEY) } + Assertions.assertFalse(multiQueueAuthenticator.canAccessSubQueue(RedisAuthenticator.RESTRICTED_KEY, false)) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt index 7f27783..5047d43 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt @@ -1,12 +1,17 @@ package au.kilemon.messagequeue.authentication.token +import com.auth0.jwt.exceptions.JWTCreationException import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mockito +import org.springframework.test.context.junit.jupiter.SpringExtension import java.util.* /** * A test class for [JwtTokenProvider] and different token issuing and verification scenarios. */ +@ExtendWith(SpringExtension::class) class JwtTokenProviderTest { private val jwtTokenProvider = JwtTokenProvider() @@ -24,6 +29,21 @@ class JwtTokenProviderTest Assertions.assertTrue(token.isPresent) } + /** + * Ensure [JwtTokenProvider.createTokenForSubQueue] returns an [Optional.empty] when the underlying method + * fails to generate the token and throws a [JWTCreationException]. + */ + @Test + fun testCreateTokenForSubQueue_failsToCreateToken() + { + val mockJwtTokenProvider = Mockito.spy(JwtTokenProvider::class.java) + val subQueue = "testCreateTokenForSubQueue_failsToCreateToken" + + Mockito.doThrow(JWTCreationException("message", Exception())).`when`(mockJwtTokenProvider).createTokenInternal(subQueue) + val token = mockJwtTokenProvider.createTokenForSubQueue(subQueue) + Assertions.assertTrue(token.isEmpty) + } + /** * Ensure [JwtTokenProvider.verifyTokenForSubQueue] correctly parses out the token's properties * and that the issuer and claim are set correctly. And expiry is not set. diff --git a/src/test/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfigurationTest.kt b/src/test/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfigurationTest.kt index ce9e259..82f419e 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfigurationTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfigurationTest.kt @@ -8,7 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.boot.test.context.TestConfiguration import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Lazy +import org.springframework.context.annotation.Import import org.springframework.test.context.junit.jupiter.SpringExtension import java.util.stream.IntStream @@ -18,6 +18,7 @@ import java.util.stream.IntStream * @author github.com/Kilemonn */ @ExtendWith(SpringExtension::class) +@Import(*[RedisConfiguration::class]) class RedisConfigurationTest { /** @@ -40,7 +41,10 @@ class RedisConfigurationTest } @Autowired - lateinit var messageQueueSettings: MessageQueueSettings + private lateinit var messageQueueSettings: MessageQueueSettings + + @Autowired + private lateinit var redisConfiguration: RedisConfiguration /** * The default port to be used when no port is supplied with the hostname endpoint string. @@ -133,9 +137,7 @@ class RedisConfigurationTest Assertions.assertTrue(messageQueueSettings.redisUseSentinels.toBoolean()) Assertions.assertEquals("", messageQueueSettings.redisEndpoint) Assertions.assertThrows(RedisInitialisationException::class.java) { - val config = RedisConfiguration() - config.messageQueueSettings = messageQueueSettings - config.getSentinelConfiguration() + redisConfiguration.getSentinelConfiguration() } } @@ -150,9 +152,7 @@ class RedisConfigurationTest Assertions.assertFalse(messageQueueSettings.redisUseSentinels.toBoolean()) Assertions.assertEquals("", messageQueueSettings.redisEndpoint) Assertions.assertThrows(RedisInitialisationException::class.java) { - val config = RedisConfiguration() - config.messageQueueSettings = messageQueueSettings - config.getStandAloneConfiguration() + redisConfiguration.getStandAloneConfiguration() } } @@ -171,9 +171,7 @@ class RedisConfigurationTest messageQueueSettings.redisEndpoint = endpoints Assertions.assertFalse(messageQueueSettings.redisUseSentinels.toBoolean()) Assertions.assertEquals(endpoints, messageQueueSettings.redisEndpoint) - val config = RedisConfiguration() - config.messageQueueSettings = messageQueueSettings - val standAloneConfiguration = config.getStandAloneConfiguration() + val standAloneConfiguration = redisConfiguration.getStandAloneConfiguration() Assertions.assertEquals(endpoint1Host, standAloneConfiguration.hostName) Assertions.assertEquals(endpoint1Port.toInt(), standAloneConfiguration.port) } From 9306bab0fdd2a774b131ce000b9eb49e4401ea90 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 4 Nov 2023 16:12:32 +1100 Subject: [PATCH 28/58] Turn the auth required endpoints into a whitelist to avoid authentication being required so I can enforce auth by default. --- .../messagequeue/filter/JwtAuthenticationFilter.kt | 14 +++++++------- .../filter/JwtAuthenticationFilterTest.kt | 4 ++-- .../rest/controller/AuthControllerTest.kt | 1 - 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index f0cb001..7343c61 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -7,6 +7,7 @@ import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthentication import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.rest.controller.AuthController import au.kilemon.messagequeue.rest.controller.MessageQueueController +import au.kilemon.messagequeue.rest.controller.SettingsController import au.kilemon.messagequeue.rest.response.RestResponseExceptionHandler import org.slf4j.Logger import org.slf4j.MDC @@ -128,15 +129,14 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger fun urlRequiresAuthentication(request: HttpServletRequest): Boolean { val requestString = request.requestURI - val authRequiredUrlPrefixes = listOf( - Pair(HttpMethod.GET, MessageQueueController.MESSAGE_QUEUE_BASE_PATH), - Pair(HttpMethod.POST, MessageQueueController.MESSAGE_QUEUE_BASE_PATH), - Pair(HttpMethod.PUT, MessageQueueController.MESSAGE_QUEUE_BASE_PATH), - Pair(HttpMethod.DELETE, MessageQueueController.MESSAGE_QUEUE_BASE_PATH), - Pair(HttpMethod.DELETE, AuthController.AUTH_PATH) + val authNotRequiredEndpoints = listOf( + Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_HEALTH_CHECK}"), + Pair(HttpMethod.POST, AuthController.AUTH_PATH), + Pair(HttpMethod.GET, SettingsController.SETTINGS_PATH) ) - return authRequiredUrlPrefixes.filter { authRequiredUrlPrefix -> authRequiredUrlPrefix.first.toString() == request.method } + return authNotRequiredEndpoints + .filter { authRequiredUrlPrefix -> authRequiredUrlPrefix.first.toString() == request.method } .any { authRequiredUrlPrefix -> requestString.startsWith(authRequiredUrlPrefix.second) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt index 9086306..f6236bf 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt @@ -217,7 +217,7 @@ class JwtAuthenticationFilterTest fun testUrlRequiresAuthentication_noAuthRequiredURL() { val request = Mockito.mock(HttpServletRequest::class.java) - val uriPath = "/another/test/endpoint/${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}" + val uriPath = "/another/test/endpoint${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}" Mockito.`when`(request.requestURI).thenReturn(uriPath) Mockito.`when`(request.method).thenReturn(HttpMethod.POST.toString()) @@ -232,7 +232,7 @@ class JwtAuthenticationFilterTest fun testUrlRequiresAuthentication_authRequiredURL() { val request = Mockito.mock(HttpServletRequest::class.java) - val uriPath = "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}/test/endpoint" + val uriPath = "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_HEALTH_CHECK}" Mockito.`when`(request.requestURI).thenReturn(uriPath) Mockito.`when`(request.method).thenReturn(HttpMethod.GET.toString()) diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index a114b04..72b9aad 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -38,7 +38,6 @@ import java.util.* * @author github.com/Kilemonn */ @ExtendWith(SpringExtension::class) -@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD) @WebMvcTest(controllers = [AuthController::class], properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=IN_MEMORY"]) @Import(*[QueueConfiguration::class, LoggingConfiguration::class]) class AuthControllerTest From c00ea010da21e107de4776a5f7d3c4a11cabb277 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 4 Nov 2023 19:01:34 +1100 Subject: [PATCH 29/58] Change assertion. --- .../kilemon/messagequeue/rest/controller/AuthControllerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index 72b9aad..0fcd393 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -226,7 +226,7 @@ class AuthControllerTest mockMvc.perform( MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") .contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().isUnauthorized) + .andExpect(MockMvcResultMatchers.status().isForbidden) } @Test From ff242a878a975f14b32c1b16280dc3375dd465fa Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 4 Nov 2023 20:09:48 +1100 Subject: [PATCH 30/58] Update auth filter check and tests. --- .../filter/JwtAuthenticationFilter.kt | 3 ++- .../filter/JwtAuthenticationFilterTest.kt | 27 ++++++++++++++----- .../rest/controller/AuthControllerTest.kt | 2 +- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index 7343c61..e58998e 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -122,6 +122,7 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger /** * Verify the requested URI requires authentication or not. + * If the URL is not in the no auth list, then it will require authentication. * * @param request the incoming request to verify the path of * @return `true` if the provided path starts with an auth required prefix, otherwise `false` @@ -135,7 +136,7 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger Pair(HttpMethod.GET, SettingsController.SETTINGS_PATH) ) - return authNotRequiredEndpoints + return !authNotRequiredEndpoints .filter { authRequiredUrlPrefix -> authRequiredUrlPrefix.first.toString() == request.method } .any { authRequiredUrlPrefix -> requestString.startsWith(authRequiredUrlPrefix.second) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt index f6236bf..dc58235 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt @@ -210,23 +210,23 @@ class JwtAuthenticationFilterTest } /** - * Ensure [JwtAuthenticationFilter.urlRequiresAuthentication] returns `false` when the provided URI does not - * start with an authorised path prefix. + * Ensure [JwtAuthenticationFilter.urlRequiresAuthentication] returns `true` when the provided URI does not + * match the "no auth required" list. */ @Test - fun testUrlRequiresAuthentication_noAuthRequiredURL() + fun testUrlRequiresAuthentication_notInWhitelist() { val request = Mockito.mock(HttpServletRequest::class.java) val uriPath = "/another/test/endpoint${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}" Mockito.`when`(request.requestURI).thenReturn(uriPath) Mockito.`when`(request.method).thenReturn(HttpMethod.POST.toString()) - Assertions.assertFalse(jwtAuthenticationFilter.urlRequiresAuthentication(request)) + Assertions.assertTrue(jwtAuthenticationFilter.urlRequiresAuthentication(request)) } /** - * Ensure [JwtAuthenticationFilter.urlRequiresAuthentication] returns `true` when the provided URI does - * start with an authorised path prefix. + * Ensure [JwtAuthenticationFilter.urlRequiresAuthentication] returns `false` when the provided URI does + * start with an un-authorised path prefix. */ @Test fun testUrlRequiresAuthentication_authRequiredURL() @@ -236,6 +236,21 @@ class JwtAuthenticationFilterTest Mockito.`when`(request.requestURI).thenReturn(uriPath) Mockito.`when`(request.method).thenReturn(HttpMethod.GET.toString()) + Assertions.assertFalse(jwtAuthenticationFilter.urlRequiresAuthentication(request)) + } + + /** + * Ensure [JwtAuthenticationFilter.urlRequiresAuthentication] returns `true` when the provided HTTP method is + * not in the whitelist. + */ + @Test + fun testUrlRequiresAuthentication_nonMatchingMethod() + { + val request = Mockito.mock(HttpServletRequest::class.java) + val uriPath = "/a/path" + Mockito.`when`(request.requestURI).thenReturn(uriPath) + Mockito.`when`(request.method).thenReturn(HttpMethod.OPTIONS.toString()) + Assertions.assertTrue(jwtAuthenticationFilter.urlRequiresAuthentication(request)) } diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index 0fcd393..72b9aad 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -226,7 +226,7 @@ class AuthControllerTest mockMvc.perform( MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") .contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().isForbidden) + .andExpect(MockMvcResultMatchers.status().isUnauthorized) } @Test From 651183e14bd8d6af425facf9ec656b6244d02cbb Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sun, 5 Nov 2023 00:42:35 +1100 Subject: [PATCH 31/58] Assert authenticationtype for all existing tests. Start working on restricted queue tests. --- .../controller/MessageQueueControllerTest.kt | 173 +++++++++++++++++- 1 file changed, 168 insertions(+), 5 deletions(-) diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt index 43dcded..1bc1c14 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt @@ -1,7 +1,11 @@ package au.kilemon.messagequeue.rest.controller +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.filter.CorrelationIdFilter +import au.kilemon.messagequeue.filter.JwtAuthenticationFilter import au.kilemon.messagequeue.logging.LoggingConfiguration import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.MultiQueue @@ -24,6 +28,7 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import import org.springframework.http.HttpStatus import org.springframework.http.MediaType +import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.junit.jupiter.SpringExtension import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.MvcResult @@ -60,6 +65,12 @@ class MessageQueueControllerTest @Autowired private lateinit var mockMvc: MockMvc + @Autowired + private lateinit var jwtTokenProvider: JwtTokenProvider + + @SpyBean + private lateinit var authenticator: MultiQueueAuthenticator + @SpyBean private lateinit var multiQueue: MultiQueue @@ -73,6 +84,9 @@ class MessageQueueControllerTest { multiQueue.clear() Assertions.assertTrue(multiQueue.isEmpty()) + + authenticator.clearRestrictedSubQueues() + Assertions.assertTrue(authenticator.getRestrictedSubQueueIdentifiers().isEmpty()) } /** @@ -81,6 +95,8 @@ class MessageQueueControllerTest @Test fun testGetQueueTypeInfo() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val queueType = "testGetQueueTypeInfo" Assertions.assertEquals(0, multiQueue.getQueueForType(queueType).size) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_TYPE + "/" + queueType) @@ -104,7 +120,8 @@ class MessageQueueControllerTest @Test fun testGetAllQueueTypeInfo() { - Assertions.assertTrue(multiQueue.isEmpty()) + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_TYPE) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) @@ -132,6 +149,8 @@ class MessageQueueControllerTest @Test fun testGetEntry() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val message = createQueueMessage(type = "testGetEntry") Assertions.assertTrue(multiQueue.add(message)) @@ -157,6 +176,8 @@ class MessageQueueControllerTest @Test fun testGetEntry_ResponseBody_NotExists() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val uuid = "invalid-not-found-uuid" mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + uuid) .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -170,6 +191,8 @@ class MessageQueueControllerTest @Test fun testCreateQueueEntry_withProvidedDefaults() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val message = createQueueMessage(type = "testCreateQueueEntry_withProvidedDefaults", assignedTo = "user-1") val mvcResult: MvcResult = mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) @@ -200,6 +223,8 @@ class MessageQueueControllerTest @Test fun testCreateQueueEntry_withOutDefaults() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val message = createQueueMessage(type = "testCreateQueueEntry_withOutDefaults") val mvcResult: MvcResult = mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) @@ -229,6 +254,8 @@ class MessageQueueControllerTest @Test fun testCreateEntry_Conflict() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val message = createQueueMessage(type = "testCreateEntry_Conflict") Assertions.assertTrue(multiQueue.add(message)) @@ -245,6 +272,8 @@ class MessageQueueControllerTest @Test fun testCreateQueueEntry_withBlankAssignedTo() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val message = createQueueMessage(type = "testCreateQueueEntry_withAssignedButNoAssignedTo") message.assignedTo = " " @@ -264,6 +293,8 @@ class MessageQueueControllerTest @Test fun testGetKeys() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val entries = initialiseMapWithEntries() val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) @@ -288,6 +319,8 @@ class MessageQueueControllerTest @Test fun testGetKeys_excludeEmpty() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val entries = initialiseMapWithEntries() Assertions.assertTrue(multiQueue.remove(entries.first[0])) Assertions.assertTrue(multiQueue.remove(entries.first[1])) @@ -316,6 +349,8 @@ class MessageQueueControllerTest @Test fun testGetAll() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val entries = initialiseMapWithEntries() val type = entries.first[0].type val detailed = true @@ -347,6 +382,8 @@ class MessageQueueControllerTest @Test fun testGetAll_SpecificQueueType() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val entries = initialiseMapWithEntries() val type = entries.first[0].type val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ALL) @@ -374,6 +411,8 @@ class MessageQueueControllerTest @Test fun testGetOwned_NoneOwned() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val entries = initialiseMapWithEntries() val assignedTo = "my-assigned-to-identifier" @@ -395,6 +434,8 @@ class MessageQueueControllerTest @Test fun testGetOwned_SomeOwned() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "my-assigned-to-identifier" val type = "testGetOwned_SomeOwned" val message1 = createQueueMessage(assignedTo = assignedTo, type = type) @@ -427,6 +468,8 @@ class MessageQueueControllerTest @Test fun testAssignMessage_doesNotExist() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val uuid = UUID.randomUUID().toString() val assignedTo = "assigned" mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + uuid) @@ -441,6 +484,8 @@ class MessageQueueControllerTest @Test fun testAssignMessage_messageIsAssigned() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assigned" val message = createQueueMessage(type = "testAssignMessage_messageIsAssigned") Assertions.assertNull(message.assignedTo) @@ -467,6 +512,8 @@ class MessageQueueControllerTest @Test fun testAssignMessage_alreadyAssignedToSameID() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assigned" val message = createQueueMessage(type = "testAssignMessage_alreadyAssignedToSameID", assignedTo = assignedTo) @@ -494,6 +541,8 @@ class MessageQueueControllerTest @Test fun testAssignMessage_alreadyAssignedToOtherID() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assignee" val message = createQueueMessage(type = "testAssignMessage_alreadyAssignedToOtherID", assignedTo = assignedTo) @@ -523,6 +572,8 @@ class MessageQueueControllerTest @Test fun testGetNext_noNewMessages() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assignee" val type = "testGetNext_noNewMessages" mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT) @@ -540,6 +591,8 @@ class MessageQueueControllerTest @Test fun testGetNext_noNewUnAssignedMessages() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assignee" val type = "testGetNext_noNewUnAssignedMessages" val message = createQueueMessage(type = type, assignedTo = assignedTo) @@ -563,6 +616,8 @@ class MessageQueueControllerTest @Test fun testGetNext() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assignee" val type = "testGetNext" val message = createQueueMessage(type = type, assignedTo = assignedTo) @@ -597,6 +652,8 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_doesNotExist() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val uuid = UUID.randomUUID().toString() mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + uuid) .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -609,6 +666,8 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_messageIsReleased() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assignee" val message = createQueueMessage(type = "testReleaseMessage_messageIsReleased", assignedTo = assignedTo) @@ -636,6 +695,8 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_messageIsReleased_withoutAssignedToInQuery() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assigned" val message = createQueueMessage(type = "testReleaseMessage_messageIsReleased_withoutAssignedToInQuery", assignedTo = assignedTo) @@ -662,6 +723,8 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_alreadyReleased() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val message = createQueueMessage(type = "testReleaseMessage_alreadyReleased") Assertions.assertNull(message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) @@ -687,6 +750,8 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_cannotBeReleasedWithMisMatchingID() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assigned" val message = createQueueMessage(type = "testReleaseMessage_cannotBeReleasedWithMisMatchingID", assignedTo = assignedTo) @@ -709,6 +774,8 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_notFound() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val uuid = UUID.randomUUID().toString() mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + uuid) @@ -722,6 +789,8 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_removeExistingEntry() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val message = createQueueMessage(type = "testRemoveMessage_removed") Assertions.assertTrue(multiQueue.add(message)) Assertions.assertTrue(multiQueue.containsUUID(message.uuid).isPresent) @@ -740,6 +809,8 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_doesNotExist() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val uuid = UUID.randomUUID().toString() Assertions.assertFalse(multiQueue.containsUUID(uuid).isPresent) @@ -756,6 +827,8 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_assignedToAnotherID() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assignee" val message = createQueueMessage(type = "testRemoveMessage_assignedToAnotherID", assignedTo = assignedTo) Assertions.assertTrue(multiQueue.add(message)) @@ -776,6 +849,8 @@ class MessageQueueControllerTest @Test fun testGetOwners_withQueueType() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assignedTo" val assignedTo2 = "assignedTo2" @@ -816,6 +891,8 @@ class MessageQueueControllerTest @Test fun testGetOwners_withoutQueueType() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assignedTo" val assignedTo2 = "assignedTo2" @@ -857,6 +934,8 @@ class MessageQueueControllerTest @Test fun testGetPerformHealthCheck() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_HEALTH_CHECK) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) @@ -869,6 +948,8 @@ class MessageQueueControllerTest @Test fun testCorrelationId_randomIdOnSuccess() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val message = createQueueMessage(type = "testCorrelationId_providedId") val mvcResult: MvcResult = mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) @@ -888,6 +969,8 @@ class MessageQueueControllerTest @Test fun testCorrelationId_providedId() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val message = createQueueMessage(type = "testCorrelationId_providedId") val correlationId = "my-correlation-id-123456" @@ -908,6 +991,8 @@ class MessageQueueControllerTest @Test fun testCorrelationId_randomIdOnError() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val assignedTo = "assignee" val message = createQueueMessage(type = "testCorrelationId_randomIdOnError", assignedTo = assignedTo) Assertions.assertTrue(multiQueue.add(message)) @@ -933,6 +1018,8 @@ class MessageQueueControllerTest @Test fun testDeleteKeys_singleKey() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val subQueue1 = "testDeleteKeys_singleKey1" var message = createQueueMessage(subQueue1) Assertions.assertTrue(multiQueue.add(message)) @@ -970,6 +1057,8 @@ class MessageQueueControllerTest @Test fun testDeleteKeys_allKeys() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val (messages, types) = initialiseMapWithEntries() Assertions.assertEquals(messages.size, multiQueue.size) types.forEach { type -> Assertions.assertTrue(multiQueue.keys().contains(type)) } @@ -990,6 +1079,8 @@ class MessageQueueControllerTest @Test fun testGetPerformHealthCheck_failureResponse() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Mockito.doThrow(RuntimeException("Failed to perform health check.")).`when`(multiQueue).performHealthCheckInternal() mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_HEALTH_CHECK) @@ -1006,6 +1097,8 @@ class MessageQueueControllerTest @Test fun testCreateMessage_addFails() { + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + val message = QueueMessage("payload", "type") Mockito.doReturn(false).`when`(multiQueue).add(message) @@ -1016,6 +1109,76 @@ class MessageQueueControllerTest .andExpect(MockMvcResultMatchers.status().isInternalServerError) } + /** + * + */ + @Test + fun testGetEntry_usingHybridMode_withRestrictedSubQueue() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val entries = initialiseMapWithEntries() + + val type1 = entries.second[0] + val message1 = entries.first[0] + val type1Token = jwtTokenProvider.createTokenForSubQueue(type1) + Assertions.assertTrue(type1Token.isPresent) + Assertions.assertTrue(authenticator.addRestrictedEntry(type1)) + Assertions.assertTrue(authenticator.isRestricted(type1)) + + // Checking 403 is returned without a token + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message1.uuid) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isForbidden) + + // Checking entry is retrieve with provided token + val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message1.uuid) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${type1Token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val messageResponse = gson.fromJson(mvcResult.response.contentAsString, MessageResponse::class.java) + + val deserialisedPayload = gson.fromJson(gson.toJson(messageResponse.message.payload), Payload::class.java) + Assertions.assertEquals(message1.payload, deserialisedPayload) + Assertions.assertNull(messageResponse.message.assignedTo) + Assertions.assertEquals(message1.type, messageResponse.message.type) + Assertions.assertEquals(message1.type, messageResponse.queueType) + Assertions.assertNotNull(messageResponse.message.uuid) + + val type2 = entries.second[1] + val message2 = entries.first[1] + Assertions.assertFalse(authenticator.isRestricted(type2)) + + val mvcResult2: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message2.uuid) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${type1Token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val messageResponse2 = gson.fromJson(mvcResult2.response.contentAsString, MessageResponse::class.java) + + val deserialisedPayload2 = gson.fromJson(gson.toJson(messageResponse2.message.payload), Payload::class.java) + Assertions.assertEquals(message2.payload, deserialisedPayload2) + Assertions.assertNull(messageResponse2.message.assignedTo) + Assertions.assertEquals(message2.type, messageResponse2.message.type) + Assertions.assertEquals(message2.type, messageResponse2.queueType) + Assertions.assertNotNull(messageResponse2.message.uuid) + } + + @Test + fun testRestrictedModeMakesAllEndpointsInaccessible() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, authenticator.getAuthenticationType()) + + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + UUID.randomUUID().toString()) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized) + } + /** * A helper method which creates `4` [QueueMessage] objects and inserts them into the [MultiQueue]. * @@ -1029,10 +1192,10 @@ class MessageQueueControllerTest val message3 = createQueueMessage(type = types[2], assignedTo = "assignee") val message4 = createQueueMessage(type = types[3]) - multiQueue.add(message) - multiQueue.add(message2) - multiQueue.add(message3) - multiQueue.add(message4) + Assertions.assertTrue(multiQueue.add(message)) + Assertions.assertTrue(multiQueue.add(message2)) + Assertions.assertTrue(multiQueue.add(message3)) + Assertions.assertTrue(multiQueue.add(message4)) return Pair(listOf(message, message2, message3, message4), types) } From 69d4e0769b7654529b531a1aeff85eb6eddb8295 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sun, 5 Nov 2023 17:07:58 +1100 Subject: [PATCH 32/58] Change response codes when removing restrictions, update tests and code docs. Update readme to use healthcheck as a test url. --- README.md | 2 +- .../rest/controller/AuthController.kt | 10 +++---- .../rest/controller/AuthControllerTest.kt | 28 +++++++++++++++++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1625b75..914350c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Once the image is running you can reach the Swagger documentation from the follo The `In-Memory` configuration is the default and requires no further configuration. Steps to run the In-Memory Multi Queue is as follows: - `docker run -p8080:8080 kilemon/message-queue` -- Once running the best endpoint to call at the moment is probably: `http://localhost:8080/queue/keys` +- Once running the best endpoint to call at the moment is probably: `http://localhost:8080/queue/healthcheck` If you really like you can provide an environment variable to the application to explicitly set the application into `In-Memory` mode: `MULTI_QUEUE_TYPE=IN_MEMORY`. diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt index 81646e1..76df2d4 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt @@ -58,7 +58,7 @@ open class AuthController : HasLogger ApiResponse(responseCode = "409", description = "A sub-queue with the provided identifier is already authorised.", content = [Content()]), ApiResponse(responseCode = "500", description = "There was an error generating the auth token for the sub-queue.", content = [Content()]) ) - fun restrictSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "") + fun restrictSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "The sub-queue that you wish to restrict to allow further access only by callers that posses the returned token.") @PathVariable(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, @Parameter(`in` = ParameterIn.QUERY, required = false, description = "The generated token's expiry in minutes.") @RequestParam(required = false, name = RestParameters.EXPIRY) expiry: Long?): ResponseEntity @@ -95,9 +95,9 @@ open class AuthController : HasLogger @DeleteMapping("/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( ApiResponse(responseCode = "200", description = "Successfully removed restriction for the sub-queue identifier."), - ApiResponse(responseCode = "204", description = "The MultiQueue is in a no-auth mode and sub-queue restrictions are disabled.", content = [Content()]), // Add empty Content() to remove duplicate responses in swagger docsApiResponse(responseCode = "204", description = "No queue messages match the provided UUID.", content = [Content()]) + ApiResponse(responseCode = "202", description = "The MultiQueue is in a no-auth mode and sub-queue restrictions are disabled.", content = [Content()]), // Add empty Content() to remove duplicate responses in swagger docsApiResponse(responseCode = "204", description = "No queue messages match the provided UUID.", content = [Content()]) + ApiResponse(responseCode = "204", description = "The requested sub-queue is not currently restricted.", content = [Content()]), ApiResponse(responseCode = "403", description = "Invalid token provided to remove restriction from requested sub-queue.", content = [Content()]), - ApiResponse(responseCode = "404", description = "The requested sub-queue is not currently restricted.", content = [Content()]), ApiResponse(responseCode = "500", description = "There was an error releasing restriction from the sub-queue.", content = [Content()]) ) fun removeRestrictionFromSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "The sub-queue identifier to remove restriction for.") @PathVariable(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, @@ -107,7 +107,7 @@ open class AuthController : HasLogger { LOG.trace("Requested to release authentication for sub-queue [{}] but queue is in mode [{}].", queueType, multiQueueAuthenticator.getAuthenticationType()) - return ResponseEntity.noContent().build() + return ResponseEntity.accepted().build() } val authedToken = JwtAuthenticationFilter.getSubQueue() @@ -137,7 +137,7 @@ open class AuthController : HasLogger else { LOG.info("Cannot remove restriction from a sub-queue [{}] that is not restricted.", queueType) - return ResponseEntity.notFound().build() + return ResponseEntity.noContent().build() } } else diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index 72b9aad..a48f0d6 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -190,7 +190,7 @@ class AuthControllerTest mockMvc.perform( MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") .contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().isNoContent) + .andExpect(MockMvcResultMatchers.status().isAccepted) } /** @@ -215,6 +215,11 @@ class AuthControllerTest .andExpect(MockMvcResultMatchers.status().isForbidden) } + /** + * Ensure [AuthController.removeRestrictionFromSubQueue] returns [org.springframework.http.HttpStatus.UNAUTHORIZED] + * when there is no auth token provided and the [MultiQueueAuthenticationType] is + * [MultiQueueAuthenticationType.RESTRICTED]. + */ @Test fun testRemoveRestrictionFromSubQueue_withoutAuthToken() { @@ -229,6 +234,10 @@ class AuthControllerTest .andExpect(MockMvcResultMatchers.status().isUnauthorized) } + /** + * Ensure [AuthController.removeRestrictionFromSubQueue] returns [org.springframework.http.HttpStatus.NO_CONTENT] + * when the token is valid but there is no restriction placed on the requested sub-queue. + */ @Test fun testRemoveRestrictionFromSubQueue_validTokenButNotRestricted() { @@ -245,9 +254,14 @@ class AuthControllerTest MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().isNotFound) + .andExpect(MockMvcResultMatchers.status().isNoContent) } + /** + * Ensure [AuthController.removeRestrictionFromSubQueue] returns + * [org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR] when there is an error when attempting to remove + * the restriction on the sub-queue. + */ @Test fun testRemoveRestrictionFromSubQueue_failedToRemoveRestriction() { @@ -270,6 +284,11 @@ class AuthControllerTest .andExpect(MockMvcResultMatchers.status().isInternalServerError) } + /** + * Ensure [AuthController.removeRestrictionFromSubQueue] returns [org.springframework.http.HttpStatus.OK] when + * the sub-queue restriction is removed BUT the sub-queue is not cleared when the query parameter + * [RestParameters.CLEAR_QUEUE] is not provided. + */ @Test fun testRemoveRestrictionFromSubQueue_removeButDontClearQueue() { @@ -304,6 +323,11 @@ class AuthControllerTest } } + /** + * Ensure [AuthController.removeRestrictionFromSubQueue] returns [org.springframework.http.HttpStatus.OK] when + * the sub-queue restriction is removed AND make sure the sub-queue is cleared when the query parameter + * [RestParameters.CLEAR_QUEUE] is provided and set to `true`. + */ @Test fun testRemoveRestrictionFromSubQueue_removeAndClearQueue() { From 7f5b5362f9109add5a822265485d9587c7c5f7eb Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sun, 5 Nov 2023 18:02:33 +1100 Subject: [PATCH 33/58] Add specific restricted tests in SettingsController and add missing case in AuthController. --- .../rest/controller/AuthControllerTest.kt | 25 ++++++++++ .../rest/controller/SettingsControllerTest.kt | 46 +++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index a48f0d6..33439c2 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -177,6 +177,31 @@ class AuthControllerTest Assertions.assertEquals(queueType, authResponse.subQueue) } + /** + * Ensure that even in [MultiQueueAuthenticationType.RESTRICTED] mode we can call the + * [AuthController.restrictSubQueue] this is important, without this being accessible new sub-queues can never + * be restricted meaning the queue would be completely inaccessible. + */ + @Test + fun testRestrictSubQueue_inRestrictedMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + + val queueType = "testRestrictSubQueue_inRestrictedMode" + + val mvcResult: MvcResult = mockMvc.perform( + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val authResponse = gson.fromJson(mvcResult.response.contentAsString, AuthResponse::class.java) + Assertions.assertNotNull(authResponse.token) + Assertions.assertNotNull(authResponse.correlationId) + Assertions.assertEquals(queueType, authResponse.subQueue) + } + /** * Ensure [AuthController.removeRestrictionFromSubQueue] returns [org.springframework.http.HttpStatus.NO_CONTENT] * when the [MultiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt index d88f3cb..e76dc6b 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt @@ -1,6 +1,7 @@ package au.kilemon.messagequeue.rest.controller import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration import au.kilemon.messagequeue.settings.MessageQueueSettings @@ -9,9 +10,11 @@ import com.google.gson.Gson import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mockito import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.boot.test.context.TestConfiguration +import org.springframework.boot.test.mock.mockito.SpyBean import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import import org.springframework.http.MediaType @@ -53,14 +56,18 @@ class SettingsControllerTest @Autowired private lateinit var mockMvc: MockMvc + @SpyBean + private lateinit var multiQueueAuthenticator: MultiQueueAuthenticator + private val gson: Gson = Gson() /** - * Test [SettingsController.getSettings] and verify the response payload and default values. + * A helper method to call [SettingsController.getSettings] and verify the response default values. */ - @Test - fun testGetSettings_defaultValues() + private fun testGetSettings_defaultValues(authenticationType: MultiQueueAuthenticationType) { + Assertions.assertEquals(authenticationType, multiQueueAuthenticator.getAuthenticationType()) + val mvcResult: MvcResult = mockMvc.perform(MockMvcRequestBuilders.get(SettingsController.SETTINGS_PATH) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) @@ -84,4 +91,37 @@ class SettingsControllerTest Assertions.assertTrue(settings.mongoUsername.isEmpty()) Assertions.assertTrue(settings.mongoUri.isEmpty()) } + + /** + * Ensure calls to [SettingsController.getSettings] is still available even then the [MultiQueueAuthenticationType] + * is set to [MultiQueueAuthenticationType.NONE]. + */ + @Test + fun testGetSettings_noneMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() + testGetSettings_defaultValues(MultiQueueAuthenticationType.NONE) + } + + /** + * Ensure calls to [SettingsController.getSettings] is still available even then the [MultiQueueAuthenticationType] + * is set to [MultiQueueAuthenticationType.HYBRID]. + */ + @Test + fun testGetSettings_hybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + testGetSettings_defaultValues(MultiQueueAuthenticationType.HYBRID) + } + + /** + * Ensure calls to [SettingsController.getSettings] is still available even then the [MultiQueueAuthenticationType] + * is set to [MultiQueueAuthenticationType.RESTRICTED]. + */ + @Test + fun testGetSettings_restrictedMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + testGetSettings_defaultValues(MultiQueueAuthenticationType.RESTRICTED) + } } From ef5d026b9498c83772d0703e529edbf8475e6abf Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sun, 5 Nov 2023 19:41:09 +1100 Subject: [PATCH 34/58] Review all endpoints and add any that don't require authentication to the jwtauthfilter whitelist. Add tests for hybrid mode. Add test for restricted mode. --- .../filter/JwtAuthenticationFilter.kt | 2 + .../kilemon/messagequeue/queue/MultiQueue.kt | 6 +- .../rest/controller/MessageQueueController.kt | 33 +- .../controller/MessageQueueControllerTest.kt | 741 +++++++++++++++--- 4 files changed, 678 insertions(+), 104 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index e58998e..f15207c 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -132,6 +132,8 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger val requestString = request.requestURI val authNotRequiredEndpoints = listOf( Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_HEALTH_CHECK}"), + Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_KEYS}"), + Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_OWNERS}"), Pair(HttpMethod.POST, AuthController.AUTH_PATH), Pair(HttpMethod.GET, SettingsController.SETTINGS_PATH) ) diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt index a26da4d..dbd716a 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt @@ -159,7 +159,7 @@ abstract class MultiQueue: Queue, HasLogger fun getOwnersAndKeysMap(queueType: String?): Map> { val responseMap = HashMap>() - if (queueType != null && multiQueueAuthenticator.canAccessSubQueue(queueType, false)) + if (queueType != null) { LOG.debug("Getting owners map for sub-queue with identifier [{}].", queueType) getOwnersAndKeysMapForType(queueType, responseMap) @@ -168,9 +168,7 @@ abstract class MultiQueue: Queue, HasLogger { LOG.debug("Getting owners map for all sub-queues.") val keys = keys(false) - keys.filter { key -> multiQueueAuthenticator.canAccessSubQueue(key, false) }.forEach { key -> - getOwnersAndKeysMapForType(key, responseMap) - } + keys.forEach { key -> getOwnersAndKeysMapForType(key, responseMap) } } return responseMap } diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt index 5d9dc50..cb414be 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt @@ -214,13 +214,13 @@ open class MessageQueueController : HasLogger { try { + authenticator.canAccessSubQueue(queueMessage.type) + if (queueMessage.assignedTo != null && queueMessage.assignedTo!!.isBlank()) { queueMessage.assignedTo = null } - authenticator.canAccessSubQueue(queueMessage.type) - val wasAdded = messageQueue.add(queueMessage) if (wasAdded) { @@ -259,7 +259,10 @@ open class MessageQueueController : HasLogger @Operation(summary = "Delete a keys or all keys, in turn clearing that sub queue.", description = "Delete the sub queue that matches the provided key. If no key is provided, all sub queues will be cleared.") @DeleteMapping(ENDPOINT_KEYS, produces = [MediaType.APPLICATION_JSON_VALUE]) - @ApiResponse(responseCode = "204", description = "Successfully cleared the sub queue(s) with the provided key, or all sub queues if the key is null.") + @ApiResponses( + ApiResponse(responseCode = "204", description = "Successfully cleared the sub queue(s) with the provided key, or all sub queues if the key is null."), + ApiResponse(responseCode = "206", description = "Successfully cleared the sub-queues that are unrestricted. Restricted sub-queues needs to be created with a valid token.") + ) fun deleteKeys(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "The queue type to clear the sub queue of. If it is not provided, all sub queues will be cleared.") @RequestParam(required = false, name = RestParameters.QUEUE_TYPE) queueType: String?): ResponseEntity { @@ -267,12 +270,32 @@ open class MessageQueueController : HasLogger { authenticator.canAccessSubQueue(queueType) messageQueue.clearForType(queueType) + return ResponseEntity.noContent().build() } else { - messageQueue.clear() + var anyAreNotCleared = false + for (key in messageQueue.keys()) + { + if (authenticator.canAccessSubQueue(key, false)) + { + messageQueue.clearForType(key) + } + else + { + anyAreNotCleared = true + } + } + + return if (anyAreNotCleared) + { + ResponseEntity.status(HttpStatus.PARTIAL_CONTENT).build() + } + else + { + ResponseEntity.noContent().build() + } } - return ResponseEntity.noContent().build() } /** diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt index 1bc1c14..91be09f 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt @@ -28,7 +28,6 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import import org.springframework.http.HttpStatus import org.springframework.http.MediaType -import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.junit.jupiter.SpringExtension import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.MvcResult @@ -77,7 +76,8 @@ class MessageQueueControllerTest private val gson: Gson = Gson() /** - * [BeforeEach] method to run [MultiQueue.clear] and ensure that [MultiQueue.isEmpty] returns `true` at the beginning of each test. + * [BeforeEach] method to run [MultiQueue.clear] and ensure that [MultiQueue.isEmpty] returns `true` at the + * beginning of each test. */ @BeforeEach fun setUp() @@ -90,7 +90,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getQueueTypeInfo] to ensure the correct information is returned for the specified `queueType`. + * Test [MessageQueueController.getQueueTypeInfo] to ensure the correct information is returned for the specified + * `queueType`. */ @Test fun testGetQueueTypeInfo() @@ -115,7 +116,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getAllQueueTypeInfo] to ensure that information for all `queue type`s is returned when no `queue type` is specified. + * Test [MessageQueueController.getAllQueueTypeInfo] to ensure that information for all `queue type`s is returned + * when no `queue type` is specified. */ @Test fun testGetAllQueueTypeInfo() @@ -144,7 +146,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getEntry] to ensure that [HttpStatus.OK] and the correct [QueueMessage] is returned as the response. + * Test [MessageQueueController.getEntry] to ensure that [HttpStatus.OK] and the correct [QueueMessage] is returned + * as the response. */ @Test fun testGetEntry() @@ -171,7 +174,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getEntry] to ensure that [HttpStatus.NO_CONTENT] is returned when a [UUID] that does not exist is provided. + * Test [MessageQueueController.getEntry] to ensure that [HttpStatus.NO_CONTENT] is returned when a [UUID] that + * does not exist is provided. */ @Test fun testGetEntry_ResponseBody_NotExists() @@ -184,6 +188,67 @@ class MessageQueueControllerTest .andExpect(MockMvcResultMatchers.status().isNoContent) } + /** + * Ensure that in [MultiQueueAuthenticationType.HYBRID] mode, when we restrict the sub-queue that we can no longer + * get entries from that specific sub-queue, other sub-queues are still accessible without a token. + */ + @Test + fun testGetEntry_usingHybridMode_withRestrictedSubQueue() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val entries = initialiseMapWithEntries() + + val type1 = entries.second[0] + val message1 = entries.first[0] + val type1Token = jwtTokenProvider.createTokenForSubQueue(type1) + Assertions.assertTrue(type1Token.isPresent) + Assertions.assertTrue(authenticator.addRestrictedEntry(type1)) + Assertions.assertTrue(authenticator.isRestricted(type1)) + + // Make sure we cannot access without a token + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message1.uuid) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isForbidden) + + // Checking entry is retrieve with provided token + val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message1.uuid) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${type1Token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val messageResponse = gson.fromJson(mvcResult.response.contentAsString, MessageResponse::class.java) + + val deserialisedPayload = gson.fromJson(gson.toJson(messageResponse.message.payload), Payload::class.java) + Assertions.assertEquals(message1.payload, deserialisedPayload) + Assertions.assertNull(messageResponse.message.assignedTo) + Assertions.assertEquals(message1.type, messageResponse.message.type) + Assertions.assertEquals(message1.type, messageResponse.queueType) + Assertions.assertNotNull(messageResponse.message.uuid) + + val type2 = entries.second[1] + val message2 = entries.first[1] + Assertions.assertFalse(authenticator.isRestricted(type2)) + + // Check un-restricted entry is still accessible without a token + val mvcResult2: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message2.uuid) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${type1Token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val messageResponse2 = gson.fromJson(mvcResult2.response.contentAsString, MessageResponse::class.java) + + val deserialisedPayload2 = gson.fromJson(gson.toJson(messageResponse2.message.payload), Payload::class.java) + Assertions.assertEquals(message2.payload, deserialisedPayload2) + Assertions.assertNull(messageResponse2.message.assignedTo) + Assertions.assertEquals(message2.type, messageResponse2.message.type) + Assertions.assertEquals(message2.type, messageResponse2.queueType) + Assertions.assertNotNull(messageResponse2.message.uuid) + } + /** * Calling create with provided [QueueMessage.assignedTo] and [QueueMessage.uuid] to * ensure they are set correctly in the returned [MessageResponse]. @@ -249,7 +314,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.createMessage] to ensure that [HttpStatus.CONFLICT] is returned if a message with the same [UUID] already exists in the queue. + * Test [MessageQueueController.createMessage] to ensure that [HttpStatus.CONFLICT] is returned if a message with + * the same [UUID] already exists in the queue. */ @Test fun testCreateEntry_Conflict() @@ -267,7 +333,8 @@ class MessageQueueControllerTest } /** - * Calling create with a blank [QueueMessage.assignedTo] to make sure that [QueueMessage.assignedTo] is provided as `null` in the response. + * Calling create with a blank [QueueMessage.assignedTo] to make sure that [QueueMessage.assignedTo] is provided as + * `null` in the response. */ @Test fun testCreateQueueEntry_withBlankAssignedTo() @@ -288,7 +355,46 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getKeys] to ensure that all keys for existing entries are provided and exist within the [MultiQueue]. + * Ensure that in [MultiQueueAuthenticationType.HYBRID] mode, when we restrict the sub-queue that we can no longer + * create entries for that specific sub-queue, other sub-queues can still have messages created without a token. + */ + @Test + fun testCreateEntry_inHybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val message = createQueueMessage(type = "testCreateEntry_inHybridMode") + + Assertions.assertTrue(authenticator.addRestrictedEntry(message.type)) + Assertions.assertTrue(authenticator.isRestricted(message.type)) + + val token = jwtTokenProvider.createTokenForSubQueue(message.type) + Assertions.assertTrue(token.isPresent) + + mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(gson.toJson(message))) + .andExpect(MockMvcResultMatchers.status().isForbidden) + + mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(gson.toJson(message))) + .andExpect(MockMvcResultMatchers.status().isCreated) + + val message2 = createQueueMessage(type = "testCreateEntry_inHybridMode2") + Assertions.assertFalse(authenticator.isRestricted(message2.type)) + + mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(gson.toJson(message2))) + .andExpect(MockMvcResultMatchers.status().isCreated) + } + + /** + * Test [MessageQueueController.getKeys] to ensure that all keys for existing entries are provided and exist within + * the [MultiQueue]. */ @Test fun testGetKeys() @@ -314,7 +420,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getKeys] to ensure that all keys are returned. Specifically when entries are added and [RestParameters.INCLUDE_EMPTY] is set to `false`. + * Test [MessageQueueController.getKeys] to ensure that all keys are returned. Specifically when entries are added + * and [RestParameters.INCLUDE_EMPTY] is set to `false`. */ @Test fun testGetKeys_excludeEmpty() @@ -343,8 +450,10 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getAll] to ensure that all entries are returned from all `queueTypes` when no explicit `queueType` is provided. - * This also checks the returned object has a `non-null` value in the payload since the `detailed` flag is set to `true`. + * Test [MessageQueueController.getAll] to ensure that all entries are returned from all `queueTypes` when no + * explicit `queueType` is provided. + * This also checks the returned object has a `non-null` value in the payload since the `detailed` flag is set to + * `true`. */ @Test fun testGetAll() @@ -376,7 +485,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getAll] to ensure that all entries are returned from the `queueType` when an explicit `queueType` is provided. + * Test [MessageQueueController.getAll] to ensure that all entries are returned from the `queueType` when an + * explicit `queueType` is provided. * This also checks the returned object has `null` in the payload since the `detailed` flag is not provided. */ @Test @@ -399,14 +509,110 @@ class MessageQueueControllerTest Assertions.assertTrue(keys.keys.contains(type)) keys.values.forEach { detailList -> Assertions.assertEquals(1, detailList.size) } Assertions.assertEquals(entries.first[0].removePayload(false).uuid, keys[type]!![0].uuid) - // Since we did not pass a detailed flag value, ensure the payload is null + // Since we did not pass a detailed flag value, ensure the payload is a placeholder value Assertions.assertEquals("***", entries.first[0].removePayload(false).payload) Assertions.assertEquals(entries.first[0].removePayload(false).assignedTo, keys[type]!![0].assignedTo) Assertions.assertEquals(entries.first[0].removePayload(false).type, keys[type]!![0].type) } /** - * Test [MessageQueueController.getOwned] to ensure that no entries are returned when no [QueueMessage] are assigned by the provided `assignedTo` parameter. + * Ensure then when in [MultiQueueAuthenticationType.HYBRID] and [MessageQueueController.getAll] is called + * that restricted queues are not included until a valid token is provided. + */ + @Test + fun testGetAll_inHybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val queueType = "testGetAll_inHybridMode" + val messages = listOf(createQueueMessage(queueType), createQueueMessage(queueType)) + messages.forEach { message -> Assertions.assertTrue(multiQueue.add(message)) } + + Assertions.assertTrue(authenticator.addRestrictedEntry(queueType)) + Assertions.assertTrue(authenticator.isRestricted(queueType)) + + val token = jwtTokenProvider.createTokenForSubQueue(queueType) + Assertions.assertTrue(token.isPresent) + + val entries = initialiseMapWithEntries() + entries.second.forEach { type -> Assertions.assertFalse(authenticator.isRestricted(type)) } + val detailed = true + + // Ensure the message in the restricted queue type are not returned + var mvcResult: MvcResult = mockMvc.perform(get("${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}/${MessageQueueController.ENDPOINT_ALL}?${RestParameters.DETAILED}=$detailed") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val mapType = object : TypeToken>>() {}.type + var keys = gson.fromJson>>(mvcResult.response.contentAsString, mapType) + Assertions.assertNotNull(keys) + Assertions.assertEquals(entries.second.size, keys.keys.size) + + Assertions.assertFalse(keys.keys.contains(queueType)) + Assertions.assertNull(keys[queueType]) + + // After providing the token we should see the messages for the restricted queue + mvcResult = mockMvc.perform(get("${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}/${MessageQueueController.ENDPOINT_ALL}?${RestParameters.DETAILED}=$detailed") + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + keys = gson.fromJson(mvcResult.response.contentAsString, mapType) + Assertions.assertNotNull(keys) + Assertions.assertEquals(entries.second.size + 1, keys.keys.size) + + Assertions.assertTrue(keys.keys.contains(queueType)) + Assertions.assertNotNull(keys[queueType]) + } + + /** + * Ensure then when in [MultiQueueAuthenticationType.HYBRID] and [MessageQueueController.getAll] is called + * and all messages are requested for a restricted queue are not accessible unless a token is provided. + */ + @Test + fun testGetAll_SpecificQueueType_inHybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val queueType = "testGetAll_SpecificQueueType_inHybridMode" + val messages = listOf(createQueueMessage(queueType), createQueueMessage(queueType)) + messages.forEach { message -> Assertions.assertTrue(multiQueue.add(message)) } + + Assertions.assertTrue(authenticator.addRestrictedEntry(queueType)) + Assertions.assertTrue(authenticator.isRestricted(queueType)) + + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ALL) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.QUEUE_TYPE, queueType)) + .andExpect(MockMvcResultMatchers.status().isForbidden) + + val token = jwtTokenProvider.createTokenForSubQueue(queueType) + Assertions.assertTrue(token.isPresent) + + val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ALL) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.QUEUE_TYPE, queueType)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val mapType = object : TypeToken>>() {}.type + val keys = gson.fromJson>>(mvcResult.response.contentAsString, mapType) + Assertions.assertNotNull(keys) + Assertions.assertEquals(1, keys.keys.size) + + Assertions.assertTrue(keys.keys.contains(queueType)) + Assertions.assertNotNull(keys[queueType]) + Assertions.assertEquals(2, keys[queueType]!!.size) + } + + /** + * Test [MessageQueueController.getOwned] to ensure that no entries are returned when no [QueueMessage] are + * assigned by the provided `assignedTo` parameter. */ @Test fun testGetOwned_NoneOwned() @@ -429,7 +635,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getOwned] to ensure that all appropriate [QueueMessage] entries are returned when the provided `assignedTo` parameter owns the existing [QueueMessage]. + * Test [MessageQueueController.getOwned] to ensure that all appropriate [QueueMessage] entries are returned when + * the provided `assignedTo` parameter owns the existing [QueueMessage]. */ @Test fun testGetOwned_SomeOwned() @@ -463,7 +670,57 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.assignMessage] to ensure that [HttpStatus.NO_CONTENT] is returned when a [QueueMessage] with the provided [UUID] does not exist. + * Ensure when [MessageQueueController.getOwned] is called on a restricted sub-queue that no entries are returned + * unless a valid token is provided. + */ + @Test + fun testGetOwned_SomeOwned_inHybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val assignedTo = "my-assigned-to-identifier" + val type = "testGetOwned_SomeOwned_inHybridMode" + val message1 = createQueueMessage(assignedTo = assignedTo, type = type) + val message2 = createQueueMessage(assignedTo = assignedTo, type = type) + + Assertions.assertTrue(multiQueue.add(message1)) + Assertions.assertTrue(multiQueue.add(message2)) + + Assertions.assertTrue(authenticator.addRestrictedEntry(type)) + Assertions.assertTrue(authenticator.isRestricted(type)) + + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_OWNED) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.ASSIGNED_TO, assignedTo) + .param(RestParameters.QUEUE_TYPE, type)) + .andExpect(MockMvcResultMatchers.status().isForbidden) + + val token = jwtTokenProvider.createTokenForSubQueue(type) + Assertions.assertTrue(token.isPresent) + + val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_OWNED) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.ASSIGNED_TO, assignedTo) + .param(RestParameters.QUEUE_TYPE, type)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val listType = object : TypeToken>() {}.type + val owned = gson.fromJson>(mvcResult.response.contentAsString, listType) + Assertions.assertTrue(owned.isNotEmpty()) + owned.forEach { message -> + Assertions.assertTrue(message.message.uuid == message1.uuid || message.message.uuid == message2.uuid) + Assertions.assertEquals(type, message.queueType) + Assertions.assertEquals(type, message.message.type) + Assertions.assertEquals(assignedTo, message.message.assignedTo) + } + } + + /** + * Test [MessageQueueController.assignMessage] to ensure that [HttpStatus.NO_CONTENT] is returned when a + * [QueueMessage] with the provided [UUID] does not exist. */ @Test fun testAssignMessage_doesNotExist() @@ -479,7 +736,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.assignMessage] to ensure that the message is assigned correctly and [HttpStatus.OK] is returned when the [QueueMessage] was initially not assigned. + * Test [MessageQueueController.assignMessage] to ensure that the message is assigned correctly and [HttpStatus.OK] + * is returned when the [QueueMessage] was initially not assigned. */ @Test fun testAssignMessage_messageIsAssigned() @@ -507,7 +765,51 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.assignMessage] to ensure that the message is assigned correctly and [HttpStatus.ACCEPTED] is returned when the [QueueMessage] is already assigned by the provided `assignTo` identifier. + * Ensure when [MessageQueueController.assignMessage] is called in [MultiQueueAuthenticationType.HYBRID] mode + * that the message is not assigned or changed if the sub-queue is restricted and a valid token is not provided. + */ + @Test + fun testAssignMessage_messageIsAssigned_inHybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val assignedTo = "assigned" + val message = createQueueMessage(type = "testAssignMessage_messageIsAssigned_inHybridMode") + Assertions.assertNull(message.assignedTo) + Assertions.assertTrue(multiQueue.add(message)) + + Assertions.assertTrue(authenticator.addRestrictedEntry(message.type)) + Assertions.assertTrue(authenticator.isRestricted(message.type)) + + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + message.uuid) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.ASSIGNED_TO, assignedTo)) + .andExpect(MockMvcResultMatchers.status().isForbidden) + + val token = jwtTokenProvider.createTokenForSubQueue(message.type) + Assertions.assertTrue(token.isPresent) + + val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + message.uuid) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.ASSIGNED_TO, assignedTo)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val messageResponse = gson.fromJson(mvcResult.response.contentAsString, MessageResponse::class.java) + Assertions.assertEquals(assignedTo, messageResponse.message.assignedTo) + Assertions.assertEquals(message.uuid, messageResponse.message.uuid) + + val assignedMessage = multiQueue.peekForType(message.type).get() + Assertions.assertEquals(assignedTo, assignedMessage.assignedTo) + Assertions.assertEquals(message.uuid, assignedMessage.uuid) + } + + /** + * Test [MessageQueueController.assignMessage] to ensure that the message is assigned correctly and + * [HttpStatus.ACCEPTED] is returned when the [QueueMessage] is already assigned by the provided `assignTo` + * identifier. */ @Test fun testAssignMessage_alreadyAssignedToSameID() @@ -536,7 +838,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.assignMessage] to ensure that [HttpStatus.CONFLICT] is returned when the [QueueMessage] is already assigned to another identifier. + * Test [MessageQueueController.assignMessage] to ensure that [HttpStatus.CONFLICT] is returned when the + * [QueueMessage] is already assigned to another identifier. */ @Test fun testAssignMessage_alreadyAssignedToOtherID() @@ -567,7 +870,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getNext] to ensure [HttpStatus.NO_CONTENT] is returned when there are no [QueueMessage]s available for the provided `queueType`. + * Test [MessageQueueController.getNext] to ensure [HttpStatus.NO_CONTENT] is returned when there are no + * [QueueMessage]s available for the provided `queueType`. */ @Test fun testGetNext_noNewMessages() @@ -586,7 +890,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getNext] to ensure that [HttpStatus.NO_CONTENT] is returned if there are no `assigned` [QueueMessage]s available. + * Test [MessageQueueController.getNext] to ensure that [HttpStatus.NO_CONTENT] is returned if there are no + * `assigned` [QueueMessage]s available. */ @Test fun testGetNext_noNewUnAssignedMessages() @@ -611,7 +916,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getNext] to ensure that the correct next message is returned if it exists in the [MultiQueue]. + * Test [MessageQueueController.getNext] to ensure that the correct next message is returned if it exists in + * the [MultiQueue]. */ @Test fun testGetNext() @@ -647,7 +953,59 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.releaseMessage] to ensure that [HttpStatus.NO_CONTENT] is returned when a [QueueMessage] with the provided [UUID] does not exist. + * Ensure that when in [MultiQueueAuthenticationType.HYBRID] mode that the next message for a restricted sub-queue + * cannot be retrieved without a valid token being provided. + */ + @Test + fun testGetNext_inHybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val assignedTo = "assignee" + val type = "testGetNext_inHybridMode" + val message = createQueueMessage(type = type, assignedTo = assignedTo) + val message2 = createQueueMessage(type = type) + + Assertions.assertTrue(multiQueue.add(message)) + Assertions.assertTrue(multiQueue.add(message2)) + + Assertions.assertTrue(authenticator.addRestrictedEntry(type)) + Assertions.assertTrue(authenticator.isRestricted(type)) + + val storedMessage2 = multiQueue.getQueueForType(type).stream().filter{ m -> m.uuid == message2.uuid }.findFirst().get() + Assertions.assertNull(storedMessage2.assignedTo) + Assertions.assertEquals(message2.uuid, storedMessage2.uuid) + + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.QUEUE_TYPE, type) + .param(RestParameters.ASSIGNED_TO, assignedTo)) + .andExpect(MockMvcResultMatchers.status().isForbidden) + + val token = jwtTokenProvider.createTokenForSubQueue(type) + Assertions.assertTrue(token.isPresent) + + val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.QUEUE_TYPE, type) + .param(RestParameters.ASSIGNED_TO, assignedTo)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val messageResponse = gson.fromJson(mvcResult.response.contentAsString, MessageResponse::class.java) + Assertions.assertEquals(assignedTo, messageResponse.message.assignedTo) + Assertions.assertEquals(message2.uuid, messageResponse.message.uuid) + + val assignedMessage2 = multiQueue.getQueueForType(type).stream().filter{ m -> m.uuid == message2.uuid }.findFirst().get() + Assertions.assertEquals(assignedTo, assignedMessage2.assignedTo) + Assertions.assertEquals(message2.uuid, assignedMessage2.uuid) + } + + /** + * Test [MessageQueueController.releaseMessage] to ensure that [HttpStatus.NO_CONTENT] is returned when a + * [QueueMessage] with the provided [UUID] does not exist. */ @Test fun testReleaseMessage_doesNotExist() @@ -661,7 +1019,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.releaseMessage] to ensure that the [QueueMessage] is released if it is currently assigned. + * Test [MessageQueueController.releaseMessage] to ensure that the [QueueMessage] is released if it is currently + * assigned. */ @Test fun testReleaseMessage_messageIsReleased() @@ -690,7 +1049,52 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.releaseMessage] to ensure that the [QueueMessage] is released if it is currently assigned. Even when the `assignedTo` is not provided. + * Ensure that when in [MultiQueueAuthenticationType.HYBRID] mode that a restricted sub-queue cannot have its + * message released without a valid token being provided. + */ + @Test + fun testReleaseMessage_messageIsReleased_inHybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val assignedTo = "assignee" + val message = createQueueMessage(type = "testReleaseMessage_messageIsReleased_inHybridMode", assignedTo = assignedTo) + + Assertions.assertEquals(assignedTo, message.assignedTo) + Assertions.assertTrue(multiQueue.add(message)) + + Assertions.assertTrue(authenticator.addRestrictedEntry(message.type)) + Assertions.assertTrue(authenticator.isRestricted(message.type)) + + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + message.uuid) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.ASSIGNED_TO, assignedTo)) + .andExpect(MockMvcResultMatchers.status().isForbidden) + + + val token = jwtTokenProvider.createTokenForSubQueue(message.type) + Assertions.assertTrue(token.isPresent) + + val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + message.uuid) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.ASSIGNED_TO, assignedTo)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val messageResponse = gson.fromJson(mvcResult.response.contentAsString, MessageResponse::class.java) + Assertions.assertNull(messageResponse.message.assignedTo) + Assertions.assertEquals(message.uuid, messageResponse.message.uuid) + + val updatedMessage = multiQueue.peekForType(message.type).get() + Assertions.assertNull(updatedMessage.assignedTo) + Assertions.assertEquals(message.uuid, updatedMessage.uuid) + } + + /** + * Test [MessageQueueController.releaseMessage] to ensure that the [QueueMessage] is released if it is currently + * assigned. Even when the `assignedTo` is not provided. */ @Test fun testReleaseMessage_messageIsReleased_withoutAssignedToInQuery() @@ -718,7 +1122,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.releaseMessage] to ensure that [HttpStatus.ACCEPTED] is returned if the message is already released and not owned by anyone. + * Test [MessageQueueController.releaseMessage] to ensure that [HttpStatus.ACCEPTED] is returned if the message + * is already released and not owned by anyone. */ @Test fun testReleaseMessage_alreadyReleased() @@ -745,7 +1150,9 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.releaseMessage] to ensure that [HttpStatus.CONFLICT] is returned if `assignedTo` is provided and does not match the [QueueMessage.assignedTo], meaning the user cannot `release` the [QueueMessage] if it's not the current [QueueMessage.assignedTo] of the [QueueMessage]. + * Test [MessageQueueController.releaseMessage] to ensure that [HttpStatus.CONFLICT] is returned if `assignedTo` + * is provided and does not match the [QueueMessage.assignedTo], meaning the user cannot `release` the + * [QueueMessage] if it's not the current [QueueMessage.assignedTo] of the [QueueMessage]. */ @Test fun testReleaseMessage_cannotBeReleasedWithMisMatchingID() @@ -769,7 +1176,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.removeMessage] to ensure that [HttpStatus.NO_CONTENT] is returned when a [QueueMessage] with the provided [UUID] does not exist. + * Test [MessageQueueController.removeMessage] to ensure that [HttpStatus.NO_CONTENT] is returned when a + * [QueueMessage] with the provided [UUID] does not exist. */ @Test fun testRemoveMessage_notFound() @@ -784,7 +1192,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.removeMessage] to ensure that a [HttpStatus.OK] is returned when the message is correctly removed. + * Test [MessageQueueController.removeMessage] to ensure that a [HttpStatus.OK] is returned when the message is + * correctly removed. */ @Test fun testRemoveMessage_removeExistingEntry() @@ -804,7 +1213,41 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.removeMessage] to ensure that a [HttpStatus.NO_CONTENT] is returned when the matching message does not exist. + * Ensure when in [MultiQueueAuthenticationType.HYBRID] mode that messages cannot be removed unless a valid + * token is provided on a restricted sub-queue. + */ + @Test + fun testRemoveMessage_removeExistingEntry_inHybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val message = createQueueMessage(type = "testRemoveMessage_removeExistingEntry_inHybridMode") + Assertions.assertTrue(multiQueue.add(message)) + Assertions.assertTrue(multiQueue.containsUUID(message.uuid).isPresent) + + Assertions.assertTrue(authenticator.addRestrictedEntry(message.type)) + Assertions.assertTrue(authenticator.isRestricted(message.type)) + + mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isForbidden) + + val token = jwtTokenProvider.createTokenForSubQueue(message.type) + Assertions.assertTrue(token.isPresent) + + mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + + Assertions.assertFalse(multiQueue.containsUUID(message.uuid).isPresent) + Assertions.assertTrue(multiQueue.getQueueForType(message.type).isEmpty()) + } + + /** + * Test [MessageQueueController.removeMessage] to ensure that a [HttpStatus.NO_CONTENT] is returned when the + * matching message does not exist. */ @Test fun testRemoveMessage_doesNotExist() @@ -822,7 +1265,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.removeMessage] to ensure that [HttpStatus.FORBIDDEN] is returned if the message is attempting to be removed while another user is consuming it. + * Test [MessageQueueController.removeMessage] to ensure that [HttpStatus.FORBIDDEN] is returned if the message is + * attempting to be removed while another user is consuming it. */ @Test fun testRemoveMessage_assignedToAnotherID() @@ -844,7 +1288,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getOwners] with a provided `queueType` parameter to ensure the appropriate map is provided in the response and [HttpStatus.OK] is returned. + * Test [MessageQueueController.getOwners] with a provided `queueType` parameter to ensure the appropriate map is + * provided in the response and [HttpStatus.OK] is returned. */ @Test fun testGetOwners_withQueueType() @@ -886,7 +1331,8 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getOwners] without a provided `queueType` parameter to ensure the appropriate map is provided in the response and [HttpStatus.OK] is returned. + * Test [MessageQueueController.getOwners] without a provided `queueType` parameter to ensure the appropriate map + * is provided in the response and [HttpStatus.OK] is returned. */ @Test fun testGetOwners_withoutQueueType() @@ -929,7 +1375,8 @@ class MessageQueueControllerTest } /** - * Perform a health check call on the [MessageQueueController] to ensure a [HttpStatus.OK] is returned when the application is running ok. + * Ensure a call to the [MessageQueueController.getHealthCheck] to ensure a [HttpStatus.OK] is returned when the + * application is running ok. */ @Test fun testGetPerformHealthCheck() @@ -943,7 +1390,8 @@ class MessageQueueControllerTest } /** - * Ensure that the [CorrelationIdFilter] will generate a random Correlation ID when one is not provided and that it is returned in the [MessageResponse]. + * Ensure that the [CorrelationIdFilter] will generate a random Correlation ID when one is not provided and that + * it is returned in the [MessageResponse]. */ @Test fun testCorrelationId_randomIdOnSuccess() @@ -964,7 +1412,8 @@ class MessageQueueControllerTest } /** - * Ensure that the [CorrelationIdFilter] will use the same correlationID that is provided is used and returned in the [MessageResponse]. + * Ensure that the [CorrelationIdFilter] will use the same correlationID that is provided is used and returned in + * the [MessageResponse]. */ @Test fun testCorrelationId_providedId() @@ -986,7 +1435,8 @@ class MessageQueueControllerTest } /** - * Ensure that the [CorrelationIdFilter] will generate a random Correlation ID is generated on error and returned in the response. + * Ensure that the [CorrelationIdFilter] will generate a random Correlation ID is generated on error and returned + * in the response. */ @Test fun testCorrelationId_randomIdOnError() @@ -1013,7 +1463,8 @@ class MessageQueueControllerTest } /** - * Ensure that [MessageQueueController.deleteKeys] will only delete keys by the specified [RestParameters.QUEUE_TYPE] when it is provided and that other sub queues are not cleared. + * Ensure that [MessageQueueController.deleteKeys] will only delete keys by the specified + * [RestParameters.QUEUE_TYPE] when it is provided and that other sub queues are not cleared. */ @Test fun testDeleteKeys_singleKey() @@ -1021,20 +1472,14 @@ class MessageQueueControllerTest Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) val subQueue1 = "testDeleteKeys_singleKey1" - var message = createQueueMessage(subQueue1) - Assertions.assertTrue(multiQueue.add(message)) - message = createQueueMessage(subQueue1) - Assertions.assertTrue(multiQueue.add(message)) - message = createQueueMessage(subQueue1) - Assertions.assertTrue(multiQueue.add(message)) + var messages = listOf(createQueueMessage(subQueue1), createQueueMessage(subQueue1), createQueueMessage(subQueue1)) + messages.forEach { message -> Assertions.assertTrue(multiQueue.add(message)) } Assertions.assertEquals(3, multiQueue.size) val subQueue2 = "testDeleteKeys_singleKey2" - message = createQueueMessage(subQueue2) - Assertions.assertTrue(multiQueue.add(message)) - message = createQueueMessage(subQueue2) - Assertions.assertTrue(multiQueue.add(message)) + messages = listOf(createQueueMessage(subQueue2), createQueueMessage(subQueue2)) + messages.forEach { message -> Assertions.assertTrue(multiQueue.add(message)) } Assertions.assertEquals(5, multiQueue.size) @@ -1052,7 +1497,64 @@ class MessageQueueControllerTest } /** - * Ensure that [MessageQueueController.deleteKeys] will only delete all keys/queues when the provided [RestParameters.QUEUE_TYPE] is `null`. + * Ensure that when in [MultiQueueAuthenticationType.HYBRID] mode any restricted sub-queues cannot be deleted + * unless a valid token is provided. + */ + @Test + fun testDeleteKeys_singleKey_inHybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val subQueue1 = "testDeleteKeys_singleKey_inHybridMode1" + var messages = listOf(createQueueMessage(subQueue1), createQueueMessage(subQueue1), createQueueMessage(subQueue1)) + messages.forEach { message -> Assertions.assertTrue(multiQueue.add(message)) } + + Assertions.assertEquals(3, multiQueue.size) + + val subQueue2 = "testDeleteKeys_singleKey_inHybridMode2" + messages = listOf(createQueueMessage(subQueue2), createQueueMessage(subQueue2)) + messages.forEach { message -> Assertions.assertTrue(multiQueue.add(message)) } + + Assertions.assertEquals(5, multiQueue.size) + + Assertions.assertTrue(multiQueue.keys().contains(subQueue1)) + Assertions.assertTrue(multiQueue.keys().contains(subQueue2)) + + Assertions.assertTrue(authenticator.addRestrictedEntry(subQueue2)) + Assertions.assertTrue(authenticator.isRestricted(subQueue2)) + + mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.QUEUE_TYPE, subQueue1)) + .andExpect(MockMvcResultMatchers.status().isNoContent) + + Assertions.assertEquals(2, multiQueue.size) + Assertions.assertFalse(multiQueue.keys().contains(subQueue1)) + Assertions.assertTrue(multiQueue.keys().contains(subQueue2)) + + mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.QUEUE_TYPE, subQueue2)) + .andExpect(MockMvcResultMatchers.status().isForbidden) + + val token = jwtTokenProvider.createTokenForSubQueue(subQueue2) + Assertions.assertTrue(token.isPresent) + + mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .param(RestParameters.QUEUE_TYPE, subQueue2)) + .andExpect(MockMvcResultMatchers.status().isNoContent) + + Assertions.assertEquals(0, multiQueue.size) + Assertions.assertFalse(multiQueue.keys().contains(subQueue1)) + Assertions.assertFalse(multiQueue.keys().contains(subQueue2)) + } + + /** + * Ensure that [MessageQueueController.deleteKeys] will only delete all keys/queues when the provided + * [RestParameters.QUEUE_TYPE] is `null`. */ @Test fun testDeleteKeys_allKeys() @@ -1071,10 +1573,48 @@ class MessageQueueControllerTest types.forEach { type -> Assertions.assertFalse(multiQueue.keys().contains(type)) } } + /** + * Ensure that when in [MultiQueueAuthenticationType.HYBRID] mode any restricted sub-queues cannot be deleted + * unless a valid token is provided. + */ + @Test + fun testDeleteKeys_allKeys_inHybridMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + + val (messages, types) = initialiseMapWithEntries() + Assertions.assertEquals(messages.size, multiQueue.size) + types.forEach { type -> Assertions.assertTrue(multiQueue.keys().contains(type)) } + + Assertions.assertTrue(authenticator.addRestrictedEntry(types[0])) + Assertions.assertTrue(authenticator.isRestricted(types[0])) + + mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isPartialContent) + + Assertions.assertEquals(1, multiQueue.size) + Assertions.assertTrue(multiQueue.keys().contains(types[0])) + types.subList(1, types.size - 1).forEach { type -> Assertions.assertFalse(multiQueue.keys().contains(type)) } + + val token = jwtTokenProvider.createTokenForSubQueue(types[0]) + Assertions.assertTrue(token.isPresent) + + mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNoContent) + + Assertions.assertTrue(multiQueue.isEmpty()) + types.forEach { type -> Assertions.assertFalse(multiQueue.keys().contains(type)) } + } + /** * `Mock Test`. * - * Perform a health check call on the [MessageQueueController] to ensure a [HttpStatus.INTERNAL_SERVER_ERROR] is returned when the health check fails. + * Perform a health check call to the [MessageQueueController.getHealthCheck] to ensure a + * [HttpStatus.INTERNAL_SERVER_ERROR] is returned when the health check fails. */ @Test fun testGetPerformHealthCheck_failureResponse() @@ -1110,73 +1650,84 @@ class MessageQueueControllerTest } /** - * + * Ensure that when [MultiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.RESTRICTED] that any + * of the endpoints not in the [JwtAuthenticationFilter.urlRequiresAuthentication] whitelist will be inaccessible. */ @Test - fun testGetEntry_usingHybridMode_withRestrictedSubQueue() + fun testRestrictedModeMakesAllEndpointsInaccessibleWithoutAToken() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) - - val entries = initialiseMapWithEntries() - - val type1 = entries.second[0] - val message1 = entries.first[0] - val type1Token = jwtTokenProvider.createTokenForSubQueue(type1) - Assertions.assertTrue(type1Token.isPresent) - Assertions.assertTrue(authenticator.addRestrictedEntry(type1)) - Assertions.assertTrue(authenticator.isRestricted(type1)) + Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, authenticator.getAuthenticationType()) - // Checking 403 is returned without a token - mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message1.uuid) + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + UUID.randomUUID().toString()) .contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().isForbidden) + .andExpect(MockMvcResultMatchers.status().isUnauthorized) - // Checking entry is retrieve with provided token - val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message1.uuid) - .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${type1Token.get()}") + mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + UUID.randomUUID().toString()) .contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().isOk) - .andReturn() + .andExpect(MockMvcResultMatchers.status().isUnauthorized) - val messageResponse = gson.fromJson(mvcResult.response.contentAsString, MessageResponse::class.java) + val message = QueueMessage("", "testRestrictedModeMakesAllEndpointsInaccessible") + mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) + .content(gson.toJson(message)) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized) - val deserialisedPayload = gson.fromJson(gson.toJson(messageResponse.message.payload), Payload::class.java) - Assertions.assertEquals(message1.payload, deserialisedPayload) - Assertions.assertNull(messageResponse.message.assignedTo) - Assertions.assertEquals(message1.type, messageResponse.message.type) - Assertions.assertEquals(message1.type, messageResponse.queueType) - Assertions.assertNotNull(messageResponse.message.uuid) + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + UUID.randomUUID().toString()) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized) - val type2 = entries.second[1] - val message2 = entries.first[1] - Assertions.assertFalse(authenticator.isRestricted(type2)) + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + UUID.randomUUID().toString()) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized) - val mvcResult2: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message2.uuid) - .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${type1Token.get()}") + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT + "?" + RestParameters.QUEUE_TYPE +"=someType&" + RestParameters.ASSIGNED_TO + "=me") .contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().isOk) - .andReturn() + .andExpect(MockMvcResultMatchers.status().isUnauthorized) - val messageResponse2 = gson.fromJson(mvcResult2.response.contentAsString, MessageResponse::class.java) + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ALL) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized) - val deserialisedPayload2 = gson.fromJson(gson.toJson(messageResponse2.message.payload), Payload::class.java) - Assertions.assertEquals(message2.payload, deserialisedPayload2) - Assertions.assertNull(messageResponse2.message.assignedTo) - Assertions.assertEquals(message2.type, messageResponse2.message.type) - Assertions.assertEquals(message2.type, messageResponse2.queueType) - Assertions.assertNotNull(messageResponse2.message.uuid) + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_OWNED + "?" + RestParameters.QUEUE_TYPE +"=someType&" + RestParameters.ASSIGNED_TO + "=me") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized) } + /** + * Ensure that the [JwtAuthenticationFilter] will respond with [HttpStatus.UNAUTHORIZED] when no token is provided, + * and it is in [MultiQueueAuthenticationType.RESTRICTED] mode. + */ @Test - fun testRestrictedModeMakesAllEndpointsInaccessible() + fun testGetEntry_inRestrictedMode() { Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, authenticator.getAuthenticationType()) - mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + UUID.randomUUID().toString()) + val type = "testRestrictedMode_getByUUID" + val message = createQueueMessage(type) + + Assertions.assertTrue(multiQueue.add(message)) + + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized) + + val token = jwtTokenProvider.createTokenForSubQueue(type) + Assertions.assertTrue(token.isPresent) + + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) + + Assertions.assertTrue(authenticator.addRestrictedEntry(type)) + Assertions.assertTrue(authenticator.isRestricted(type)) + + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid) + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) } /** From 5081dd641f697748ab753bcc420a9d2e12ed2d48 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Wed, 8 Nov 2023 22:37:22 +1100 Subject: [PATCH 35/58] Resolve warning on logger initialisation call. --- .../authenticator/cache/redis/RedisAuthenticator.kt | 2 +- .../authenticator/inmemory/InMemoryAuthenticator.kt | 2 +- .../authenticator/nosql/mongo/MongoAuthenticator.kt | 2 +- .../authentication/authenticator/sql/SqlAuthenticator.kt | 2 +- .../au/kilemon/messagequeue/configuration/QueueConfiguration.kt | 2 +- .../configuration/cache/redis/RedisConfiguration.kt | 2 +- .../au/kilemon/messagequeue/filter/CorrelationIdFilter.kt | 2 +- src/main/kotlin/au/kilemon/messagequeue/logging/HasLogger.kt | 2 +- .../au/kilemon/messagequeue/logging/LoggingConfiguration.kt | 2 +- .../kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt | 2 +- .../kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt | 2 +- .../kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt | 2 +- .../kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt | 2 +- .../messagequeue/rest/controller/MessageQueueController.kt | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt index 8d50b61..91b2739 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt @@ -19,7 +19,7 @@ class RedisAuthenticator: MultiQueueAuthenticator() const val RESTRICTED_KEY = AuthenticationMatrix.TABLE_NAME + "_restricted" } - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() @Autowired lateinit var redisTemplate: RedisTemplate diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt index 0316d52..8dcd51d 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticator.kt @@ -11,7 +11,7 @@ import org.slf4j.Logger */ class InMemoryAuthenticator: MultiQueueAuthenticator() { - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() private val restrictedSubQueues = HashSet() diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt index ed26b83..6454051 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt @@ -13,7 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired */ class MongoAuthenticator: MultiQueueAuthenticator() { - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() @Autowired lateinit var authenticationMatrixRepository: MongoAuthenticationMatrixRepository diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt index 353584c..5d7b92e 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt @@ -13,7 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired */ class SqlAuthenticator: MultiQueueAuthenticator() { - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() @Autowired lateinit var authenticationMatrixRepository: SqlAuthenticationMatrixRepository diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt index 5c7baf6..98af556 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt @@ -37,7 +37,7 @@ import java.util.* @Configuration class QueueConfiguration : HasLogger { - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() @Autowired private lateinit var messageQueueSettings: MessageQueueSettings diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt index 8f34cb1..38faaa5 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt @@ -28,7 +28,7 @@ import java.net.InetSocketAddress @Configuration class RedisConfiguration: HasLogger { - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() companion object { diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/CorrelationIdFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/CorrelationIdFilter.kt index 4f0a3e2..20f170d 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/CorrelationIdFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/CorrelationIdFilter.kt @@ -30,7 +30,7 @@ class CorrelationIdFilter: OncePerRequestFilter(), HasLogger const val CORRELATION_ID = "correlationId" } - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) { diff --git a/src/main/kotlin/au/kilemon/messagequeue/logging/HasLogger.kt b/src/main/kotlin/au/kilemon/messagequeue/logging/HasLogger.kt index 4b511c2..0b67d72 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/logging/HasLogger.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/logging/HasLogger.kt @@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory * ``` * class ALogger: HasLogger * { - * override val LOG: Logger = initialiseLogger() + * override val LOG: Logger = this.initialiseLogger() * ... * fun function() * { diff --git a/src/main/kotlin/au/kilemon/messagequeue/logging/LoggingConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/logging/LoggingConfiguration.kt index 5d8b3b0..9defbf2 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/logging/LoggingConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/logging/LoggingConfiguration.kt @@ -14,7 +14,7 @@ import java.util.* @Configuration class LoggingConfiguration : HasLogger { - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() companion object { diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt index 9a9bb3e..9b15804 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt @@ -23,7 +23,7 @@ import kotlin.collections.HashMap */ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate: RedisTemplate) : MultiQueue(), HasLogger { - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() /** * Append the [MessageQueueSettings.redisPrefix] to the provided [queueType] [String]. diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt index a7bfefd..c952420 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt @@ -21,7 +21,7 @@ import kotlin.jvm.Throws */ open class InMemoryMultiQueue : MultiQueue(), HasLogger { - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() /** * An internal [Map] that holds known [UUID]s (as a [String]) and their related `queueType` to quickly find entries within the [MultiQueue]. diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt index e1fb803..7b02fc7 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt @@ -26,7 +26,7 @@ class MongoMultiQueue : MultiQueue(), HasLogger const val INDEX_ID = "index_id" } - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() @Lazy @Autowired diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt index 8457cde..6f64c28 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt @@ -19,7 +19,7 @@ import java.util.concurrent.ConcurrentLinkedQueue */ class SqlMultiQueue : MultiQueue(), HasLogger { - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() @Lazy @Autowired diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt index cb414be..c9098cf 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt @@ -37,7 +37,7 @@ import javax.validation.Valid @RequestMapping(MessageQueueController.MESSAGE_QUEUE_BASE_PATH) open class MessageQueueController : HasLogger { - override val LOG: Logger = initialiseLogger() + override val LOG: Logger = this.initialiseLogger() companion object { From db9fa8308bc904fdfb75f400cb54197f43dbc910 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 11 Nov 2023 18:57:03 +1100 Subject: [PATCH 36/58] Bump to version 0.3.0. Bump gradle version up to 8.4.0 in docker file. --- Dockerfile | 2 +- build.gradle.kts | 2 +- .../kotlin/au/kilemon/messagequeue/MessageQueueApplication.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2530361..f6924de 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ # Push image to remote # docker push kilemon/message-queue:0.1.5 -FROM gradle:7.5.1-jdk17-alpine as builder +FROM gradle:8.4.0-jdk17-alpine as builder WORKDIR /builder diff --git a/build.gradle.kts b/build.gradle.kts index 55e2028..cb77cf3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ plugins { group = "au.kilemon" // Make sure version matches version defined in MessageQueueApplication -version = "0.2.1" +version = "0.3.0" java.sourceCompatibility = JavaVersion.VERSION_17 repositories { diff --git a/src/main/kotlin/au/kilemon/messagequeue/MessageQueueApplication.kt b/src/main/kotlin/au/kilemon/messagequeue/MessageQueueApplication.kt index f783dd5..9d6913b 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/MessageQueueApplication.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/MessageQueueApplication.kt @@ -17,7 +17,7 @@ open class MessageQueueApplication /** * Application version number, make sure this matches what is defined in `build.gradle.kts`. */ - const val VERSION: String = "0.2.1" + const val VERSION: String = "0.3.0" } } From 344d7f599bd07feab6c9c0d2082004b39984e915 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sat, 11 Nov 2023 19:10:48 +1100 Subject: [PATCH 37/58] Update container versions in tests for storage mechanisms. --- .../authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt | 2 +- .../cache/redis/RedisStandAloneAuthenticatorTest.kt | 2 +- .../authentication/authenticator/sql/MySqlAuthenticatorTest.kt | 2 +- .../authenticator/sql/PostgreSqlAuthenticatorTest.kt | 2 +- .../queue/cache/redis/RedisSentinelMultiQueueTest.kt | 2 +- .../queue/cache/redis/RedisStandAloneMultiQueueTest.kt | 2 +- .../au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt | 2 +- .../kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt index 8fad6c5..2c9c9e4 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt @@ -35,7 +35,7 @@ class RedisSentinelAuthenticatorTest: MultiQueueAuthenticatorTest() { companion object { - private const val REDIS_CONTAINER: String = "redis:7.0.5-alpine" + private const val REDIS_CONTAINER: String = "redis:7.2.3-alpine" private const val REDIS_SENTINEL_CONTAINER: String = "s7anley/redis-sentinel-docker:3.2.12" lateinit var redis: GenericContainer<*> diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt index 994949a..df7f3d8 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt @@ -38,7 +38,7 @@ class RedisStandAloneAuthenticatorTest: MultiQueueAuthenticatorTest() companion object { private const val REDIS_PORT: Int = 6379 - private const val REDIS_CONTAINER: String = "redis:7.0.5-alpine" + private const val REDIS_CONTAINER: String = "redis:7.2.3-alpine" lateinit var redis: GenericContainer<*> diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt index 35ac6f8..bd2ec17 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt @@ -38,7 +38,7 @@ class MySqlAuthenticatorTest: MultiQueueAuthenticatorTest() { lateinit var database: GenericContainer<*> - private const val MYSQL_CONTAINER = "mysql:8.0.31" + private const val MYSQL_CONTAINER = "mysql:8.0.35" private const val MYSQL_PORT = 3306 /** diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt index c7286c2..b4e43d9 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt @@ -38,7 +38,7 @@ class PostgreSqlAuthenticatorTest: MultiQueueAuthenticatorTest() { lateinit var database: GenericContainer<*> - private const val POSTGRES_CONTAINER = "postgres:14.5" + private const val POSTGRES_CONTAINER = "postgres:14.9-alpine" private const val POSTGRES_PORT = 5432 /** diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt index 2a2e52d..f15954f 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt @@ -37,7 +37,7 @@ class RedisSentinelMultiQueueTest: MultiQueueTest() { companion object { - private const val REDIS_CONTAINER: String = "redis:7.0.5-alpine" + private const val REDIS_CONTAINER: String = "redis:7.2.3-alpine" private const val REDIS_SENTINEL_CONTAINER: String = "s7anley/redis-sentinel-docker:3.2.12" lateinit var redis: GenericContainer<*> diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt index f031730..96c8ffb 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt @@ -48,7 +48,7 @@ class RedisStandAloneMultiQueueTest: MultiQueueTest() companion object { private const val REDIS_PORT: Int = 6379 - private const val REDIS_CONTAINER: String = "redis:7.0.5-alpine" + private const val REDIS_CONTAINER: String = "redis:7.2.3-alpine" lateinit var redis: GenericContainer<*> diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt index 5719d9a..d697817 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/MySqlMultiQueueTest.kt @@ -28,7 +28,7 @@ class MySqlMultiQueueTest : SqlMultiQueueTest() { lateinit var database: GenericContainer<*> - private const val MYSQL_CONTAINER = "mysql:8.0.31" + private const val MYSQL_CONTAINER = "mysql:8.0.35" private const val MYSQL_PORT = 3306 /** diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt index a01b4fb..4c9849f 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/PostgreSqlMultiQueueTest.kt @@ -29,7 +29,7 @@ class PostgreSqlMultiQueueTest: SqlMultiQueueTest() { lateinit var database: GenericContainer<*> - private const val POSTGRES_CONTAINER = "postgres:14.5" + private const val POSTGRES_CONTAINER = "postgres:14.9-alpine" private const val POSTGRES_PORT = 5432 /** From 52dc3d787b9559ea34d8a5f156b5c80b61f47fa0 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Mon, 13 Nov 2023 19:27:45 +1100 Subject: [PATCH 38/58] Add logging when clearing keys. --- .../rest/controller/MessageQueueController.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt index c9098cf..eb83fa9 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt @@ -25,6 +25,7 @@ import org.springframework.web.server.ResponseStatusException import java.util.* import java.util.stream.Collectors import javax.validation.Valid +import kotlin.collections.HashSet /** * The REST controller for the [MultiQueue]. It exposes endpoints to access and manipulate the queue and the messages inside it. @@ -270,25 +271,34 @@ open class MessageQueueController : HasLogger { authenticator.canAccessSubQueue(queueType) messageQueue.clearForType(queueType) + LOG.info("Cleared queue with key [{}]", queueType) return ResponseEntity.noContent().build() } else { + val clearedKeys = HashSet() + val retainedKeys = HashSet() var anyAreNotCleared = false + for (key in messageQueue.keys()) { if (authenticator.canAccessSubQueue(key, false)) { messageQueue.clearForType(key) + clearedKeys.add(key) } else { anyAreNotCleared = true + retainedKeys.add(key) } } + LOG.info("Cleared queue with keys: [{}]", clearedKeys) + return if (anyAreNotCleared) { + LOG.info("Retained queues with keys: [{}]", retainedKeys) ResponseEntity.status(HttpStatus.PARTIAL_CONTENT).build() } else From 664b41901a725ce0940475cdf21e89c79cd782de Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Mon, 13 Nov 2023 21:07:26 +1100 Subject: [PATCH 39/58] Fix look up by ID for SQLMultiQueue to return the payload correctly. --- .../au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt | 10 +++++++++- .../au/kilemon/messagequeue/queue/MultiQueueTest.kt | 5 ++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt index 6f64c28..c2748f1 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt @@ -64,7 +64,15 @@ class SqlMultiQueue : MultiQueue(), HasLogger override fun getMessageByUUID(uuid: String): Optional { - return queueMessageRepository.findByUuid(uuid) + val message = queueMessageRepository.findByUuid(uuid) + return if (message.isPresent) + { + Optional.of(message.get().resolvePayloadObject()) + } + else + { + Optional.empty() + } } override fun clearForTypeInternal(queueType: String): Int diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt index fea3213..02a332a 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt @@ -894,7 +894,10 @@ abstract class MultiQueueTest val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), type) Assertions.assertTrue(multiQueue.add(message)) - Assertions.assertEquals(message, multiQueue.getMessageByUUID(message.uuid).get()) + val retrievedMessage = multiQueue.getMessageByUUID(message.uuid) + Assertions.assertTrue(retrievedMessage.isPresent) + Assertions.assertEquals(message, retrievedMessage.get()) + Assertions.assertEquals(message.payload, retrievedMessage.get().payload) } /** From 05ddd399c0dd6b02d6d34637380b6c6152812c65 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Tue, 14 Nov 2023 18:40:02 +1100 Subject: [PATCH 40/58] Add endpoint to get all restricted sub-queue identifiers. --- .../filter/JwtAuthenticationFilter.kt | 1 + .../rest/controller/AuthController.kt | 17 +++++++ .../rest/controller/AuthControllerTest.kt | 45 +++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index f15207c..e8c8916 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -134,6 +134,7 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_HEALTH_CHECK}"), Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_KEYS}"), Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_OWNERS}"), + Pair(HttpMethod.GET, AuthController.AUTH_PATH), Pair(HttpMethod.POST, AuthController.AUTH_PATH), Pair(HttpMethod.GET, SettingsController.SETTINGS_PATH) ) diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt index 76df2d4..3ec0234 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt @@ -50,6 +50,23 @@ open class AuthController : HasLogger @Autowired private lateinit var jwtTokenProvider: JwtTokenProvider + @Operation(summary = "Get restricted sub-queue identifiers", description = "Get a list of the restricted sub-queue identifiers.") + @GetMapping("", produces = [MediaType.APPLICATION_JSON_VALUE]) + @ApiResponses( + ApiResponse(responseCode = "200", description = "Returns a list of sub-queues marked as restricted that require a token to interact with."), + ApiResponse(responseCode = "204", description = "The MultiQueue is in a no-auth mode and no sub-queues are marked as restricted.", content = [Content()]) + ) + fun getRestrictedSubQueueIdentifiers(): ResponseEntity> + { + if (multiQueueAuthenticator.isInNoneMode()) + { + LOG.trace("Returning no restricted identifiers since the authentication type is set to [{}].", multiQueueAuthenticator.getAuthenticationType()) + return ResponseEntity.noContent().build() + } + + return ResponseEntity.ok(multiQueueAuthenticator.getRestrictedSubQueueIdentifiers()) + } + @Operation(summary = "Create restriction on sub-queue.", description = "Create restriction a specific sub-queue to require authentication for future interactions and retrieve a token used to interact with this sub-queue.") @PostMapping("/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index 33439c2..7f52a8c 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -11,6 +11,7 @@ import au.kilemon.messagequeue.queue.MultiQueue import au.kilemon.messagequeue.rest.response.AuthResponse import au.kilemon.messagequeue.settings.MessageQueueSettings import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -386,4 +387,48 @@ class AuthControllerTest multiQueue.clear() } } + + /** + * Ensure [AuthController.getRestrictedSubQueueIdentifiers] returns [org.springframework.http.HttpStatus.NO_CONTENT] + * when the [MultiQueueAuthenticationType] is [MultiQueueAuthenticationType.NONE]. + */ + @Test + fun testGetRestrictedSubQueueIdentifiers_inNoneMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + + mockMvc.perform(MockMvcRequestBuilders.get(AuthController.AUTH_PATH) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNoContent) + } + + /** + * Ensure [AuthController.getRestrictedSubQueueIdentifiers] returns [org.springframework.http.HttpStatus.OK] + * when the [MultiQueueAuthenticationType] is not in [MultiQueueAuthenticationType.NONE]. + * And the response set matches the entries that are restricted. + */ + @Test + fun testGetRestrictedSubQueueIdentifiers_notInNoneMode() + { + Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + + val restrictedIdentifiers = setOf("testGetRestrictedSubQueueIdentifiers_inNoneMode1", "testGetRestrictedSubQueueIdentifiers_inNoneMode2", + "testGetRestrictedSubQueueIdentifiers_inNoneMode3", "testGetRestrictedSubQueueIdentifiers_inNoneMode4", "testGetRestrictedSubQueueIdentifiers_inNoneMode5") + + restrictedIdentifiers.forEach { identifier -> Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(identifier)) } + restrictedIdentifiers.forEach { identifier -> Assertions.assertTrue(multiQueueAuthenticator.isRestricted(identifier)) } + + val mvcResult: MvcResult = mockMvc.perform(MockMvcRequestBuilders.get(AuthController.AUTH_PATH) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + + val stringSetType = object : TypeToken>() {}.type + val identifiers = gson.fromJson>(mvcResult.response.contentAsString, stringSetType) + + Assertions.assertEquals(restrictedIdentifiers.size, identifiers.size) + identifiers.forEach { identifier -> Assertions.assertTrue(restrictedIdentifiers.contains(identifier)) } + } } From c85304a682515c44504ea1c819952f12128a71e6 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Tue, 14 Nov 2023 19:03:06 +1100 Subject: [PATCH 41/58] Changes paths for assign and release to be ".../entry//(assign/release)" --- .../rest/controller/MessageQueueController.kt | 4 +-- .../controller/MessageQueueControllerTest.kt | 30 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt index eb83fa9..2d9c958 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt @@ -380,7 +380,7 @@ open class MessageQueueController : HasLogger * @return the [QueueMessage] object after it has been marked as `assigned`. Returns [HttpStatus.ACCEPTED] if the [QueueMessage] is already assigned to the current user, otherwise [HttpStatus.OK] if it was not `assigned` previously. */ @Operation(summary = "Assign an existing queue message to the provided identifier.", description = "Assign an existing queue message to the provided identifier. The message must already exist and not be assigned already to another identifier in order to be successfully assigned to the provided identifier.") - @PutMapping("$ENDPOINT_ASSIGN/{${RestParameters.UUID}}", produces = [MediaType.APPLICATION_JSON_VALUE]) + @PutMapping("$ENDPOINT_ENTRY/{${RestParameters.UUID}}$ENDPOINT_ASSIGN", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( ApiResponse(responseCode = "200", description = "Successfully assigned the message to the provided identifier. The message was not previously assigned."), ApiResponse(responseCode = "202", description = "The message was already assigned to the provided identifier.", content = [Content()]), @@ -468,7 +468,7 @@ open class MessageQueueController : HasLogger * @return the [QueueMessage] object after it has been `released`. Returns [HttpStatus.ACCEPTED] if the [QueueMessage] is already `released`, otherwise [HttpStatus.OK] if it was `released` successfully. */ @Operation(summary = "Release the message assigned to the provided identifier.", description = "Release an assigned message so it can be assigned to another identifier.") - @PutMapping("$ENDPOINT_RELEASE/{${RestParameters.UUID}}", produces = [MediaType.APPLICATION_JSON_VALUE]) + @PutMapping("$ENDPOINT_ENTRY/{${RestParameters.UUID}}$ENDPOINT_RELEASE", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( ApiResponse(responseCode = "200", description = "Successfully released the message. The message was previously assigned."), ApiResponse(responseCode = "202", description = "The message is not currently assigned."), diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt index 91be09f..3c06fc0 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt @@ -729,7 +729,7 @@ class MessageQueueControllerTest val uuid = UUID.randomUUID().toString() val assignedTo = "assigned" - mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + uuid) + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + uuid + MessageQueueController.ENDPOINT_ASSIGN) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isNoContent) @@ -749,7 +749,7 @@ class MessageQueueControllerTest Assertions.assertNull(message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) - val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + message.uuid) + val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_ASSIGN) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isOk) @@ -782,7 +782,7 @@ class MessageQueueControllerTest Assertions.assertTrue(authenticator.addRestrictedEntry(message.type)) Assertions.assertTrue(authenticator.isRestricted(message.type)) - mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + message.uuid) + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_ASSIGN) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isForbidden) @@ -790,7 +790,7 @@ class MessageQueueControllerTest val token = jwtTokenProvider.createTokenForSubQueue(message.type) Assertions.assertTrue(token.isPresent) - val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + message.uuid) + val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_ASSIGN) .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo)) @@ -822,7 +822,7 @@ class MessageQueueControllerTest Assertions.assertEquals(assignedTo, message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) - val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + message.uuid) + val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_ASSIGN) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isAccepted) @@ -858,7 +858,7 @@ class MessageQueueControllerTest Assertions.assertEquals(message.uuid, assignedMessage.uuid) val wrongAssignee = "wrong-assignee" - mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + message.uuid) + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_ASSIGN) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, wrongAssignee)) .andExpect(MockMvcResultMatchers.status().isConflict) @@ -1013,7 +1013,7 @@ class MessageQueueControllerTest Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) val uuid = UUID.randomUUID().toString() - mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + uuid) + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + uuid + MessageQueueController.ENDPOINT_RELEASE) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isNoContent) } @@ -1033,7 +1033,7 @@ class MessageQueueControllerTest Assertions.assertEquals(assignedTo, message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) - val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + message.uuid) + val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_RELEASE) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isOk) @@ -1067,7 +1067,7 @@ class MessageQueueControllerTest Assertions.assertTrue(authenticator.addRestrictedEntry(message.type)) Assertions.assertTrue(authenticator.isRestricted(message.type)) - mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + message.uuid) + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_RELEASE) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isForbidden) @@ -1076,7 +1076,7 @@ class MessageQueueControllerTest val token = jwtTokenProvider.createTokenForSubQueue(message.type) Assertions.assertTrue(token.isPresent) - val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + message.uuid) + val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_RELEASE) .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo)) @@ -1107,7 +1107,7 @@ class MessageQueueControllerTest Assertions.assertEquals(assignedTo, message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) - val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + message.uuid) + val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_RELEASE) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -1134,7 +1134,7 @@ class MessageQueueControllerTest Assertions.assertNull(message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) - val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + message.uuid) + val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_RELEASE) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isAccepted) .andReturn() @@ -1166,7 +1166,7 @@ class MessageQueueControllerTest Assertions.assertTrue(multiQueue.add(message)) val wrongAssignedTo = "wrong-assigned" - mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + message.uuid) + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_RELEASE) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, wrongAssignedTo)) .andExpect(MockMvcResultMatchers.status().isConflict) @@ -1673,11 +1673,11 @@ class MessageQueueControllerTest .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) - mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_RELEASE + "/" + UUID.randomUUID().toString()) + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + UUID.randomUUID().toString() + MessageQueueController.ENDPOINT_RELEASE) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) - mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ASSIGN + "/" + UUID.randomUUID().toString()) + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + UUID.randomUUID().toString() + MessageQueueController.ENDPOINT_ASSIGN) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) From 138426946c10787895223e2798a9130f308890d5 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 17 Nov 2023 19:57:17 +1100 Subject: [PATCH 42/58] Return 201 when creating a new restriction. --- .../au/kilemon/messagequeue/rest/controller/AuthController.kt | 4 ++-- .../messagequeue/rest/controller/AuthControllerTest.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt index 3ec0234..08f743d 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt @@ -70,7 +70,7 @@ open class AuthController : HasLogger @Operation(summary = "Create restriction on sub-queue.", description = "Create restriction a specific sub-queue to require authentication for future interactions and retrieve a token used to interact with this sub-queue.") @PostMapping("/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( - ApiResponse(responseCode = "200", description = "Successfully registered the sub-queue identifier and returns an appropriate token for future access to the sub-queue."), + ApiResponse(responseCode = "201", description = "Successfully registered the sub-queue identifier and returns an appropriate token for future access to the sub-queue."), ApiResponse(responseCode = "204", description = "The MultiQueue is in a no-auth mode and tokens cannot be generated.", content = [Content()]), // Add empty Content() to remove duplicate responses in swagger docsApiResponse(responseCode = "204", description = "No queue messages match the provided UUID.", content = [Content()]) ApiResponse(responseCode = "409", description = "A sub-queue with the provided identifier is already authorised.", content = [Content()]), ApiResponse(responseCode = "500", description = "There was an error generating the auth token for the sub-queue.", content = [Content()]) @@ -103,7 +103,7 @@ open class AuthController : HasLogger else { LOG.info("Successfully generated token for sub-queue [{}] with expiry [{}] minutes.", queueType, expiry) - ResponseEntity.ok(AuthResponse(token.get(), queueType)) + ResponseEntity.status(HttpStatus.CREATED).body(AuthResponse(token.get(), queueType)) } } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index 7f52a8c..2597471 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -169,7 +169,7 @@ class AuthControllerTest val mvcResult: MvcResult = mockMvc.perform( MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") .contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(MockMvcResultMatchers.status().isCreated) .andReturn() val authResponse = gson.fromJson(mvcResult.response.contentAsString, AuthResponse::class.java) @@ -194,7 +194,7 @@ class AuthControllerTest val mvcResult: MvcResult = mockMvc.perform( MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") .contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(MockMvcResultMatchers.status().isCreated) .andReturn() val authResponse = gson.fromJson(mvcResult.response.contentAsString, AuthResponse::class.java) From b244a25d728430cb9deb3cb52e2dad9fbceef88b Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 17 Nov 2023 20:00:08 +1100 Subject: [PATCH 43/58] Update testcontainers to the latest. --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index cb77cf3..ec792aa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -55,7 +55,7 @@ dependencies { // Required to mock MultiQueue objects since they apparently override a final 'remove(Object)' method. testImplementation("org.mockito:mockito-inline:5.1.0") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") - testImplementation("org.testcontainers:testcontainers:1.17.5") + testImplementation("org.testcontainers:testcontainers:1.19.2") testImplementation("org.testcontainers:junit-jupiter:1.17.5") testImplementation(kotlin("test")) } From bb129474f2fd7278f01937d06da3fc91c3e6323a Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sun, 19 Nov 2023 13:35:20 +1100 Subject: [PATCH 44/58] Add more default asserts to MeesageQueueSettingsDefaultTest. Add tests for key generationOrGet in JwtTokenProvider. --- .../authentication/token/JwtTokenProvider.kt | 11 +++--- .../token/JwtTokenProviderTest.kt | 37 +++++++++++++++++++ .../MessageQueueSettingsDefaultTest.kt | 11 ++++++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt index 5d3dc27..e5a4f2e 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt @@ -32,7 +32,8 @@ class JwtTokenProvider: HasLogger private var algorithm: Algorithm? = null @Value("\${${MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY}:\"\"}") - private var tokenKey: String = "" + var tokenKey: String = "" + private set /** * Lazily initialise and get the [Algorithm] using [Algorithm.HMAC512] and a random key. @@ -43,7 +44,7 @@ class JwtTokenProvider: HasLogger { if (algorithm == null) { - algorithm = Algorithm.HMAC512(getKey()) + algorithm = Algorithm.HMAC512(getOrGenerateKey(tokenKey)) } return algorithm!! } @@ -54,12 +55,12 @@ class JwtTokenProvider: HasLogger * @return If a value is provided via [MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY] then we will use it if it is * not blank. Otherwise, a randomly generated a byte array is returned */ - private fun getKey(): ByteArray + fun getOrGenerateKey(key: String): ByteArray { - return if (tokenKey.isNotBlank()) + return if (key.isNotBlank()) { LOG.info("Using provided key in property [{}] as the HMAC512 token generation and verification key.", MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY) - tokenKey.toByteArray() + key.toByteArray() } else { diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt index 5047d43..f19a058 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProviderTest.kt @@ -1,6 +1,7 @@ package au.kilemon.messagequeue.authentication.token import com.auth0.jwt.exceptions.JWTCreationException +import org.junit.Assert import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -120,4 +121,40 @@ class JwtTokenProviderTest Assertions.assertNotNull(decodedJwt) Assertions.assertTrue(decodedJwt.isEmpty) } + + /** + * Ensure the [JwtTokenProvider.tokenKey] is set to `""` by default. + */ + @Test + fun testCheckTokenDefaultValue() + { + Assertions.assertEquals("", jwtTokenProvider.tokenKey) + } + + /** + * Ensure when [JwtTokenProvider.getOrGenerateKey] is called with an empty or blank string that a randomly generated byte array is returned. + */ + @Test + fun testGetOrGenerateKey_emptyOrBlankKey() + { + val emptyKey = "" + val generatedEmpty = jwtTokenProvider.getOrGenerateKey(emptyKey) + Assertions.assertFalse(emptyKey.toByteArray().contentEquals(generatedEmpty)) + + val blankKey = " " + val generatedBlank = jwtTokenProvider.getOrGenerateKey(blankKey) + Assertions.assertFalse(blankKey.toByteArray().contentEquals(generatedBlank)) + + Assertions.assertFalse(generatedEmpty.contentEquals(generatedBlank)) + } + + /** + * Ensure when [JwtTokenProvider.getOrGenerateKey] with a non-blank argument that it will be returned as a [ByteArray]. + */ + @Test + fun testGetOrGenerateKey_withProvidedKey() + { + val newKey = "testGetOrGenerateKey_withProvidedKey" + Assertions.assertTrue(newKey.toByteArray().contentEquals(jwtTokenProvider.getOrGenerateKey(newKey))) + } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt b/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt index c3b9088..c194ef6 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt @@ -43,9 +43,20 @@ class MessageQueueSettingsDefaultTest { Assertions.assertNotNull(messageQueueSettings) Assertions.assertEquals(MessageQueueSettings.MULTI_QUEUE_TYPE_DEFAULT, messageQueueSettings.multiQueueType) + Assertions.assertEquals(MessageQueueSettings.MULTI_QUEUE_AUTHENTICATION_DEFAULT, messageQueueSettings.multiQueueAuthentication) + Assertions.assertEquals(MessageQueueSettings.REDIS_ENDPOINT_DEFAULT, messageQueueSettings.redisEndpoint) Assertions.assertEquals("", messageQueueSettings.redisPrefix) Assertions.assertEquals(MessageQueueSettings.REDIS_MASTER_NAME_DEFAULT, messageQueueSettings.redisMasterName) Assertions.assertEquals(false.toString(), messageQueueSettings.redisUseSentinels) + + Assertions.assertEquals("", messageQueueSettings.sqlEndpoint) + Assertions.assertEquals("", messageQueueSettings.sqlUsername) + + Assertions.assertEquals("", messageQueueSettings.mongoHost) + Assertions.assertEquals("", messageQueueSettings.mongoUri) + Assertions.assertEquals("", messageQueueSettings.mongoPort) + Assertions.assertEquals("", messageQueueSettings.mongoDatabase) + Assertions.assertEquals("", messageQueueSettings.mongoUsername) } } From bae588db11e615a64321966a58a61d27bad1bc52 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sun, 19 Nov 2023 19:24:56 +1100 Subject: [PATCH 45/58] Make a "getQueueForTypeInternal()" method to wrap this and check an invalid subqueue id is not used. Add changes to check us of reserved sub queue identifiers. Fix in memory mock tests. Create new exception IllegalSubQueueIdentifierException used when a reserved subqueue id is used. --- .../cache/redis/RedisAuthenticator.kt | 7 ++- .../kilemon/messagequeue/queue/MultiQueue.kt | 55 +++++++++++++++++-- .../queue/cache/redis/RedisMultiQueue.kt | 4 +- .../IllegalSubQueueIdentifierException.kt | 8 +++ .../queue/inmemory/InMemoryMultiQueue.kt | 6 +- .../queue/nosql/mongo/MongoMultiQueue.kt | 6 +- .../messagequeue/queue/sql/SqlMultiQueue.kt | 6 +- .../response/RestResponseExceptionHandler.kt | 7 +++ .../redis/RedisStandAloneAuthenticatorTest.kt | 2 +- .../inmemory/InMemoryMockMultiQueueTest.kt | 17 +++++- .../RestResponseExceptionHandlerTest.kt | 22 ++++++++ 11 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 src/main/kotlin/au/kilemon/messagequeue/queue/exception/IllegalSubQueueIdentifierException.kt diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt index 91b2739..bd0edfa 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt @@ -26,10 +26,15 @@ class RedisAuthenticator: MultiQueueAuthenticator() /** * Overriding to completely remove all access to the [RESTRICTED_KEY]. + * Only if [isInNoneMode] returns `false`. */ override fun getReservedSubQueues(): Set { - return setOf(RESTRICTED_KEY) + if (!isInNoneMode()) + { + return setOf(RESTRICTED_KEY) + } + return setOf() } private fun getMembersSet(): Set diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt index dbd716a..7c665a7 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt @@ -1,10 +1,11 @@ package au.kilemon.messagequeue.queue import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator -import au.kilemon.messagequeue.queue.exception.DuplicateMessageException import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.message.QueueMessage +import au.kilemon.messagequeue.queue.exception.DuplicateMessageException import au.kilemon.messagequeue.queue.exception.HealthCheckFailureException +import au.kilemon.messagequeue.queue.exception.IllegalSubQueueIdentifierException import au.kilemon.messagequeue.queue.exception.MessageUpdateException import lombok.Generated import org.slf4j.Logger @@ -12,9 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired import java.util.* import java.util.concurrent.ConcurrentLinkedQueue import java.util.stream.Collectors -import kotlin.collections.HashMap import kotlin.collections.HashSet -import kotlin.jvm.Throws /** * A [MultiQueue] base class, which extends [Queue]. @@ -97,6 +96,18 @@ abstract class MultiQueue: Queue, HasLogger @Throws(MessageUpdateException::class) abstract fun persistMessageInternal(message: QueueMessage) + /** + * Retrieves or creates a new [Queue] of type [QueueMessage] for the provided [String]. + * If the underlying [Queue] does not exist for the provided [String] then a new [Queue] will + * be created. + * + * **This method should not be called directly, please use [getQueueForType]** + * + * @param queueType the identifier of the sub-queue [Queue] + * @return the [Queue] matching the provided [String] + */ + abstract fun getQueueForTypeInternal(queueType: String): Queue + /** * Retrieves or creates a new [Queue] of type [QueueMessage] for the provided [String]. * If the underlying [Queue] does not exist for the provided [String] then a new [Queue] will @@ -104,8 +115,18 @@ abstract class MultiQueue: Queue, HasLogger * * @param queueType the identifier of the sub-queue [Queue] * @return the [Queue] matching the provided [String] + * @throws IllegalSubQueueIdentifierException If the provided [queueType] is part of the [MultiQueueAuthenticator.getReservedSubQueues] */ - abstract fun getQueueForType(queueType: String): Queue + @Throws(IllegalSubQueueIdentifierException::class) + fun getQueueForType(queueType: String): Queue + { + if (multiQueueAuthenticator.getReservedSubQueues().contains(queueType)) + { + throw IllegalSubQueueIdentifierException(queueType) + } + + return getQueueForTypeInternal(queueType) + } /** * Retrieves only assigned messages in the sub-queue for the provided [queueType]. @@ -323,11 +344,27 @@ abstract class MultiQueue: Queue, HasLogger /** * Retrieves the underlying key list as a set. + * **Should be called directly, please using [keys].** + * + * @param includeEmpty *true* to include any empty queues which one had elements in them, otherwise *false* to only include keys from queues which have elements. + * @return a [HashSet] of the available `QueueTypes` that have entries in the [MultiQueue]. + */ + abstract fun keysInternal(includeEmpty: Boolean = true): HashSet + + /** + * Delegates to [keysInternal] and removes any keys that match in the [MultiQueueAuthenticator.getReservedSubQueues]. * * @param includeEmpty *true* to include any empty queues which one had elements in them, otherwise *false* to only include keys from queues which have elements. * @return a [Set] of the available `QueueTypes` that have entries in the [MultiQueue]. */ - abstract fun keys(includeEmpty: Boolean = true): Set + fun keys(includeEmpty: Boolean = true): Set + { + val keysSet = keysInternal(includeEmpty) + + // Remove the restricted key(s) + multiQueueAuthenticator.getReservedSubQueues().forEach { reservedSubQueue -> keysSet.remove(reservedSubQueue) } + return keysSet + } /** * Returns the `queueType` that the [QueueMessage] with the provided [UUID] exists in. @@ -347,11 +384,17 @@ abstract class MultiQueue: Queue, HasLogger * not force it to be auto incremented or unusable by another thread. * * @throws [DuplicateMessageException] if a message already exists with the same [QueueMessage.uuid] in `any` other queue. + * @throws [IllegalSubQueueIdentifierException] if the [QueueMessage.type] is invalid or reserved */ - @Throws(DuplicateMessageException::class) + @Throws(DuplicateMessageException::class, IllegalSubQueueIdentifierException::class) @Synchronized override fun add(element: QueueMessage): Boolean { + if (multiQueueAuthenticator.getReservedSubQueues().contains(element.type)) + { + throw IllegalSubQueueIdentifierException(element.type) + } + val elementIsMappedToType = containsUUID(element.uuid) if ( !elementIsMappedToType.isPresent) { diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt index 9b15804..924b7ed 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt @@ -1,5 +1,6 @@ package au.kilemon.messagequeue.queue.cache.redis +import au.kilemon.messagequeue.authentication.authenticator.cache.redis.RedisAuthenticator import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.MultiQueue @@ -13,6 +14,7 @@ import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.atomic.AtomicLong import java.util.stream.Collectors import kotlin.collections.HashMap +import kotlin.collections.HashSet /** * A `Redis` specific implementation of the [MultiQueue]. @@ -43,7 +45,7 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate /** * Attempts to append the prefix before requesting the underlying redis entry if the provided [queueType] is not prefixed with [MessageQueueSettings.redisPrefix]. */ - override fun getQueueForType(queueType: String): Queue + override fun getQueueForTypeInternal(queueType: String): Queue { val queue = ConcurrentLinkedQueue() val set = redisTemplate.opsForSet().members(appendPrefix(queueType)) diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/exception/IllegalSubQueueIdentifierException.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/exception/IllegalSubQueueIdentifierException.kt new file mode 100644 index 0000000..65fa398 --- /dev/null +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/exception/IllegalSubQueueIdentifierException.kt @@ -0,0 +1,8 @@ +package au.kilemon.messagequeue.queue.exception + +/** + * A specific exception used to indicate that an invalid or reserved sub-queue identifier cannot be used. + * + * @author github.com/Kilemonn + */ +class IllegalSubQueueIdentifierException(subQueue: String) : Exception("Cannot access sub-queue with identifier [$subQueue] since it is reserved or invalid.") diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt index c952420..95b15c6 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt @@ -50,7 +50,7 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger return Optional.of(index.getAndIncrement()) } - override fun getQueueForType(queueType: String): Queue + override fun getQueueForTypeInternal(queueType: String): Queue { var queueForType: Queue? = messageQueue[queueType] if (queueForType == null) @@ -153,12 +153,12 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger return queueForType.isEmpty() } - override fun keys(includeEmpty: Boolean): Set + override fun keysInternal(includeEmpty: Boolean): HashSet { if (includeEmpty) { LOG.debug("Including all empty queue keys in call to keys(). Total queue keys [{}].", messageQueue.keys.size) - return messageQueue.keys.toSet() + return HashSet(messageQueue.keys) } else { diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt index 7b02fc7..1a5bf8b 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt @@ -71,7 +71,7 @@ class MongoMultiQueue : MultiQueue(), HasLogger return ConcurrentLinkedQueue(entries.map { entry -> QueueMessage(entry) }) } - override fun getQueueForType(queueType: String): Queue + override fun getQueueForTypeInternal(queueType: String): Queue { val entries = queueMessageRepository.findByTypeOrderByIdAsc(queueType) return ConcurrentLinkedQueue(entries.map { entry -> QueueMessage(entry) }) @@ -123,9 +123,9 @@ class MongoMultiQueue : MultiQueue(), HasLogger /** * The [includeEmpty] value makes no difference it is always effectively `false`. */ - override fun keys(includeEmpty: Boolean): Set + override fun keysInternal(includeEmpty: Boolean): HashSet { - val keySet = queueMessageRepository.getDistinctTypes().toSet() + val keySet = HashSet(queueMessageRepository.getDistinctTypes()) LOG.debug("Total amount of queue keys [{}].", keySet.size) return keySet } diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt index c2748f1..364df17 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt @@ -25,7 +25,7 @@ class SqlMultiQueue : MultiQueue(), HasLogger @Autowired private lateinit var queueMessageRepository: SqlQueueMessageRepository - override fun getQueueForType(queueType: String): Queue + override fun getQueueForTypeInternal(queueType: String): Queue { val entries = queueMessageRepository.findByTypeOrderByIdAsc(queueType) return ConcurrentLinkedQueue(entries.map { entry -> entry.resolvePayloadObject() }) @@ -103,9 +103,9 @@ class SqlMultiQueue : MultiQueue(), HasLogger /** * The [includeEmpty] value makes no difference it is always effectively `false`. */ - override fun keys(includeEmpty: Boolean): Set + override fun keysInternal(includeEmpty: Boolean): HashSet { - val keySet = queueMessageRepository.findDistinctType().toSet() + val keySet = HashSet(queueMessageRepository.findDistinctType()) LOG.debug("Total amount of queue keys [{}].", keySet.size) return keySet } diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt index ea70716..6748788 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandler.kt @@ -2,6 +2,7 @@ package au.kilemon.messagequeue.rest.response import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException +import au.kilemon.messagequeue.queue.exception.IllegalSubQueueIdentifierException import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice @@ -34,4 +35,10 @@ class RestResponseExceptionHandler: ResponseEntityExceptionHandler() { return ResponseEntity(ErrorResponse(ex.message), HttpStatus.UNAUTHORIZED) } + + @ExceptionHandler(IllegalSubQueueIdentifierException::class) + fun handleIllegalSubQueueIdentifierException(ex: IllegalSubQueueIdentifierException): ResponseEntity + { + return ResponseEntity(ErrorResponse(ex.message), HttpStatus.BAD_REQUEST) + } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt index df7f3d8..9bb7c0a 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt @@ -86,7 +86,7 @@ class RedisStandAloneAuthenticatorTest: MultiQueueAuthenticatorTest() /** * Ensure that the [RedisAuthenticator.getReservedSubQueues] always contains [RedisAuthenticator.RESTRICTED_KEY] and - * that calls to [MultiQueueAuthenticator.canAccessSubQueue] will throw a [MultiQueueAuthorisationException]. + * that calls to [RedisAuthenticator.canAccessSubQueue] will throw a [MultiQueueAuthorisationException]. */ @Test fun testGetReservedSubQueues() diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMockMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMockMultiQueueTest.kt index 7cb8f27..bc4e64a 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMockMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMockMultiQueueTest.kt @@ -1,12 +1,19 @@ package au.kilemon.messagequeue.queue.inmemory +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.configuration.QueueConfiguration +import au.kilemon.messagequeue.logging.LoggingConfiguration import au.kilemon.messagequeue.message.QueueMessage +import au.kilemon.messagequeue.queue.MultiQueue +import au.kilemon.messagequeue.queue.MultiQueueTest import au.kilemon.messagequeue.queue.exception.HealthCheckFailureException import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Mockito +import org.springframework.boot.test.mock.mockito.SpyBean +import org.springframework.context.annotation.Import import org.springframework.test.context.junit.jupiter.SpringExtension import java.util.* @@ -14,9 +21,17 @@ import java.util.* * A [Mockito] test that is used to simulate hard to cover error cases in calling code for all `MultiQueue` related methods that are hard to test. */ @ExtendWith(SpringExtension::class) +@Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) class InMemoryMockMultiQueueTest { - private val multiQueue: InMemoryMultiQueue = Mockito.spy(InMemoryMultiQueue::class.java) + @SpyBean + private lateinit var multiQueue: MultiQueue + + @BeforeEach + fun setup() + { + multiQueue.clear() + } /** * Test [InMemoryMultiQueue.add] to ensure that `false` is returned when [InMemoryMultiQueue.addInternal] returns `false`. diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt index 179ed31..4bbc3a6 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt @@ -4,12 +4,15 @@ import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException import au.kilemon.messagequeue.filter.CorrelationIdFilter +import au.kilemon.messagequeue.queue.exception.IllegalSubQueueIdentifierException import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.slf4j.MDC import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.server.ResponseStatusException import java.util.* @@ -93,4 +96,23 @@ class RestResponseExceptionHandlerTest Assertions.assertEquals(MultiQueueAuthenticationException.ERROR_MESSAGE, response.body!!.message) Assertions.assertEquals(correlationId, response.body!!.correlationId) } + + /** + * Ensure the [RestResponseExceptionHandler.handleIllegalSubQueueIdentifierException] returns the appropriate reponse + * and error message. + */ + @Test + fun testHandleIllegalSubQueueIdentifierException() + { + val correlationId = UUID.randomUUID().toString() + MDC.put(CorrelationIdFilter.CORRELATION_ID, correlationId) + val type = "testHandleIllegalSubQueueIdentifierException" + val exception = IllegalSubQueueIdentifierException(type) + val response = responseHandler.handleIllegalSubQueueIdentifierException(exception) + + Assertions.assertEquals(HttpStatus.BAD_REQUEST, response.statusCode) + Assertions.assertNotNull(response.body) + Assertions.assertTrue(response.body!!.message!!.contains(type)) + Assertions.assertEquals(correlationId, response.body!!.correlationId) + } } From 04b64cb2a19a47fd4b06dd66e5c9b11f8cd38e15 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sun, 19 Nov 2023 19:45:48 +1100 Subject: [PATCH 46/58] Remove test it will be moved up to the MultiQueueTest. Change method signature in RedisMultiQueue. --- .../queue/cache/redis/RedisMultiQueue.kt | 2 +- .../redis/RedisStandAloneAuthenticatorTest.kt | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt index 924b7ed..561616a 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt @@ -150,7 +150,7 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate return Optional.empty() } - override fun keys(includeEmpty: Boolean): Set + override fun keysInternal(includeEmpty: Boolean): HashSet { val scanOptions = ScanOptions.scanOptions().match(appendPrefix("*")).build() val cursor = redisTemplate.scan(scanOptions) diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt index 9bb7c0a..1d3a1e2 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt @@ -83,19 +83,4 @@ class RedisStandAloneAuthenticatorTest: MultiQueueAuthenticatorTest() Assertions.assertTrue(redis.isRunning) multiQueueAuthenticator.clearRestrictedSubQueues() } - - /** - * Ensure that the [RedisAuthenticator.getReservedSubQueues] always contains [RedisAuthenticator.RESTRICTED_KEY] and - * that calls to [RedisAuthenticator.canAccessSubQueue] will throw a [MultiQueueAuthorisationException]. - */ - @Test - fun testGetReservedSubQueues() - { - Assertions.assertTrue(multiQueueAuthenticator.getReservedSubQueues().contains(RedisAuthenticator.RESTRICTED_KEY)) - Assertions.assertThrows(MultiQueueAuthorisationException::class.java) { - multiQueueAuthenticator.canAccessSubQueue(RedisAuthenticator.RESTRICTED_KEY) - } - Assertions.assertFalse(multiQueueAuthenticator.canAccessSubQueue(RedisAuthenticator.RESTRICTED_KEY, false)) - } - } From f5bb2b0407a7cfbc8bb217acdb7edb5668cabdf5 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sun, 19 Nov 2023 22:35:06 +1100 Subject: [PATCH 47/58] Add tests for reserved sub queue names. Specifically for Redis. Add "doWithAuthType" method to perform actions with the authenticator set in a specific mode. --- .../authenticator/MultiQueueAuthenticator.kt | 10 +++ .../configuration/QueueConfiguration.kt | 15 ++-- .../kilemon/messagequeue/queue/MultiQueue.kt | 2 +- .../messagequeue/queue/MultiQueueTest.kt | 88 +++++++++++++++++++ 4 files changed, 106 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt index 6c4bde0..fcff5d3 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt @@ -28,6 +28,16 @@ abstract class MultiQueueAuthenticator: HasLogger return multiQueueAuthenticationType } + /** + * Used only for tests to update the set [MultiQueueAuthenticationType]. + * + * @param authenticationType the new [MultiQueueAuthenticationType] to set + */ + fun setAuthenticationType(authenticationType: MultiQueueAuthenticationType) + { + multiQueueAuthenticationType = authenticationType + } + /** * Used to return a list of completed reserved sub-queue identifiers that can never be used. Even when * [MultiQueueAuthenticationType.NONE] is being used. diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt index 98af556..32c198f 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt @@ -1,6 +1,13 @@ package au.kilemon.messagequeue.configuration import au.kilemon.messagequeue.MessageQueueApplication +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.cache.redis.RedisAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.inmemory.InMemoryAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.nosql.mongo.MongoAuthenticator +import au.kilemon.messagequeue.authentication.authenticator.sql.SqlAuthenticator +import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.logging.Messages import au.kilemon.messagequeue.message.QueueMessage @@ -10,15 +17,7 @@ import au.kilemon.messagequeue.queue.inmemory.InMemoryMultiQueue import au.kilemon.messagequeue.queue.nosql.mongo.MongoMultiQueue import au.kilemon.messagequeue.queue.sql.SqlMultiQueue import au.kilemon.messagequeue.settings.MessageQueueSettings -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType -import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator -import au.kilemon.messagequeue.authentication.authenticator.cache.redis.RedisAuthenticator -import au.kilemon.messagequeue.authentication.authenticator.inmemory.InMemoryAuthenticator -import au.kilemon.messagequeue.authentication.authenticator.nosql.mongo.MongoAuthenticator -import au.kilemon.messagequeue.authentication.authenticator.sql.SqlAuthenticator -import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.settings.MultiQueueType -import lombok.Generated import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Bean diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt index 7c665a7..6ec19c2 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt @@ -120,7 +120,7 @@ abstract class MultiQueue: Queue, HasLogger @Throws(IllegalSubQueueIdentifierException::class) fun getQueueForType(queueType: String): Queue { - if (multiQueueAuthenticator.getReservedSubQueues().contains(queueType)) + if (!multiQueueAuthenticator.isInNoneMode() && multiQueueAuthenticator.getReservedSubQueues().contains(queueType)) { throw IllegalSubQueueIdentifierException(queueType) } diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt index 02a332a..d4bd52a 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt @@ -1,7 +1,10 @@ package au.kilemon.messagequeue.queue +import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.exception.DuplicateMessageException +import au.kilemon.messagequeue.queue.exception.IllegalSubQueueIdentifierException import au.kilemon.messagequeue.queue.exception.MessageUpdateException import au.kilemon.messagequeue.queue.inmemory.InMemoryMultiQueue import au.kilemon.messagequeue.queue.nosql.mongo.MongoMultiQueue @@ -23,6 +26,7 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Lazy import java.io.Serializable import java.util.* +import java.util.function.Supplier import java.util.stream.Stream /** @@ -58,6 +62,9 @@ abstract class MultiQueueTest @Autowired protected lateinit var multiQueue: MultiQueue + @Autowired + private lateinit var authenticator: MultiQueueAuthenticator + /** * Ensure that when a new entry is added, that the [MultiQueue] is no longer empty and reports the correct size. * @@ -386,6 +393,22 @@ abstract class MultiQueueTest } } + /** + * Ensure that calls to [MultiQueue.getQueueForType] with a [MultiQueueAuthenticator.getReservedSubQueues] as an + * argument will throw [IllegalSubQueueIdentifierException]. + */ + @Test + fun testGetQueueForType_reservedSubQueue() + { + doWithAuthType(MultiQueueAuthenticationType.HYBRID) { + authenticator.getReservedSubQueues().forEach { reservedSubQueueIdentifier -> + Assertions.assertThrows(IllegalSubQueueIdentifierException::class.java) { + multiQueue.getQueueForType(reservedSubQueueIdentifier) + } + } + } + } + /** * Ensure that all elements are added, and contained and removed via the provided [Collection]. */ @@ -920,6 +943,71 @@ abstract class MultiQueueTest multiQueue.performHealthCheck() } + /** + * Ensure that we cannot add a new [QueueMessage] with [QueueMessage.type] set to any of the [MultiQueueAuthenticator.getReservedSubQueues] entries. + */ + @Test + fun testAddReservedSubQueue() + { + doWithAuthType(MultiQueueAuthenticationType.RESTRICTED) { + authenticator.getReservedSubQueues().forEach { reservedSubQueueIdentifier -> + val message = QueueMessage("Data", reservedSubQueueIdentifier) + Assertions.assertThrows(IllegalSubQueueIdentifierException::class.java) { + multiQueue.add(message) + } + } + } + } + + /** + * Ensure that even we have a restricted queue entry registered, when [MultiQueue.keys] is called, the entry + * is removed and not returned. + */ + @Test + fun testKeysWithReservedSubQueueUsage() + { + doWithAuthType(MultiQueueAuthenticationType.HYBRID) { + var keys = multiQueue.keys() + authenticator.getReservedSubQueues().forEach { reservedSubQueueIdentifier -> + Assertions.assertFalse(keys.contains(reservedSubQueueIdentifier)) + } + + val restrictedSubQueue = "testKeysWithReservedSubQueueUsage" + authenticator.addRestrictedEntry(restrictedSubQueue) + + keys = multiQueue.keys() + authenticator.getReservedSubQueues().forEach { reservedSubQueueIdentifier -> + Assertions.assertFalse(keys.contains(reservedSubQueueIdentifier)) + } + + // Need to clear the restricted queue otherwise it affects other redis tests if they are not in a "non-None" auth state + authenticator.clearRestrictedSubQueues() + } + } + + /** + * Perform the provided [function] with the [MultiQueueAuthenticationType] set to [authenticationType]. + * Once completed the [MultiQueueAuthenticationType] will be set back to its initial value. + * + * @param authenticationType the [MultiQueueAuthenticationType] to be set while the [function] is being called + * @param function the function to call with the provided [MultiQueueAuthenticationType] being active + * @return `T` the result of the [function] + */ + private fun doWithAuthType(authenticationType: MultiQueueAuthenticationType, function: Supplier): T + { + val previousAuthType = authenticator.getAuthenticationType() + authenticator.setAuthenticationType(authenticationType) + + try + { + return function.get() + } + finally + { + authenticator.setAuthenticationType(previousAuthType) + } + } + /** * Ensure that all applicable methods throw an [UnsupportedOperationException]. */ From 15afd0e6eeb074d4ceadc1fca312a487a0d8bf4c Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Mon, 20 Nov 2023 18:30:32 +1100 Subject: [PATCH 48/58] Refactor URL skip verification to be more readable. --- .../messagequeue/filter/JwtAuthenticationFilter.kt | 9 ++++----- .../filter/JwtAuthenticationFilterTest.kt | 12 ++++++------ .../rest/controller/MessageQueueControllerTest.kt | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index e8c8916..0804743 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -8,7 +8,6 @@ import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.rest.controller.AuthController import au.kilemon.messagequeue.rest.controller.MessageQueueController import au.kilemon.messagequeue.rest.controller.SettingsController -import au.kilemon.messagequeue.rest.response.RestResponseExceptionHandler import org.slf4j.Logger import org.slf4j.MDC import org.springframework.beans.factory.annotation.Autowired @@ -81,7 +80,7 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger val subQueue = getSubQueueInTokenFromHeaders(request) setSubQueue(subQueue) - if (!urlRequiresAuthentication(request)) + if (canSkipTokenVerification(request)) { LOG.trace("Allowed access to path [{}] as it does not require authentication.", request.requestURI) filterChain.doFilter(request, response) @@ -127,10 +126,10 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger * @param request the incoming request to verify the path of * @return `true` if the provided path starts with an auth required prefix, otherwise `false` */ - fun urlRequiresAuthentication(request: HttpServletRequest): Boolean + fun canSkipTokenVerification(request: HttpServletRequest): Boolean { val requestString = request.requestURI - val authNotRequiredEndpoints = listOf( + val noTokenCheckEndpoints = listOf( Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_HEALTH_CHECK}"), Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_KEYS}"), Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_OWNERS}"), @@ -139,7 +138,7 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger Pair(HttpMethod.GET, SettingsController.SETTINGS_PATH) ) - return !authNotRequiredEndpoints + return noTokenCheckEndpoints .filter { authRequiredUrlPrefix -> authRequiredUrlPrefix.first.toString() == request.method } .any { authRequiredUrlPrefix -> requestString.startsWith(authRequiredUrlPrefix.second) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt index dc58235..b9598b2 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilterTest.kt @@ -210,7 +210,7 @@ class JwtAuthenticationFilterTest } /** - * Ensure [JwtAuthenticationFilter.urlRequiresAuthentication] returns `true` when the provided URI does not + * Ensure [JwtAuthenticationFilter.canSkipTokenVerification] returns `true` when the provided URI does not * match the "no auth required" list. */ @Test @@ -221,11 +221,11 @@ class JwtAuthenticationFilterTest Mockito.`when`(request.requestURI).thenReturn(uriPath) Mockito.`when`(request.method).thenReturn(HttpMethod.POST.toString()) - Assertions.assertTrue(jwtAuthenticationFilter.urlRequiresAuthentication(request)) + Assertions.assertFalse(jwtAuthenticationFilter.canSkipTokenVerification(request)) } /** - * Ensure [JwtAuthenticationFilter.urlRequiresAuthentication] returns `false` when the provided URI does + * Ensure [JwtAuthenticationFilter.canSkipTokenVerification] returns `false` when the provided URI does * start with an un-authorised path prefix. */ @Test @@ -236,11 +236,11 @@ class JwtAuthenticationFilterTest Mockito.`when`(request.requestURI).thenReturn(uriPath) Mockito.`when`(request.method).thenReturn(HttpMethod.GET.toString()) - Assertions.assertFalse(jwtAuthenticationFilter.urlRequiresAuthentication(request)) + Assertions.assertTrue(jwtAuthenticationFilter.canSkipTokenVerification(request)) } /** - * Ensure [JwtAuthenticationFilter.urlRequiresAuthentication] returns `true` when the provided HTTP method is + * Ensure [JwtAuthenticationFilter.canSkipTokenVerification] returns `true` when the provided HTTP method is * not in the whitelist. */ @Test @@ -251,7 +251,7 @@ class JwtAuthenticationFilterTest Mockito.`when`(request.requestURI).thenReturn(uriPath) Mockito.`when`(request.method).thenReturn(HttpMethod.OPTIONS.toString()) - Assertions.assertTrue(jwtAuthenticationFilter.urlRequiresAuthentication(request)) + Assertions.assertFalse(jwtAuthenticationFilter.canSkipTokenVerification(request)) } /** diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt index 3c06fc0..a63a90c 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt @@ -1651,7 +1651,7 @@ class MessageQueueControllerTest /** * Ensure that when [MultiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.RESTRICTED] that any - * of the endpoints not in the [JwtAuthenticationFilter.urlRequiresAuthentication] whitelist will be inaccessible. + * of the endpoints failing the [JwtAuthenticationFilter.canSkipTokenVerification] will be inaccessible. */ @Test fun testRestrictedModeMakesAllEndpointsInaccessibleWithoutAToken() From c4560f80368c0766f2964e017951a705b29f4ae7 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Fri, 1 Dec 2023 17:44:58 +1100 Subject: [PATCH 49/58] Reorder token generation to remove unnecessary roll back calls or logic. --- .../messagequeue/rest/controller/AuthController.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt index 08f743d..eae3e76 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt @@ -93,11 +93,17 @@ open class AuthController : HasLogger } else { - val wasAdded = multiQueueAuthenticator.addRestrictedEntry(queueType) + // Generating the token first, so we don't need to roll back restriction add later if there is a problem val token = jwtTokenProvider.createTokenForSubQueue(queueType, expiry) - return if (token.isEmpty || !wasAdded) + if (token.isEmpty) { LOG.error("Failed to generated token for sub-queue [{}].", queueType) + return ResponseEntity.internalServerError().build() + } + + return if (!multiQueueAuthenticator.addRestrictedEntry(queueType)) + { + LOG.error("Failed to add restriction for sub-queue [{}].", queueType) ResponseEntity.internalServerError().build() } else From da130c7bc0584ecbcbf2b2c01f2b5fabed91168f Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Sun, 3 Dec 2023 00:00:19 +1100 Subject: [PATCH 50/58] Remove authenticator check for owners endpoint. --- .../messagequeue/filter/JwtAuthenticationFilter.kt | 3 +-- .../rest/controller/MessageQueueController.kt | 8 +------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index 0804743..f1fb33c 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -128,7 +128,6 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger */ fun canSkipTokenVerification(request: HttpServletRequest): Boolean { - val requestString = request.requestURI val noTokenCheckEndpoints = listOf( Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_HEALTH_CHECK}"), Pair(HttpMethod.GET, "${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}${MessageQueueController.ENDPOINT_KEYS}"), @@ -140,7 +139,7 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger return noTokenCheckEndpoints .filter { authRequiredUrlPrefix -> authRequiredUrlPrefix.first.toString() == request.method } - .any { authRequiredUrlPrefix -> requestString.startsWith(authRequiredUrlPrefix.second) } + .any { authRequiredUrlPrefix -> request.requestURI.startsWith(authRequiredUrlPrefix.second) } } /** diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt index 2d9c958..7c0efd2 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt @@ -394,8 +394,7 @@ open class MessageQueueController : HasLogger if (message.isPresent) { val messageToAssign = message.get() - authenticator.canAccessSubQueue(messageToAssign.type - ) + authenticator.canAccessSubQueue(messageToAssign.type) if (!messageToAssign.assignedTo.isNullOrBlank()) { if (messageToAssign.assignedTo == assignedTo) @@ -567,11 +566,6 @@ open class MessageQueueController : HasLogger @ApiResponse(responseCode = "200", description = "Successfully returns the map of owner identifiers mapped to all the sub-queues that they have one or more assigned messages in.") fun getOwners(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "The sub queue to search for the owner identifiers.") @RequestParam(required = false, name = RestParameters.QUEUE_TYPE) queueType: String?): ResponseEntity>> { - if (queueType != null) - { - authenticator.canAccessSubQueue(queueType) - } - return ResponseEntity.ok(messageQueue.getOwnersAndKeysMap(queueType)) } } From 98de2141496fb5aafad03c3ca585a6dc268c03d5 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Mon, 4 Dec 2023 22:15:43 +1100 Subject: [PATCH 51/58] Remove storage mechanism notes from the README. --- README.md | 191 ++++-------------------------------------------------- 1 file changed, 14 insertions(+), 177 deletions(-) diff --git a/README.md b/README.md index 914350c..66e6e8e 100644 --- a/README.md +++ b/README.md @@ -4,197 +4,34 @@ ## Overview A message queue service, which can receive, hold and provide messages that are sent between services. -The message storage mechanisms supported are: -- In-memory (default) -- Redis (stand alone and sentinel support) -- SQL Database (MySQL, PostgreSQL) -- No SQL Database (Mongo) +A storage mechanism can be used to persist messages and sub queues can be restricted so only correctly provided credentials +can interact with such queues. -## Rest API Documentation - -The application provides a REST API to interact with the messages queued within the Multi Queue. -REST Documentation is provided as Swagger docs from the running application. -You can simply run the docker image: -> docker run -p8080:8080 kilemon/message-queue - -Once the image is running you can reach the Swagger documentation from the following endpoint: `http://localhost:8080/swagger-ui/index.html`. +**More detailed documentation can be found in the Wiki!** ## Quick Start -## In-Memory - -The `In-Memory` configuration is the default and requires no further configuration. -Steps to run the In-Memory Multi Queue is as follows: -- `docker run -p8080:8080 kilemon/message-queue` -- Once running the best endpoint to call at the moment is probably: `http://localhost:8080/queue/healthcheck` - -If you really like you can provide an environment variable to the application to explicitly set the application into `In-Memory` mode: `MULTI_QUEUE_TYPE=IN_MEMORY`. - -## Redis - -The `Redis` setup requires some additional environmental configuration. -Firstly to set the application into `Redis` mode you need to provide the following environment variable with the appropriate value: `MULTI_QUEUE_TYPE=REDIS`. -Once this is set you will need to provide further environment variable in order to correctly configure the redis standalone or sentinel configuration (depending on your setup). - -### Redis Environment Properties - -Below are the optional and required properties for the `Redis` configuration. - -#### REDIS_USE_SENTINELS - -By default, this property is set to `false` (defaulting to direct connection to a single Redis instance). - -This flag indicates whether the `MultiQueue` should connect directly to the redis instance or connect via one or more sentinel instances. -If set to `true` the `MultiQueue` will create a sentinel pool connection instead of a direct connection to a single redis node. - -#### REDIS_PREFIX - -By default, this property is set to `""` the application will apply no prefix. - -For each defined "sub-queue" or "queue type", the application will create a single set entry into redis. This prefix can be used to remove/reduce the likelihood of any collisions if this is being used in an existing redis instance. - -The defined value will be used as a prefix used for all redis entry keys that the application will create. -E.g. if the initial value for the redis entry key is `my-key` and no prefix is defined the entries would be stored under `my-key`. -Using the same scenario if the prefix is `prefix` then the prefix and entry key will be concatenated and the resultant key would be `prefixmy-key`. - -#### REDIS_ENDPOINT - -By default, this property is set to `127.0.0.1` (the application will auto append the default redis port if it is not defined). - -The input endpoint string which is used for both standalone and the sentinel redis configurations. -This supports a comma separated list or single definition of a redis endpoint in the following formats: -`:,:,`. - -If you are using standalone and provide multiple endpoints, only the first will be used. - -#### REDIS_MASTER_NAME - -By default, this property is set to `mymaster`. -This is **REQUIRED** when `REDIS_USE_SENTINELS` is set to `true`. Is used to indicate the name of the redis master instance. - -### Example: - -An example of `Redis` configuration environment variables is below: -```yaml -environment: - - MULTI_QUEUE_TYPE=REDIS - - REDIS_USE_SENTINELS=true - - REDIS_PREFIX=my-prefix - - REDIS_ENDPOINT=sentinel1.com:5545,sentinel2.org:9980 - - REDIS_MASTER_NAME=not-my-master -``` - -## SQL Database - -The `SQL` mechanism requires some configuration too similarly to `Redis`. -To set the application into `SQL` mode you need to provide the following environment variable with the appropriate value: `MULTI_QUEUE_TYPE=SQL`. - -### SQL Environment Properties - -Below are the required properties for `SQL` configuration. - -#### spring.jpa.hibernate.ddl-auto - -Depending on your setup this is probably required initially but may change based on your usage needs. Since the application uses Hibernate to create and generate the database structure. -If the structure is not initialised, I recommend setting this property to `create` (E.g. `spring.jpa.hibernate.ddl-auto=create`). - -Please refer to https://docs.spring.io/spring-boot/docs/1.1.0.M1/reference/html/howto-database-initialization.html#howto-initialize-a-database-using-hibernate - -#### spring.autoconfigure.exclude - -***This property is required***. +By default, the application will be store messages in memory and no queue restriction will be available. +To start the application you can use the following command to pull and run the latest version of the image: -Just providing `spring.autoconfigure.exclude=` as one of the environment variables is required to force JPA to initialise correctly. -By default, it is suppressed to allow of more stream lined configuration of the other mechanisms. +`docker run -p8080:8080 kilemon/message-queue` -#### spring.datasource.url +Once running the best endpoint to call at the moment is probably: `http://localhost:8080/queue/healthcheck` -***This property is required***. - -This defines the database connection string that the application should connect to. E.g: `jdbc:mysql://localhost:3306/message-queue` - -#### spring.datasource.username - -***This property is required***. - -This is the username/account name used to access the database at the configured endpoint. - -#### spring.datasource.password - -***This property is required***. - -This is the password used to access the database at the configured endpoint. - -### Example: -```yaml -environment: - - MULTI_QUEUE_TYPE=SQL - - spring.jpa.hibernate.ddl-auto=create - - spring.autoconfigure.exclude= - - spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/postgres - - spring.datasource.username=postgres - - spring.datasource.password=5up3r5tR0nG! -``` - -## NO SQL (Mongo DB) - -The application can be set into `MONGO` mode to interface with a NoSQL database. Similarly to the others you can set the type with `MULTI_QUEUE_TYPE=MONGO`. - -### NoSQL Environment Properties - -You can either specify all properties individually via, `spring.data.mongodb.host`, `spring.data.mongodb.port`, `spring.data.mongodb.database`, `spring.data.mongodb.username`, `spring.data.mongodb.password`. -Or you can provide all together in a single property: `spring.data.mongodb.uri`. - -#### spring.data.mongodb.host - -***This property is required unless `spring.data.mongodb.uri` is provided***. - -This is the host that the mongo DB is accessible from. - -#### spring.data.mongodb.database - -***This property is required unless `spring.data.mongodb.uri` is provided***. - -This is the database that should be connected to and where the related documents will be created. - -#### spring.data.mongodb.username - -***This property is required unless `spring.data.mongodb.uri` is provided***. - -This is the username/account name used to access the database at the configured endpoint. - -#### spring.data.mongodb.password - -***This property is required unless `spring.data.mongodb.uri` is provided***. - -This is the password used to access the database at the configured endpoint. - -#### spring.data.mongodb.port - -***This property is required unless `spring.data.mongodb.uri` is provided***. - -The port that the mongo db has exposed. - -#### spring.data.mongodb.uri - -***This property is required unless the above properties are already provided***. - -The whole url can be provided in the following format: `mongodb://:@:/` for example: `mongodb://root:password@localhost:27107/messagequeue`. +The application provides a REST API to interact with the messages queued within the Multi Queue. +REST Documentation is provided as Swagger docs from the running application. +You can simply run the docker image: +> docker run -p8080:8080 kilemon/message-queue -### Example: -***Note:** the use of `?authSource=admin` is to allow you to get up and running quickly, properly secured credentials and a non-admin account should always be used.* +## Rest API Documentation -```yaml -environment: -- MULTI_QUEUE_TYPE=MONGO -- spring.data.mongodb.uri=mongodb://root:password@mongo:27017/messagequeue?authSource=admin -``` +Once the image is running you can reach the Swagger documentation from the following endpoint: `http://localhost:8080/swagger-ui/index.html`. --- ## HTTPS -By default the `MessageQueue` does not have HTTPS enabled and is exposed on port `8080`. +By default, the `MessageQueue` does not have HTTPS enabled and is exposed on port `8080`. To enable HTTPS you'll need to provide your own SSL certificate and extend the current version of the image hosted at: https://hub.docker.com/r/kilemon/message-queue. When extending this image you want to add your own SSL certificate into the container and take note of the generated file location as you'll need to reference it in the environment properties you provide to the `MessageQueue`. **NOTE: You need to use version 0.1.9 or above of the `MessageQueue` image.** From f4d0d47390be3c98c420130e95415c3d72f75739 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Mon, 4 Dec 2023 22:38:25 +1100 Subject: [PATCH 52/58] Remove HTTPS from readme and move it to the Wiki. --- README.md | 49 ------------------------------------------------- 1 file changed, 49 deletions(-) diff --git a/README.md b/README.md index 66e6e8e..73056a4 100644 --- a/README.md +++ b/README.md @@ -26,52 +26,3 @@ You can simply run the docker image: ## Rest API Documentation Once the image is running you can reach the Swagger documentation from the following endpoint: `http://localhost:8080/swagger-ui/index.html`. - ---- - -## HTTPS - -By default, the `MessageQueue` does not have HTTPS enabled and is exposed on port `8080`. -To enable HTTPS you'll need to provide your own SSL certificate and extend the current version of the image hosted at: https://hub.docker.com/r/kilemon/message-queue. When extending this image you want to add your own SSL certificate into the container and take note of the generated file location as you'll need to reference it in the environment properties you provide to the `MessageQueue`. -**NOTE: You need to use version 0.1.9 or above of the `MessageQueue` image.** - -Below is an example Dockerfile that you could use to generate a self signed certificate. -Dockerfile: -``` -FROM kilemon/message-queue:latest - -# The generated cert will be placed at /messagequeue/keystore.p12 in the container (refer to path in docker compose file). -RUN ["keytool", "-genkeypair", "-alias", "sslcert", "-keyalg", "RSA", "-keysize", "4096", "-validity", "3650", "-dname", "CN=message-queue", "-keypass", "changeit", "-keystore", "keystore.p12", "-storeType", "PKCS12", "-storepass", "changeit"] - -EXPOSE 8443 - -ENTRYPOINT ["java", "-jar", "messagequeue.jar"] -``` - -Using docker compose you can reference and build this Dockerfile and pass in the appropriate parameters to enable HTTP on the `MessageQueue` application: - -docker-compose.yml: -```yaml -version: "3.9" -services: - queue: - container_name: queue - build: . - ports: - - "8443:8443" - environment: - MULTI_QUEUE_TYPE: IN_MEMORY - server.port: 8443 # The port set here must match the health check port below and the exposed port from the Dockerfile - server.ssl.enabled: true - server.ssl.key-store-type: PKCS12 - server.ssl.key-store: keystore.p12 # This path is relative to the `messagequeue.jar` location. The full location is /messagequeue/keystore.p12 for this example - server.ssl.key-store-password: changeit - healthcheck: # Example simple health check, disabling cert check for this example since it is self-signed - test: wget --no-check-certificate https://localhost:8443/queue/healthcheck - start_period: 3s - interval: 3s - timeout: 3s - retries: 5 -``` - -Once this starts up you should be able to access the application using HTTPS on the exposed port `8443`. From 566a1f1e08e4a6da39dc621cf8f8ba73a0a67038 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Mon, 4 Dec 2023 23:33:06 +1100 Subject: [PATCH 53/58] Update docs. --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 73056a4..4a4308b 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,8 @@ To start the application you can use the following command to pull and run the l Once running the best endpoint to call at the moment is probably: `http://localhost:8080/queue/healthcheck` -The application provides a REST API to interact with the messages queued within the Multi Queue. -REST Documentation is provided as Swagger docs from the running application. -You can simply run the docker image: -> docker run -p8080:8080 kilemon/message-queue +The application provides REST APIs to interact with the messages queued within the MultiQueue. ## Rest API Documentation -Once the image is running you can reach the Swagger documentation from the following endpoint: `http://localhost:8080/swagger-ui/index.html`. +REST Documentation is provided as Swagger docs from the running application. Once the image is running you can reach the Swagger documentation from the following endpoint: `http://localhost:8080/swagger-ui/index.html`. From 5e53bbbb38926befe4145a68fb7edf361c6f36c0 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Tue, 5 Dec 2023 18:20:18 +1100 Subject: [PATCH 54/58] Refactor property names. Remove expiry API arg from the restrict subqueue endpoint as it doesn't make sense to have this at the moment. --- .../settings/MessageQueueSettings.kt | 58 +++++++++---------- .../redis/RedisStandAloneAuthenticatorTest.kt | 4 +- .../mongo/MongoMultiAuthenticatorTest.kt | 2 +- .../sql/MySqlAuthenticatorTest.kt | 2 +- .../sql/PostgreSqlAuthenticatorTest.kt | 2 +- .../redis/RedisSentinelMultiQueueTest.kt | 2 +- .../redis/RedisStandAloneMultiQueueTest.kt | 2 +- .../queue/nosql/mongo/MongoMultiQueueTest.kt | 2 +- .../queue/sql/SqlMultiQueueTest.kt | 2 +- .../rest/controller/AuthControllerTest.kt | 3 +- .../controller/MessageQueueControllerTest.kt | 2 +- .../rest/controller/SettingsControllerTest.kt | 2 +- .../MessageQueueSettingsDefaultTest.kt | 4 +- .../settings/MessageQueueSettingsTest.kt | 2 +- 14 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt index aab6803..359caf2 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt @@ -4,8 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.google.gson.annotations.SerializedName import lombok.Generated import org.springframework.beans.factory.annotation.Value -import org.springframework.beans.factory.config.ConfigurableBeanFactory -import org.springframework.context.annotation.Scope import org.springframework.stereotype.Component /** @@ -26,21 +24,23 @@ class MessageQueueSettings { companion object { - const val MULTI_QUEUE_TYPE: String = "MULTI_QUEUE_TYPE" - const val MULTI_QUEUE_TYPE_DEFAULT: String = "IN_MEMORY" + private const val MESSAGE_QUEUE: String = "message-queue" + + const val STORAGE_MEDIUM: String = "$MESSAGE_QUEUE.storage-medium" + const val STORAGE_MEDIUM_DEFAULT: String = "IN_MEMORY" /** * Start redis related properties */ - const val REDIS_PREFIX: String = "REDIS_PREFIX" - - const val REDIS_ENDPOINT: String = "REDIS_ENDPOINT" + private const val REDIS: String = "redis" + const val REDIS_PREFIX: String = "$MESSAGE_QUEUE.$REDIS.prefix" + const val REDIS_ENDPOINT: String = "$MESSAGE_QUEUE.$REDIS.endpoint" const val REDIS_ENDPOINT_DEFAULT: String = "127.0.0.1" // Redis sentinel related properties - const val REDIS_USE_SENTINELS: String = "REDIS_USE_SENTINELS" + const val REDIS_USE_SENTINELS: String = "$MESSAGE_QUEUE.$REDIS.sentinel" - const val REDIS_MASTER_NAME: String = "REDIS_MASTER_NAME" + const val REDIS_MASTER_NAME: String = "$MESSAGE_QUEUE.$REDIS.master-name" const val REDIS_MASTER_NAME_DEFAULT: String = "mymaster" /** @@ -72,44 +72,44 @@ class MessageQueueSettings /** * Indicates what authentication mode the `MultiQueue` should be in. */ - const val MULTI_QUEUE_AUTHENTICATION: String = "MULTI_QUEUE_AUTHENTICATION" - const val MULTI_QUEUE_AUTHENTICATION_DEFAULT: String = "NONE" + const val RESTRICTION_MODE: String = "$MESSAGE_QUEUE.restriction-mode" + const val RESTRICTION_MODE_DEFAULT: String = "NONE" /** * A property that is passed through to the [au.kilemon.messagequeue.authentication.token.JwtTokenProvider] and * used as the token generation and verification key. If this is not provided, a new key will be generated each * time the application starts. */ - const val MULTI_QUEUE_TOKEN_KEY: String = "MULTI_QUEUE_TOKEN_KEY" + const val ACCESS_TOKEN_KEY: String = "$MESSAGE_QUEUE.access-token.key" } /** - * `Optional` uses the [MULTI_QUEUE_TYPE] environment variable to determine where + * `Optional` uses the [STORAGE_MEDIUM] environment variable to determine where * the underlying multi queue is persisted. It can be any value of [MultiQueueType]. - * Defaults to [MultiQueueType.IN_MEMORY] ([MULTI_QUEUE_TYPE_DEFAULT]). + * Defaults to [MultiQueueType.IN_MEMORY] ([STORAGE_MEDIUM_DEFAULT]). */ - @SerializedName(MULTI_QUEUE_TYPE) - @JsonProperty(MULTI_QUEUE_TYPE) - @Value("\${$MULTI_QUEUE_TYPE:$MULTI_QUEUE_TYPE_DEFAULT}") + @SerializedName(STORAGE_MEDIUM) + @JsonProperty(STORAGE_MEDIUM) + @Value("\${$STORAGE_MEDIUM:$STORAGE_MEDIUM_DEFAULT}") @get:Generated @set:Generated lateinit var multiQueueType: String /** - * `Optional` uses the [MULTI_QUEUE_AUTHENTICATION] environment variable to determine whether specific sub-queues + * `Optional` uses the [RESTRICTION_MODE] environment variable to determine whether specific sub-queues * will require authentication or not to create or access. It can be any value of [MultiQueueType]. - * Defaults to [MultiQueueType.IN_MEMORY] ([MULTI_QUEUE_AUTHENTICATION_DEFAULT]). + * Defaults to [MultiQueueType.IN_MEMORY] ([RESTRICTION_MODE_DEFAULT]). */ - @SerializedName(MULTI_QUEUE_AUTHENTICATION) - @JsonProperty(MULTI_QUEUE_AUTHENTICATION) - @Value("\${$MULTI_QUEUE_AUTHENTICATION:$MULTI_QUEUE_AUTHENTICATION_DEFAULT}") + @SerializedName(RESTRICTION_MODE) + @JsonProperty(RESTRICTION_MODE) + @Value("\${$RESTRICTION_MODE:$RESTRICTION_MODE_DEFAULT}") @get:Generated @set:Generated lateinit var multiQueueAuthentication: String /** - * `Optional` when [MULTI_QUEUE_TYPE] is set to [MultiQueueType.REDIS]. + * `Optional` when [STORAGE_MEDIUM] is set to [MultiQueueType.REDIS]. * Uses the [REDIS_PREFIX] to set a prefix used for all redis entry keys. * * E.g. if the initial value for the redis entry is "my-key" and no prefix is defined the entries would be stored under "my-key". @@ -123,7 +123,7 @@ class MessageQueueSettings lateinit var redisPrefix: String /** - * `Required` when [MULTI_QUEUE_TYPE] is set to [MultiQueueType.REDIS]. + * `Required` when [STORAGE_MEDIUM] is set to [MultiQueueType.REDIS]. * The input endpoint string which is used for both standalone and the sentinel redis configurations. * This supports a comma separated list or single definition of a redis endpoint in the following formats: * `:,:,` @@ -138,7 +138,7 @@ class MessageQueueSettings lateinit var redisEndpoint: String /** - * `Optional` when [MULTI_QUEUE_TYPE] is set to [MultiQueueType.REDIS]. + * `Optional` when [STORAGE_MEDIUM] is set to [MultiQueueType.REDIS]. * Indicates whether the `MultiQueue` should connect directly to the redis instance or connect via one or more sentinel instances. * If set to `true` the `MultiQueue` will create a sentinel pool connection instead of a direct connection which is what would occur if this is left as `false`. * By default, this is `false`. @@ -151,7 +151,7 @@ class MessageQueueSettings lateinit var redisUseSentinels: String /** - * `Optional` when [MULTI_QUEUE_TYPE] is set to [MultiQueueType.REDIS]. + * `Optional` when [STORAGE_MEDIUM] is set to [MultiQueueType.REDIS]. * `Required` when [redisUseSentinels] is set to `true`. Is used to indicate the name of the redis master instance. * By default, this is [REDIS_MASTER_NAME_DEFAULT]. */ @@ -163,7 +163,7 @@ class MessageQueueSettings lateinit var redisMasterName: String /** - * `Required` when [MULTI_QUEUE_TYPE] is set to [MultiQueueType.SQL]. + * `Required` when [STORAGE_MEDIUM] is set to [MultiQueueType.SQL]. * This defines the database connection string e.g: * `"jdbc:mysql://localhost:3306/message-queue"` */ @@ -175,7 +175,7 @@ class MessageQueueSettings lateinit var sqlEndpoint: String /** - * `Required` when [MULTI_QUEUE_TYPE] is set to [MultiQueueType.SQL]. + * `Required` when [STORAGE_MEDIUM] is set to [MultiQueueType.SQL]. * This is the username/account name used to access the database defined in [SQL_ENDPOINT]. */ @SerializedName(SQL_USERNAME) @@ -186,7 +186,7 @@ class MessageQueueSettings lateinit var sqlUsername: String /** - * `Required` when [MULTI_QUEUE_TYPE] is set to [MultiQueueType.SQL]. + * `Required` when [STORAGE_MEDIUM] is set to [MultiQueueType.SQL]. * This is the password used to access the database defined in [SQL_ENDPOINT]. */ // TODO: Commenting out since it is unused and returned in the settings endpoint without masking diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt index 1d3a1e2..3446d16 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisStandAloneAuthenticatorTest.kt @@ -1,7 +1,6 @@ package au.kilemon.messagequeue.authentication.authenticator.cache.redis import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticatorTest -import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.configuration.cache.redis.RedisConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration @@ -10,7 +9,6 @@ import au.kilemon.messagequeue.settings.MessageQueueSettings import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.springframework.boot.test.util.TestPropertyValues import org.springframework.context.ApplicationContextInitializer @@ -29,7 +27,7 @@ import org.testcontainers.utility.DockerImageName * @author github.com/Kilemonn */ @ExtendWith(SpringExtension::class) -@TestPropertySource(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS", "${MessageQueueSettings.REDIS_PREFIX}=test"]) +@TestPropertySource(properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=REDIS", "${MessageQueueSettings.REDIS_PREFIX}=test"]) @Testcontainers @ContextConfiguration(initializers = [RedisStandAloneAuthenticatorTest.Initializer::class]) @Import(*[QueueConfiguration::class, LoggingConfiguration::class, RedisConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class]) diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoMultiAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoMultiAuthenticatorTest.kt index 9c4111d..0373c50 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoMultiAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoMultiAuthenticatorTest.kt @@ -30,7 +30,7 @@ import org.testcontainers.utility.DockerImageName */ @ExtendWith(SpringExtension::class) @Testcontainers -@DataMongoTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=MONGO"]) +@DataMongoTest(properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=MONGO"]) @ContextConfiguration(initializers = [MongoMultiAuthenticatorTest.Initializer::class]) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt index bd2ec17..f34e523 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/MySqlAuthenticatorTest.kt @@ -28,7 +28,7 @@ import org.testcontainers.utility.DockerImageName */ @ExtendWith(SpringExtension::class) @Testcontainers -@DataJpaTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=SQL", "spring.jpa.hibernate.ddl-auto=create", "spring.autoconfigure.exclude="]) +@DataJpaTest(properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=SQL", "spring.jpa.hibernate.ddl-auto=create", "spring.autoconfigure.exclude="]) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ContextConfiguration(initializers = [MySqlAuthenticatorTest.Initializer::class]) @Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt index b4e43d9..a92fdc5 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/PostgreSqlAuthenticatorTest.kt @@ -28,7 +28,7 @@ import org.testcontainers.utility.DockerImageName */ @ExtendWith(SpringExtension::class) @Testcontainers -@DataJpaTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=SQL", "spring.jpa.hibernate.ddl-auto=create", "spring.autoconfigure.exclude="]) +@DataJpaTest(properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=SQL", "spring.jpa.hibernate.ddl-auto=create", "spring.autoconfigure.exclude="]) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ContextConfiguration(initializers = [PostgreSqlAuthenticatorTest.Initializer::class]) @Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt index f15954f..b7a4002 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisSentinelMultiQueueTest.kt @@ -29,7 +29,7 @@ import java.util.* * @author github.com/Kilemonn */ @ExtendWith(SpringExtension::class) -@TestPropertySource(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS"]) +@TestPropertySource(properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=REDIS"]) @Testcontainers @ContextConfiguration(initializers = [RedisSentinelMultiQueueTest.Initializer::class]) @Import(*[LoggingConfiguration::class, RedisConfiguration::class, QueueConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class]) diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt index 96c8ffb..2a411a5 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt @@ -39,7 +39,7 @@ import org.testcontainers.utility.DockerImageName * @author github.com/Kilemonn */ @ExtendWith(SpringExtension::class) -@TestPropertySource(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS", "${MessageQueueSettings.REDIS_PREFIX}=test"]) +@TestPropertySource(properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=REDIS", "${MessageQueueSettings.REDIS_PREFIX}=test"]) @Testcontainers @ContextConfiguration(initializers = [RedisStandAloneMultiQueueTest.Initializer::class]) @Import(*[QueueConfiguration::class, LoggingConfiguration::class, RedisConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class]) diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt index ebfb2df..b10391a 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt @@ -28,7 +28,7 @@ import org.testcontainers.utility.DockerImageName */ @ExtendWith(SpringExtension::class) @Testcontainers -@DataMongoTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=MONGO"]) +@DataMongoTest(properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=MONGO"]) @ContextConfiguration(initializers = [MongoMultiQueueTest.Initializer::class]) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Import( *[QueueConfiguration::class, LoggingConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class] ) diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueueTest.kt index aee2255..accda91 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueueTest.kt @@ -25,6 +25,6 @@ import org.testcontainers.junit.jupiter.Testcontainers */ @ExtendWith(SpringExtension::class) @Testcontainers -@DataJpaTest(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=SQL", "spring.jpa.hibernate.ddl-auto=create", "spring.autoconfigure.exclude="]) +@DataJpaTest(properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=SQL", "spring.jpa.hibernate.ddl-auto=create", "spring.autoconfigure.exclude="]) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) abstract class SqlMultiQueueTest: MultiQueueTest() diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index 2597471..8509e51 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -24,7 +24,6 @@ import org.springframework.boot.test.mock.mockito.SpyBean import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import import org.springframework.http.MediaType -import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.junit.jupiter.SpringExtension import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.MvcResult @@ -39,7 +38,7 @@ import java.util.* * @author github.com/Kilemonn */ @ExtendWith(SpringExtension::class) -@WebMvcTest(controllers = [AuthController::class], properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=IN_MEMORY"]) +@WebMvcTest(controllers = [AuthController::class], properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=IN_MEMORY"]) @Import(*[QueueConfiguration::class, LoggingConfiguration::class]) class AuthControllerTest { diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt index a63a90c..e7831f8 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt @@ -42,7 +42,7 @@ import java.util.* * @author github.com/Kilemonn */ @ExtendWith(SpringExtension::class) -@WebMvcTest(controllers = [MessageQueueController::class], properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=IN_MEMORY"]) +@WebMvcTest(controllers = [MessageQueueController::class], properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=IN_MEMORY"]) @Import(*[QueueConfiguration::class, LoggingConfiguration::class]) class MessageQueueControllerTest { diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt index e76dc6b..070eb28 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt @@ -30,7 +30,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers * @author github.com/Kilemonn */ @ExtendWith(SpringExtension::class) -@WebMvcTest(controllers = [SettingsController::class], properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=IN_MEMORY"]) +@WebMvcTest(controllers = [SettingsController::class], properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=IN_MEMORY"]) @Import(*[QueueConfiguration::class, LoggingConfiguration::class]) class SettingsControllerTest { diff --git a/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt b/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt index c194ef6..22cb8fa 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt @@ -42,8 +42,8 @@ class MessageQueueSettingsDefaultTest fun testDefaults() { Assertions.assertNotNull(messageQueueSettings) - Assertions.assertEquals(MessageQueueSettings.MULTI_QUEUE_TYPE_DEFAULT, messageQueueSettings.multiQueueType) - Assertions.assertEquals(MessageQueueSettings.MULTI_QUEUE_AUTHENTICATION_DEFAULT, messageQueueSettings.multiQueueAuthentication) + Assertions.assertEquals(MessageQueueSettings.STORAGE_MEDIUM_DEFAULT, messageQueueSettings.multiQueueType) + Assertions.assertEquals(MessageQueueSettings.RESTRICTION_MODE_DEFAULT, messageQueueSettings.multiQueueAuthentication) Assertions.assertEquals(MessageQueueSettings.REDIS_ENDPOINT_DEFAULT, messageQueueSettings.redisEndpoint) Assertions.assertEquals("", messageQueueSettings.redisPrefix) diff --git a/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsTest.kt b/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsTest.kt index 2c072c3..8f56377 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsTest.kt @@ -16,7 +16,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension */ @ExtendWith(SpringExtension::class) @TestPropertySource(properties = [ - "${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS", + "${MessageQueueSettings.STORAGE_MEDIUM}=REDIS", "${MessageQueueSettings.REDIS_ENDPOINT}=123.123.123.123", "${MessageQueueSettings.REDIS_PREFIX}=redis", "${MessageQueueSettings.REDIS_USE_SENTINELS}=true", From 1e33d88f12dcabc6d9f831de3176703b429fa4ec Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Tue, 5 Dec 2023 18:20:33 +1100 Subject: [PATCH 55/58] Add remaining files with property rename. --- .../messagequeue/authentication/token/JwtTokenProvider.kt | 8 ++++---- .../messagequeue/configuration/QueueConfiguration.kt | 6 +++--- .../configuration/cache/redis/RedisConfiguration.kt | 7 +++---- .../messagequeue/rest/controller/AuthController.kt | 8 ++++---- .../cache/redis/RedisSentinelAuthenticatorTest.kt | 2 +- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt index e5a4f2e..d5a31d4 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/token/JwtTokenProvider.kt @@ -31,7 +31,7 @@ class JwtTokenProvider: HasLogger private var algorithm: Algorithm? = null - @Value("\${${MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY}:\"\"}") + @Value("\${${MessageQueueSettings.ACCESS_TOKEN_KEY}:\"\"}") var tokenKey: String = "" private set @@ -52,19 +52,19 @@ class JwtTokenProvider: HasLogger /** * Get the key to be used for Jwt token generation and verification. * - * @return If a value is provided via [MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY] then we will use it if it is + * @return If a value is provided via [MessageQueueSettings.ACCESS_TOKEN_KEY] then we will use it if it is * not blank. Otherwise, a randomly generated a byte array is returned */ fun getOrGenerateKey(key: String): ByteArray { return if (key.isNotBlank()) { - LOG.info("Using provided key in property [{}] as the HMAC512 token generation and verification key.", MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY) + LOG.info("Using provided key in property [{}] as the HMAC512 token generation and verification key.", MessageQueueSettings.ACCESS_TOKEN_KEY) key.toByteArray() } else { - LOG.info("No HMAC512 key provided in property [{}] for token generation and verification key. Generating a new random key.", MessageQueueSettings.MULTI_QUEUE_TOKEN_KEY) + LOG.info("No HMAC512 key provided in property [{}] for token generation and verification key. Generating a new random key.", MessageQueueSettings.ACCESS_TOKEN_KEY) val random = SecureRandom() val bytes = ByteArray(128) random.nextBytes(bytes) diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt index 32c198f..cd4b129 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt @@ -70,7 +70,7 @@ class QueueConfiguration : HasLogger } } - LOG.info("Initialising [{}] queue as the [{}] is set to [{}].", queue::class.java.name, MessageQueueSettings.MULTI_QUEUE_TYPE, messageQueueSettings.multiQueueType) + LOG.info("Initialising [{}] queue as the [{}] is set to [{}].", queue::class.java.name, MessageQueueSettings.STORAGE_MEDIUM, messageQueueSettings.multiQueueType) return queue } @@ -95,7 +95,7 @@ class QueueConfiguration : HasLogger } } - LOG.info("Using [{}] authentication as the [{}] is set to [{}].", authenticationType, MessageQueueSettings.MULTI_QUEUE_AUTHENTICATION, messageQueueSettings.multiQueueAuthentication) + LOG.info("Using [{}] authentication as the [{}] is set to [{}].", authenticationType, MessageQueueSettings.RESTRICTION_MODE, messageQueueSettings.multiQueueAuthentication) return authenticationType } @@ -119,7 +119,7 @@ class QueueConfiguration : HasLogger } } - LOG.info("Initialising [{}] authenticator as the [{}] is set to [{}].", authenticator::class.java.name, MessageQueueSettings.MULTI_QUEUE_TYPE, messageQueueSettings.multiQueueType) + LOG.info("Initialising [{}] authenticator as the [{}] is set to [{}].", authenticator::class.java.name, MessageQueueSettings.STORAGE_MEDIUM, messageQueueSettings.multiQueueType) return authenticator } diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt index 38faaa5..8f79c27 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/cache/redis/RedisConfiguration.kt @@ -4,7 +4,6 @@ import au.kilemon.messagequeue.authentication.AuthenticationMatrix import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.settings.MessageQueueSettings -import lombok.Generated import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty @@ -92,7 +91,7 @@ class RedisConfiguration: HasLogger * @return the created [RedisConnectionFactory] based on the configured [MessageQueueSettings] */ @Bean - @ConditionalOnProperty(name=[MessageQueueSettings.MULTI_QUEUE_TYPE], havingValue="REDIS") + @ConditionalOnProperty(name=[MessageQueueSettings.STORAGE_MEDIUM], havingValue="REDIS") fun getConnectionFactory(): RedisConnectionFactory { return if (messageQueueSettings.redisUseSentinels.toBoolean()) @@ -160,7 +159,7 @@ class RedisConfiguration: HasLogger * @return the [RedisTemplate] used to interface with the [RedisTemplate] cache. */ @Bean - @ConditionalOnProperty(name=[MessageQueueSettings.MULTI_QUEUE_TYPE], havingValue="REDIS") + @ConditionalOnProperty(name=[MessageQueueSettings.STORAGE_MEDIUM], havingValue="REDIS") fun getQueueRedisTemplate(): RedisTemplate { val template = RedisTemplate() @@ -175,7 +174,7 @@ class RedisConfiguration: HasLogger * @return the [RedisTemplate] used to interface with the [RedisTemplate] cache. */ @Bean - @ConditionalOnProperty(name=[MessageQueueSettings.MULTI_QUEUE_TYPE], havingValue="REDIS") + @ConditionalOnProperty(name=[MessageQueueSettings.STORAGE_MEDIUM], havingValue="REDIS") fun getAuthMatrixRedisTemplate(): RedisTemplate { val template = RedisTemplate() diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt index eae3e76..1f640a7 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt @@ -77,8 +77,8 @@ open class AuthController : HasLogger ) fun restrictSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "The sub-queue that you wish to restrict to allow further access only by callers that posses the returned token.") @PathVariable(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, - @Parameter(`in` = ParameterIn.QUERY, required = false, description = "The generated token's expiry in minutes.") - @RequestParam(required = false, name = RestParameters.EXPIRY) expiry: Long?): ResponseEntity + /*@Parameter(`in` = ParameterIn.QUERY, required = false, description = "The generated token's expiry in minutes.") + @RequestParam(required = false, name = RestParameters.EXPIRY) expiry: Long?*/): ResponseEntity { if (multiQueueAuthenticator.isInNoneMode()) { @@ -94,7 +94,7 @@ open class AuthController : HasLogger else { // Generating the token first, so we don't need to roll back restriction add later if there is a problem - val token = jwtTokenProvider.createTokenForSubQueue(queueType, expiry) + val token = jwtTokenProvider.createTokenForSubQueue(queueType, null) if (token.isEmpty) { LOG.error("Failed to generated token for sub-queue [{}].", queueType) @@ -108,7 +108,7 @@ open class AuthController : HasLogger } else { - LOG.info("Successfully generated token for sub-queue [{}] with expiry [{}] minutes.", queueType, expiry) + LOG.info("Successfully generated token for sub-queue [{}].", queueType) ResponseEntity.status(HttpStatus.CREATED).body(AuthResponse(token.get(), queueType)) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt index 2c9c9e4..fe5953d 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisSentinelAuthenticatorTest.kt @@ -27,7 +27,7 @@ import org.testcontainers.utility.DockerImageName * @author github.com/Kilemonn */ @ExtendWith(SpringExtension::class) -@TestPropertySource(properties = ["${MessageQueueSettings.MULTI_QUEUE_TYPE}=REDIS"]) +@TestPropertySource(properties = ["${MessageQueueSettings.STORAGE_MEDIUM}=REDIS"]) @Testcontainers @ContextConfiguration(initializers = [RedisSentinelAuthenticatorTest.Initializer::class]) @Import(*[LoggingConfiguration::class, RedisConfiguration::class, QueueConfiguration::class, MultiQueueTest.MultiQueueTestConfiguration::class]) From 9cd5410956e9568b8ce8f6a32a84aee4ecdf5a91 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Tue, 5 Dec 2023 19:15:10 +1100 Subject: [PATCH 56/58] Add "removePrefix" method just for the RedisMultiQueue. Add test for new method. Update stream collect calls to go straight to Set. --- .../cache/redis/RedisAuthenticator.kt | 3 +- .../nosql/mongo/MongoAuthenticator.kt | 3 +- .../authenticator/sql/SqlAuthenticator.kt | 3 +- .../queue/cache/redis/RedisMultiQueue.kt | 38 ++++++++++++++++++- .../rest/controller/MessageQueueController.kt | 8 +++- .../redis/RedisStandAloneMultiQueueTest.kt | 33 ++++++++++++++++ 6 files changed, 82 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt index bd0edfa..2f1f33f 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/cache/redis/RedisAuthenticator.kt @@ -5,6 +5,7 @@ import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthentica import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired import org.springframework.data.redis.core.RedisTemplate +import java.util.stream.Collectors /** * A [MultiQueueAuthenticator] implementation using Redis as the storage mechanism for the restricted @@ -60,7 +61,7 @@ class RedisAuthenticator: MultiQueueAuthenticator() override fun getRestrictedSubQueueIdentifiers(): Set { - return getMembersSet().map { authMatrix -> authMatrix.subQueue }.toList().toSet() + return getMembersSet().stream().map { authMatrix -> authMatrix.subQueue }.collect(Collectors.toSet()) } override fun clearRestrictedSubQueues(): Long diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt index 6454051..9d5d77f 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/nosql/mongo/MongoAuthenticator.kt @@ -4,6 +4,7 @@ import au.kilemon.messagequeue.authentication.AuthenticationMatrixDocument import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired +import java.util.stream.Collectors /** * A [MultiQueueAuthenticator] implementation using MongoDB as the storage mechanism for the restricted sub-queue @@ -59,7 +60,7 @@ class MongoAuthenticator: MultiQueueAuthenticator() override fun getRestrictedSubQueueIdentifiers(): Set { return authenticationMatrixRepository.findAll().stream().map { authMatrix -> authMatrix.subQueue } - .toList().toSet() + .collect(Collectors.toSet()) } override fun clearRestrictedSubQueues(): Long diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt index 5d7b92e..d59500d 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/sql/SqlAuthenticator.kt @@ -4,6 +4,7 @@ import au.kilemon.messagequeue.authentication.AuthenticationMatrix import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired +import java.util.stream.Collectors /** * A [MultiQueueAuthenticator] implementation using SQL as the storage mechanism for the restricted sub-queue @@ -42,7 +43,7 @@ class SqlAuthenticator: MultiQueueAuthenticator() override fun getRestrictedSubQueueIdentifiers(): Set { return authenticationMatrixRepository.findAll().stream().map { authMatrix -> authMatrix.subQueue } - .toList().toSet() + .collect(Collectors.toSet()) } override fun clearRestrictedSubQueues(): Long diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt index 561616a..e034c24 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt @@ -35,13 +35,47 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate */ private fun appendPrefix(queueType: String): String { - if (prefix.isNotBlank() && !queueType.startsWith(prefix)) + if (hasPrefix() && !queueType.startsWith(getPrefix())) { - return "${prefix}$queueType" + return "${getPrefix()}$queueType" } return queueType } + /** + * @return whether the [prefix] is [String.isNotBlank] + */ + internal fun hasPrefix(): Boolean + { + return getPrefix().isNotBlank() + } + + /** + * @return [prefix] + */ + internal fun getPrefix(): String + { + return prefix + } + + /** + * If [prefix] is set, removes this from all provided [keys]. + * If [prefix] is null or blank, then the provided [keys] [Set] is immediately returned. + * + * @param keys the [Set] of [String] to remove the [prefix] from + * @return the updated [Set] of [String] with the [prefix] removed + */ + fun removePrefix(keys: Set): Set + { + if (!hasPrefix()) + { + return keys + } + + val prefixLength = getPrefix().length + return keys.stream().filter { key -> key.startsWith(getPrefix()) }.map { key -> key.substring(prefixLength) }.collect(Collectors.toSet()) + } + /** * Attempts to append the prefix before requesting the underlying redis entry if the provided [queueType] is not prefixed with [MessageQueueSettings.redisPrefix]. */ diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt index 7c0efd2..6261d37 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt @@ -4,6 +4,7 @@ import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthentica import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.MultiQueue +import au.kilemon.messagequeue.queue.cache.redis.RedisMultiQueue import au.kilemon.messagequeue.queue.exception.DuplicateMessageException import au.kilemon.messagequeue.queue.exception.HealthCheckFailureException import au.kilemon.messagequeue.rest.response.MessageResponse @@ -255,7 +256,12 @@ open class MessageQueueController : HasLogger fun getKeys(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "Indicates whether to include keys that currently have zero entries (but have had entries previously). Is true by default.") @RequestParam(required = false, name = RestParameters.INCLUDE_EMPTY) includeEmpty: Boolean?): ResponseEntity> { - return ResponseEntity.ok(messageQueue.keys(includeEmpty ?: true)) + val keys = messageQueue.keys(includeEmpty ?: true) + if (messageQueue is RedisMultiQueue) + { + return ResponseEntity.ok((messageQueue as RedisMultiQueue).removePrefix(keys)) + } + return ResponseEntity.ok(keys) } @Operation(summary = "Delete a keys or all keys, in turn clearing that sub queue.", description = "Delete the sub queue that matches the provided key. If no key is provided, all sub queues will be cleared.") diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt index 2a411a5..d19a5e2 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt @@ -3,12 +3,14 @@ package au.kilemon.messagequeue.queue.cache.redis import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.configuration.cache.redis.RedisConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration +import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.MultiQueueTest import au.kilemon.messagequeue.settings.MessageQueueSettings import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.springframework.boot.test.context.TestConfiguration import org.springframework.boot.test.util.TestPropertyValues @@ -96,4 +98,35 @@ class RedisStandAloneMultiQueueTest: MultiQueueTest() Assertions.assertTrue(redis.isRunning) multiQueue.clear() } + + /** + * Test [RedisMultiQueue.removePrefix] to make sure the prefix is removed correctly. + */ + @Test + fun testRemovePrefix() + { + Assertions.assertTrue(multiQueue is RedisMultiQueue) + val redisMultiQueue: RedisMultiQueue = (multiQueue as RedisMultiQueue) + Assertions.assertTrue(redisMultiQueue.hasPrefix()) + + val prefix = redisMultiQueue.getPrefix() + + val type = "removePrefix" + val type2 = "removePrefix2" + Assertions.assertTrue(redisMultiQueue.add(QueueMessage("data", type))) + Assertions.assertTrue(redisMultiQueue.add(QueueMessage("data2", type2))) + + val keys = redisMultiQueue.keys() + Assertions.assertTrue(keys.contains("$prefix$type")) + Assertions.assertTrue(keys.contains("$prefix$type2")) + keys.forEach { key -> Assertions.assertTrue(key.startsWith(prefix)) } + + val removedPrefix = redisMultiQueue.removePrefix(keys) + Assertions.assertFalse(removedPrefix.contains("$prefix$type")) + Assertions.assertFalse(removedPrefix.contains("$prefix$type2")) + removedPrefix.forEach { key -> Assertions.assertFalse(key.startsWith(prefix)) } + + Assertions.assertTrue(removedPrefix.contains(type)) + Assertions.assertTrue(removedPrefix.contains(type2)) + } } From de1dc9d7fe110381c42a419eaca6cb3739bc0e60 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Tue, 5 Dec 2023 21:13:26 +1100 Subject: [PATCH 57/58] Rename to StorageMedium and RestrictionMode to match documentation change. --- ...thenticationType.kt => RestrictionMode.kt} | 2 +- .../authenticator/MultiQueueAuthenticator.kt | 26 +-- .../MultiQueueAuthorisationException.kt | 4 +- .../configuration/QueueConfiguration.kt | 26 +-- .../filter/JwtAuthenticationFilter.kt | 18 +- .../settings/MessageQueueSettings.kt | 34 ++-- .../{MultiQueueType.kt => StorageMedium.kt} | 2 +- .../MultiQueueAuthenticatorTest.kt | 71 ++++---- .../inmemory/InMemoryAuthenticatorTest.kt | 28 ++-- .../MultiQueueAuthorisationExceptionTest.kt | 4 +- .../messagequeue/queue/MultiQueueTest.kt | 18 +- .../rest/controller/AuthControllerTest.kt | 72 ++++---- .../controller/MessageQueueControllerTest.kt | 158 +++++++++--------- .../rest/controller/SettingsControllerTest.kt | 34 ++-- .../RestResponseExceptionHandlerTest.kt | 8 +- 15 files changed, 251 insertions(+), 254 deletions(-) rename src/main/kotlin/au/kilemon/messagequeue/authentication/{MultiQueueAuthenticationType.kt => RestrictionMode.kt} (93%) rename src/main/kotlin/au/kilemon/messagequeue/settings/{MultiQueueType.kt => StorageMedium.kt} (96%) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/MultiQueueAuthenticationType.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/RestrictionMode.kt similarity index 93% rename from src/main/kotlin/au/kilemon/messagequeue/authentication/MultiQueueAuthenticationType.kt rename to src/main/kotlin/au/kilemon/messagequeue/authentication/RestrictionMode.kt index d571c90..04d9d55 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/MultiQueueAuthenticationType.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/RestrictionMode.kt @@ -6,7 +6,7 @@ package au.kilemon.messagequeue.authentication * * @author github.com/Kilemonn */ -enum class MultiQueueAuthenticationType +enum class RestrictionMode { /** * This is the default, which enforces no authentication on any sub queue, messages can be enqueued and dequeued diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt index fcff5d3..467a476 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt @@ -1,6 +1,6 @@ package au.kilemon.messagequeue.authentication.authenticator -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException import au.kilemon.messagequeue.filter.JwtAuthenticationFilter import au.kilemon.messagequeue.logging.HasLogger @@ -18,29 +18,29 @@ abstract class MultiQueueAuthenticator: HasLogger abstract override val LOG: Logger @Autowired - private lateinit var multiQueueAuthenticationType: MultiQueueAuthenticationType + private lateinit var multiQueueAuthenticationType: RestrictionMode /** * @return [multiQueueAuthenticationType] */ - fun getAuthenticationType(): MultiQueueAuthenticationType + fun getAuthenticationType(): RestrictionMode { return multiQueueAuthenticationType } /** - * Used only for tests to update the set [MultiQueueAuthenticationType]. + * Used only for tests to update the set [RestrictionMode]. * - * @param authenticationType the new [MultiQueueAuthenticationType] to set + * @param authenticationType the new [RestrictionMode] to set */ - fun setAuthenticationType(authenticationType: MultiQueueAuthenticationType) + fun setAuthenticationType(authenticationType: RestrictionMode) { multiQueueAuthenticationType = authenticationType } /** * Used to return a list of completed reserved sub-queue identifiers that can never be used. Even when - * [MultiQueueAuthenticationType.NONE] is being used. + * [RestrictionMode.NONE] is being used. * * @return list of sub-queue identifiers that cannot be used */ @@ -107,27 +107,27 @@ abstract class MultiQueueAuthenticator: HasLogger } /** - * Indicates whether [multiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. + * Indicates whether [multiQueueAuthenticationType] is set to [RestrictionMode.NONE]. */ fun isInNoneMode(): Boolean { - return getAuthenticationType() == MultiQueueAuthenticationType.NONE + return getAuthenticationType() == RestrictionMode.NONE } /** - * Indicates whether [multiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.HYBRID]. + * Indicates whether [multiQueueAuthenticationType] is set to [RestrictionMode.HYBRID]. */ fun isInHybridMode(): Boolean { - return getAuthenticationType() == MultiQueueAuthenticationType.HYBRID + return getAuthenticationType() == RestrictionMode.HYBRID } /** - * Indicates whether [multiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.RESTRICTED]. + * Indicates whether [multiQueueAuthenticationType] is set to [RestrictionMode.RESTRICTED]. */ fun isInRestrictedMode(): Boolean { - return getAuthenticationType() == MultiQueueAuthenticationType.RESTRICTED + return getAuthenticationType() == RestrictionMode.RESTRICTED } /** diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt index ad066f7..4d28a83 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt @@ -1,6 +1,6 @@ package au.kilemon.messagequeue.authentication.exception -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode /** * An authorisation exception used when the `MultiQueueAuthenticator` does not allow the caller to perform the @@ -9,7 +9,7 @@ import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType * * @author github.com/Kilemonn */ -class MultiQueueAuthorisationException(subQueue: String, authenticationType: MultiQueueAuthenticationType) : Exception(String.format(MESSAGE_FORMAT, subQueue, authenticationType)) +class MultiQueueAuthorisationException(subQueue: String, authenticationType: RestrictionMode) : Exception(String.format(MESSAGE_FORMAT, subQueue, authenticationType)) { companion object { diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt index cd4b129..8854b3b 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt @@ -1,7 +1,7 @@ package au.kilemon.messagequeue.configuration import au.kilemon.messagequeue.MessageQueueApplication -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.authentication.authenticator.cache.redis.RedisAuthenticator import au.kilemon.messagequeue.authentication.authenticator.inmemory.InMemoryAuthenticator @@ -17,7 +17,7 @@ import au.kilemon.messagequeue.queue.inmemory.InMemoryMultiQueue import au.kilemon.messagequeue.queue.nosql.mongo.MongoMultiQueue import au.kilemon.messagequeue.queue.sql.SqlMultiQueue import au.kilemon.messagequeue.settings.MessageQueueSettings -import au.kilemon.messagequeue.settings.MultiQueueType +import au.kilemon.messagequeue.settings.StorageMedium import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Bean @@ -59,13 +59,13 @@ class QueueConfiguration : HasLogger // Default to in-memory var queue: MultiQueue = InMemoryMultiQueue() when (messageQueueSettings.multiQueueType.uppercase()) { - MultiQueueType.REDIS.toString() -> { + StorageMedium.REDIS.toString() -> { queue = RedisMultiQueue(messageQueueSettings.redisPrefix, redisTemplate) } - MultiQueueType.SQL.toString() -> { + StorageMedium.SQL.toString() -> { queue = SqlMultiQueue() } - MultiQueueType.MONGO.toString() -> { + StorageMedium.MONGO.toString() -> { queue = MongoMultiQueue() } } @@ -76,22 +76,22 @@ class QueueConfiguration : HasLogger } /** - * Initialise the [MultiQueueAuthenticationType] which drives how sub queues are accessed and created. + * Initialise the [RestrictionMode] which drives how sub queues are accessed and created. */ @Bean - open fun getMultiQueueAuthenticationType(): MultiQueueAuthenticationType + open fun getMultiQueueAuthenticationType(): RestrictionMode { - var authenticationType = MultiQueueAuthenticationType.NONE + var authenticationType = RestrictionMode.NONE if (messageQueueSettings.multiQueueAuthentication.isNotBlank()) { try { - authenticationType = MultiQueueAuthenticationType.valueOf(messageQueueSettings.multiQueueAuthentication.uppercase()) + authenticationType = RestrictionMode.valueOf(messageQueueSettings.multiQueueAuthentication.uppercase()) } catch (ex: Exception) { - LOG.warn("Unable to initialise appropriate authentication type with provided value [{}], falling back to default [{}].", messageQueueSettings.multiQueueAuthentication, MultiQueueAuthenticationType.NONE, ex) + LOG.warn("Unable to initialise appropriate authentication type with provided value [{}], falling back to default [{}].", messageQueueSettings.multiQueueAuthentication, RestrictionMode.NONE, ex) } } @@ -108,13 +108,13 @@ class QueueConfiguration : HasLogger { var authenticator: MultiQueueAuthenticator = InMemoryAuthenticator() when (messageQueueSettings.multiQueueType.uppercase()) { - MultiQueueType.REDIS.toString() -> { + StorageMedium.REDIS.toString() -> { authenticator = RedisAuthenticator() } - MultiQueueType.SQL.toString() -> { + StorageMedium.SQL.toString() -> { authenticator = SqlAuthenticator() } - MultiQueueType.MONGO.toString() -> { + StorageMedium.MONGO.toString() -> { authenticator = MongoAuthenticator() } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index f1fb33c..b6e9623 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -1,7 +1,7 @@ package au.kilemon.messagequeue.filter import au.kilemon.messagequeue.logging.HasLogger -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException import au.kilemon.messagequeue.authentication.token.JwtTokenProvider @@ -62,16 +62,16 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger /** * Perform appropriate validation of the [AUTHORIZATION_HEADER] if it is provided. - * Depending on the set [MultiQueueAuthenticationType] will determine how this filter handles a request. - * - [MultiQueueAuthenticationType.NONE] all requests will be allowed, whether they provide a valid token or not. - * - [MultiQueueAuthenticationType.HYBRID] all requests will be allowed and the provided token [SUB_QUEUE] parameter + * Depending on the set [RestrictionMode] will determine how this filter handles a request. + * - [RestrictionMode.NONE] all requests will be allowed, whether they provide a valid token or not. + * - [RestrictionMode.HYBRID] all requests will be allowed and the provided token [SUB_QUEUE] parameter * will be set if a token is provided. It's up to the lower level controllers to determine how they need to react * in accordance with the active [MultiQueueAuthenticator]. - * - [MultiQueueAuthenticationType.RESTRICTED] a token is required and if not valid the request will be rejected + * - [RestrictionMode.RESTRICTED] a token is required and if not valid the request will be rejected * here and a [MultiQueueAuthenticationException] will be thrown * - * @throws MultiQueueAuthenticationException if [MultiQueueAuthenticationType] is set to - * [MultiQueueAuthenticationType.RESTRICTED] and an invalid token OR NO token is provided + * @throws MultiQueueAuthenticationException if [RestrictionMode] is set to + * [RestrictionMode.RESTRICTED] and an invalid token OR NO token is provided */ override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) { @@ -89,12 +89,12 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger if (authenticator.isInNoneMode()) { - LOG.trace("Allowed access as authentication is set to [{}].", MultiQueueAuthenticationType.NONE) + LOG.trace("Allowed access as authentication is set to [{}].", RestrictionMode.NONE) filterChain.doFilter(request, response) } else if (authenticator.isInHybridMode()) { - LOG.trace("Allowing request through for lower layer to check as authentication is set to [{}].", MultiQueueAuthenticationType.NONE) + LOG.trace("Allowing request through for lower layer to check as authentication is set to [{}].", RestrictionMode.NONE) filterChain.doFilter(request, response) } else if (authenticator.isInRestrictedMode()) diff --git a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt index 359caf2..55591ff 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt @@ -85,8 +85,8 @@ class MessageQueueSettings /** * `Optional` uses the [STORAGE_MEDIUM] environment variable to determine where - * the underlying multi queue is persisted. It can be any value of [MultiQueueType]. - * Defaults to [MultiQueueType.IN_MEMORY] ([STORAGE_MEDIUM_DEFAULT]). + * the underlying multi queue is persisted. It can be any value of [StorageMedium]. + * Defaults to [StorageMedium.IN_MEMORY] ([STORAGE_MEDIUM_DEFAULT]). */ @SerializedName(STORAGE_MEDIUM) @JsonProperty(STORAGE_MEDIUM) @@ -97,8 +97,8 @@ class MessageQueueSettings /** * `Optional` uses the [RESTRICTION_MODE] environment variable to determine whether specific sub-queues - * will require authentication or not to create or access. It can be any value of [MultiQueueType]. - * Defaults to [MultiQueueType.IN_MEMORY] ([RESTRICTION_MODE_DEFAULT]). + * will require authentication or not to create or access. It can be any value of [StorageMedium]. + * Defaults to [StorageMedium.IN_MEMORY] ([RESTRICTION_MODE_DEFAULT]). */ @SerializedName(RESTRICTION_MODE) @JsonProperty(RESTRICTION_MODE) @@ -109,7 +109,7 @@ class MessageQueueSettings /** - * `Optional` when [STORAGE_MEDIUM] is set to [MultiQueueType.REDIS]. + * `Optional` when [STORAGE_MEDIUM] is set to [StorageMedium.REDIS]. * Uses the [REDIS_PREFIX] to set a prefix used for all redis entry keys. * * E.g. if the initial value for the redis entry is "my-key" and no prefix is defined the entries would be stored under "my-key". @@ -123,7 +123,7 @@ class MessageQueueSettings lateinit var redisPrefix: String /** - * `Required` when [STORAGE_MEDIUM] is set to [MultiQueueType.REDIS]. + * `Required` when [STORAGE_MEDIUM] is set to [StorageMedium.REDIS]. * The input endpoint string which is used for both standalone and the sentinel redis configurations. * This supports a comma separated list or single definition of a redis endpoint in the following formats: * `:,:,` @@ -138,7 +138,7 @@ class MessageQueueSettings lateinit var redisEndpoint: String /** - * `Optional` when [STORAGE_MEDIUM] is set to [MultiQueueType.REDIS]. + * `Optional` when [STORAGE_MEDIUM] is set to [StorageMedium.REDIS]. * Indicates whether the `MultiQueue` should connect directly to the redis instance or connect via one or more sentinel instances. * If set to `true` the `MultiQueue` will create a sentinel pool connection instead of a direct connection which is what would occur if this is left as `false`. * By default, this is `false`. @@ -151,7 +151,7 @@ class MessageQueueSettings lateinit var redisUseSentinels: String /** - * `Optional` when [STORAGE_MEDIUM] is set to [MultiQueueType.REDIS]. + * `Optional` when [STORAGE_MEDIUM] is set to [StorageMedium.REDIS]. * `Required` when [redisUseSentinels] is set to `true`. Is used to indicate the name of the redis master instance. * By default, this is [REDIS_MASTER_NAME_DEFAULT]. */ @@ -163,7 +163,7 @@ class MessageQueueSettings lateinit var redisMasterName: String /** - * `Required` when [STORAGE_MEDIUM] is set to [MultiQueueType.SQL]. + * `Required` when [STORAGE_MEDIUM] is set to [StorageMedium.SQL]. * This defines the database connection string e.g: * `"jdbc:mysql://localhost:3306/message-queue"` */ @@ -175,7 +175,7 @@ class MessageQueueSettings lateinit var sqlEndpoint: String /** - * `Required` when [STORAGE_MEDIUM] is set to [MultiQueueType.SQL]. + * `Required` when [STORAGE_MEDIUM] is set to [StorageMedium.SQL]. * This is the username/account name used to access the database defined in [SQL_ENDPOINT]. */ @SerializedName(SQL_USERNAME) @@ -186,7 +186,7 @@ class MessageQueueSettings lateinit var sqlUsername: String /** - * `Required` when [STORAGE_MEDIUM] is set to [MultiQueueType.SQL]. + * `Required` when [STORAGE_MEDIUM] is set to [StorageMedium.SQL]. * This is the password used to access the database defined in [SQL_ENDPOINT]. */ // TODO: Commenting out since it is unused and returned in the settings endpoint without masking @@ -197,7 +197,7 @@ class MessageQueueSettings // lateinit var sqlPassword: String /** - * Required when [MultiQueueType.MONGO] is used and [mongoUri] is empty. + * Required when [StorageMedium.MONGO] is used and [mongoUri] is empty. * It specifies the host name that the mongo db is available at. */ @SerializedName(MONGO_HOST) @@ -208,7 +208,7 @@ class MessageQueueSettings lateinit var mongoHost: String /** - * Required when [MultiQueueType.MONGO] is used and [mongoUri] is empty. + * Required when [StorageMedium.MONGO] is used and [mongoUri] is empty. * It specifies the port that the mongo db is available on. */ @SerializedName(MONGO_PORT) @@ -219,7 +219,7 @@ class MessageQueueSettings lateinit var mongoPort: String /** - * Required when [MultiQueueType.MONGO] is used and [mongoUri] is empty. + * Required when [StorageMedium.MONGO] is used and [mongoUri] is empty. * It specifies the database you wish to connect to. */ @SerializedName(MONGO_DATABASE) @@ -230,7 +230,7 @@ class MessageQueueSettings lateinit var mongoDatabase: String /** - * Required when [MultiQueueType.MONGO] is used and [mongoUri] is empty. + * Required when [StorageMedium.MONGO] is used and [mongoUri] is empty. * It specifies the username that you wish to connect with. */ @SerializedName(MONGO_USERNAME) @@ -241,7 +241,7 @@ class MessageQueueSettings lateinit var mongoUsername: String /** - * Required when [MultiQueueType.MONGO] is used and [mongoUri] is empty. + * Required when [StorageMedium.MONGO] is used and [mongoUri] is empty. * It specifies the password for the user that you wish to connect with. */ // TODO: Commenting out since it is unused and returned in the settings endpoint without masking @@ -252,7 +252,7 @@ class MessageQueueSettings // lateinit var mongoPassword: String /** - * Required when [MultiQueueType.MONGO] is used and the above mongo properties are empty. + * Required when [StorageMedium.MONGO] is used and the above mongo properties are empty. * It specifies all properties of the mongo connection in the format of `mongodb://:@:/`. */ @SerializedName(MONGO_URI) diff --git a/src/main/kotlin/au/kilemon/messagequeue/settings/MultiQueueType.kt b/src/main/kotlin/au/kilemon/messagequeue/settings/StorageMedium.kt similarity index 96% rename from src/main/kotlin/au/kilemon/messagequeue/settings/MultiQueueType.kt rename to src/main/kotlin/au/kilemon/messagequeue/settings/StorageMedium.kt index 4e1ff15..db97125 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/settings/MultiQueueType.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/settings/StorageMedium.kt @@ -6,7 +6,7 @@ package au.kilemon.messagequeue.settings * * @author github.com/Kilemonn */ -enum class MultiQueueType +enum class StorageMedium { /** * Will initialise an in-memory multiqueue to store queue messages. diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt index 193e0a3..d401b8b 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt @@ -1,10 +1,9 @@ package au.kilemon.messagequeue.authentication.authenticator -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException import au.kilemon.messagequeue.filter.JwtAuthenticationFilter import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import org.mockito.Mockito @@ -26,12 +25,12 @@ abstract class MultiQueueAuthenticatorTest /** * Ensure [MultiQueueAuthenticator.addRestrictedEntry] always returns and does not add an entry if the - * [MultiQueueAuthenticator.getAuthenticationType] is [MultiQueueAuthenticationType.NONE]. + * [MultiQueueAuthenticator.getAuthenticationType] is [RestrictionMode.NONE]. */ @Test fun testAddRestrictedEntry_WithNoneMode() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testAddRestrictedEntry_WithNoneMode" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) Assertions.assertFalse(multiQueueAuthenticator.addRestrictedEntry(subQueue)) @@ -40,14 +39,14 @@ abstract class MultiQueueAuthenticatorTest /** * Ensure [MultiQueueAuthenticator.addRestrictedEntry] will add the request sub queue identifier when the - * [MultiQueueAuthenticator.getAuthenticationType] is NOT [MultiQueueAuthenticationType.NONE]. + * [MultiQueueAuthenticator.getAuthenticationType] is NOT [RestrictionMode.NONE]. * Also tests [MultiQueueAuthenticator.isRestricted] can determine the sub queue is restricted after its been added. */ @Test fun testAddRestrictedEntry_WithARestrictedNoneMode() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testAddRestrictedEntry_WithARestrictedNoneMode" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) @@ -57,21 +56,21 @@ abstract class MultiQueueAuthenticatorTest /** * Ensure that [MultiQueueAuthenticator.removeRestriction] will not be able to remove a restriction if the - * [MultiQueueAuthenticator.getAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. + * [MultiQueueAuthenticator.getAuthenticationType] is set to [RestrictionMode.NONE]. */ @Test fun testRemoveRestriction_WithNoneMode() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testRemoveRestriction_WithNoneMode" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) - Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) Assertions.assertFalse(multiQueueAuthenticator.removeRestriction(subQueue)) } @@ -82,8 +81,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testRemoveRestriction_AddExistingSubQueueIdentifier() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testRemoveRestriction_AddExistingSubQueueIdentifier" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) @@ -96,13 +95,13 @@ abstract class MultiQueueAuthenticatorTest /** * Ensure that [MultiQueueAuthenticator.removeRestriction] will not be able to remove a restriction if the - * [MultiQueueAuthenticator.getAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. + * [MultiQueueAuthenticator.getAuthenticationType] is set to [RestrictionMode.NONE]. */ @Test fun testRemoveRestriction_WithARestrictedNoneMode() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testRemoveRestriction_WithARestrictedNoneMode" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) @@ -120,8 +119,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testRemoveRestriction_DoesNotExist() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testRemoveRestriction_DoesNotExist" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) Assertions.assertFalse(multiQueueAuthenticator.removeRestriction(subQueue)) @@ -134,7 +133,7 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithNoneMode() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testCanAccessSubQueue_WithNoneMode" Assertions.assertTrue(multiQueueAuthenticator.canAccessSubQueue(subQueue)) } @@ -146,8 +145,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithHybridMode_isNotRestricted() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testCanAccessSubQueue_WithHybridMode_isNotRestricted" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) @@ -163,8 +162,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithHybridMode_isRestricted_matchesStoredSubQueue() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testCanAccessSubQueue_WithHybridMode_isRestricted_matchesStoredSubQueue" Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) @@ -189,8 +188,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithHybridMode_isRestricted_doesNotMatchStoredSubQueue() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testCanAccessSubQueue_WithHybridMode_isRestricted_doesNotMatchStoredSubQueue" Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) @@ -217,8 +216,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithRestrictedMode_isNotRestricted() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testCanAccessSubQueue_WithRestrictedMode_isNotRestricted" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) @@ -236,8 +235,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithRestrictedMode_isRestricted_matchesStoredSubQueue() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testCanAccessSubQueue_WithRestrictedMode_isRestricted_matchesStoredSubQueue" Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) @@ -263,8 +262,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithRestrictedMode_isRestricted_doesNotMatchStoredSubQueue() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val subQueue = "testCanAccessSubQueue_WithRestrictedMode_isRestricted_doesNotMatchStoredSubQueue" Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) @@ -290,8 +289,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testClearRestrictedSubQueues() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val subQueues = listOf("testClearRestrictedSubQueues1", "testClearRestrictedSubQueues2", "testClearRestrictedSubQueues3", "testClearRestrictedSubQueues4", "testClearRestrictedSubQueues5", "testClearRestrictedSubQueues6") @@ -311,8 +310,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testGetRestrictedSubQueueIdentifiers() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val subQueues = listOf("testGetRestrictedSubQueueIdentifiers1", "testGetRestrictedSubQueueIdentifiers2", "testGetRestrictedSubQueueIdentifiers3", "testGetRestrictedSubQueueIdentifiers4", diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt index 1d14f83..3610fe6 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt @@ -1,6 +1,6 @@ package au.kilemon.messagequeue.authentication.authenticator.inmemory -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticatorTest import au.kilemon.messagequeue.configuration.QueueConfiguration @@ -17,7 +17,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension /** * A test class for the [InMemoryAuthenticator] class. * - * This class also does mock testing for the different types of [MultiQueueAuthenticationType] since they don't + * This class also does mock testing for the different types of [RestrictionMode] since they don't * rely on the backing mechanism. * * @author github.com/Kilemonn @@ -34,55 +34,55 @@ class InMemoryAuthenticatorTest: MultiQueueAuthenticatorTest() /** * Ensure that [MultiQueueAuthenticator.isInNoneMode] returns the correct value based on the stored - * [MultiQueueAuthenticationType]. + * [RestrictionMode]. */ @Test fun testIsInNoneMode() { val authenticator = Mockito.spy(MultiQueueAuthenticator::class.java) - Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.NONE).`when`(authenticator).getAuthenticationType() Assertions.assertTrue(authenticator.isInNoneMode()) - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() Assertions.assertFalse(authenticator.isInNoneMode()) - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getAuthenticationType() Assertions.assertFalse(authenticator.isInNoneMode()) } /** * Ensure that [MultiQueueAuthenticator.isInHybridMode] returns the correct value based on the stored - * [MultiQueueAuthenticationType]. + * [RestrictionMode]. */ @Test fun testIsInHybridMode() { val authenticator = Mockito.spy(MultiQueueAuthenticator::class.java) - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() Assertions.assertTrue(authenticator.isInHybridMode()) - Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.NONE).`when`(authenticator).getAuthenticationType() Assertions.assertFalse(authenticator.isInHybridMode()) - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getAuthenticationType() Assertions.assertFalse(authenticator.isInHybridMode()) } /** * Ensure that [MultiQueueAuthenticator.isInRestrictedMode] returns the correct value based on the stored - * [MultiQueueAuthenticationType]. + * [RestrictionMode]. */ @Test fun testIsInRestrictedMode() { val authenticator = Mockito.spy(MultiQueueAuthenticator::class.java) - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getAuthenticationType() Assertions.assertTrue(authenticator.isInRestrictedMode()) - Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.NONE).`when`(authenticator).getAuthenticationType() Assertions.assertFalse(authenticator.isInRestrictedMode()) - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() Assertions.assertFalse(authenticator.isInRestrictedMode()) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt index 01f808e..e418347 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt @@ -1,6 +1,6 @@ package au.kilemon.messagequeue.authentication.exception -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test @@ -18,7 +18,7 @@ class MultiQueueAuthorisationExceptionTest @Test fun testTypeOfException() { - val e = MultiQueueAuthorisationException("Sub queue", MultiQueueAuthenticationType.NONE) + val e = MultiQueueAuthorisationException("Sub queue", RestrictionMode.NONE) Assertions.assertTrue(Exception::class.isInstance(e)) Assertions.assertFalse(RuntimeException::class.isInstance(e)) } diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt index d4bd52a..7b32b5a 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt @@ -1,6 +1,6 @@ package au.kilemon.messagequeue.queue -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.exception.DuplicateMessageException @@ -400,7 +400,7 @@ abstract class MultiQueueTest @Test fun testGetQueueForType_reservedSubQueue() { - doWithAuthType(MultiQueueAuthenticationType.HYBRID) { + doWithAuthType(RestrictionMode.HYBRID) { authenticator.getReservedSubQueues().forEach { reservedSubQueueIdentifier -> Assertions.assertThrows(IllegalSubQueueIdentifierException::class.java) { multiQueue.getQueueForType(reservedSubQueueIdentifier) @@ -949,7 +949,7 @@ abstract class MultiQueueTest @Test fun testAddReservedSubQueue() { - doWithAuthType(MultiQueueAuthenticationType.RESTRICTED) { + doWithAuthType(RestrictionMode.RESTRICTED) { authenticator.getReservedSubQueues().forEach { reservedSubQueueIdentifier -> val message = QueueMessage("Data", reservedSubQueueIdentifier) Assertions.assertThrows(IllegalSubQueueIdentifierException::class.java) { @@ -966,7 +966,7 @@ abstract class MultiQueueTest @Test fun testKeysWithReservedSubQueueUsage() { - doWithAuthType(MultiQueueAuthenticationType.HYBRID) { + doWithAuthType(RestrictionMode.HYBRID) { var keys = multiQueue.keys() authenticator.getReservedSubQueues().forEach { reservedSubQueueIdentifier -> Assertions.assertFalse(keys.contains(reservedSubQueueIdentifier)) @@ -986,14 +986,14 @@ abstract class MultiQueueTest } /** - * Perform the provided [function] with the [MultiQueueAuthenticationType] set to [authenticationType]. - * Once completed the [MultiQueueAuthenticationType] will be set back to its initial value. + * Perform the provided [function] with the [RestrictionMode] set to [authenticationType]. + * Once completed the [RestrictionMode] will be set back to its initial value. * - * @param authenticationType the [MultiQueueAuthenticationType] to be set while the [function] is being called - * @param function the function to call with the provided [MultiQueueAuthenticationType] being active + * @param authenticationType the [RestrictionMode] to be set while the [function] is being called + * @param function the function to call with the provided [RestrictionMode] being active * @return `T` the result of the [function] */ - private fun doWithAuthType(authenticationType: MultiQueueAuthenticationType, function: Supplier): T + private fun doWithAuthType(authenticationType: RestrictionMode, function: Supplier): T { val previousAuthType = authenticator.getAuthenticationType() authenticator.setAuthenticationType(authenticationType) diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index 8509e51..fd7c828 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -1,6 +1,6 @@ package au.kilemon.messagequeue.rest.controller -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.configuration.QueueConfiguration @@ -82,13 +82,13 @@ class AuthControllerTest /** * Ensure [AuthController.restrictSubQueue] returns [org.springframework.http.HttpStatus.NO_CONTENT] when the - * [MultiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. + * [RestrictionMode] is set to [RestrictionMode.NONE]. */ @Test fun testRestrictSubQueue_inNoneMode() { val queueType = "testRestrictSubQueue_inNoneMode" - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) mockMvc.perform( MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -102,8 +102,8 @@ class AuthControllerTest @Test fun testRestrictSubQueue_alreadyRestricted() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRestrictSubQueue_alreadyRestricted" Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(queueType)) @@ -122,8 +122,8 @@ class AuthControllerTest @Test fun testRestrictSubQueue_wasNotAdded() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRestrictSubQueue_wasNotAdded" Mockito.doReturn(false).`when`(multiQueueAuthenticator).addRestrictedEntry(queueType) @@ -141,8 +141,8 @@ class AuthControllerTest @Test fun testRestrictSubQueue_tokenGenerationFailure() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRestrictSubQueue_tokenGenerationFailure" Mockito.doReturn(Optional.empty()).`when`(jwtTokenProvider).createTokenForSubQueue(queueType) @@ -160,8 +160,8 @@ class AuthControllerTest @Test fun testRestrictSubQueue_tokenGenerated() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRestrictSubQueue_tokenGenerated" @@ -178,15 +178,15 @@ class AuthControllerTest } /** - * Ensure that even in [MultiQueueAuthenticationType.RESTRICTED] mode we can call the + * Ensure that even in [RestrictionMode.RESTRICTED] mode we can call the * [AuthController.restrictSubQueue] this is important, without this being accessible new sub-queues can never * be restricted meaning the queue would be completely inaccessible. */ @Test fun testRestrictSubQueue_inRestrictedMode() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRestrictSubQueue_inRestrictedMode" @@ -204,14 +204,14 @@ class AuthControllerTest /** * Ensure [AuthController.removeRestrictionFromSubQueue] returns [org.springframework.http.HttpStatus.NO_CONTENT] - * when the [MultiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.NONE]. + * when the [RestrictionMode] is set to [RestrictionMode.NONE]. */ @Test fun testRemoveRestrictionFromSubQueue_inNoneMode() { val queueType = "testRemoveRestrictionFromSubQueue_inNoneMode" - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) mockMvc.perform( MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -225,8 +225,8 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_invalidToken() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRemoveRestrictionFromSubQueue_invalidToken" val invalidQueueType = "invalidQueueType" @@ -242,14 +242,14 @@ class AuthControllerTest /** * Ensure [AuthController.removeRestrictionFromSubQueue] returns [org.springframework.http.HttpStatus.UNAUTHORIZED] - * when there is no auth token provided and the [MultiQueueAuthenticationType] is - * [MultiQueueAuthenticationType.RESTRICTED]. + * when there is no auth token provided and the [RestrictionMode] is + * [RestrictionMode.RESTRICTED]. */ @Test fun testRemoveRestrictionFromSubQueue_withoutAuthToken() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRemoveRestrictionFromSubQueue_withoutAuthToken" @@ -266,8 +266,8 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_validTokenButNotRestricted() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRemoveRestrictionFromSubQueue_validToken" val token = jwtTokenProvider.createTokenForSubQueue(queueType) @@ -290,8 +290,8 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_failedToRemoveRestriction() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRemoveRestrictionFromSubQueue_failedToRemoveRestriction" val token = jwtTokenProvider.createTokenForSubQueue(queueType) @@ -317,8 +317,8 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_removeButDontClearQueue() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRemoveRestrictionFromSubQueue_removeButDontClearQueue" val token = jwtTokenProvider.createTokenForSubQueue(queueType) @@ -356,8 +356,8 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_removeAndClearQueue() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val queueType = "testRemoveRestrictionFromSubQueue_removeAndClearQueue" val token = jwtTokenProvider.createTokenForSubQueue(queueType) @@ -389,13 +389,13 @@ class AuthControllerTest /** * Ensure [AuthController.getRestrictedSubQueueIdentifiers] returns [org.springframework.http.HttpStatus.NO_CONTENT] - * when the [MultiQueueAuthenticationType] is [MultiQueueAuthenticationType.NONE]. + * when the [RestrictionMode] is [RestrictionMode.NONE]. */ @Test fun testGetRestrictedSubQueueIdentifiers_inNoneMode() { - Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) mockMvc.perform(MockMvcRequestBuilders.get(AuthController.AUTH_PATH) .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -404,14 +404,14 @@ class AuthControllerTest /** * Ensure [AuthController.getRestrictedSubQueueIdentifiers] returns [org.springframework.http.HttpStatus.OK] - * when the [MultiQueueAuthenticationType] is not in [MultiQueueAuthenticationType.NONE]. + * when the [RestrictionMode] is not in [RestrictionMode.NONE]. * And the response set matches the entries that are restricted. */ @Test fun testGetRestrictedSubQueueIdentifiers_notInNoneMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) val restrictedIdentifiers = setOf("testGetRestrictedSubQueueIdentifiers_inNoneMode1", "testGetRestrictedSubQueueIdentifiers_inNoneMode2", "testGetRestrictedSubQueueIdentifiers_inNoneMode3", "testGetRestrictedSubQueueIdentifiers_inNoneMode4", "testGetRestrictedSubQueueIdentifiers_inNoneMode5") diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt index e7831f8..5bbb6d5 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt @@ -1,6 +1,6 @@ package au.kilemon.messagequeue.rest.controller -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.authentication.token.JwtTokenProvider import au.kilemon.messagequeue.configuration.QueueConfiguration @@ -96,7 +96,7 @@ class MessageQueueControllerTest @Test fun testGetQueueTypeInfo() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val queueType = "testGetQueueTypeInfo" Assertions.assertEquals(0, multiQueue.getQueueForType(queueType).size) @@ -122,7 +122,7 @@ class MessageQueueControllerTest @Test fun testGetAllQueueTypeInfo() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_TYPE) .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -152,7 +152,7 @@ class MessageQueueControllerTest @Test fun testGetEntry() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testGetEntry") @@ -180,7 +180,7 @@ class MessageQueueControllerTest @Test fun testGetEntry_ResponseBody_NotExists() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val uuid = "invalid-not-found-uuid" mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + uuid) @@ -189,14 +189,14 @@ class MessageQueueControllerTest } /** - * Ensure that in [MultiQueueAuthenticationType.HYBRID] mode, when we restrict the sub-queue that we can no longer + * Ensure that in [RestrictionMode.HYBRID] mode, when we restrict the sub-queue that we can no longer * get entries from that specific sub-queue, other sub-queues are still accessible without a token. */ @Test fun testGetEntry_usingHybridMode_withRestrictedSubQueue() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val entries = initialiseMapWithEntries() @@ -256,7 +256,7 @@ class MessageQueueControllerTest @Test fun testCreateQueueEntry_withProvidedDefaults() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testCreateQueueEntry_withProvidedDefaults", assignedTo = "user-1") @@ -288,7 +288,7 @@ class MessageQueueControllerTest @Test fun testCreateQueueEntry_withOutDefaults() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testCreateQueueEntry_withOutDefaults") @@ -320,7 +320,7 @@ class MessageQueueControllerTest @Test fun testCreateEntry_Conflict() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testCreateEntry_Conflict") @@ -339,7 +339,7 @@ class MessageQueueControllerTest @Test fun testCreateQueueEntry_withBlankAssignedTo() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testCreateQueueEntry_withAssignedButNoAssignedTo") message.assignedTo = " " @@ -355,14 +355,14 @@ class MessageQueueControllerTest } /** - * Ensure that in [MultiQueueAuthenticationType.HYBRID] mode, when we restrict the sub-queue that we can no longer + * Ensure that in [RestrictionMode.HYBRID] mode, when we restrict the sub-queue that we can no longer * create entries for that specific sub-queue, other sub-queues can still have messages created without a token. */ @Test fun testCreateEntry_inHybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testCreateEntry_inHybridMode") @@ -399,7 +399,7 @@ class MessageQueueControllerTest @Test fun testGetKeys() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val entries = initialiseMapWithEntries() @@ -426,7 +426,7 @@ class MessageQueueControllerTest @Test fun testGetKeys_excludeEmpty() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val entries = initialiseMapWithEntries() Assertions.assertTrue(multiQueue.remove(entries.first[0])) @@ -458,7 +458,7 @@ class MessageQueueControllerTest @Test fun testGetAll() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val entries = initialiseMapWithEntries() val type = entries.first[0].type @@ -492,7 +492,7 @@ class MessageQueueControllerTest @Test fun testGetAll_SpecificQueueType() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val entries = initialiseMapWithEntries() val type = entries.first[0].type @@ -516,14 +516,14 @@ class MessageQueueControllerTest } /** - * Ensure then when in [MultiQueueAuthenticationType.HYBRID] and [MessageQueueController.getAll] is called + * Ensure then when in [RestrictionMode.HYBRID] and [MessageQueueController.getAll] is called * that restricted queues are not included until a valid token is provided. */ @Test fun testGetAll_inHybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val queueType = "testGetAll_inHybridMode" val messages = listOf(createQueueMessage(queueType), createQueueMessage(queueType)) @@ -569,14 +569,14 @@ class MessageQueueControllerTest } /** - * Ensure then when in [MultiQueueAuthenticationType.HYBRID] and [MessageQueueController.getAll] is called + * Ensure then when in [RestrictionMode.HYBRID] and [MessageQueueController.getAll] is called * and all messages are requested for a restricted queue are not accessible unless a token is provided. */ @Test fun testGetAll_SpecificQueueType_inHybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val queueType = "testGetAll_SpecificQueueType_inHybridMode" val messages = listOf(createQueueMessage(queueType), createQueueMessage(queueType)) @@ -617,7 +617,7 @@ class MessageQueueControllerTest @Test fun testGetOwned_NoneOwned() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val entries = initialiseMapWithEntries() val assignedTo = "my-assigned-to-identifier" @@ -641,7 +641,7 @@ class MessageQueueControllerTest @Test fun testGetOwned_SomeOwned() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "my-assigned-to-identifier" val type = "testGetOwned_SomeOwned" @@ -676,8 +676,8 @@ class MessageQueueControllerTest @Test fun testGetOwned_SomeOwned_inHybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val assignedTo = "my-assigned-to-identifier" val type = "testGetOwned_SomeOwned_inHybridMode" @@ -725,7 +725,7 @@ class MessageQueueControllerTest @Test fun testAssignMessage_doesNotExist() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val uuid = UUID.randomUUID().toString() val assignedTo = "assigned" @@ -742,7 +742,7 @@ class MessageQueueControllerTest @Test fun testAssignMessage_messageIsAssigned() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assigned" val message = createQueueMessage(type = "testAssignMessage_messageIsAssigned") @@ -765,14 +765,14 @@ class MessageQueueControllerTest } /** - * Ensure when [MessageQueueController.assignMessage] is called in [MultiQueueAuthenticationType.HYBRID] mode + * Ensure when [MessageQueueController.assignMessage] is called in [RestrictionMode.HYBRID] mode * that the message is not assigned or changed if the sub-queue is restricted and a valid token is not provided. */ @Test fun testAssignMessage_messageIsAssigned_inHybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val assignedTo = "assigned" val message = createQueueMessage(type = "testAssignMessage_messageIsAssigned_inHybridMode") @@ -814,7 +814,7 @@ class MessageQueueControllerTest @Test fun testAssignMessage_alreadyAssignedToSameID() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assigned" val message = createQueueMessage(type = "testAssignMessage_alreadyAssignedToSameID", assignedTo = assignedTo) @@ -844,7 +844,7 @@ class MessageQueueControllerTest @Test fun testAssignMessage_alreadyAssignedToOtherID() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assignee" val message = createQueueMessage(type = "testAssignMessage_alreadyAssignedToOtherID", assignedTo = assignedTo) @@ -876,7 +876,7 @@ class MessageQueueControllerTest @Test fun testGetNext_noNewMessages() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assignee" val type = "testGetNext_noNewMessages" @@ -896,7 +896,7 @@ class MessageQueueControllerTest @Test fun testGetNext_noNewUnAssignedMessages() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assignee" val type = "testGetNext_noNewUnAssignedMessages" @@ -922,7 +922,7 @@ class MessageQueueControllerTest @Test fun testGetNext() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assignee" val type = "testGetNext" @@ -953,14 +953,14 @@ class MessageQueueControllerTest } /** - * Ensure that when in [MultiQueueAuthenticationType.HYBRID] mode that the next message for a restricted sub-queue + * Ensure that when in [RestrictionMode.HYBRID] mode that the next message for a restricted sub-queue * cannot be retrieved without a valid token being provided. */ @Test fun testGetNext_inHybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val assignedTo = "assignee" val type = "testGetNext_inHybridMode" @@ -1010,7 +1010,7 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_doesNotExist() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val uuid = UUID.randomUUID().toString() mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + uuid + MessageQueueController.ENDPOINT_RELEASE) @@ -1025,7 +1025,7 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_messageIsReleased() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assignee" val message = createQueueMessage(type = "testReleaseMessage_messageIsReleased", assignedTo = assignedTo) @@ -1049,14 +1049,14 @@ class MessageQueueControllerTest } /** - * Ensure that when in [MultiQueueAuthenticationType.HYBRID] mode that a restricted sub-queue cannot have its + * Ensure that when in [RestrictionMode.HYBRID] mode that a restricted sub-queue cannot have its * message released without a valid token being provided. */ @Test fun testReleaseMessage_messageIsReleased_inHybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val assignedTo = "assignee" val message = createQueueMessage(type = "testReleaseMessage_messageIsReleased_inHybridMode", assignedTo = assignedTo) @@ -1099,7 +1099,7 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_messageIsReleased_withoutAssignedToInQuery() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assigned" val message = createQueueMessage(type = "testReleaseMessage_messageIsReleased_withoutAssignedToInQuery", assignedTo = assignedTo) @@ -1128,7 +1128,7 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_alreadyReleased() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testReleaseMessage_alreadyReleased") Assertions.assertNull(message.assignedTo) @@ -1157,7 +1157,7 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_cannotBeReleasedWithMisMatchingID() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assigned" val message = createQueueMessage(type = "testReleaseMessage_cannotBeReleasedWithMisMatchingID", assignedTo = assignedTo) @@ -1182,7 +1182,7 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_notFound() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val uuid = UUID.randomUUID().toString() @@ -1198,7 +1198,7 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_removeExistingEntry() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testRemoveMessage_removed") Assertions.assertTrue(multiQueue.add(message)) @@ -1213,14 +1213,14 @@ class MessageQueueControllerTest } /** - * Ensure when in [MultiQueueAuthenticationType.HYBRID] mode that messages cannot be removed unless a valid + * Ensure when in [RestrictionMode.HYBRID] mode that messages cannot be removed unless a valid * token is provided on a restricted sub-queue. */ @Test fun testRemoveMessage_removeExistingEntry_inHybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testRemoveMessage_removeExistingEntry_inHybridMode") Assertions.assertTrue(multiQueue.add(message)) @@ -1252,7 +1252,7 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_doesNotExist() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val uuid = UUID.randomUUID().toString() Assertions.assertFalse(multiQueue.containsUUID(uuid).isPresent) @@ -1271,7 +1271,7 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_assignedToAnotherID() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assignee" val message = createQueueMessage(type = "testRemoveMessage_assignedToAnotherID", assignedTo = assignedTo) @@ -1294,7 +1294,7 @@ class MessageQueueControllerTest @Test fun testGetOwners_withQueueType() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assignedTo" val assignedTo2 = "assignedTo2" @@ -1337,7 +1337,7 @@ class MessageQueueControllerTest @Test fun testGetOwners_withoutQueueType() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assignedTo" val assignedTo2 = "assignedTo2" @@ -1381,7 +1381,7 @@ class MessageQueueControllerTest @Test fun testGetPerformHealthCheck() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_HEALTH_CHECK) .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -1396,7 +1396,7 @@ class MessageQueueControllerTest @Test fun testCorrelationId_randomIdOnSuccess() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testCorrelationId_providedId") @@ -1418,7 +1418,7 @@ class MessageQueueControllerTest @Test fun testCorrelationId_providedId() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val message = createQueueMessage(type = "testCorrelationId_providedId") val correlationId = "my-correlation-id-123456" @@ -1441,7 +1441,7 @@ class MessageQueueControllerTest @Test fun testCorrelationId_randomIdOnError() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val assignedTo = "assignee" val message = createQueueMessage(type = "testCorrelationId_randomIdOnError", assignedTo = assignedTo) @@ -1469,7 +1469,7 @@ class MessageQueueControllerTest @Test fun testDeleteKeys_singleKey() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val subQueue1 = "testDeleteKeys_singleKey1" var messages = listOf(createQueueMessage(subQueue1), createQueueMessage(subQueue1), createQueueMessage(subQueue1)) @@ -1497,14 +1497,14 @@ class MessageQueueControllerTest } /** - * Ensure that when in [MultiQueueAuthenticationType.HYBRID] mode any restricted sub-queues cannot be deleted + * Ensure that when in [RestrictionMode.HYBRID] mode any restricted sub-queues cannot be deleted * unless a valid token is provided. */ @Test fun testDeleteKeys_singleKey_inHybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val subQueue1 = "testDeleteKeys_singleKey_inHybridMode1" var messages = listOf(createQueueMessage(subQueue1), createQueueMessage(subQueue1), createQueueMessage(subQueue1)) @@ -1559,7 +1559,7 @@ class MessageQueueControllerTest @Test fun testDeleteKeys_allKeys() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val (messages, types) = initialiseMapWithEntries() Assertions.assertEquals(messages.size, multiQueue.size) @@ -1574,14 +1574,14 @@ class MessageQueueControllerTest } /** - * Ensure that when in [MultiQueueAuthenticationType.HYBRID] mode any restricted sub-queues cannot be deleted + * Ensure that when in [RestrictionMode.HYBRID] mode any restricted sub-queues cannot be deleted * unless a valid token is provided. */ @Test fun testDeleteKeys_allKeys_inHybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) val (messages, types) = initialiseMapWithEntries() Assertions.assertEquals(messages.size, multiQueue.size) @@ -1619,7 +1619,7 @@ class MessageQueueControllerTest @Test fun testGetPerformHealthCheck_failureResponse() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) Mockito.doThrow(RuntimeException("Failed to perform health check.")).`when`(multiQueue).performHealthCheckInternal() @@ -1637,7 +1637,7 @@ class MessageQueueControllerTest @Test fun testCreateMessage_addFails() { - Assertions.assertEquals(MultiQueueAuthenticationType.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) val message = QueueMessage("payload", "type") @@ -1650,14 +1650,14 @@ class MessageQueueControllerTest } /** - * Ensure that when [MultiQueueAuthenticationType] is set to [MultiQueueAuthenticationType.RESTRICTED] that any + * Ensure that when [RestrictionMode] is set to [RestrictionMode.RESTRICTED] that any * of the endpoints failing the [JwtAuthenticationFilter.canSkipTokenVerification] will be inaccessible. */ @Test fun testRestrictedModeMakesAllEndpointsInaccessibleWithoutAToken() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, authenticator.getAuthenticationType()) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + UUID.randomUUID().toString()) .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -1696,13 +1696,13 @@ class MessageQueueControllerTest /** * Ensure that the [JwtAuthenticationFilter] will respond with [HttpStatus.UNAUTHORIZED] when no token is provided, - * and it is in [MultiQueueAuthenticationType.RESTRICTED] mode. + * and it is in [RestrictionMode.RESTRICTED] mode. */ @Test fun testGetEntry_inRestrictedMode() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(MultiQueueAuthenticationType.RESTRICTED, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getAuthenticationType() + Assertions.assertEquals(RestrictionMode.RESTRICTED, authenticator.getAuthenticationType()) val type = "testRestrictedMode_getByUUID" val message = createQueueMessage(type) diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt index 070eb28..d49d120 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt @@ -1,11 +1,11 @@ package au.kilemon.messagequeue.rest.controller -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import au.kilemon.messagequeue.authentication.authenticator.MultiQueueAuthenticator import au.kilemon.messagequeue.configuration.QueueConfiguration import au.kilemon.messagequeue.logging.LoggingConfiguration import au.kilemon.messagequeue.settings.MessageQueueSettings -import au.kilemon.messagequeue.settings.MultiQueueType +import au.kilemon.messagequeue.settings.StorageMedium import com.google.gson.Gson import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test @@ -64,7 +64,7 @@ class SettingsControllerTest /** * A helper method to call [SettingsController.getSettings] and verify the response default values. */ - private fun testGetSettings_defaultValues(authenticationType: MultiQueueAuthenticationType) + private fun testGetSettings_defaultValues(authenticationType: RestrictionMode) { Assertions.assertEquals(authenticationType, multiQueueAuthenticator.getAuthenticationType()) @@ -74,8 +74,8 @@ class SettingsControllerTest .andReturn() val settings = gson.fromJson(mvcResult.response.contentAsString, MessageQueueSettings::class.java) - Assertions.assertEquals(MultiQueueType.IN_MEMORY.toString(), settings.multiQueueType) - Assertions.assertEquals(MultiQueueAuthenticationType.NONE.toString(), settings.multiQueueAuthentication) + Assertions.assertEquals(StorageMedium.IN_MEMORY.toString(), settings.multiQueueType) + Assertions.assertEquals(RestrictionMode.NONE.toString(), settings.multiQueueAuthentication) Assertions.assertTrue(settings.redisPrefix.isEmpty()) Assertions.assertEquals(MessageQueueSettings.REDIS_ENDPOINT_DEFAULT, settings.redisEndpoint) @@ -93,35 +93,35 @@ class SettingsControllerTest } /** - * Ensure calls to [SettingsController.getSettings] is still available even then the [MultiQueueAuthenticationType] - * is set to [MultiQueueAuthenticationType.NONE]. + * Ensure calls to [SettingsController.getSettings] is still available even then the [RestrictionMode] + * is set to [RestrictionMode.NONE]. */ @Test fun testGetSettings_noneMode() { - Mockito.doReturn(MultiQueueAuthenticationType.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() - testGetSettings_defaultValues(MultiQueueAuthenticationType.NONE) + Mockito.doReturn(RestrictionMode.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() + testGetSettings_defaultValues(RestrictionMode.NONE) } /** - * Ensure calls to [SettingsController.getSettings] is still available even then the [MultiQueueAuthenticationType] - * is set to [MultiQueueAuthenticationType.HYBRID]. + * Ensure calls to [SettingsController.getSettings] is still available even then the [RestrictionMode] + * is set to [RestrictionMode.HYBRID]. */ @Test fun testGetSettings_hybridMode() { - Mockito.doReturn(MultiQueueAuthenticationType.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - testGetSettings_defaultValues(MultiQueueAuthenticationType.HYBRID) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + testGetSettings_defaultValues(RestrictionMode.HYBRID) } /** - * Ensure calls to [SettingsController.getSettings] is still available even then the [MultiQueueAuthenticationType] - * is set to [MultiQueueAuthenticationType.RESTRICTED]. + * Ensure calls to [SettingsController.getSettings] is still available even then the [RestrictionMode] + * is set to [RestrictionMode.RESTRICTED]. */ @Test fun testGetSettings_restrictedMode() { - Mockito.doReturn(MultiQueueAuthenticationType.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - testGetSettings_defaultValues(MultiQueueAuthenticationType.RESTRICTED) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + testGetSettings_defaultValues(RestrictionMode.RESTRICTED) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt index 4bbc3a6..f7f6267 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt @@ -1,6 +1,6 @@ package au.kilemon.messagequeue.rest.response -import au.kilemon.messagequeue.authentication.MultiQueueAuthenticationType +import au.kilemon.messagequeue.authentication.RestrictionMode import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthenticationException import au.kilemon.messagequeue.authentication.exception.MultiQueueAuthorisationException import au.kilemon.messagequeue.filter.CorrelationIdFilter @@ -11,8 +11,6 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.slf4j.MDC import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.server.ResponseStatusException import java.util.* @@ -70,12 +68,12 @@ class RestResponseExceptionHandlerTest val correlationId = UUID.randomUUID().toString() MDC.put(CorrelationIdFilter.CORRELATION_ID, correlationId) val message = "testHandleMultiQueueAuthorisationException" - val exception = MultiQueueAuthorisationException(message, MultiQueueAuthenticationType.NONE) + val exception = MultiQueueAuthorisationException(message, RestrictionMode.NONE) val response = responseHandler.handleMultiQueueAuthorisationException(exception) Assertions.assertEquals(HttpStatus.FORBIDDEN, response.statusCode) Assertions.assertNotNull(response.body) - Assertions.assertEquals(String.format(MultiQueueAuthorisationException.MESSAGE_FORMAT, message, MultiQueueAuthenticationType.NONE), response.body!!.message) + Assertions.assertEquals(String.format(MultiQueueAuthorisationException.MESSAGE_FORMAT, message, RestrictionMode.NONE), response.body!!.message) Assertions.assertEquals(correlationId, response.body!!.correlationId) } From 7ff52d6c24ffb8da74a69ed0392dd45fd6a9caf5 Mon Sep 17 00:00:00 2001 From: Kilemonn Date: Tue, 5 Dec 2023 22:53:46 +1100 Subject: [PATCH 58/58] Remove all usages of type and queue type and use sub-queue instead. --- .../authentication/AuthenticationMatrix.kt | 4 +- .../AuthenticationMatrixDocument.kt | 2 +- .../authentication/RestrictionMode.kt | 12 +- .../authenticator/MultiQueueAuthenticator.kt | 54 +- .../MultiQueueAuthorisationException.kt | 2 +- .../configuration/QueueConfiguration.kt | 28 +- .../filter/JwtAuthenticationFilter.kt | 8 +- .../messagequeue/message/QueueMessage.kt | 19 +- .../message/QueueMessageDocument.kt | 6 +- .../kilemon/messagequeue/queue/MultiQueue.kt | 192 +++--- .../queue/cache/redis/RedisMultiQueue.kt | 81 ++- .../exception/DuplicateMessageException.kt | 2 +- .../queue/inmemory/InMemoryMultiQueue.kt | 101 ++- .../queue/nosql/mongo/MongoMultiQueue.kt | 39 +- .../repository/MongoQueueMessageRepository.kt | 46 +- .../messagequeue/queue/sql/SqlMultiQueue.kt | 38 +- .../repository/SqlQueueMessageRepository.kt | 48 +- .../rest/controller/AuthController.kt | 59 +- .../rest/controller/MessageQueueController.kt | 167 ++--- .../rest/controller/RestParameters.kt | 2 +- .../rest/response/MessageResponse.kt | 6 +- .../settings/MessageQueueSettings.kt | 9 +- .../MultiQueueAuthenticatorTest.kt | 76 +-- .../inmemory/InMemoryAuthenticatorTest.kt | 18 +- .../MultiQueueAuthorisationExceptionTest.kt | 2 +- .../messagequeue/message/QueueMessageTest.kt | 52 +- .../messagequeue/queue/MultiQueueTest.kt | 403 ++++++------ .../redis/RedisStandAloneMultiQueueTest.kt | 20 +- .../inmemory/InMemoryMockMultiQueueTest.kt | 4 +- .../queue/nosql/mongo/MongoMultiQueueTest.kt | 2 - .../rest/controller/AuthControllerTest.kt | 162 ++--- .../controller/MessageQueueControllerTest.kt | 584 +++++++++--------- .../rest/controller/SettingsControllerTest.kt | 12 +- .../RestResponseExceptionHandlerTest.kt | 6 +- .../MessageQueueSettingsDefaultTest.kt | 4 +- .../settings/MessageQueueSettingsTest.kt | 2 +- 36 files changed, 1137 insertions(+), 1135 deletions(-) diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt index 1a48fda..fe29fdf 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrix.kt @@ -6,8 +6,8 @@ import javax.persistence.* /** * An object that holds subqueue authentication information. - * If a specific sub queue is in restricted mode it will have a matching [AuthenticationMatrix] created which will - * be checked to verify if a specific sub queue can be operated on. + * If a specific sub-queue is in restricted mode it will have a matching [AuthenticationMatrix] created which will + * be checked to verify if a specific sub-queue can be operated on. * This object is used for `In-memory`, `SQL` and `Redis`. * * @author github.com/Kilemonn diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt index 4559df8..6514ac4 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/AuthenticationMatrixDocument.kt @@ -5,7 +5,7 @@ import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.mapping.Document /** - * A holder object for the restricted sub queues. Refer to [AuthenticationMatrix]. + * A holder object for the restricted sub-queues. Refer to [AuthenticationMatrix]. * This is used only for `Mongo`. * * @author github.com/Kilemonn diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/RestrictionMode.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/RestrictionMode.kt index 04d9d55..d647367 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/RestrictionMode.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/RestrictionMode.kt @@ -2,29 +2,29 @@ package au.kilemon.messagequeue.authentication /** * An enum class used to represent the different types of `MultiQueueAuthentication`. - * This will drive whether authentication is available and for which sub queues. + * This will drive whether authentication is available and for which sub-queues. * * @author github.com/Kilemonn */ enum class RestrictionMode { /** - * This is the default, which enforces no authentication on any sub queue, messages can be enqueued and dequeued + * This is the default, which enforces no authentication on any sub-queue, messages can be enqueued and dequeued * as required by any called without any form of authentication. */ NONE, /** - * This is a hybrid mode where sub queues can be created without authentication, but other sub queues can + * This is a hybrid mode where sub-queues can be created without authentication, but other sub-queues can * be created with it (if they do not already exist). - * Any sub queue created with authentication will not be accessible without a token, sub queues created without a + * Any sub-queue created with authentication will not be accessible without a token, sub-queues created without a * token will continue to be accessible without one. */ HYBRID, /** - * This is a restricted mode that forces any sub queue to be pre-created and a token will be given before messages - * can be stored or accessed in any sub queue. + * This is a restricted mode that forces any sub-queue to be pre-created and a token will be given before messages + * can be stored or accessed in any sub-queue. */ RESTRICTED; } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt index 467a476..6cf05aa 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticator.kt @@ -8,7 +8,7 @@ import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired /** - * The base Authenticator class. This is responsible to tracking which sub queues are marked as restricted and + * The base Authenticator class. This is responsible to tracking which sub-queues are marked as restricted and * maintaining this underlying collection within the specified storage medium. * * @author github.com/Kilemonn @@ -18,24 +18,24 @@ abstract class MultiQueueAuthenticator: HasLogger abstract override val LOG: Logger @Autowired - private lateinit var multiQueueAuthenticationType: RestrictionMode + private lateinit var restrictionMode: RestrictionMode /** - * @return [multiQueueAuthenticationType] + * @return [restrictionMode] */ - fun getAuthenticationType(): RestrictionMode + fun getRestrictionMode(): RestrictionMode { - return multiQueueAuthenticationType + return restrictionMode } /** * Used only for tests to update the set [RestrictionMode]. * - * @param authenticationType the new [RestrictionMode] to set + * @param restrictionMode the new [RestrictionMode] to set */ - fun setAuthenticationType(authenticationType: RestrictionMode) + fun setRestrictionMode(restrictionMode: RestrictionMode) { - multiQueueAuthenticationType = authenticationType + this.restrictionMode = restrictionMode } /** @@ -50,8 +50,8 @@ abstract class MultiQueueAuthenticator: HasLogger } /** - * Determines whether based on the currently set [getAuthenticationType] and the provided [subQueue] and - * [JwtAuthenticationFilter.getSubQueue] to determine if the user is able to interact with the requested sub queue. + * Determines whether based on the currently set [getRestrictionMode] and the provided [subQueue] and + * [JwtAuthenticationFilter.getSubQueue] to determine if the user is able to interact with the requested sub-queue. * * @param subQueue the sub-queue identifier that is being requested access to * @param throwException `true` to throw an exception if the [subQueue] cannot be accessed, otherwise the return @@ -67,7 +67,7 @@ abstract class MultiQueueAuthenticator: HasLogger { if (throwException) { - throw MultiQueueAuthorisationException(subQueue, getAuthenticationType()) + throw MultiQueueAuthorisationException(subQueue, getRestrictionMode()) } return false } @@ -87,7 +87,7 @@ abstract class MultiQueueAuthenticator: HasLogger } else { - // If we are in hybrid mode and the sub queue is not restricted we should let it pass + // If we are in hybrid mode and the sub-queue is not restricted we should let it pass return true } } @@ -101,33 +101,33 @@ abstract class MultiQueueAuthenticator: HasLogger if (throwException) { - throw MultiQueueAuthorisationException(subQueue, getAuthenticationType()) + throw MultiQueueAuthorisationException(subQueue, getRestrictionMode()) } return false } /** - * Indicates whether [multiQueueAuthenticationType] is set to [RestrictionMode.NONE]. + * Indicates whether [restrictionMode] is set to [RestrictionMode.NONE]. */ fun isInNoneMode(): Boolean { - return getAuthenticationType() == RestrictionMode.NONE + return getRestrictionMode() == RestrictionMode.NONE } /** - * Indicates whether [multiQueueAuthenticationType] is set to [RestrictionMode.HYBRID]. + * Indicates whether [restrictionMode] is set to [RestrictionMode.HYBRID]. */ fun isInHybridMode(): Boolean { - return getAuthenticationType() == RestrictionMode.HYBRID + return getRestrictionMode() == RestrictionMode.HYBRID } /** - * Indicates whether [multiQueueAuthenticationType] is set to [RestrictionMode.RESTRICTED]. + * Indicates whether [restrictionMode] is set to [RestrictionMode.RESTRICTED]. */ fun isInRestrictedMode(): Boolean { - return getAuthenticationType() == RestrictionMode.RESTRICTED + return getRestrictionMode() == RestrictionMode.RESTRICTED } /** @@ -163,26 +163,26 @@ abstract class MultiQueueAuthenticator: HasLogger * This will delegate to [addRestrictedEntryInternal]. * * @param subQueue the sub-queue identifier to make restricted - * @return `true` if the sub queue identifier was added to the restriction set, otherwise `false` if there was + * @return `true` if the sub-queue identifier was added to the restriction set, otherwise `false` if there was * no underlying change made. If [isInNoneMode] is set this will always return `false`. */ fun addRestrictedEntry(subQueue: String): Boolean { if (isInNoneMode()) { - LOG.trace("Skipping adding restricted entry for [{}] since the authentication type is set to [{}].", subQueue, getAuthenticationType()) + LOG.trace("Skipping adding restricted entry for [{}] since the restriction mode is set to [{}].", subQueue, getRestrictionMode()) return false } else { return if (isRestricted(subQueue)) { - LOG.trace("Restriction for sub queue [{}] was not increased as it is already restricted.", subQueue) + LOG.trace("Restriction for sub-queue [{}] was not increased as it is already restricted.", subQueue) false } else { - LOG.info("Adding restriction to sub queue [{}].", subQueue) + LOG.info("Adding restriction to sub-queue [{}].", subQueue) addRestrictedEntryInternal(subQueue) true } @@ -208,19 +208,19 @@ abstract class MultiQueueAuthenticator: HasLogger { return if (isInNoneMode()) { - LOG.trace("Skipping removing restricted entry for [{}] since the authentication type is set to [{}].", subQueue, getAuthenticationType()) + LOG.trace("Skipping removing restricted entry for [{}] since the restriction mode is set to [{}].", subQueue, getRestrictionMode()) false } else { return if (isRestricted(subQueue)) { - LOG.info("Removing restriction to sub queue [{}].", subQueue) + LOG.info("Removing restriction to sub-queue [{}].", subQueue) removeRestrictionInternal(subQueue) } else { - LOG.trace("Restriction for sub queue [{}] was not removed as it is currently unrestricted.", subQueue) + LOG.trace("Restriction for sub-queue [{}] was not removed as it is currently unrestricted.", subQueue) false } @@ -243,7 +243,7 @@ abstract class MultiQueueAuthenticator: HasLogger /** * Clear the underlying restriction storage entries. (This is mainly used for testing). * - * @return the amount of sub queue restrictions that were cleared + * @return the amount of sub-queue restrictions that were cleared */ abstract fun clearRestrictedSubQueues(): Long } diff --git a/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt index 4d28a83..04589a7 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationException.kt @@ -9,7 +9,7 @@ import au.kilemon.messagequeue.authentication.RestrictionMode * * @author github.com/Kilemonn */ -class MultiQueueAuthorisationException(subQueue: String, authenticationType: RestrictionMode) : Exception(String.format(MESSAGE_FORMAT, subQueue, authenticationType)) +class MultiQueueAuthorisationException(subQueue: String, restrictionMode: RestrictionMode) : Exception(String.format(MESSAGE_FORMAT, subQueue, restrictionMode)) { companion object { diff --git a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt index 8854b3b..71b7af9 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/configuration/QueueConfiguration.kt @@ -49,7 +49,7 @@ class QueueConfiguration : HasLogger private lateinit var redisTemplate: RedisTemplate /** - * Initialise the [MultiQueue] [Bean] based on the [MessageQueueSettings.multiQueueType]. + * Initialise the [MultiQueue] [Bean] based on the [MessageQueueSettings.storageMedium]. */ @Bean open fun getMultiQueue(): MultiQueue @@ -58,7 +58,7 @@ class QueueConfiguration : HasLogger // Default to in-memory var queue: MultiQueue = InMemoryMultiQueue() - when (messageQueueSettings.multiQueueType.uppercase()) { + when (messageQueueSettings.storageMedium.uppercase()) { StorageMedium.REDIS.toString() -> { queue = RedisMultiQueue(messageQueueSettings.redisPrefix, redisTemplate) } @@ -70,44 +70,44 @@ class QueueConfiguration : HasLogger } } - LOG.info("Initialising [{}] queue as the [{}] is set to [{}].", queue::class.java.name, MessageQueueSettings.STORAGE_MEDIUM, messageQueueSettings.multiQueueType) + LOG.info("Initialising [{}] queue as the [{}] is set to [{}].", queue::class.java.name, MessageQueueSettings.STORAGE_MEDIUM, messageQueueSettings.storageMedium) return queue } /** - * Initialise the [RestrictionMode] which drives how sub queues are accessed and created. + * Initialise the [RestrictionMode] which drives how sub-queues are accessed and created. */ @Bean - open fun getMultiQueueAuthenticationType(): RestrictionMode + open fun getRestrictionMode(): RestrictionMode { - var authenticationType = RestrictionMode.NONE + var restrictionMode = RestrictionMode.NONE - if (messageQueueSettings.multiQueueAuthentication.isNotBlank()) + if (messageQueueSettings.restrictionMode.isNotBlank()) { try { - authenticationType = RestrictionMode.valueOf(messageQueueSettings.multiQueueAuthentication.uppercase()) + restrictionMode = RestrictionMode.valueOf(messageQueueSettings.restrictionMode.uppercase()) } catch (ex: Exception) { - LOG.warn("Unable to initialise appropriate authentication type with provided value [{}], falling back to default [{}].", messageQueueSettings.multiQueueAuthentication, RestrictionMode.NONE, ex) + LOG.warn("Unable to initialise appropriate restriction mode with provided value [{}], falling back to default [{}].", messageQueueSettings.restrictionMode, RestrictionMode.NONE, ex) } } - LOG.info("Using [{}] authentication as the [{}] is set to [{}].", authenticationType, MessageQueueSettings.RESTRICTION_MODE, messageQueueSettings.multiQueueAuthentication) + LOG.info("Using [{}] restriction mode as the [{}] is set to [{}].", restrictionMode, MessageQueueSettings.RESTRICTION_MODE, messageQueueSettings.restrictionMode) - return authenticationType + return restrictionMode } /** - * Initialise the [MultiQueueAuthenticator] [Bean] based on the [MessageQueueSettings.multiQueueType]. + * Initialise the [MultiQueueAuthenticator] [Bean] based on the [MessageQueueSettings.storageMedium]. */ @Bean open fun getMultiQueueAuthenticator(): MultiQueueAuthenticator { var authenticator: MultiQueueAuthenticator = InMemoryAuthenticator() - when (messageQueueSettings.multiQueueType.uppercase()) { + when (messageQueueSettings.storageMedium.uppercase()) { StorageMedium.REDIS.toString() -> { authenticator = RedisAuthenticator() } @@ -119,7 +119,7 @@ class QueueConfiguration : HasLogger } } - LOG.info("Initialising [{}] authenticator as the [{}] is set to [{}].", authenticator::class.java.name, MessageQueueSettings.STORAGE_MEDIUM, messageQueueSettings.multiQueueType) + LOG.info("Initialising [{}] authenticator as the [{}] is set to [{}].", authenticator::class.java.name, MessageQueueSettings.STORAGE_MEDIUM, messageQueueSettings.storageMedium) return authenticator } diff --git a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt index b6e9623..f7c221c 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/filter/JwtAuthenticationFilter.kt @@ -101,13 +101,13 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger { if (tokenIsPresentAndQueueIsRestricted(subQueue, authenticator)) { - LOG.trace("Accepted request for sub queue [{}].", subQueue.get()) + LOG.trace("Accepted request for sub-queue [{}].", subQueue.get()) filterChain.doFilter(request, response) } else { val token = if (subQueue.isPresent) subQueue.get() else "null" - LOG.error("Failed to manipulate sub queue [{}] with provided token as the authentication level is set to [{}].", token, authenticator.getAuthenticationType()) + LOG.error("Failed to manipulate sub-queue [{}] with provided token as the authentication level is set to [{}].", token, authenticator.getRestrictionMode()) handlerExceptionResolver.resolveException(request, response, null, MultiQueueAuthenticationException()) return } @@ -156,13 +156,13 @@ class JwtAuthenticationFilter: OncePerRequestFilter(), HasLogger /** * Set the provided [Optional][String] into the [MDC] as [JwtAuthenticationFilter.SUB_QUEUE] if it is not [Optional.empty]. * - * @param subQueue an optional sub queue identifier, if it is not [Optional.empty] it will be placed into the [MDC] + * @param subQueue an optional sub-queue identifier, if it is not [Optional.empty] it will be placed into the [MDC] */ fun setSubQueue(subQueue: Optional) { if (subQueue.isPresent) { - LOG.trace("Setting resolved sub queue from token into request context [{}].", subQueue.get()) + LOG.trace("Setting resolved sub-queue from token into request context [{}].", subQueue.get()) MDC.put(SUB_QUEUE, subQueue.get()) } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/message/QueueMessage.kt b/src/main/kotlin/au/kilemon/messagequeue/message/QueueMessage.kt index 3c15fdc..a395a86 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/message/QueueMessage.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/message/QueueMessage.kt @@ -8,7 +8,7 @@ import javax.persistence.* /** * A base [QueueMessage] object which will wrap any object that is placed into the `MultiQueue`. - * This object wraps a [Any] type `T` which is the payload to be stored in the queue. (This is actually a [Serializable] but causes issues in initialisation + * This object wraps an [Any] which is the payload to be stored in the queue. (This is actually a [Serializable] but causes issues in initialisation * if the type is an `interface`. This needs to be [Serializable] if you want to use it with `Redis` or anything else). * * This is used for `InMemory`, `Redis` and `SQL` queues. @@ -17,7 +17,7 @@ import javax.persistence.* */ @Entity @Table(name = QueueMessage.TABLE_NAME) // TODO: Schema configuration schema = "\${${MessageQueueSettings.SQL_SCHEMA}:${MessageQueueSettings.SQL_SCHEMA_DEFAULT}}") -class QueueMessage(payload: Any?, @Column(nullable = false) var type: String, @Column(name = "assignedto") var assignedTo: String? = null): Serializable +class QueueMessage(payload: Any?, @Column(name = "subqueue", nullable = false) var subQueue: String, @Column(name = "assignedto") var assignedTo: String? = null): Serializable { companion object { @@ -52,7 +52,7 @@ class QueueMessage(payload: Any?, @Column(nullable = false) var type: String, @C constructor(queueMessageDocument: QueueMessageDocument) : this() { - this.type = queueMessageDocument.type + this.subQueue = queueMessageDocument.subQueue this.uuid = queueMessageDocument.uuid this.id = queueMessageDocument.id this.payload = queueMessageDocument.payload @@ -94,7 +94,7 @@ class QueueMessage(payload: Any?, @Column(nullable = false) var type: String, @C { // Create a temporary object since the object is edited in place if we are using the in-memory queue val newMessage = QueueMessage() - newMessage.type = type + newMessage.subQueue = subQueue newMessage.assignedTo = assignedTo newMessage.uuid = uuid newMessage.payload = "***" // Mark as stars to indicate that it is there but not returned @@ -107,9 +107,10 @@ class QueueMessage(payload: Any?, @Column(nullable = false) var type: String, @C /** * Overriding to only include specific properties when checking if messages are equal. * This checks the following are equal in order to return `true`: - * - UUID - * - payload value - * - type + * - [uuid] + * - [payload] + * - [payloadBytes] + * - [subQueue] */ override fun equals(other: Any?): Boolean { @@ -120,7 +121,7 @@ class QueueMessage(payload: Any?, @Column(nullable = false) var type: String, @C return other.uuid == this.uuid && (this.payload == other.payload || this.payloadBytes.contentEquals(other.payloadBytes)) - && this.type == other.type + && this.subQueue == other.subQueue } /** @@ -129,7 +130,7 @@ class QueueMessage(payload: Any?, @Column(nullable = false) var type: String, @C override fun hashCode(): Int { var result = payload?.hashCode() ?: 0 result = 31 * result + (payloadBytes?.hashCode() ?: 0) - result = 31 * result + type.hashCode() + result = 31 * result + subQueue.hashCode() result = 31 * result + uuid.hashCode() return result } diff --git a/src/main/kotlin/au/kilemon/messagequeue/message/QueueMessageDocument.kt b/src/main/kotlin/au/kilemon/messagequeue/message/QueueMessageDocument.kt index 749deed..1a9c39f 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/message/QueueMessageDocument.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/message/QueueMessageDocument.kt @@ -3,9 +3,7 @@ package au.kilemon.messagequeue.message import com.fasterxml.jackson.annotation.JsonIgnore import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.mapping.Document -import org.springframework.util.SerializationUtils import java.util.* -import javax.persistence.* /** * This is used for `No-SQL` queues. @@ -13,7 +11,7 @@ import javax.persistence.* * @author github.com/Kilemonn */ @Document(value = QueueMessageDocument.DOCUMENT_NAME) -class QueueMessageDocument(var payload: Any?, var type: String, var assignedTo: String? = null) +class QueueMessageDocument(var payload: Any?, var subQueue: String, var assignedTo: String? = null) { companion object { @@ -34,7 +32,7 @@ class QueueMessageDocument(var payload: Any?, var type: String, var assignedTo: constructor(queueMessage: QueueMessage) : this() { val resolvedQueueMessage = queueMessage.resolvePayloadObject() - this.type = resolvedQueueMessage.type + this.subQueue = resolvedQueueMessage.subQueue this.uuid = resolvedQueueMessage.uuid this.id = resolvedQueueMessage.id this.payload = resolvedQueueMessage.payload diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt index 6ec19c2..bd93c55 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/MultiQueue.kt @@ -17,7 +17,7 @@ import kotlin.collections.HashSet /** * A [MultiQueue] base class, which extends [Queue]. - * It contains various extra methods for interfacing with the [MultiQueue] using the [String] as a queue type identifier + * It contains various extra methods for interfacing with the [MultiQueue] using the [String] as a sub-queue identifier * to manipulate the appropriate underlying [Queue]s. * * @author github.com/Kilemonn @@ -38,7 +38,7 @@ abstract class MultiQueue: Queue, HasLogger /** * Get the underlying size of the [MultiQueue]. - * This is done by summing the length of each [getQueueForType] for each key in [keys]. + * This is done by summing the length of each [getSubQueue] for each key in [keys]. * * This is to allow the underlying storage to be the source of truth instead of any temporary counters, since the underlying storage could * change at any timeout without direct interaction from the [MultiQueue]. @@ -47,7 +47,7 @@ abstract class MultiQueue: Queue, HasLogger get() { var internalSize = 0 keys(false).forEach { key -> - internalSize += getQueueForType(key).size + internalSize += getSubQueue(key).size } return internalSize } @@ -66,7 +66,7 @@ abstract class MultiQueue: Queue, HasLogger * * @return the current value of the index before it was incremented */ - abstract fun getNextQueueIndex(queueType: String): Optional + abstract fun getNextSubQueueIndex(subQueue: String): Optional /** * A wrapper for the [MultiQueue.persistMessageInternal] so this method can be synchronised. @@ -97,128 +97,128 @@ abstract class MultiQueue: Queue, HasLogger abstract fun persistMessageInternal(message: QueueMessage) /** - * Retrieves or creates a new [Queue] of type [QueueMessage] for the provided [String]. - * If the underlying [Queue] does not exist for the provided [String] then a new [Queue] will + * Retrieves or creates a new [Queue] of [QueueMessage] for the provided [subQueue]. + * If the underlying [Queue] does not exist for the provided [subQueue] then a new [Queue] will * be created. * - * **This method should not be called directly, please use [getQueueForType]** + * **This method should not be called directly, please use [getSubQueue]** * - * @param queueType the identifier of the sub-queue [Queue] + * @param subQueue the identifier of the sub-queue [Queue] * @return the [Queue] matching the provided [String] */ - abstract fun getQueueForTypeInternal(queueType: String): Queue + abstract fun getSubQueueInternal(subQueue: String): Queue /** * Retrieves or creates a new [Queue] of type [QueueMessage] for the provided [String]. * If the underlying [Queue] does not exist for the provided [String] then a new [Queue] will * be created. * - * @param queueType the identifier of the sub-queue [Queue] + * @param subQueue the identifier of the sub-queue [Queue] * @return the [Queue] matching the provided [String] - * @throws IllegalSubQueueIdentifierException If the provided [queueType] is part of the [MultiQueueAuthenticator.getReservedSubQueues] + * @throws IllegalSubQueueIdentifierException If the provided [subQueue] is part of the [MultiQueueAuthenticator.getReservedSubQueues] */ @Throws(IllegalSubQueueIdentifierException::class) - fun getQueueForType(queueType: String): Queue + fun getSubQueue(subQueue: String): Queue { - if (!multiQueueAuthenticator.isInNoneMode() && multiQueueAuthenticator.getReservedSubQueues().contains(queueType)) + if (!multiQueueAuthenticator.isInNoneMode() && multiQueueAuthenticator.getReservedSubQueues().contains(subQueue)) { - throw IllegalSubQueueIdentifierException(queueType) + throw IllegalSubQueueIdentifierException(subQueue) } - return getQueueForTypeInternal(queueType) + return getSubQueueInternal(subQueue) } /** - * Retrieves only assigned messages in the sub-queue for the provided [queueType]. + * Retrieves only assigned messages in the sub-queue for the provided [subQueue]. * - * By default, this calls [getQueueForType] and iterates through this to determine if the [QueueMessage.assignedTo] + * By default, this calls [getSubQueue] and iterates through this to determine if the [QueueMessage.assignedTo] * field is `not-null`, if [assignedTo] is `null` or is equal to the provided [assignedTo] if it is `not-null`. * - * @param queueType the identifier of the sub-queue [Queue] + * @param subQueue the identifier of the sub-queue [Queue] * @param assignedTo to further filter the messages returned this can be provided * @return a limited version of the [Queue] containing only assigned messages */ - open fun getAssignedMessagesForType(queueType: String, assignedTo: String?): Queue + open fun getAssignedMessagesInSubQueue(subQueue: String, assignedTo: String?): Queue { - val queue = ConcurrentLinkedQueue() - val queueForType = getQueueForType(queueType) + val assignedMessages = ConcurrentLinkedQueue() + val queue = getSubQueue(subQueue) if (assignedTo == null) { - queue.addAll(queueForType.stream().filter { message -> message.assignedTo != null }.collect(Collectors.toList())) + assignedMessages.addAll(queue.stream().filter { message -> message.assignedTo != null }.collect(Collectors.toList())) } else { - queue.addAll(queueForType.stream().filter { message -> message.assignedTo == assignedTo }.collect(Collectors.toList())) + assignedMessages.addAll(queue.stream().filter { message -> message.assignedTo == assignedTo }.collect(Collectors.toList())) } - return queue + return assignedMessages } /** - * Retrieves only unassigned messages in the sub-queue for the provided [queueType]. + * Retrieves only unassigned messages in the sub-queue for the provided [subQueue]. * - * By default, this iterates over [getQueueForType] and includes only entries where [QueueMessage.assignedTo] is `null`. + * By default, this iterates over [getSubQueue] and includes only entries where [QueueMessage.assignedTo] is `null`. * - * @param queueType the identifier of the sub-queue [Queue] + * @param subQueue the identifier of the sub-queue [Queue] * @return a limited version of the [Queue] containing only unassigned messages */ - open fun getUnassignedMessagesForType(queueType:String): Queue + open fun getUnassignedMessagesInSubQueue(subQueue: String): Queue { - val queue = ConcurrentLinkedQueue() - val queueForType = getQueueForType(queueType) - queue.addAll(queueForType.stream().filter { message -> message.assignedTo == null }.collect(Collectors.toList())) - return queue + val unassignedMessages = ConcurrentLinkedQueue() + val queue = getSubQueue(subQueue) + unassignedMessages.addAll(queue.stream().filter { message -> message.assignedTo == null }.collect(Collectors.toList())) + return unassignedMessages } /** * Get a map of assignee identifiers and the sub-queue identifier that they own messages in. - * If the [queueType] is provided this will iterate over all sub-queues and call [getOwnersAndKeysMapForType] for each of them. - * Otherwise, it will only call [getOwnersAndKeysMapForType] on the provided [queueType] if it is not null. + * If the [subQueue] is provided this will iterate over all sub-queues and call [getOwnersAndKeysMapForSubQueue] for each of them. + * Otherwise, it will only call [getOwnersAndKeysMapForSubQueue] on the provided [subQueue] if it is not null. * - * @param queueType the queue type retrieve the [Map] from + * @param subQueue to retrieve the [Map] from * @return the [Map] of assignee identifiers mapped to a list of the sub-queue identifiers that they own any messages in */ - fun getOwnersAndKeysMap(queueType: String?): Map> + fun getOwnersAndKeysMap(subQueue: String?): Map> { val responseMap = HashMap>() - if (queueType != null) + if (subQueue != null) { - LOG.debug("Getting owners map for sub-queue with identifier [{}].", queueType) - getOwnersAndKeysMapForType(queueType, responseMap) + LOG.debug("Getting owners map for sub-queue with identifier [{}].", subQueue) + getOwnersAndKeysMapForSubQueue(subQueue, responseMap) } else { LOG.debug("Getting owners map for all sub-queues.") val keys = keys(false) - keys.forEach { key -> getOwnersAndKeysMapForType(key, responseMap) } + keys.forEach { key -> getOwnersAndKeysMapForSubQueue(key, responseMap) } } return responseMap } /** * Add an entry to the provided [Map] if any of the messages in the sub-queue are assigned. - * The [QueueMessage.type] is appended to the [Set] under it's [QueueMessage.assignedTo] identifier. + * The [QueueMessage.subQueue] is appended to the [Set] under it's [QueueMessage.assignedTo] identifier. * - * @param queueType the sub-queue to iterate and update the map from + * @param subQueue the sub-queue to iterate and update the map from * @param responseMap the map to update */ - fun getOwnersAndKeysMapForType(queueType: String, responseMap: HashMap>) + fun getOwnersAndKeysMapForSubQueue(subQueue: String, responseMap: HashMap>) { - val queueForType: Queue = getAssignedMessagesForType(queueType, null) - queueForType.forEach { message -> - val type = message.type + val queue: Queue = getAssignedMessagesInSubQueue(subQueue, null) + queue.forEach { message -> + val subQueueID = message.subQueue val assigned = message.assignedTo if (assigned != null) { - LOG.trace("Appending sub-queue identifier [{}] to map for assignee ID [{}].", type, assigned) + LOG.trace("Appending sub-queue identifier [{}] to map for assignee ID [{}].", subQueueID, assigned) if (!responseMap.contains(assigned)) { - val set = hashSetOf(type) + val set = hashSetOf(subQueueID) responseMap[assigned] = set } else { // Set should not be null since we initialise and set it if the key is contained - responseMap[assigned]!!.add(type) + responseMap[assigned]!!.add(subQueueID) } } } @@ -262,48 +262,48 @@ abstract class MultiQueue: Queue, HasLogger * * This method should update the [size] property as part of the clearing of the sub-queue. * - * @param queueType the [String] of the [Queue] to clear + * @param subQueue the [String] of the [Queue] to clear * @return the number of entries removed */ - abstract fun clearForTypeInternal(queueType: String): Int + abstract fun clearSubQueueInternal(subQueue: String): Int /** - * Call to [MultiQueue.clearForTypeInternal]. + * Call to [MultiQueue.clearSubQueueInternal]. * - * @param queueType the [String] of the [Queue] to clear + * @param subQueue the [String] of the [Queue] to clear * @return the number of entries removed */ - fun clearForType(queueType: String): Int + fun clearSubQueue(subQueue: String): Int { - return clearForTypeInternal(queueType) + return clearSubQueueInternal(subQueue) } /** * Indicates whether the underlying [Queue] for the provided [String] is empty. By calling [Queue.isEmpty]. * - * @param queueType the [String] of the [Queue] to check whether it is empty + * @param subQueue the [String] of the [Queue] to check whether it is empty * @return `true` if the [Queue] for the [String] is empty, otherwise `false` */ - abstract fun isEmptyForType(queueType: String): Boolean + abstract fun isEmptySubQueue(subQueue: String): Boolean /** * Calls [Queue.poll] on the underlying [Queue] for the provided [String]. * This will retrieve **AND** remove the head element of the [Queue]. * - * @param queueType [String] of the [Queue] to poll + * @param subQueue [String] of the [Queue] to poll * @return the head element or `null` */ - open fun pollForType(queueType: String): Optional + open fun pollSubQueue(subQueue: String): Optional { - val head = pollInternal(queueType) + val head = pollInternal(subQueue) if (head.isPresent) { removeInternal(head.get()) - LOG.debug("Found and removed head element with UUID [{}] from queue with type [{}].", head.get().uuid, queueType) + LOG.debug("Found and removed head element with UUID [{}] from sub-queue [{}].", head.get().uuid, subQueue) } else { - LOG.debug("No head element found when polling queue with type [{}].", queueType) + LOG.debug("No head element found when polling sub-queue [{}].", subQueue) } return head } @@ -312,32 +312,32 @@ abstract class MultiQueue: Queue, HasLogger * The internal poll method to be called. * This is not to be called directly. * - * This method should return the first element in the queue for the provided [queueType]. + * This method should return the first element in the queue for the provided [subQueue]. * *The caller will remove this element*. * - * @param queueType the sub-queue to poll + * @param subQueue the sub-queue to poll * @return the first message wrapped as an [Optional] otherwise [Optional.empty] */ - abstract fun pollInternal(queueType: String): Optional + abstract fun pollInternal(subQueue: String): Optional /** * Calls [Queue.peek] on the underlying [Queue] for the provided [String]. * This will retrieve the head element of the [Queue] without removing it. * - * @param queueType [String] of the [Queue] to peek + * @param subQueue [String] of the [Queue] to peek * @return the head element or `null` */ - fun peekForType(queueType: String): Optional + fun peekSubQueue(subQueue: String): Optional { - val queueForType: Queue = getQueueForType(queueType) - val peeked = Optional.ofNullable(queueForType.peek()) + val queue: Queue = getSubQueue(subQueue) + val peeked = Optional.ofNullable(queue.peek()) if (peeked.isPresent) { - LOG.debug("Found head element with UUID [{}] from queue with type [{}].", peeked.get().uuid, queueType) + LOG.debug("Found head element with UUID [{}] from sub-queue [{}].", peeked.get().uuid, subQueue) } else { - LOG.debug("No head element found when peeking queue with type [{}].", queueType) + LOG.debug("No head element found when peeking sub-queue [{}].", subQueue) } return peeked } @@ -347,7 +347,7 @@ abstract class MultiQueue: Queue, HasLogger * **Should be called directly, please using [keys].** * * @param includeEmpty *true* to include any empty queues which one had elements in them, otherwise *false* to only include keys from queues which have elements. - * @return a [HashSet] of the available `QueueTypes` that have entries in the [MultiQueue]. + * @return a [HashSet] of the available `Sub-Queues` that have entries in the [MultiQueue]. */ abstract fun keysInternal(includeEmpty: Boolean = true): HashSet @@ -355,7 +355,7 @@ abstract class MultiQueue: Queue, HasLogger * Delegates to [keysInternal] and removes any keys that match in the [MultiQueueAuthenticator.getReservedSubQueues]. * * @param includeEmpty *true* to include any empty queues which one had elements in them, otherwise *false* to only include keys from queues which have elements. - * @return a [Set] of the available `QueueTypes` that have entries in the [MultiQueue]. + * @return a [Set] of the available `Sub-Queues` that have entries in the [MultiQueue]. */ fun keys(includeEmpty: Boolean = true): Set { @@ -367,10 +367,10 @@ abstract class MultiQueue: Queue, HasLogger } /** - * Returns the `queueType` that the [QueueMessage] with the provided [UUID] exists in. + * Returns the `sub-queue` that the [QueueMessage] with the provided [UUID] exists in. * * @param uuid the [UUID] (as a [String]) to look up - * @return the `queueType` [String] if a [QueueMessage] exists with the provided [UUID] otherwise [Optional.empty] + * @return the `sub-queue` [String] if a [QueueMessage] exists with the provided [UUID] otherwise [Optional.empty] */ abstract fun containsUUID(uuid: String): Optional @@ -380,27 +380,27 @@ abstract class MultiQueue: Queue, HasLogger /** * Override [add] method to declare [Throws] [DuplicateMessageException] annotation. * - * [Synchronized] so that the call to [MultiQueue.getNextQueueIndex] does not cause issues, since retrieving the next index does + * [Synchronized] so that the call to [MultiQueue.getNextSubQueueIndex] does not cause issues, since retrieving the next index does * not force it to be auto incremented or unusable by another thread. * * @throws [DuplicateMessageException] if a message already exists with the same [QueueMessage.uuid] in `any` other queue. - * @throws [IllegalSubQueueIdentifierException] if the [QueueMessage.type] is invalid or reserved + * @throws [IllegalSubQueueIdentifierException] if the [QueueMessage.subQueue] is invalid or reserved */ @Throws(DuplicateMessageException::class, IllegalSubQueueIdentifierException::class) @Synchronized override fun add(element: QueueMessage): Boolean { - if (multiQueueAuthenticator.getReservedSubQueues().contains(element.type)) + if (multiQueueAuthenticator.getReservedSubQueues().contains(element.subQueue)) { - throw IllegalSubQueueIdentifierException(element.type) + throw IllegalSubQueueIdentifierException(element.subQueue) } - val elementIsMappedToType = containsUUID(element.uuid) - if ( !elementIsMappedToType.isPresent) + val subQueueMessageAlreadyExistsIn = containsUUID(element.uuid) + if ( !subQueueMessageAlreadyExistsIn.isPresent) { if (element.id == null) { - val index = getNextQueueIndex(element.type) + val index = getNextSubQueueIndex(element.subQueue) if (index.isPresent) { element.id = index.get() @@ -409,20 +409,20 @@ abstract class MultiQueue: Queue, HasLogger val wasAdded = addInternal(element) return if (wasAdded) { - LOG.debug("Added new message with uuid [{}] to queue with type [{}].", element.uuid, element.type) + LOG.debug("Added new message with uuid [{}] to sub-queue [{}].", element.uuid, element.subQueue) true } else { - LOG.error("Failed to add message with uuid [{}] to queue with type [{}].", element.uuid, element.type) + LOG.error("Failed to add message with uuid [{}] to sub-queue [{}].", element.uuid, element.subQueue) false } } else { - val existingQueueType = elementIsMappedToType.get() - LOG.warn("Did not add new message with uuid [{}] to queue with type [{}] as it already exists in queue with type [{}].", element.uuid, element.type, existingQueueType) - throw DuplicateMessageException(element.uuid, existingQueueType) + val existingSubQueue = subQueueMessageAlreadyExistsIn.get() + LOG.warn("Did not add new message with uuid [{}] to sub-queue [{}] as it already exists in sub-queue [{}].", element.uuid, element.subQueue, existingSubQueue) + throw DuplicateMessageException(element.uuid, existingSubQueue) } } @@ -440,11 +440,11 @@ abstract class MultiQueue: Queue, HasLogger val wasRemoved = removeInternal(element) if (wasRemoved) { - LOG.debug("Removed element with UUID [{}] from queue with type [{}].", element.uuid, element.type) + LOG.debug("Removed element with UUID [{}] from sub-queue [{}].", element.uuid, element.subQueue) } else { - LOG.error("Failed to remove element with UUID [{}] from queue with type [{}].", element.uuid, element.type) + LOG.error("Failed to remove element with UUID [{}] from sub-queue [{}].", element.uuid, element.subQueue) } return wasRemoved } @@ -464,8 +464,8 @@ abstract class MultiQueue: Queue, HasLogger { return false } - val queueForType: Queue = getQueueForType(element.type) - return queueForType.contains(element) + val queue: Queue = getSubQueue(element.subQueue) + return queue.contains(element) } override fun containsAll(elements: Collection): Boolean @@ -496,7 +496,7 @@ abstract class MultiQueue: Queue, HasLogger for (key: String in keys(false)) { // The queue should never be new or created since we passed `false` into `keys()` above. - val queueForKey: Queue = getQueueForType(key) + val queueForKey: Queue = getSubQueue(key) for(entry: QueueMessage in queueForKey) { if ( !elements.contains(entry)) @@ -533,11 +533,11 @@ abstract class MultiQueue: Queue, HasLogger } /** - * @return `true` any of the [keys] returns `false` for [isEmptyForType], otherwise `false`. + * @return `true` any of the [keys] returns `false` for [isEmptySubQueue], otherwise `false`. */ override fun isEmpty(): Boolean { - val anyHasElements = keys(false).stream().anyMatch { key -> !isEmptyForType(key) } + val anyHasElements = keys(false).stream().anyMatch { key -> !isEmptySubQueue(key) } return !anyHasElements } @@ -547,10 +547,10 @@ abstract class MultiQueue: Queue, HasLogger var removedEntryCount = 0 for (key in keys) { - val amountRemovedForQueue = clearForType(key) + val amountRemovedForQueue = clearSubQueue(key) removedEntryCount += amountRemovedForQueue } - LOG.debug("Cleared multi-queue, removed [{}] message entries over [{}] queue types.", removedEntryCount, keys) + LOG.debug("Cleared multi-queue, removed [{}] message entries over [{}] sub-queues.", removedEntryCount, keys) } /** diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt index e034c24..722c5e0 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisMultiQueue.kt @@ -1,6 +1,5 @@ package au.kilemon.messagequeue.queue.cache.redis -import au.kilemon.messagequeue.authentication.authenticator.cache.redis.RedisAuthenticator import au.kilemon.messagequeue.logging.HasLogger import au.kilemon.messagequeue.message.QueueMessage import au.kilemon.messagequeue.queue.MultiQueue @@ -11,9 +10,7 @@ import org.springframework.data.redis.core.RedisTemplate import org.springframework.data.redis.core.ScanOptions import java.util.* import java.util.concurrent.ConcurrentLinkedQueue -import java.util.concurrent.atomic.AtomicLong import java.util.stream.Collectors -import kotlin.collections.HashMap import kotlin.collections.HashSet /** @@ -28,18 +25,18 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate override val LOG: Logger = this.initialiseLogger() /** - * Append the [MessageQueueSettings.redisPrefix] to the provided [queueType] [String]. + * Append the [MessageQueueSettings.redisPrefix] to the provided [subQueue] [String]. * - * @param queueType the [String] to add the prefix to - * @return a [String] with the provided [queueType] type with the [MessageQueueSettings.redisPrefix] appended to the beginning. + * @param subQueue the [String] to add the prefix to + * @return a [String] with the provided [subQueue] with the [MessageQueueSettings.redisPrefix] appended to the beginning. */ - private fun appendPrefix(queueType: String): String + private fun appendPrefix(subQueue: String): String { - if (hasPrefix() && !queueType.startsWith(getPrefix())) + if (hasPrefix() && !subQueue.startsWith(getPrefix())) { - return "${getPrefix()}$queueType" + return "${getPrefix()}$subQueue" } - return queueType + return subQueue } /** @@ -77,12 +74,12 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate } /** - * Attempts to append the prefix before requesting the underlying redis entry if the provided [queueType] is not prefixed with [MessageQueueSettings.redisPrefix]. + * Attempts to append the prefix before requesting the underlying redis entry if the provided [subQueue] is not prefixed with [MessageQueueSettings.redisPrefix]. */ - override fun getQueueForTypeInternal(queueType: String): Queue + override fun getSubQueueInternal(subQueue: String): Queue { val queue = ConcurrentLinkedQueue() - val set = redisTemplate.opsForSet().members(appendPrefix(queueType)) + val set = redisTemplate.opsForSet().members(appendPrefix(subQueue)) if (!set.isNullOrEmpty()) { queue.addAll(set.toSortedSet { message1, message2 -> (message1.id ?: 0).minus(message2.id ?: 0).toInt() }) @@ -90,10 +87,10 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate return queue } - override fun getAssignedMessagesForType(queueType: String, assignedTo: String?): Queue + override fun getAssignedMessagesInSubQueue(subQueue: String, assignedTo: String?): Queue { val queue = ConcurrentLinkedQueue() - val existingQueue = getQueueForType(queueType) + val existingQueue = getSubQueue(subQueue) if (existingQueue.isNotEmpty()) { if (assignedTo == null) @@ -115,30 +112,30 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate override fun getMessageByUUID(uuid: String): Optional { - val queueType = containsUUID(uuid) - if (queueType.isPresent) + val subQueue = containsUUID(uuid) + if (subQueue.isPresent) { - val queueForType: Queue = getQueueForType(queueType.get()) - return queueForType.stream().filter { message -> message.uuid == uuid }.findFirst() + val queue: Queue = getSubQueue(subQueue.get()) + return queue.stream().filter { message -> message.uuid == uuid }.findFirst() } return Optional.empty() } override fun addInternal(element: QueueMessage): Boolean { - val result = redisTemplate.opsForSet().add(appendPrefix(element.type), element) + val result = redisTemplate.opsForSet().add(appendPrefix(element.subQueue), element) return result != null && result > 0 } /** - * Overriding to pass in the [queueType] into [appendPrefix]. + * Overriding to pass in the [subQueue] into [appendPrefix]. */ - override fun getNextQueueIndex(queueType: String): Optional + override fun getNextSubQueueIndex(subQueue: String): Optional { - val queueForType = getQueueForType(appendPrefix(queueType)) - return if (queueForType.isNotEmpty()) + val queue = getSubQueue(appendPrefix(subQueue)) + return if (queue.isNotEmpty()) { - Optional.ofNullable(queueForType.last().id?.plus(1) ?: 1) + Optional.ofNullable(queue.last().id?.plus(1) ?: 1) } else { @@ -148,35 +145,35 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate override fun removeInternal(element: QueueMessage): Boolean { - val result = redisTemplate.opsForSet().remove(appendPrefix(element.type), element) + val result = redisTemplate.opsForSet().remove(appendPrefix(element.subQueue), element) return result != null && result > 0 } - override fun clearForTypeInternal(queueType: String): Int + override fun clearSubQueueInternal(subQueue: String): Int { var amountRemoved = 0 - val queueForType = getQueueForType(queueType) - if (queueForType.isNotEmpty()) + val queue = getSubQueue(subQueue) + if (queue.isNotEmpty()) { - amountRemoved = queueForType.size - redisTemplate.delete(appendPrefix(queueType)) - LOG.debug("Cleared existing queue for type [{}]. Removed [{}] message entries.", queueType, amountRemoved) + amountRemoved = queue.size + redisTemplate.delete(appendPrefix(subQueue)) + LOG.debug("Cleared existing sub-queue [{}]. Removed [{}] message entries.", subQueue, amountRemoved) } else { - LOG.debug("Attempting to clear non-existent queue for type [{}]. No messages cleared.", queueType) + LOG.debug("Attempting to clear non-existent sub-queue [{}]. No messages cleared.", subQueue) } return amountRemoved } - override fun isEmptyForType(queueType: String): Boolean + override fun isEmptySubQueue(subQueue: String): Boolean { - return getQueueForType(queueType).isEmpty() + return getSubQueue(subQueue).isEmpty() } - override fun pollInternal(queueType: String): Optional + override fun pollInternal(subQueue: String): Optional { - val queue = getQueueForType(queueType) + val queue = getSubQueue(subQueue) if (queue.isNotEmpty()) { return Optional.of(queue.iterator().next()) @@ -203,7 +200,7 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate val sizeOfQueue = redisTemplate.opsForSet().size(key) if (sizeOfQueue != null && sizeOfQueue > 0) { - LOG.trace("Queue type [{}] is not empty and will be returned in keys() call.", key) + LOG.trace("Sub-queue [{}] is not empty and will be returned in keys() call.", key) retainedKeys.add(key) } } @@ -216,15 +213,15 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate { for (key in keys()) { - val queue = getQueueForType(key) + val queue = getSubQueue(key) val anyMatchTheUUID = queue.stream().anyMatch{ message -> uuid == message.uuid } if (anyMatchTheUUID) { - LOG.debug("Found queue type [{}] for UUID: [{}].", key, uuid) + LOG.debug("Found sub-queue [{}] for message UUID: [{}].", key, uuid) return Optional.of(key) } } - LOG.debug("No queue type exists for UUID: [{}].", uuid) + LOG.debug("No sub-queue contains message with UUID: [{}].", uuid) return Optional.empty() } @@ -234,7 +231,7 @@ class RedisMultiQueue(private val prefix: String = "", private val redisTemplate */ override fun persistMessageInternal(message: QueueMessage) { - val queue = getQueueForType(message.type) + val queue = getSubQueue(message.subQueue) val matchingMessage = queue.stream().filter{ element -> element.uuid == message.uuid }.findFirst() if (matchingMessage.isPresent) { diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/exception/DuplicateMessageException.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/exception/DuplicateMessageException.kt index 338567b..4541f2e 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/exception/DuplicateMessageException.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/exception/DuplicateMessageException.kt @@ -5,4 +5,4 @@ package au.kilemon.messagequeue.queue.exception * * @author github.com/Kilemonn */ -class DuplicateMessageException(uuid: String, queueType: String) : Exception("Duplicate message with UUID [$uuid] exists in queue with type [$queueType].") +class DuplicateMessageException(uuid: String, subQueue: String) : Exception("Duplicate message with UUID [$uuid] exists in sub-queue [$subQueue].") diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt index 95b15c6..9226b73 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMultiQueue.kt @@ -9,7 +9,6 @@ import java.util.* import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.atomic.AtomicLong -import java.util.stream.Collectors import kotlin.collections.HashMap import kotlin.jvm.Throws @@ -24,7 +23,7 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger override val LOG: Logger = this.initialiseLogger() /** - * An internal [Map] that holds known [UUID]s (as a [String]) and their related `queueType` to quickly find entries within the [MultiQueue]. + * An internal [Map] that holds known [UUID]s (as a [String]) and their related `sub-queue` to quickly find entries within the [MultiQueue]. */ private val uuidMap: ConcurrentHashMap = ConcurrentHashMap() @@ -36,34 +35,34 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger private val maxQueueIndex: HashMap = HashMap() /** - * This index is special compared to the other types it will be incremented once retrieved. So we could be skipping - * indexes, but it should be fine since it's only used for message ordering. + * This index is special compared to the other [au.kilemon.messagequeue.settings.StorageMedium] it will be incremented once retrieved. + * So we could be skipping indexes, but it should be fine since it's only used for message ordering. */ - override fun getNextQueueIndex(queueType: String): Optional + override fun getNextSubQueueIndex(subQueue: String): Optional { - var index = maxQueueIndex[queueType] + var index = maxQueueIndex[subQueue] if (index == null) { index = AtomicLong(1) - maxQueueIndex[queueType] = index + maxQueueIndex[subQueue] = index } return Optional.of(index.getAndIncrement()) } - override fun getQueueForTypeInternal(queueType: String): Queue + override fun getSubQueueInternal(subQueue: String): Queue { - var queueForType: Queue? = messageQueue[queueType] - if (queueForType == null) + var queue: Queue? = messageQueue[subQueue] + if (queue == null) { - queueForType = ConcurrentLinkedQueue() - LOG.debug("Initialising new queue for type [{}].", queueType) - messageQueue[queueType] = queueForType + queue = ConcurrentLinkedQueue() + LOG.debug("Initialising new sub-queue [{}].", subQueue) + messageQueue[subQueue] = queue } else { - LOG.debug("Found existing queue for type [{}] with size [{}].", queueType, queueForType.size) + LOG.debug("Found existing sub-queue [{}] with size [{}].", subQueue, queue.size) } - return queueForType + return queue } override fun performHealthCheckInternal() @@ -73,31 +72,31 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger override fun getMessageByUUID(uuid: String): Optional { - val queueType = containsUUID(uuid) - if (queueType.isPresent) + val subQueue = containsUUID(uuid) + if (subQueue.isPresent) { - val queueForType: Queue = getQueueForType(queueType.get()) - return queueForType.stream().filter { message -> message.uuid == uuid }.findFirst() + val queue: Queue = getSubQueue(subQueue.get()) + return queue.stream().filter { message -> message.uuid == uuid }.findFirst() } return Optional.empty() } - override fun clearForTypeInternal(queueType: String): Int + override fun clearSubQueueInternal(subQueue: String): Int { var amountRemoved = 0 - val queueForType: Queue? = messageQueue[queueType] - maxQueueIndex.remove(queueType) - if (queueForType != null) + val queue: Queue? = messageQueue[subQueue] + maxQueueIndex.remove(subQueue) + if (queue != null) { - amountRemoved = queueForType.size - queueForType.forEach { message -> uuidMap.remove(message.uuid) } - queueForType.clear() - messageQueue.remove(queueType) - LOG.debug("Cleared existing queue for type [{}]. Removed [{}] message entries.", queueType, amountRemoved) + amountRemoved = queue.size + queue.forEach { message -> uuidMap.remove(message.uuid) } + queue.clear() + messageQueue.remove(subQueue) + LOG.debug("Cleared existing sub-queue [{}]. Removed [{}] message entries.", subQueue, amountRemoved) } else { - LOG.debug("Attempting to clear non-existent queue for type [{}]. No messages cleared.", queueType) + LOG.debug("Attempting to clear non-existent sub-queue [{}]. No messages cleared.", subQueue) } return amountRemoved } @@ -114,7 +113,7 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger val wasAdded = super.add(element) if (wasAdded) { - uuidMap[element.uuid] = element.type + uuidMap[element.uuid] = element.subQueue } return wasAdded } @@ -124,8 +123,8 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger */ override fun addInternal(element: QueueMessage): Boolean { - val queueForType: Queue = getQueueForType(element.type) - return queueForType.add(element) + val queue: Queue = getSubQueue(element.subQueue) + return queue.add(element) } override fun remove(element: QueueMessage): Boolean @@ -143,14 +142,14 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger */ override fun removeInternal(element: QueueMessage): Boolean { - val queueForType: Queue = getQueueForType(element.type) - return queueForType.remove(element) + val queue: Queue = getSubQueue(element.subQueue) + return queue.remove(element) } - override fun isEmptyForType(queueType: String): Boolean + override fun isEmptySubQueue(subQueue: String): Boolean { - val queueForType: Queue = getQueueForType(queueType) - return queueForType.isEmpty() + val queue: Queue = getSubQueue(subQueue) + return queue.isEmpty() } override fun keysInternal(includeEmpty: Boolean): HashSet @@ -165,10 +164,10 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger val keys = HashSet() for (key: String in messageQueue.keys) { - val queueForType = getQueueForType(key) - if (queueForType.isNotEmpty()) + val queue = getSubQueue(key) + if (queue.isNotEmpty()) { - LOG.trace("Queue type [{}] is not empty and will be returned in keys() call.", queueForType) + LOG.trace("Sub-queue [{}] is not empty and will be returned in keys() call.", queue) keys.add(key) } } @@ -179,24 +178,24 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger override fun containsUUID(uuid: String): Optional { - val queueTypeForUUID: String? = uuidMap[uuid] - if (queueTypeForUUID.isNullOrBlank()) + val subQueueID: String? = uuidMap[uuid] + if (subQueueID.isNullOrBlank()) { - LOG.debug("No queue type exists for UUID: [{}].", uuid) + LOG.debug("No sub-queue exists for UUID: [{}].", uuid) } else { - LOG.debug("Found queue type [{}] for UUID: [{}].", queueTypeForUUID, uuid) + LOG.debug("Found sub-queue [{}] for UUID: [{}].", subQueueID, uuid) } - return Optional.ofNullable(queueTypeForUUID) + return Optional.ofNullable(subQueueID) } /** * Update the [uuidMap] and remove the entry if it is returned (removed). */ - override fun pollForType(queueType: String): Optional + override fun pollSubQueue(subQueue: String): Optional { - val message = super.pollForType(queueType) + val message = super.pollSubQueue(subQueue) if (message.isPresent) { uuidMap.remove(message.get().uuid) @@ -205,12 +204,12 @@ open class InMemoryMultiQueue : MultiQueue(), HasLogger return message } - override fun pollInternal(queueType: String): Optional + override fun pollInternal(subQueue: String): Optional { - val queueForType: Queue = getQueueForType(queueType) - return if (queueForType.isNotEmpty()) + val queue: Queue = getSubQueue(subQueue) + return if (queue.isNotEmpty()) { - Optional.of(queueForType.iterator().next()) + Optional.of(queue.iterator().next()) } else { diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt index 1a5bf8b..1353f67 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueue.kt @@ -11,7 +11,6 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Lazy import java.util.* import java.util.concurrent.ConcurrentLinkedQueue -import java.util.concurrent.atomic.AtomicLong /** * A NoSql mongo backed [MultiQueue]. All operations are performed directly on the database it is the complete source of truth. @@ -48,15 +47,15 @@ class MongoMultiQueue : MultiQueue(), HasLogger /** * Overriding to use more direct optimised queries. */ - override fun getAssignedMessagesForType(queueType: String, assignedTo: String?): Queue + override fun getAssignedMessagesInSubQueue(subQueue: String, assignedTo: String?): Queue { val entries = if (assignedTo == null) { - queueMessageRepository.findByTypeAndAssignedToIsNotNullOrderByIdAsc(queueType) + queueMessageRepository.findBySubQueueAndAssignedToIsNotNullOrderByIdAsc(subQueue) } else { - queueMessageRepository.findByTypeAndAssignedToOrderByIdAsc(queueType, assignedTo) + queueMessageRepository.findBySubQueueAndAssignedToOrderByIdAsc(subQueue, assignedTo) } return ConcurrentLinkedQueue(entries.map { entry -> QueueMessage(entry) }) @@ -65,15 +64,15 @@ class MongoMultiQueue : MultiQueue(), HasLogger /** * Overriding since we can filter via the DB query. */ - override fun getUnassignedMessagesForType(queueType: String): Queue + override fun getUnassignedMessagesInSubQueue(subQueue: String): Queue { - val entries = queueMessageRepository.findByTypeAndAssignedToIsNullOrderByIdAsc(queueType) + val entries = queueMessageRepository.findBySubQueueAndAssignedToIsNullOrderByIdAsc(subQueue) return ConcurrentLinkedQueue(entries.map { entry -> QueueMessage(entry) }) } - override fun getQueueForTypeInternal(queueType: String): Queue + override fun getSubQueueInternal(subQueue: String): Queue { - val entries = queueMessageRepository.findByTypeOrderByIdAsc(queueType) + val entries = queueMessageRepository.findBySubQueueOrderByIdAsc(subQueue) return ConcurrentLinkedQueue(entries.map { entry -> QueueMessage(entry) }) } @@ -95,21 +94,21 @@ class MongoMultiQueue : MultiQueue(), HasLogger } } - override fun clearForTypeInternal(queueType: String): Int + override fun clearSubQueueInternal(subQueue: String): Int { - val amountCleared = queueMessageRepository.deleteByType(queueType) - LOG.debug("Cleared existing queue for type [{}]. Removed [{}] message entries.", queueType, amountCleared) + val amountCleared = queueMessageRepository.deleteBySubQueue(subQueue) + LOG.debug("Cleared existing queue for sub-queue [{}]. Removed [{}] message entries.", subQueue, amountCleared) return amountCleared } - override fun isEmptyForType(queueType: String): Boolean + override fun isEmptySubQueue(subQueue: String): Boolean { - return queueMessageRepository.findByTypeOrderByIdAsc(queueType).isEmpty() + return queueMessageRepository.findBySubQueueOrderByIdAsc(subQueue).isEmpty() } - override fun pollInternal(queueType: String): Optional + override fun pollInternal(subQueue: String): Optional { - val messages = queueMessageRepository.findByTypeOrderByIdAsc(queueType) + val messages = queueMessageRepository.findBySubQueueOrderByIdAsc(subQueue) return if (messages.isNotEmpty()) { return Optional.of(QueueMessage(messages[0])) @@ -125,7 +124,7 @@ class MongoMultiQueue : MultiQueue(), HasLogger */ override fun keysInternal(includeEmpty: Boolean): HashSet { - val keySet = HashSet(queueMessageRepository.getDistinctTypes()) + val keySet = HashSet(queueMessageRepository.getDistinctSubQueues()) LOG.debug("Total amount of queue keys [{}].", keySet.size) return keySet } @@ -136,12 +135,12 @@ class MongoMultiQueue : MultiQueue(), HasLogger return if (optionalMessage.isPresent) { val message = optionalMessage.get() - LOG.debug("Found queue type [{}] for UUID: [{}].", message.type, uuid) - Optional.of(message.type) + LOG.debug("Found sub-queue [{}] for UUID: [{}].", message.subQueue, uuid) + Optional.of(message.subQueue) } else { - LOG.debug("No queue type exists for UUID: [{}].", uuid) + LOG.debug("No sub-queue exists for UUID: [{}].", uuid) Optional.empty() } } @@ -163,7 +162,7 @@ class MongoMultiQueue : MultiQueue(), HasLogger * Overriding to use the constant [INDEX_ID] for all look-ups since the ID is shared and needs to be assigned to * the [QueueMessageDocument] before it is created. */ - override fun getNextQueueIndex(queueType: String): Optional + override fun getNextSubQueueIndex(subQueue: String): Optional { val largestIdMessage = queueMessageRepository.findTopByOrderByIdDesc() return if (largestIdMessage.isPresent) diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/repository/MongoQueueMessageRepository.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/repository/MongoQueueMessageRepository.kt index 8d5e674..b8f3a74 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/repository/MongoQueueMessageRepository.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/repository/MongoQueueMessageRepository.kt @@ -16,20 +16,20 @@ import java.util.* interface MongoQueueMessageRepository: MongoRepository { /** - * Get a distinct [List] of [String] [QueueMessageDocument.type] that currently exist. + * Get a distinct [List] of [String] [QueueMessageDocument.subQueue] that currently exist. * - * @return a [List] of all the existing [QueueMessageDocument.type] as [String]s + * @return a [List] of all the existing [QueueMessageDocument.subQueue] as [String]s */ - @Aggregation(pipeline = [ "{ '\$group': { '_id' : '\$type' } }" ]) - fun getDistinctTypes(): List + @Aggregation(pipeline = [ "{ '\$group': { '_id' : '\$subQueue' } }" ]) + fun getDistinctSubQueues(): List /** - * Get a list of [QueueMessageDocument] which have [QueueMessageDocument.type] matching the provided [type]. + * Get a list of [QueueMessageDocument] which have [QueueMessageDocument.subQueue] matching the provided [subQueue]. * - * @param type the type to match [QueueMessageDocument.type] with - * @return a [List] of [QueueMessageDocument] who have a matching [QueueMessageDocument.type] with the provided [type] + * @param subQueue the type to match [QueueMessageDocument.subQueue] with + * @return a [List] of [QueueMessageDocument] who have a matching [QueueMessageDocument.subQueue] with the provided [subQueue] */ - fun findByTypeOrderByIdAsc(type: String): List + fun findBySubQueueOrderByIdAsc(subQueue: String): List /** * Find and return a [QueueMessageDocument] that matches the provided [uuid]. @@ -40,13 +40,13 @@ interface MongoQueueMessageRepository: MongoRepository /** - * Delete all [QueueMessageDocument] that have a [QueueMessageDocument.type] that matches the provided [type]. + * Delete all [QueueMessageDocument] that have a [QueueMessageDocument.subQueue] that matches the provided [subQueue]. * - * @param type messages that are assigned this queue type will be removed + * @param subQueue messages that are assigned this sub-queue will be removed * @return the [Int] number of deleted entries */ @Modifying - fun deleteByType(type: String): Int + fun deleteBySubQueue(subQueue: String): Int /** * Delete a [QueueMessageDocument] by `uuid`. @@ -65,30 +65,30 @@ interface MongoQueueMessageRepository: MongoRepository /** - * Find the entity with the matching [QueueMessageDocument.type] and that has a non-null [QueueMessageDocument.assignedTo]. Sorted by ID ascending. + * Find the entity with the matching [QueueMessageDocument.subQueue] and that has a non-null [QueueMessageDocument.assignedTo]. Sorted by ID ascending. * - * @param type the type to match [QueueMessageDocument.type] with - * @return a [List] of [QueueMessageDocument] who have a matching [QueueMessageDocument.type] with the provided [type] and non-null [QueueMessageDocument.assignedTo] + * @param subQueue the type to match [QueueMessageDocument.subQueue] with + * @return a [List] of [QueueMessageDocument] who have a matching [QueueMessageDocument.subQueue] with the provided [subQueue] and non-null [QueueMessageDocument.assignedTo] */ @Transactional - fun findByTypeAndAssignedToIsNotNullOrderByIdAsc(type: String): List + fun findBySubQueueAndAssignedToIsNotNullOrderByIdAsc(subQueue: String): List /** - * Find the entity with the matching [QueueMessageDocument.type] and [QueueMessageDocument.assignedTo]. Sorted by ID ascending. + * Find the entity with the matching [QueueMessageDocument.subQueue] and [QueueMessageDocument.assignedTo]. Sorted by ID ascending. * - * @param type the type to match [QueueMessageDocument.type] with + * @param subQueue the type to match [QueueMessageDocument.subQueue] with * @param assignedTo the identifier to match [QueueMessageDocument.assignedTo] with - * @return a [List] of [QueueMessageDocument] who have a matching [QueueMessageDocument.type] and [QueueMessageDocument.assignedTo] + * @return a [List] of [QueueMessageDocument] who have a matching [QueueMessageDocument.subQueue] and [QueueMessageDocument.assignedTo] */ @Transactional - fun findByTypeAndAssignedToOrderByIdAsc(type: String, assignedTo: String): List + fun findBySubQueueAndAssignedToOrderByIdAsc(subQueue: String, assignedTo: String): List /** - * Find the entity with the matching [QueueMessageDocument.type] and that has [QueueMessageDocument.assignedTo] set to `null`. Sorted by ID ascending. + * Find the entity with the matching [QueueMessageDocument.subQueue] and that has [QueueMessageDocument.assignedTo] set to `null`. Sorted by ID ascending. * - * @param type the type to match [QueueMessageDocument.type] with - * @return a [List] of [QueueMessageDocument] who have a matching [QueueMessageDocument.type] with the provided [type] and `null` [QueueMessageDocument.assignedTo] + * @param subQueue the type to match [QueueMessageDocument.subQueue] with + * @return a [List] of [QueueMessageDocument] who have a matching [QueueMessageDocument.subQueue] with the provided [subQueue] and `null` [QueueMessageDocument.assignedTo] */ @Transactional - fun findByTypeAndAssignedToIsNullOrderByIdAsc(type: String): List + fun findBySubQueueAndAssignedToIsNullOrderByIdAsc(subQueue: String): List } diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt index 364df17..1764b05 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/SqlMultiQueue.kt @@ -25,24 +25,24 @@ class SqlMultiQueue : MultiQueue(), HasLogger @Autowired private lateinit var queueMessageRepository: SqlQueueMessageRepository - override fun getQueueForTypeInternal(queueType: String): Queue + override fun getSubQueueInternal(subQueue: String): Queue { - val entries = queueMessageRepository.findByTypeOrderByIdAsc(queueType) + val entries = queueMessageRepository.findBySubQueueOrderByIdAsc(subQueue) return ConcurrentLinkedQueue(entries.map { entry -> entry.resolvePayloadObject() }) } /** * Overriding since we can filter via the DB query. */ - override fun getAssignedMessagesForType(queueType: String, assignedTo: String?): Queue + override fun getAssignedMessagesInSubQueue(subQueue: String, assignedTo: String?): Queue { val entries = if (assignedTo == null) { - queueMessageRepository.findByTypeAndAssignedToIsNotNullOrderByIdAsc(queueType) + queueMessageRepository.findBySubQueueAndAssignedToIsNotNullOrderByIdAsc(subQueue) } else { - queueMessageRepository.findByTypeAndAssignedToOrderByIdAsc(queueType, assignedTo) + queueMessageRepository.findBySubQueueAndAssignedToOrderByIdAsc(subQueue, assignedTo) } return ConcurrentLinkedQueue(entries.map { entry -> entry.resolvePayloadObject() }) @@ -51,9 +51,9 @@ class SqlMultiQueue : MultiQueue(), HasLogger /** * Overriding since we can filter via the DB query. */ - override fun getUnassignedMessagesForType(queueType: String): Queue + override fun getUnassignedMessagesInSubQueue(subQueue: String): Queue { - val entries = queueMessageRepository.findByTypeAndAssignedToIsNullOrderByIdAsc(queueType) + val entries = queueMessageRepository.findBySubQueueAndAssignedToIsNullOrderByIdAsc(subQueue) return ConcurrentLinkedQueue(entries.map { entry -> entry.resolvePayloadObject() }) } @@ -75,21 +75,21 @@ class SqlMultiQueue : MultiQueue(), HasLogger } } - override fun clearForTypeInternal(queueType: String): Int + override fun clearSubQueueInternal(subQueue: String): Int { - val amountCleared = queueMessageRepository.deleteByType(queueType) - LOG.debug("Cleared existing queue for type [{}]. Removed [{}] message entries.", queueType, amountCleared) + val amountCleared = queueMessageRepository.deleteBySubQueue(subQueue) + LOG.debug("Cleared existing sub-queue [{}]. Removed [{}] message entries.", subQueue, amountCleared) return amountCleared } - override fun isEmptyForType(queueType: String): Boolean + override fun isEmptySubQueue(subQueue: String): Boolean { - return queueMessageRepository.findByTypeOrderByIdAsc(queueType).isEmpty() + return queueMessageRepository.findBySubQueueOrderByIdAsc(subQueue).isEmpty() } - override fun pollInternal(queueType: String): Optional + override fun pollInternal(subQueue: String): Optional { - val messages = queueMessageRepository.findByTypeOrderByIdAsc(queueType) + val messages = queueMessageRepository.findBySubQueueOrderByIdAsc(subQueue) return if (messages.isNotEmpty()) { return Optional.of(messages[0].resolvePayloadObject()) @@ -105,7 +105,7 @@ class SqlMultiQueue : MultiQueue(), HasLogger */ override fun keysInternal(includeEmpty: Boolean): HashSet { - val keySet = HashSet(queueMessageRepository.findDistinctType()) + val keySet = HashSet(queueMessageRepository.findDistinctSubQueue()) LOG.debug("Total amount of queue keys [{}].", keySet.size) return keySet } @@ -116,12 +116,12 @@ class SqlMultiQueue : MultiQueue(), HasLogger return if (optionalMessage.isPresent) { val message = optionalMessage.get() - LOG.debug("Found queue type [{}] for UUID: [{}].", message.type, uuid) - Optional.of(message.type) + LOG.debug("Found sub-queue [{}] for message with UUID: [{}].", message.subQueue, uuid) + Optional.of(message.subQueue) } else { - LOG.debug("No queue type exists for UUID: [{}].", uuid) + LOG.debug("No sub-queue found for message with UUID: [{}].", uuid) Optional.empty() } } @@ -159,7 +159,7 @@ class SqlMultiQueue : MultiQueue(), HasLogger * Overriding to return [Optional.EMPTY] so that the [MultiQueue.add] does set an `id` into the [QueueMessage] * even if the id is `null`. */ - override fun getNextQueueIndex(queueType: String): Optional + override fun getNextSubQueueIndex(subQueue: String): Optional { return Optional.empty() } diff --git a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/SqlQueueMessageRepository.kt b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/SqlQueueMessageRepository.kt index 295c9c6..12afb42 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/SqlQueueMessageRepository.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/queue/sql/repository/SqlQueueMessageRepository.kt @@ -20,61 +20,61 @@ import java.util.* interface SqlQueueMessageRepository: JpaRepository { /** - * Delete a [QueueMessage] by the provided [QueueMessage.type] [String]. + * Delete a [QueueMessage] by the provided [QueueMessage.subQueue] [String]. * - * @param type the [QueueMessage.type] to remove entries by + * @param subQueue the [QueueMessage.subQueue] to remove entries by * @return the number of deleted entities */ @Modifying @Transactional - @Query("DELETE FROM QueueMessage WHERE type = ?1") - fun deleteByType(type: String): Int + @Query("DELETE FROM QueueMessage WHERE subQueue = ?1") + fun deleteBySubQueue(subQueue: String): Int /** - * Get a distinct [List] of [String] [QueueMessage.type] that currently exist. + * Get a distinct [List] of [String] [QueueMessage.subQueue] that currently exist. * - * @return a [List] of all the existing [QueueMessage.type] as [String]s + * @return a [List] of all the existing [QueueMessage.subQueue] as [String]s */ @Transactional - @Query("SELECT DISTINCT type FROM QueueMessage") - fun findDistinctType(): List + @Query("SELECT DISTINCT subQueue FROM QueueMessage") + fun findDistinctSubQueue(): List /** - * Get a list of [QueueMessage] which have [QueueMessage.type] matching the provided [type]. + * Get a list of [QueueMessage] which have [QueueMessage.subQueue] matching the provided [subQueue]. * - * @param type the type to match [QueueMessage.type] with - * @return a [List] of [QueueMessage] who have a matching [QueueMessage.type] with the provided [type] + * @param subQueue to match [QueueMessage.subQueue] with + * @return a [List] of [QueueMessage] who have a matching [QueueMessage.subQueue] with the provided [subQueue] */ @Transactional - fun findByTypeOrderByIdAsc(type: String): List + fun findBySubQueueOrderByIdAsc(subQueue: String): List /** - * Find the entity with the matching [QueueMessage.type] and that has a non-null [QueueMessage.assignedTo]. Sorted by ID ascending. + * Find the entity with the matching [QueueMessage.subQueue] and that has a non-null [QueueMessage.assignedTo]. Sorted by ID ascending. * - * @param type the type to match [QueueMessage.type] with - * @return a [List] of [QueueMessage] who have a matching [QueueMessage.type] with the provided [type] and non-null [QueueMessage.assignedTo] + * @param subQueue to match [QueueMessage.subQueue] with + * @return a [List] of [QueueMessage] who have a matching [QueueMessage.subQueue] with the provided [subQueue] and non-null [QueueMessage.assignedTo] */ @Transactional - fun findByTypeAndAssignedToIsNotNullOrderByIdAsc(type: String): List + fun findBySubQueueAndAssignedToIsNotNullOrderByIdAsc(subQueue: String): List /** - * Find the entity with the matching [QueueMessage.type] and that has [QueueMessage.assignedTo] set to `null`. Sorted by ID ascending. + * Find the entity with the matching [QueueMessage.subQueue] and that has [QueueMessage.assignedTo] set to `null`. Sorted by ID ascending. * - * @param type the type to match [QueueMessage.type] with - * @return a [List] of [QueueMessage] who have a matching [QueueMessage.type] with the provided [type] and `null` [QueueMessage.assignedTo] + * @param subQueue the type to match [QueueMessage.subQueue] with + * @return a [List] of [QueueMessage] who have a matching [QueueMessage.subQueue] with the provided [subQueue] and `null` [QueueMessage.assignedTo] */ @Transactional - fun findByTypeAndAssignedToIsNullOrderByIdAsc(type: String): List + fun findBySubQueueAndAssignedToIsNullOrderByIdAsc(subQueue: String): List /** - * Find the entity with the matching [QueueMessage.type] and [QueueMessage.assignedTo]. Sorted by ID ascending. + * Find the entity with the matching [QueueMessage.subQueue] and [QueueMessage.assignedTo]. Sorted by ID ascending. * - * @param type the type to match [QueueMessage.type] with + * @param subQueue the type to match [QueueMessage.subQueue] with * @param assignedTo the identifier to match [QueueMessage.assignedTo] with - * @return a [List] of [QueueMessage] who have a matching [QueueMessage.type] and [QueueMessage.assignedTo] + * @return a [List] of [QueueMessage] who have a matching [QueueMessage.subQueue] and [QueueMessage.assignedTo] */ @Transactional - fun findByTypeAndAssignedToOrderByIdAsc(type: String, assignedTo: String): List + fun findBySubQueueAndAssignedToOrderByIdAsc(subQueue: String, assignedTo: String): List /** * Find the entity which has a [QueueMessage.uuid] matching the provided [uuid]. diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt index 1f640a7..c05a3fc 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/AuthController.kt @@ -13,7 +13,6 @@ import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses import io.swagger.v3.oas.annotations.tags.Tag -import lombok.Generated import org.slf4j.Logger import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.HttpStatus @@ -60,7 +59,7 @@ open class AuthController : HasLogger { if (multiQueueAuthenticator.isInNoneMode()) { - LOG.trace("Returning no restricted identifiers since the authentication type is set to [{}].", multiQueueAuthenticator.getAuthenticationType()) + LOG.trace("Returning no restricted identifiers since the restriction mode is set to [{}].", multiQueueAuthenticator.getRestrictionMode()) return ResponseEntity.noContent().build() } @@ -68,7 +67,7 @@ open class AuthController : HasLogger } @Operation(summary = "Create restriction on sub-queue.", description = "Create restriction a specific sub-queue to require authentication for future interactions and retrieve a token used to interact with this sub-queue.") - @PostMapping("/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) + @PostMapping("/{${RestParameters.SUB_QUEUE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( ApiResponse(responseCode = "201", description = "Successfully registered the sub-queue identifier and returns an appropriate token for future access to the sub-queue."), ApiResponse(responseCode = "204", description = "The MultiQueue is in a no-auth mode and tokens cannot be generated.", content = [Content()]), // Add empty Content() to remove duplicate responses in swagger docsApiResponse(responseCode = "204", description = "No queue messages match the provided UUID.", content = [Content()]) @@ -76,46 +75,46 @@ open class AuthController : HasLogger ApiResponse(responseCode = "500", description = "There was an error generating the auth token for the sub-queue.", content = [Content()]) ) fun restrictSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "The sub-queue that you wish to restrict to allow further access only by callers that posses the returned token.") - @PathVariable(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, - /*@Parameter(`in` = ParameterIn.QUERY, required = false, description = "The generated token's expiry in minutes.") - @RequestParam(required = false, name = RestParameters.EXPIRY) expiry: Long?*/): ResponseEntity + @PathVariable(required = true, name = RestParameters.SUB_QUEUE) subQueue: String, + /*@Parameter(`in` = ParameterIn.QUERY, required = false, description = "The generated token's expiry in minutes.") + @RequestParam(required = false, name = RestParameters.EXPIRY) expiry: Long?*/): ResponseEntity { if (multiQueueAuthenticator.isInNoneMode()) { - LOG.trace("Requested token for sub-queue [{}] is not provided as queue is in mode [{}].", queueType, - multiQueueAuthenticator.getAuthenticationType()) + LOG.trace("Requested token for sub-queue [{}] is not provided as queue is in mode [{}].", subQueue, + multiQueueAuthenticator.getRestrictionMode()) return ResponseEntity.noContent().build() } - if (multiQueueAuthenticator.isRestricted(queueType)) + if (multiQueueAuthenticator.isRestricted(subQueue)) { return ResponseEntity.status(HttpStatus.CONFLICT).build() } else { // Generating the token first, so we don't need to roll back restriction add later if there is a problem - val token = jwtTokenProvider.createTokenForSubQueue(queueType, null) + val token = jwtTokenProvider.createTokenForSubQueue(subQueue, null) if (token.isEmpty) { - LOG.error("Failed to generated token for sub-queue [{}].", queueType) + LOG.error("Failed to generated token for sub-queue [{}].", subQueue) return ResponseEntity.internalServerError().build() } - return if (!multiQueueAuthenticator.addRestrictedEntry(queueType)) + return if (!multiQueueAuthenticator.addRestrictedEntry(subQueue)) { - LOG.error("Failed to add restriction for sub-queue [{}].", queueType) + LOG.error("Failed to add restriction for sub-queue [{}].", subQueue) ResponseEntity.internalServerError().build() } else { - LOG.info("Successfully generated token for sub-queue [{}].", queueType) - ResponseEntity.status(HttpStatus.CREATED).body(AuthResponse(token.get(), queueType)) + LOG.info("Successfully generated token for sub-queue [{}].", subQueue) + ResponseEntity.status(HttpStatus.CREATED).body(AuthResponse(token.get(), subQueue)) } } } @Operation(summary = "Remove restriction from sub-queue.", description = "Remove restriction from sub-queue so it can be accessed without restriction.") - @DeleteMapping("/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) + @DeleteMapping("/{${RestParameters.SUB_QUEUE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( ApiResponse(responseCode = "200", description = "Successfully removed restriction for the sub-queue identifier."), ApiResponse(responseCode = "202", description = "The MultiQueue is in a no-auth mode and sub-queue restrictions are disabled.", content = [Content()]), // Add empty Content() to remove duplicate responses in swagger docsApiResponse(responseCode = "204", description = "No queue messages match the provided UUID.", content = [Content()]) @@ -123,49 +122,51 @@ open class AuthController : HasLogger ApiResponse(responseCode = "403", description = "Invalid token provided to remove restriction from requested sub-queue.", content = [Content()]), ApiResponse(responseCode = "500", description = "There was an error releasing restriction from the sub-queue.", content = [Content()]) ) - fun removeRestrictionFromSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "The sub-queue identifier to remove restriction for.") @PathVariable(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, - @Parameter(`in` = ParameterIn.QUERY, required = false, description = "If restriction is removed successfully indicate whether the sub-queue should be cleared now that it is accessible without a token.") @RequestParam(required = false, name = RestParameters.CLEAR_QUEUE) clearQueue: Boolean?): ResponseEntity + fun removeRestrictionFromSubQueue(@Parameter(`in` = ParameterIn.PATH, required = true, description = "The sub-queue identifier to remove restriction for.") + @PathVariable(required = true, name = RestParameters.SUB_QUEUE) subQueue: String, + @Parameter(`in` = ParameterIn.QUERY, required = false, description = "If restriction is removed successfully indicate whether the sub-queue should be cleared now that it is accessible without a token.") + @RequestParam(required = false, name = RestParameters.CLEAR_QUEUE) clearQueue: Boolean?): ResponseEntity { if (multiQueueAuthenticator.isInNoneMode()) { - LOG.trace("Requested to release authentication for sub-queue [{}] but queue is in mode [{}].", queueType, - multiQueueAuthenticator.getAuthenticationType()) + LOG.trace("Requested to release authentication for sub-queue [{}] but queue is in mode [{}].", subQueue, + multiQueueAuthenticator.getRestrictionMode()) return ResponseEntity.accepted().build() } val authedToken = JwtAuthenticationFilter.getSubQueue() - if (authedToken == queueType) + if (authedToken == subQueue) { - if (multiQueueAuthenticator.isRestricted(queueType)) + if (multiQueueAuthenticator.isRestricted(subQueue)) { - return if (multiQueueAuthenticator.removeRestriction(queueType)) + return if (multiQueueAuthenticator.removeRestriction(subQueue)) { if (clearQueue == true) { - LOG.info("Restriction removed and clearing sub-queue [{}].", queueType) - multiQueue.clearForType(queueType) + LOG.info("Restriction removed and clearing sub-queue [{}].", subQueue) + multiQueue.clearSubQueue(subQueue) } else { - LOG.info("Removed restriction from sub-queue [{}] without clearing stored messages.", queueType) + LOG.info("Removed restriction from sub-queue [{}] without clearing stored messages.", subQueue) } ResponseEntity.ok().build() } else { - LOG.error("Failed to remove restriction for sub-queue [{}].", queueType) + LOG.error("Failed to remove restriction for sub-queue [{}].", subQueue) ResponseEntity.internalServerError().build() } } else { - LOG.info("Cannot remove restriction from a sub-queue [{}] that is not restricted.", queueType) + LOG.info("Cannot remove restriction from a sub-queue [{}] that is not restricted.", subQueue) return ResponseEntity.noContent().build() } } else { - LOG.error("Failed to release authentication for sub-queue [{}] since provided token [{}] is not for the requested sub-queue.", queueType, authedToken) + LOG.error("Failed to release authentication for sub-queue [{}] since provided token [{}] is not for the requested sub-queue.", subQueue, authedToken) return ResponseEntity.status(HttpStatus.FORBIDDEN).build() } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt index 6261d37..b276398 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueController.kt @@ -64,7 +64,7 @@ open class MessageQueueController : HasLogger const val ENDPOINT_ENTRY: String = "/entry" /** - * The resource path used to view messages that are within the same `sub queue`. + * The resource path used to view messages that are within the same `sub-queue`. */ const val ENDPOINT_TYPE: String = "/type" @@ -117,7 +117,7 @@ open class MessageQueueController : HasLogger @Operation(summary = "Retrieve queue information for the whole multi queue.", description = "Retrieve information about the whole queue, specifically information on the queue entries.") @GetMapping(ENDPOINT_TYPE, produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponse(responseCode = "200", description = "Successfully returns the information payload.") - fun getAllQueueTypeInfo(): ResponseEntity + fun getAllQueueInfo(): ResponseEntity { val size = messageQueue.size LOG.debug("Returning total multi-queue size [{}].", size) @@ -125,20 +125,20 @@ open class MessageQueueController : HasLogger } /** - * Retrieve information about a specific queue within [MultiQueue], based on the provided `queueType`. Specifically data related information. + * Retrieve information about a specific queue within [MultiQueue], based on the provided `sub-queue`. Specifically data related information. */ @Hidden - @Operation(summary = "Retrieve queue information for a specific sub queue.", description = "Retrieve information about the specified queueType within the queue, specifically information on the queue entries.") - @GetMapping("$ENDPOINT_TYPE/{${RestParameters.QUEUE_TYPE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) + @Operation(summary = "Retrieve queue information for a specific sub-queue.", description = "Retrieve information about the specified sub-queue, specifically information on the queue entries.") + @GetMapping("$ENDPOINT_TYPE/{${RestParameters.SUB_QUEUE}}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponse(responseCode = "200", description = "Successfully returns the information payload.") - fun getQueueTypeInfo(@Parameter(`in` = ParameterIn.PATH, required = true, description = "The queueType to retrieve information about.") - @PathVariable(name = RestParameters.QUEUE_TYPE) queueType: String): ResponseEntity + fun getSubQueueInfo(@Parameter(`in` = ParameterIn.PATH, required = true, description = "The sub-queue to retrieve information about.") + @PathVariable(name = RestParameters.SUB_QUEUE) subQueue: String): ResponseEntity { - authenticator.canAccessSubQueue(queueType) + authenticator.canAccessSubQueue(subQueue) - val queueForType = messageQueue.getQueueForType(queueType) - LOG.debug("Returning size [{}] for queue with type [{}].", queueForType.size, queueType) - return ResponseEntity.ok(queueForType.size.toString()) + val queue = messageQueue.getSubQueue(subQueue) + LOG.debug("Returning size [{}] for sub-queue [{}].", queue.size, subQueue) + return ResponseEntity.ok(queue.size.toString()) } /** @@ -174,7 +174,7 @@ open class MessageQueueController : HasLogger * @param uuid the [UUID] of the message to retrieve * @return [MessageResponse] containing the found [QueueMessage] otherwise a [HttpStatus.NO_CONTENT] exception will be thrown */ - @Operation(summary = "Retrieve a queue message by UUID.", description = "Retrieve a queue message regardless of its sub queue, directly by UUID.") + @Operation(summary = "Retrieve a queue message by UUID.", description = "Retrieve a queue message regardless of its sub-queue, directly by UUID.") @GetMapping("$ENDPOINT_ENTRY/{${RestParameters.UUID}}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( ApiResponse(responseCode = "200", description = "Successfully returns the queue message matching the provided UUID."), @@ -186,8 +186,8 @@ open class MessageQueueController : HasLogger if (entry.isPresent) { val foundEntry = entry.get() - authenticator.canAccessSubQueue(foundEntry.type) - LOG.debug("Found message with UUID [{}] in queue with type [{}].", foundEntry.uuid, foundEntry.type) + authenticator.canAccessSubQueue(foundEntry.subQueue) + LOG.debug("Found message with UUID [{}] in sub-queue [{}].", foundEntry.uuid, foundEntry.subQueue) return ResponseEntity.ok(MessageResponse(foundEntry)) } @@ -216,7 +216,7 @@ open class MessageQueueController : HasLogger { try { - authenticator.canAccessSubQueue(queueMessage.type) + authenticator.canAccessSubQueue(queueMessage.subQueue) if (queueMessage.assignedTo != null && queueMessage.assignedTo!!.isBlank()) { @@ -226,31 +226,31 @@ open class MessageQueueController : HasLogger val wasAdded = messageQueue.add(queueMessage) if (wasAdded) { - LOG.debug("Added new message with UUID [{}] to queue with type [{}}.", queueMessage.uuid, queueMessage.type) + LOG.debug("Added new message with UUID [{}] to sub-queue [{}}.", queueMessage.uuid, queueMessage.subQueue) return ResponseEntity.status(HttpStatus.CREATED).body(MessageResponse(queueMessage)) } else { - LOG.error("Failed to add entry with UUID [{}] to queue with type [{}]. AND the message does not already exist. This could be a memory limitation or an issue with the underlying collection.", queueMessage.uuid, queueMessage.type) - throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to add entry with UUID: [${queueMessage.uuid}] to queue with type [${queueMessage.type}]") + LOG.error("Failed to add entry with UUID [{}] to sub-queue [{}]. AND the message does not already exist. This could be a memory limitation or an issue with the underlying collection.", queueMessage.uuid, queueMessage.subQueue) + throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to add entry with UUID: [${queueMessage.uuid}] to sub-queue [${queueMessage.subQueue}]") } } catch (ex: DuplicateMessageException) { - val queueType = messageQueue.containsUUID(queueMessage.uuid).get() - val errorMessage = "Failed to add entry with UUID [${queueMessage.uuid}], an entry with the same UUID already exists in queue with type [$queueType]." + val subQueue = messageQueue.containsUUID(queueMessage.uuid).get() + val errorMessage = "Failed to add entry with UUID [${queueMessage.uuid}], an entry with the same UUID already exists in sub-queue [$subQueue]." LOG.error(errorMessage) throw ResponseStatusException(HttpStatus.CONFLICT, errorMessage, ex) } } /** - * A [GetMapping] which returns a list of all the `QueueTypes` defined in the [MultiQueue]. + * A [GetMapping] which returns a list of all the `sub-queue` IDs defined in the [MultiQueue]. * * @param includeEmpty to include `keys` which one had elements stored against them but don't at the moment. Default is `true`. - * @return a [Set] of [String] `queueType`s + * @return a [Set] of [String] `sub-queue`s */ - @Operation(summary = "Retrieve a list of all keys.", description = "Retrieve a list of all sub queue key values in the multi queue.") + @Operation(summary = "Retrieve a list of all keys.", description = "Retrieve a list of all sub-queue key values in the multi queue.") @GetMapping(ENDPOINT_KEYS, produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponse(responseCode = "200", description = "Successfully returns the list of keys.") fun getKeys(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "Indicates whether to include keys that currently have zero entries (but have had entries previously). Is true by default.") @@ -264,20 +264,20 @@ open class MessageQueueController : HasLogger return ResponseEntity.ok(keys) } - @Operation(summary = "Delete a keys or all keys, in turn clearing that sub queue.", description = "Delete the sub queue that matches the provided key. If no key is provided, all sub queues will be cleared.") + @Operation(summary = "Delete a keys or all keys, in turn clearing that sub-queue.", description = "Delete the sub-queue that matches the provided key. If no key is provided, all sub-queues will be cleared.") @DeleteMapping(ENDPOINT_KEYS, produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( - ApiResponse(responseCode = "204", description = "Successfully cleared the sub queue(s) with the provided key, or all sub queues if the key is null."), + ApiResponse(responseCode = "204", description = "Successfully cleared the sub-queue(s) with the provided key, or all sub-queues if the key is null."), ApiResponse(responseCode = "206", description = "Successfully cleared the sub-queues that are unrestricted. Restricted sub-queues needs to be created with a valid token.") ) - fun deleteKeys(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "The queue type to clear the sub queue of. If it is not provided, all sub queues will be cleared.") - @RequestParam(required = false, name = RestParameters.QUEUE_TYPE) queueType: String?): ResponseEntity + fun deleteKeys(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "The sub-queue to clear. If it is not provided, all sub-queues will be cleared.") + @RequestParam(required = false, name = RestParameters.SUB_QUEUE) subQueue: String?): ResponseEntity { - if (queueType != null) + if (subQueue != null) { - authenticator.canAccessSubQueue(queueType) - messageQueue.clearForType(queueType) - LOG.info("Cleared queue with key [{}]", queueType) + authenticator.canAccessSubQueue(subQueue) + messageQueue.clearSubQueue(subQueue) + LOG.info("Cleared queue with key [{}]", subQueue) return ResponseEntity.noContent().build() } else @@ -290,7 +290,7 @@ open class MessageQueueController : HasLogger { if (authenticator.canAccessSubQueue(key, false)) { - messageQueue.clearForType(key) + messageQueue.clearSubQueue(key) clearedKeys.add(key) } else @@ -318,34 +318,36 @@ open class MessageQueueController : HasLogger * A [GetMapping] endpoint which retrieves all the stored [QueueMessage]s that are currently available in the [MultiQueue]. * * @param detailed *true* if you require detailed information about each message and their payload/owner, otherwise **false** which displayed only limited information about each message - * @param queueType the `type` to include, if provided only messages in this `queueType` will be retrieved. - * @return a [Map] where the `key` is the `queueType` and the `value` is a comma separated list of all the [QueueMessage.removePayload] + * @param subQueue the `sub-queue` to include, if provided only messages in this `sub-queue` will be retrieved. + * @return a [Map] where the `key` is the `sub-queue` and the `value` is a comma separated list of all the [QueueMessage.removePayload] */ - @Operation(summary = "Retrieve a limited or full version of the held messages.", description = "Retrieve queue message summaries for the held messages. This can be limited to a specific sub queue type and complete message detail to be included in the response if requested.") + @Operation(summary = "Retrieve a limited or full version of the held messages.", description = "Retrieve queue message summaries for the held messages. This can be limited to a specific sub-queue and complete message detail to be included in the response if requested.") @GetMapping(ENDPOINT_ALL, produces = [MediaType.APPLICATION_JSON_VALUE]) - @ApiResponse(responseCode = "200", description = "Successfully returns the list of summary entries for either the whole multi-queue or the sub queue.") - fun getAll(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "Indicates whether the response messages should contain all message details including the underlying payload. By default details are hidden.") @RequestParam(required = false, name = RestParameters.DETAILED) detailed: Boolean = false, - @Parameter(`in` = ParameterIn.QUERY, required = false, description = "The sub queue type to search, if not provide all messages in the whole multi-queue will be returned.") @RequestParam(required = false, name = RestParameters.QUEUE_TYPE) queueType: String?): ResponseEntity>> + @ApiResponse(responseCode = "200", description = "Successfully returns the list of summary entries for either the whole multi-queue or the sub-queue.") + fun getAll(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "Indicates whether the response messages should contain all message details including the underlying payload. By default details are hidden.") + @RequestParam(required = false, name = RestParameters.DETAILED) detailed: Boolean = false, + @Parameter(`in` = ParameterIn.QUERY, required = false, description = "The sub-queue to search, if not provide all messages in the whole multi-queue will be returned.") + @RequestParam(required = false, name = RestParameters.SUB_QUEUE) subQueue: String?): ResponseEntity>> { val responseMap = HashMap>() - if ( !queueType.isNullOrBlank()) + if ( !subQueue.isNullOrBlank()) { - LOG.debug("Retrieving all entry details from queue with type [{}].", queueType) - authenticator.canAccessSubQueue(queueType) - val queueForType: Queue = messageQueue.getQueueForType(queueType) - val queueDetails = queueForType.stream().map { message -> message.removePayload(detailed) }.collect(Collectors.toList()) - responseMap[queueType] = queueDetails + LOG.debug("Retrieving all entry details from sub-queue [{}].", subQueue) + authenticator.canAccessSubQueue(subQueue) + val queue: Queue = messageQueue.getSubQueue(subQueue) + val queueDetails = queue.stream().map { message -> message.removePayload(detailed) }.collect(Collectors.toList()) + responseMap[subQueue] = queueDetails } else { - LOG.debug("Retrieving all entry details from all queue types.") + LOG.debug("Retrieving all entry details from all sub-queues.") for (key: String in messageQueue.keys(false)) { if (authenticator.canAccessSubQueue(key, false)) { // No need to empty check since we passed `false` to `keys()` above - val queueForType: Queue = messageQueue.getQueueForType(key) - val queueDetails = queueForType.stream().map { message -> message.removePayload(detailed) }.collect(Collectors.toList()) + val queue: Queue = messageQueue.getSubQueue(key) + val queueDetails = queue.stream().map { message -> message.removePayload(detailed) }.collect(Collectors.toList()) responseMap[key] = queueDetails } } @@ -357,20 +359,22 @@ open class MessageQueueController : HasLogger * Retrieve all owned [QueueMessage] based on the provided user identifier. * * @param assignedTo the identifier used to indicate the owner of the [QueueMessage]s to return - * @param queueType the `queueType` to search for the related [QueueMessage] owned by [assignedTo] - * @return a [List] of [QueueMessage] based on messages that are `assigned` to the [assignedTo] in the `queue` mapped to [queueType] + * @param subQueue the `sub-queue` to search for the related [QueueMessage] owned by [assignedTo] + * @return a [List] of [QueueMessage] based on messages that are `assigned` to the [assignedTo] in the `queue` mapped to [subQueue] */ - @Operation(summary = "Retrieve all owned queue messages based on the provided user identifier.", description = "Retrieve all owned messages for the provided assignee identifier for the provided sub queue type.") + @Operation(summary = "Retrieve all owned queue messages based on the provided user identifier.", description = "Retrieve all owned messages for the provided assignee identifier for the provided sub-queue.") @GetMapping(ENDPOINT_OWNED, produces = [MediaType.APPLICATION_JSON_VALUE]) - @ApiResponse(responseCode = "200", description = "Successfully returns the list of owned queue messages in the sub queue for the provided assignee identifier.") - fun getOwned(@Parameter(`in` = ParameterIn.QUERY, required = true, description = "The identifier that must match the message's `assigned` property in order to be returned.") @RequestParam(required = true, name = RestParameters.ASSIGNED_TO) assignedTo: String, - @Parameter(`in` = ParameterIn.QUERY, required = true, description = "The sub queue to search for the assigned messages.") @RequestParam(required = true, name = RestParameters.QUEUE_TYPE) queueType: String): ResponseEntity> + @ApiResponse(responseCode = "200", description = "Successfully returns the list of owned queue messages in the sub-queue for the provided assignee identifier.") + fun getOwned(@Parameter(`in` = ParameterIn.QUERY, required = true, description = "The identifier that must match the message's `assigned` property in order to be returned.") + @RequestParam(required = true, name = RestParameters.ASSIGNED_TO) assignedTo: String, + @Parameter(`in` = ParameterIn.QUERY, required = true, description = "The sub-queue to search for the assigned messages.") + @RequestParam(required = true, name = RestParameters.SUB_QUEUE) subQueue: String): ResponseEntity> { - authenticator.canAccessSubQueue(queueType) + authenticator.canAccessSubQueue(subQueue) - val assignedMessages: Queue = messageQueue.getAssignedMessagesForType(queueType, assignedTo) + val assignedMessages: Queue = messageQueue.getAssignedMessagesInSubQueue(subQueue, assignedTo) val ownedMessages = assignedMessages.stream().map { message -> MessageResponse(message) }.collect(Collectors.toList()) - LOG.debug("Found [{}] owned entries within queue with type [{}] for user with identifier [{}].", ownedMessages.size, queueType, assignedTo) + LOG.debug("Found [{}] owned entries within sub-queue [{}] for user with identifier [{}].", ownedMessages.size, subQueue, assignedTo) return ResponseEntity.ok(ownedMessages) } @@ -400,19 +404,19 @@ open class MessageQueueController : HasLogger if (message.isPresent) { val messageToAssign = message.get() - authenticator.canAccessSubQueue(messageToAssign.type) + authenticator.canAccessSubQueue(messageToAssign.subQueue) if (!messageToAssign.assignedTo.isNullOrBlank()) { if (messageToAssign.assignedTo == assignedTo) { // The message is already in this state, returning 202 to tell the client that it is accepted but no action was done - LOG.debug("Message with uuid [{}] in queue with type [{}] is already assigned to the identifier [{}].", messageToAssign.uuid, messageToAssign.type, assignedTo) + LOG.debug("Message with uuid [{}] in sub-queue [{}] is already assigned to the identifier [{}].", messageToAssign.uuid, messageToAssign.subQueue, assignedTo) return ResponseEntity.accepted().body(MessageResponse(messageToAssign)) } else { - LOG.error("Message with uuid [{}] in queue with type [{}] is already assigned to the identifier [{}]. Attempting to assign to identifier [{}].", messageToAssign.uuid, messageToAssign.type, messageToAssign.assignedTo, assignedTo) - throw ResponseStatusException(HttpStatus.CONFLICT, "The message with UUID: [$uuid] and [${messageToAssign.type}] is already assigned to the identifier [${messageToAssign.assignedTo}].") + LOG.error("Message with uuid [{}] in sub-queue [{}] is already assigned to the identifier [{}]. Attempting to assign to identifier [{}].", messageToAssign.uuid, messageToAssign.subQueue, messageToAssign.assignedTo, assignedTo) + throw ResponseStatusException(HttpStatus.CONFLICT, "The message with UUID: [$uuid] and [${messageToAssign.subQueue}] is already assigned to the identifier [${messageToAssign.assignedTo}].") } } @@ -428,35 +432,37 @@ open class MessageQueueController : HasLogger } /** - * Retrieve the next `non-assigned` message in the [MultiQueue] for the provided [queueType] and assign it to the provided identifier [assignedTo]. + * Retrieve the next `non-assigned` message in the [MultiQueue] for the provided [subQueue] and assign it to the provided identifier [assignedTo]. * - * @param queueType the sub queue that the next [QueueMessage] should be from + * @param subQueue the sub-queue that the next [QueueMessage] should be from * @param assignedTo the identifier that the next [QueueMessage] should be `assigned` to before being returned - * @return the next [QueueMessage] that is not `assigned` in the provided [queueType]. If none exist then [HttpStatus.NO_CONTENT] will be returned indicating that the queue is either empty or has no available [QueueMessage]s to assign. + * @return the next [QueueMessage] that is not `assigned` in the provided [subQueue]. If none exist then [HttpStatus.NO_CONTENT] will be returned indicating that the queue is either empty or has no available [QueueMessage]s to assign. */ - @Operation(summary = "Retrieve the next available unassigned message in the queue.", description = "Retrieve the next available message in the queue for the provided sub queue identifier that is not assigned. The message will be assigned to the provided identifier then returned.") + @Operation(summary = "Retrieve the next available unassigned message in the queue.", description = "Retrieve the next available message in the queue for the provided sub-queue identifier that is not assigned. The message will be assigned to the provided identifier then returned.") @PutMapping(ENDPOINT_NEXT, produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponses( ApiResponse(responseCode = "200", description = "Successfully returns the next message in queue after assigning it to the provided `assignedTo` identifier."), ApiResponse(responseCode = "204", description = "No messages are available.", content = [Content()]) ) - fun getNext(@Parameter(`in` = ParameterIn.QUERY, required = true, description = "The sub queue identifier to query the next available message from.") @RequestParam(required = true, name = RestParameters.QUEUE_TYPE) queueType: String, - @Parameter(`in` = ParameterIn.QUERY, required = true, description = "The identifier to assign the next available message to if one exists.") @RequestParam(required = true, name = RestParameters.ASSIGNED_TO) assignedTo: String): ResponseEntity + fun getNext(@Parameter(`in` = ParameterIn.QUERY, required = true, description = "The sub-queue identifier to query the next available message from.") + @RequestParam(required = true, name = RestParameters.SUB_QUEUE) subQueue: String, + @Parameter(`in` = ParameterIn.QUERY, required = true, description = "The identifier to assign the next available message to if one exists.") + @RequestParam(required = true, name = RestParameters.ASSIGNED_TO) assignedTo: String): ResponseEntity { - authenticator.canAccessSubQueue(queueType) + authenticator.canAccessSubQueue(subQueue) - val queueForType: Queue = messageQueue.getUnassignedMessagesForType(queueType) - return if (queueForType.iterator().hasNext()) + val queue: Queue = messageQueue.getUnassignedMessagesInSubQueue(subQueue) + return if (queue.iterator().hasNext()) { - val nextUnassignedMessage = queueForType.iterator().next() - LOG.debug("Retrieving and assigning next message for queue type [{}] with UUID [{}] to identifier [{}].", queueType, nextUnassignedMessage.uuid, assignedTo) + val nextUnassignedMessage = queue.iterator().next() + LOG.debug("Retrieving and assigning next message for sub-queue [{}] with UUID [{}] to identifier [{}].", subQueue, nextUnassignedMessage.uuid, assignedTo) nextUnassignedMessage.assignedTo = assignedTo messageQueue.persistMessage(nextUnassignedMessage) ResponseEntity.ok(MessageResponse(nextUnassignedMessage)) } else { - LOG.debug("No unassigned entries in queue with type [{}].", queueType) + LOG.debug("No unassigned entries in sub-queue [{}].", subQueue) ResponseEntity.noContent().build() } } @@ -487,7 +493,7 @@ open class MessageQueueController : HasLogger if (message.isPresent) { val messageToRelease = message.get() - authenticator.canAccessSubQueue(messageToRelease.type) + authenticator.canAccessSubQueue(messageToRelease.subQueue) if (messageToRelease.assignedTo == null) { @@ -498,7 +504,7 @@ open class MessageQueueController : HasLogger if (!assignedTo.isNullOrBlank() && messageToRelease.assignedTo != assignedTo) { - val errorMessage = "The message with UUID: [$uuid] and [${messageToRelease.type}] cannot be released because it is already assigned to identifier [${messageToRelease.assignedTo}] and the provided identifier was [$assignedTo]." + val errorMessage = "The message with UUID: [$uuid] and [${messageToRelease.subQueue}] cannot be released because it is already assigned to identifier [${messageToRelease.assignedTo}] and the provided identifier was [$assignedTo]." LOG.error(errorMessage) throw ResponseStatusException(HttpStatus.CONFLICT, errorMessage) } @@ -508,7 +514,7 @@ open class MessageQueueController : HasLogger return ResponseEntity.ok(MessageResponse(messageToRelease)) } - // No entries match the provided UUID (and queue type) + // No entries match the provided UUID (and sub-queue) LOG.debug("Could not find message to release with UUID [{}].", uuid) return ResponseEntity.noContent().build() } @@ -539,10 +545,10 @@ open class MessageQueueController : HasLogger if (message.isPresent) { val messageToRemove = message.get() - authenticator.canAccessSubQueue(messageToRemove.type) + authenticator.canAccessSubQueue(messageToRemove.subQueue) if ( !assignedTo.isNullOrBlank() && messageToRemove.assignedTo != assignedTo) { - val errorMessage = "Unable to remove message with UUID [$uuid] in Queue [${messageToRemove.type}] because the provided assignee identifier: [$assignedTo] does not match the message's assignee identifier: [${messageToRemove.assignedTo}]" + val errorMessage = "Unable to remove message with UUID [$uuid] in Queue [${messageToRemove.subQueue}] because the provided assignee identifier: [$assignedTo] does not match the message's assignee identifier: [${messageToRemove.assignedTo}]" LOG.error(errorMessage) throw ResponseStatusException(HttpStatus.FORBIDDEN, errorMessage) } @@ -564,14 +570,15 @@ open class MessageQueueController : HasLogger * "identifier2": ["queue-A", "queue-B", "queue-Z"] * } * ``` - * @param queueType the sub-queue identifier that you are interested in. If not provided, all sub-queues will be iterated through. + * @param subQueue the sub-queue identifier that you are interested in. If not provided, all sub-queues will be iterated through. * @return a [Map] of assignee identifiers mapped to a [Set] of the sub-queue identifiers that they have any assigned messages in. */ @Operation(summary = "Retrieve all unique owner identifiers for either a specified sub-queue or all sub-queues.", description = "Retrieve all owner identifier mapped to a list of the sub-queue identifiers that they are assigned any messages in.") @GetMapping(ENDPOINT_OWNERS, produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiResponse(responseCode = "200", description = "Successfully returns the map of owner identifiers mapped to all the sub-queues that they have one or more assigned messages in.") - fun getOwners(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "The sub queue to search for the owner identifiers.") @RequestParam(required = false, name = RestParameters.QUEUE_TYPE) queueType: String?): ResponseEntity>> + fun getOwners(@Parameter(`in` = ParameterIn.QUERY, required = false, description = "The sub-queue to search for the owner identifiers.") + @RequestParam(required = false, name = RestParameters.SUB_QUEUE) subQueue: String?): ResponseEntity>> { - return ResponseEntity.ok(messageQueue.getOwnersAndKeysMap(queueType)) + return ResponseEntity.ok(messageQueue.getOwnersAndKeysMap(subQueue)) } } diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt index 033209e..6d1e5cb 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/controller/RestParameters.kt @@ -12,7 +12,7 @@ object RestParameters { const val ASSIGNED_TO = "assignedTo" - const val QUEUE_TYPE = "queueType" + const val SUB_QUEUE = "subQueue" const val DETAILED = "detailed" diff --git a/src/main/kotlin/au/kilemon/messagequeue/rest/response/MessageResponse.kt b/src/main/kotlin/au/kilemon/messagequeue/rest/response/MessageResponse.kt index a89ad9b..6a53b13 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/rest/response/MessageResponse.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/rest/response/MessageResponse.kt @@ -6,9 +6,9 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder import org.slf4j.MDC /** - * A response object which wraps the [QueueMessage], and exposes the `type` [String]. + * A response object which wraps the [QueueMessage], and exposes the `sub-queue` [String]. * * @author github.com/Kilemonn */ -@JsonPropertyOrder("correlationId", "queueType", "message") -data class MessageResponse(val message: QueueMessage, val queueType: String = message.type, val correlationId: String? = MDC.get(CorrelationIdFilter.CORRELATION_ID)) +@JsonPropertyOrder("correlationId", "subQueue", "message") +data class MessageResponse(val message: QueueMessage, val subQueue: String = message.subQueue, val correlationId: String? = MDC.get(CorrelationIdFilter.CORRELATION_ID)) diff --git a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt index 55591ff..f56d154 100644 --- a/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt +++ b/src/main/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettings.kt @@ -10,7 +10,8 @@ import org.springframework.stereotype.Component * An object that holds application level properties and is set initially on application start up. * This will control things such as: * - Credentials to external data storage - * - The type of `MultiQueue` being used + * - The storage medium of `MultiQueue` being used + * - The restriction mode being used * - Other utility configuration for the application to use. * * When `SQL` is used, the following property must be provided: @@ -67,7 +68,7 @@ class MessageQueueSettings const val SQL_SCHEMA_DEFAULT: String = "public" /** - * Start authenticated sub queue properties. + * Start authenticated sub-queue properties. */ /** * Indicates what authentication mode the `MultiQueue` should be in. @@ -93,7 +94,7 @@ class MessageQueueSettings @Value("\${$STORAGE_MEDIUM:$STORAGE_MEDIUM_DEFAULT}") @get:Generated @set:Generated - lateinit var multiQueueType: String + lateinit var storageMedium: String /** * `Optional` uses the [RESTRICTION_MODE] environment variable to determine whether specific sub-queues @@ -105,7 +106,7 @@ class MessageQueueSettings @Value("\${$RESTRICTION_MODE:$RESTRICTION_MODE_DEFAULT}") @get:Generated @set:Generated - lateinit var multiQueueAuthentication: String + lateinit var restrictionMode: String /** diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt index d401b8b..437cdc4 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/MultiQueueAuthenticatorTest.kt @@ -25,12 +25,12 @@ abstract class MultiQueueAuthenticatorTest /** * Ensure [MultiQueueAuthenticator.addRestrictedEntry] always returns and does not add an entry if the - * [MultiQueueAuthenticator.getAuthenticationType] is [RestrictionMode.NONE]. + * [MultiQueueAuthenticator.getRestrictionMode] is [RestrictionMode.NONE]. */ @Test fun testAddRestrictedEntry_WithNoneMode() { - Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testAddRestrictedEntry_WithNoneMode" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) Assertions.assertFalse(multiQueueAuthenticator.addRestrictedEntry(subQueue)) @@ -38,15 +38,15 @@ abstract class MultiQueueAuthenticatorTest } /** - * Ensure [MultiQueueAuthenticator.addRestrictedEntry] will add the request sub queue identifier when the - * [MultiQueueAuthenticator.getAuthenticationType] is NOT [RestrictionMode.NONE]. - * Also tests [MultiQueueAuthenticator.isRestricted] can determine the sub queue is restricted after its been added. + * Ensure [MultiQueueAuthenticator.addRestrictedEntry] will add the request sub-queue identifier when the + * [MultiQueueAuthenticator.getRestrictionMode] is NOT [RestrictionMode.NONE]. + * Also tests [MultiQueueAuthenticator.isRestricted] can determine the sub-queue is restricted after its been added. */ @Test fun testAddRestrictedEntry_WithARestrictedNoneMode() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testAddRestrictedEntry_WithARestrictedNoneMode" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) @@ -56,33 +56,33 @@ abstract class MultiQueueAuthenticatorTest /** * Ensure that [MultiQueueAuthenticator.removeRestriction] will not be able to remove a restriction if the - * [MultiQueueAuthenticator.getAuthenticationType] is set to [RestrictionMode.NONE]. + * [MultiQueueAuthenticator.getRestrictionMode] is set to [RestrictionMode.NONE]. */ @Test fun testRemoveRestriction_WithNoneMode() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testRemoveRestriction_WithNoneMode" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) - Mockito.doReturn(RestrictionMode.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.NONE).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getRestrictionMode()) Assertions.assertFalse(multiQueueAuthenticator.removeRestriction(subQueue)) } /** - * Ensure that [MultiQueueAuthenticator.addRestrictedEntry] returns `false` when an existing sub queue identifier + * Ensure that [MultiQueueAuthenticator.addRestrictedEntry] returns `false` when an existing sub-queue identifier * is attempting to be added. */ @Test fun testRemoveRestriction_AddExistingSubQueueIdentifier() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testRemoveRestriction_AddExistingSubQueueIdentifier" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) @@ -95,13 +95,13 @@ abstract class MultiQueueAuthenticatorTest /** * Ensure that [MultiQueueAuthenticator.removeRestriction] will not be able to remove a restriction if the - * [MultiQueueAuthenticator.getAuthenticationType] is set to [RestrictionMode.NONE]. + * [MultiQueueAuthenticator.getRestrictionMode] is set to [RestrictionMode.NONE]. */ @Test fun testRemoveRestriction_WithARestrictedNoneMode() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testRemoveRestriction_WithARestrictedNoneMode" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) @@ -113,14 +113,14 @@ abstract class MultiQueueAuthenticatorTest } /** - * Ensure that [MultiQueueAuthenticator.removeRestriction] returns `false` when you attempt to remove a sub queue + * Ensure that [MultiQueueAuthenticator.removeRestriction] returns `false` when you attempt to remove a sub-queue * identifier that does not exist. */ @Test fun testRemoveRestriction_DoesNotExist() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testRemoveRestriction_DoesNotExist" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) Assertions.assertFalse(multiQueueAuthenticator.removeRestriction(subQueue)) @@ -133,7 +133,7 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithNoneMode() { - Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testCanAccessSubQueue_WithNoneMode" Assertions.assertTrue(multiQueueAuthenticator.canAccessSubQueue(subQueue)) } @@ -145,8 +145,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithHybridMode_isNotRestricted() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testCanAccessSubQueue_WithHybridMode_isNotRestricted" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) @@ -162,8 +162,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithHybridMode_isRestricted_matchesStoredSubQueue() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testCanAccessSubQueue_WithHybridMode_isRestricted_matchesStoredSubQueue" Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) @@ -188,8 +188,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithHybridMode_isRestricted_doesNotMatchStoredSubQueue() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testCanAccessSubQueue_WithHybridMode_isRestricted_doesNotMatchStoredSubQueue" Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) @@ -216,8 +216,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithRestrictedMode_isNotRestricted() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testCanAccessSubQueue_WithRestrictedMode_isNotRestricted" Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) @@ -235,8 +235,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithRestrictedMode_isRestricted_matchesStoredSubQueue() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testCanAccessSubQueue_WithRestrictedMode_isRestricted_matchesStoredSubQueue" Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) @@ -262,8 +262,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testCanAccessSubQueue_WithRestrictedMode_isRestricted_doesNotMatchStoredSubQueue() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) val subQueue = "testCanAccessSubQueue_WithRestrictedMode_isRestricted_doesNotMatchStoredSubQueue" Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) @@ -289,8 +289,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testClearRestrictedSubQueues() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) val subQueues = listOf("testClearRestrictedSubQueues1", "testClearRestrictedSubQueues2", "testClearRestrictedSubQueues3", "testClearRestrictedSubQueues4", "testClearRestrictedSubQueues5", "testClearRestrictedSubQueues6") @@ -310,8 +310,8 @@ abstract class MultiQueueAuthenticatorTest @Test fun testGetRestrictedSubQueueIdentifiers() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) val subQueues = listOf("testGetRestrictedSubQueueIdentifiers1", "testGetRestrictedSubQueueIdentifiers2", "testGetRestrictedSubQueueIdentifiers3", "testGetRestrictedSubQueueIdentifiers4", diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt index 3610fe6..218534c 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/authenticator/inmemory/InMemoryAuthenticatorTest.kt @@ -40,13 +40,13 @@ class InMemoryAuthenticatorTest: MultiQueueAuthenticatorTest() fun testIsInNoneMode() { val authenticator = Mockito.spy(MultiQueueAuthenticator::class.java) - Mockito.doReturn(RestrictionMode.NONE).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.NONE).`when`(authenticator).getRestrictionMode() Assertions.assertTrue(authenticator.isInNoneMode()) - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() Assertions.assertFalse(authenticator.isInNoneMode()) - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getRestrictionMode() Assertions.assertFalse(authenticator.isInNoneMode()) } @@ -58,13 +58,13 @@ class InMemoryAuthenticatorTest: MultiQueueAuthenticatorTest() fun testIsInHybridMode() { val authenticator = Mockito.spy(MultiQueueAuthenticator::class.java) - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() Assertions.assertTrue(authenticator.isInHybridMode()) - Mockito.doReturn(RestrictionMode.NONE).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.NONE).`when`(authenticator).getRestrictionMode() Assertions.assertFalse(authenticator.isInHybridMode()) - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getRestrictionMode() Assertions.assertFalse(authenticator.isInHybridMode()) } @@ -76,13 +76,13 @@ class InMemoryAuthenticatorTest: MultiQueueAuthenticatorTest() fun testIsInRestrictedMode() { val authenticator = Mockito.spy(MultiQueueAuthenticator::class.java) - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getRestrictionMode() Assertions.assertTrue(authenticator.isInRestrictedMode()) - Mockito.doReturn(RestrictionMode.NONE).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.NONE).`when`(authenticator).getRestrictionMode() Assertions.assertFalse(authenticator.isInRestrictedMode()) - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() Assertions.assertFalse(authenticator.isInRestrictedMode()) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt b/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt index e418347..2fb693d 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/authentication/exception/MultiQueueAuthorisationExceptionTest.kt @@ -18,7 +18,7 @@ class MultiQueueAuthorisationExceptionTest @Test fun testTypeOfException() { - val e = MultiQueueAuthorisationException("Sub queue", RestrictionMode.NONE) + val e = MultiQueueAuthorisationException("sub-queue", RestrictionMode.NONE) Assertions.assertTrue(Exception::class.isInstance(e)) Assertions.assertFalse(RuntimeException::class.isInstance(e)) } diff --git a/src/test/kotlin/au/kilemon/messagequeue/message/QueueMessageTest.kt b/src/test/kotlin/au/kilemon/messagequeue/message/QueueMessageTest.kt index 58396a9..1b41d37 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/message/QueueMessageTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/message/QueueMessageTest.kt @@ -33,18 +33,18 @@ class QueueMessageTest /** * Ensure that two [QueueMessage]s are not equal if one has `null` [QueueMessage.payload] and [QueueMessage.payloadBytes], but the same - * [QueueMessage.uuid] and [QueueMessage.type]. + * [QueueMessage.uuid] and [QueueMessage.subQueue]. */ @Test fun testEquals_withOneMessageHavingNullPayloadAndBytes() { val uuid = UUID.randomUUID().toString() - val type = "type" + val subQueue = "testEquals_withOneMessageHavingNullPayloadAndBytes" val message1 = QueueMessage() message1.payload = null message1.uuid = uuid - message1.type = type - val message2 = QueueMessage(payload = "stuff", type = type) + message1.subQueue = subQueue + val message2 = QueueMessage(payload = "stuff", subQueue = subQueue) message2.uuid = uuid Assertions.assertNull(message1.payload) @@ -56,17 +56,17 @@ class QueueMessageTest /** * Ensure that two [QueueMessage] are equal if they both have `null` [QueueMessage.payload] but `equal` [QueueMessage.payloadBytes], and the same - * [QueueMessage.uuid] and [QueueMessage.type]. + * [QueueMessage.uuid] and [QueueMessage.subQueue]. */ @Test fun testEquals_withEqualPayloadBytes() { val uuid = UUID.randomUUID().toString() - val type = "type" - val message1 = QueueMessage(payload = "stuff", type = type) + val subQueue = "testEquals_withEqualPayloadBytes" + val message1 = QueueMessage(payload = "stuff", subQueue = subQueue) message1.payload = null message1.uuid = uuid - val message2 = QueueMessage(payload = "stuff", type = type) + val message2 = QueueMessage(payload = "stuff", subQueue = subQueue) message2.payload = null message2.uuid = uuid @@ -76,19 +76,19 @@ class QueueMessageTest /** * Ensure that two [QueueMessage] are equal if they both have `null` [QueueMessage.payloadBytes] but `equal` [QueueMessage.payload], and the same - * [QueueMessage.uuid] and [QueueMessage.type]. + * [QueueMessage.uuid] and [QueueMessage.subQueue]. */ @Test fun testEquals_withEqualPayloads() { val uuid = UUID.randomUUID().toString() - val type = "type" + val subQueue = "testEquals_withEqualPayloads" val message1 = QueueMessage() message1.uuid = uuid - message1.type = type + message1.subQueue = subQueue val message2 = QueueMessage() message2.uuid = uuid - message2.type = type + message2.subQueue = subQueue // Set the payload into both objects to ensure this is considered in the equals check too val obj = 1287354 @@ -103,16 +103,16 @@ class QueueMessageTest /** * Ensure that two [QueueMessage] are equal if they both have `equal` [QueueMessage.payloadBytes] and [QueueMessage.payload], and the same - * [QueueMessage.uuid] and [QueueMessage.type]. + * [QueueMessage.uuid] and [QueueMessage.subQueue]. */ @Test fun testEquals_withEqualPayloadsAndBytes() { val uuid = UUID.randomUUID().toString() - val type = "type" - val message1 = QueueMessage(payload = "stuff", type = type) + val subQueue = "testEquals_withEqualPayloadsAndBytes" + val message1 = QueueMessage(payload = "stuff", subQueue = subQueue) message1.uuid = uuid - val message2 = QueueMessage(payload = "stuff", type = type) + val message2 = QueueMessage(payload = "stuff", subQueue = subQueue) message2.uuid = uuid Assertions.assertEquals(message1.payload, message2.payload) @@ -121,15 +121,15 @@ class QueueMessageTest } /** - * Ensure that [QueueMessage.equals] returns `false` when all properties are equal except [QueueMessage.type]. + * Ensure that [QueueMessage.equals] returns `false` when all properties are equal except [QueueMessage.subQueue]. */ @Test - fun testEquals_nonEqualType() + fun testEquals_nonEqualSubQueue() { val uuid = UUID.randomUUID().toString() - val message1 = QueueMessage(payload = "stuff", type = "type1") + val message1 = QueueMessage(payload = "stuff", subQueue = "type1") message1.uuid = uuid - val message2 = QueueMessage(payload = "stuff", type = "type2") + val message2 = QueueMessage(payload = "stuff", subQueue = "type2") message2.uuid = uuid Assertions.assertEquals(message1.payload, message2.payload) @@ -143,7 +143,7 @@ class QueueMessageTest @Test fun testEquals_withNull() { - val message = QueueMessage(payload = "data", type = "testEquals_withNull") + val message = QueueMessage(payload = "data", subQueue = "testEquals_withNull") Assertions.assertNotEquals(message, null) } @@ -153,7 +153,7 @@ class QueueMessageTest @Test fun testEquals_withNonQueueMessageObject() { - val message = QueueMessage(payload = "data", type = "testEquals_withNonQueueMessageObject") + val message = QueueMessage(payload = "data", subQueue = "testEquals_withNonQueueMessageObject") val obj = Any() Assertions.assertTrue(obj !is QueueMessage) Assertions.assertNotEquals(message, obj) @@ -167,7 +167,7 @@ class QueueMessageTest fun testResolvePayload_payloadNotNullBytesNull() { val payload = "testResolvePayload_payloadNotNullBytesNull" - val message = QueueMessage(null, type = "test") + val message = QueueMessage(null, subQueue = "test") Assertions.assertNull(message.payloadBytes) message.payload = payload message.resolvePayloadObject() @@ -183,7 +183,7 @@ class QueueMessageTest { val payload1 = "testResolvePayload_payloadNotNullBytesNotNull" val payload2 = "payload-bytes" - val message = QueueMessage(payload1, type = "test") + val message = QueueMessage(payload1, subQueue = "test") message.payloadBytes = SerializationUtils.serialize(payload2) message.resolvePayloadObject() Assertions.assertEquals(payload1, message.payload) @@ -197,7 +197,7 @@ class QueueMessageTest @Test fun testResolvePayload_payloadNullBytesNull() { - val message = QueueMessage(null, type = "test") + val message = QueueMessage(null, subQueue = "test") Assertions.assertNull(message.payload) Assertions.assertNull(message.payloadBytes) @@ -215,7 +215,7 @@ class QueueMessageTest fun testResolvePayload_payloadNullBytesNotNull() { val payload = "testResolvePayload_payloadNullBytesNotNull" - val message = QueueMessage(null, type = "test") + val message = QueueMessage(null, subQueue = "test") message.payloadBytes = SerializationUtils.serialize(payload) // At this point the payload property will quest payloadBytes, we need to overwrite diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt index 7b32b5a..9812ba0 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/MultiQueueTest.kt @@ -68,24 +68,24 @@ abstract class MultiQueueTest /** * Ensure that when a new entry is added, that the [MultiQueue] is no longer empty and reports the correct size. * - * @param data the incoming [Serializable] data to store in the [MultiQueue] to test that we can cater for multiple types + * @param data the incoming [Serializable] data to store in the [MultiQueue] to test that we can cater for multiple [QueueMessage.subQueue] */ @ParameterizedTest @MethodSource("parameters_testAdd") fun testAdd(data: Serializable) { Assertions.assertTrue(multiQueue.isEmpty()) - val message = QueueMessage(data, "type") + val message = QueueMessage(data, "testAdd") Assertions.assertTrue(multiQueue.add(message)) Assertions.assertFalse(multiQueue.isEmpty()) Assertions.assertEquals(1, multiQueue.size) // Getting the element two ways, via the queue for type and via poll to ensure both ways resolve the object payload properly - val queue = multiQueue.getQueueForType(message.type) + val queue = multiQueue.getSubQueue(message.subQueue) Assertions.assertEquals(1, queue.size) val storedElement = queue.elementAt(0) - val retrievedMessage = multiQueue.pollForType(message.type) + val retrievedMessage = multiQueue.pollSubQueue(message.subQueue) Assertions.assertTrue(multiQueue.isEmpty()) Assertions.assertEquals(0, multiQueue.size) @@ -112,37 +112,37 @@ abstract class MultiQueueTest } /*** - * Test [MultiQueue.add] to ensure that [DuplicateMessageException] is thrown if a [QueueMessage] already exists with the same `UUID` even if it is assigned to a different `queue type`. + * Test [MultiQueue.add] to ensure that [DuplicateMessageException] is thrown if a [QueueMessage] already exists with the same `UUID` even if it is assigned to a different `sub-queue`. */ @Test - fun testAdd_entryAlreadyExistsInDifferentQueueType() + fun testAdd_entryAlreadyExistsInDifferentSubQueue() { Assertions.assertTrue(multiQueue.isEmpty()) - val message = QueueMessage("test", "type") + val message = QueueMessage("test", "testAdd_entryAlreadyExistsInDifferentSubQueue") Assertions.assertTrue(multiQueue.add(message)) - val differentType = "different-type" - val differentTypeMessage = QueueMessage(message.payload, differentType) - differentTypeMessage.uuid = message.uuid + val differentSubQueue = "testAdd_entryAlreadyExistsInDifferentSubQueue2" + val differentMessage = QueueMessage(message.payload, differentSubQueue) + differentMessage.uuid = message.uuid - Assertions.assertEquals(message.payload, differentTypeMessage.payload) - Assertions.assertEquals(message.uuid, differentTypeMessage.uuid) - Assertions.assertNotEquals(message.type, differentTypeMessage.type) + Assertions.assertEquals(message.payload, differentMessage.payload) + Assertions.assertEquals(message.uuid, differentMessage.uuid) + Assertions.assertNotEquals(message.subQueue, differentMessage.subQueue) Assertions.assertThrows(DuplicateMessageException::class.java) { - multiQueue.add(differentTypeMessage) + multiQueue.add(differentMessage) } } /*** - * Test [MultiQueue.add] to ensure that [DuplicateMessageException] is thrown if a [QueueMessage] already exists with the same `UUID` even if it is assigned to the same `queue type`. + * Test [MultiQueue.add] to ensure that [DuplicateMessageException] is thrown if a [QueueMessage] already exists with the same `UUID` even if it is assigned to the same `sub-queue`. */ @Test fun testAdd_sameEntryAlreadyExists() { Assertions.assertTrue(multiQueue.isEmpty()) - val message = QueueMessage("test", "type") + val message = QueueMessage("test", "testAdd_sameEntryAlreadyExists") Assertions.assertTrue(multiQueue.add(message)) Assertions.assertThrows(DuplicateMessageException::class.java) @@ -159,7 +159,7 @@ abstract class MultiQueueTest { Assertions.assertTrue(multiQueue.isEmpty()) - val message = QueueMessage("A test value", "type") + val message = QueueMessage("A test value", "testRemove") Assertions.assertTrue(multiQueue.add(message)) Assertions.assertFalse(multiQueue.isEmpty()) @@ -177,7 +177,7 @@ abstract class MultiQueueTest fun testRemove_whenEntryDoesntExist() { Assertions.assertTrue(multiQueue.isEmpty()) - val messageThatDoesntExist = QueueMessage(Payload("some Other data", 23, false, PayloadEnum.A), "type") + val messageThatDoesntExist = QueueMessage(Payload("some Other data", 23, false, PayloadEnum.A), "testRemove_whenEntryDoesntExist") Assertions.assertFalse(multiQueue.remove(messageThatDoesntExist)) Assertions.assertTrue(multiQueue.isEmpty()) @@ -190,9 +190,9 @@ abstract class MultiQueueTest fun testContains_whenEntryDoesntExist() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "type" + val subQueue = "testContains_whenEntryDoesntExist" val otherData = Payload("some Other data", 65, true, PayloadEnum.B) - val messageThatDoesntExist = QueueMessage(otherData, type) + val messageThatDoesntExist = QueueMessage(otherData, subQueue) Assertions.assertFalse(multiQueue.contains(messageThatDoesntExist)) } @@ -203,7 +203,7 @@ abstract class MultiQueueTest fun testContains_whenEntryExists() { Assertions.assertTrue(multiQueue.isEmpty()) - val message = QueueMessage(0x52347, "type") + val message = QueueMessage(0x52347, "testContains_whenEntryExists") Assertions.assertTrue(multiQueue.add(message)) Assertions.assertFalse(multiQueue.isEmpty()) @@ -221,7 +221,7 @@ abstract class MultiQueueTest fun testContains_whenMetadataPropertiesAreSet() { Assertions.assertTrue(multiQueue.isEmpty()) - val message = QueueMessage(0x5234, "type") + val message = QueueMessage(0x5234, "testContains_whenMetadataPropertiesAreSet") Assertions.assertTrue(multiQueue.add(message)) Assertions.assertFalse(multiQueue.isEmpty()) @@ -248,94 +248,94 @@ abstract class MultiQueueTest @Test fun testGetNextQueueIndex_doesNotIncrement() { - val queueType = "testGetNextQueueIndex_doesNotIncrement" + val subQueue = "testGetNextQueueIndex_doesNotIncrement" if (multiQueue is SqlMultiQueue) { - Assertions.assertTrue(multiQueue.getNextQueueIndex(queueType).isEmpty) + Assertions.assertTrue(multiQueue.getNextSubQueueIndex(subQueue).isEmpty) } else if (multiQueue is InMemoryMultiQueue) { - Assertions.assertEquals(1, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(2, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(3, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(4, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(5, multiQueue.getNextQueueIndex(queueType).get()) - - multiQueue.clearForType(queueType) - Assertions.assertEquals(1, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(2, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(3, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(4, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(5, multiQueue.getNextQueueIndex(queueType).get()) + Assertions.assertEquals(1, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(2, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(3, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(4, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(5, multiQueue.getNextSubQueueIndex(subQueue).get()) + + multiQueue.clearSubQueue(subQueue) + Assertions.assertEquals(1, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(2, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(3, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(4, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(5, multiQueue.getNextSubQueueIndex(subQueue).get()) multiQueue.clear() - Assertions.assertEquals(1, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(2, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(3, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(4, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(5, multiQueue.getNextQueueIndex(queueType).get()) + Assertions.assertEquals(1, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(2, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(3, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(4, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(5, multiQueue.getNextSubQueueIndex(subQueue).get()) } else { - Assertions.assertTrue(multiQueue.getNextQueueIndex(queueType).isPresent) - Assertions.assertEquals(1, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(1, multiQueue.getNextQueueIndex(queueType).get()) - Assertions.assertEquals(1, multiQueue.getNextQueueIndex(queueType).get()) + Assertions.assertTrue(multiQueue.getNextSubQueueIndex(subQueue).isPresent) + Assertions.assertEquals(1, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(1, multiQueue.getNextSubQueueIndex(subQueue).get()) + Assertions.assertEquals(1, multiQueue.getNextSubQueueIndex(subQueue).get()) } } /** - * Ensure that [MultiQueue.getNextQueueIndex] starts at `1` and increments properly as called once entries are added. + * Ensure that [MultiQueue.getNextSubQueueIndex] starts at `1` and increments properly as called once entries are added. */ @Test fun testGetNextQueueIndex_withMessages() { Assertions.assertTrue(multiQueue.isEmpty()) - val queueType1 = "testGetNextQueueIndex_reInitialise1" - val queueType2 = "testGetNextQueueIndex_reInitialise2" + val subQueue1 = "testGetNextQueueIndex_reInitialise1" + val subQueue2 = "testGetNextQueueIndex_reInitialise2" - val list1 = listOf(QueueMessage(81273648, queueType1), QueueMessage("test test test", queueType1), QueueMessage(false, queueType1)) - val list2 = listOf(QueueMessage("test", queueType2), QueueMessage(123, queueType2)) + val list1 = listOf(QueueMessage(81273648, subQueue1), QueueMessage("test test test", subQueue1), QueueMessage(false, subQueue1)) + val list2 = listOf(QueueMessage("test", subQueue2), QueueMessage(123, subQueue2)) Assertions.assertTrue(multiQueue.addAll(list1)) Assertions.assertTrue(multiQueue.addAll(list2)) if (multiQueue is SqlMultiQueue) { - Assertions.assertTrue(multiQueue.getNextQueueIndex(queueType1).isEmpty) - Assertions.assertTrue(multiQueue.getNextQueueIndex(queueType2).isEmpty) + Assertions.assertTrue(multiQueue.getNextSubQueueIndex(subQueue1).isEmpty) + Assertions.assertTrue(multiQueue.getNextSubQueueIndex(subQueue2).isEmpty) } else if (multiQueue is InMemoryMultiQueue) { - Assertions.assertEquals((list1.size + 1).toLong(), multiQueue.getNextQueueIndex(queueType1).get()) - Assertions.assertEquals((list2.size + 1).toLong(), multiQueue.getNextQueueIndex(queueType2).get()) + Assertions.assertEquals((list1.size + 1).toLong(), multiQueue.getNextSubQueueIndex(subQueue1).get()) + Assertions.assertEquals((list2.size + 1).toLong(), multiQueue.getNextSubQueueIndex(subQueue2).get()) } else if (multiQueue is MongoMultiQueue) { - Assertions.assertEquals((list1.size + list2.size + 1).toLong(), multiQueue.getNextQueueIndex(queueType1).get()) - Assertions.assertEquals((list1.size + list2.size + 1).toLong(), multiQueue.getNextQueueIndex(queueType2).get()) + Assertions.assertEquals((list1.size + list2.size + 1).toLong(), multiQueue.getNextSubQueueIndex(subQueue1).get()) + Assertions.assertEquals((list1.size + list2.size + 1).toLong(), multiQueue.getNextSubQueueIndex(subQueue2).get()) } else { - Assertions.assertEquals((list1.size + 1).toLong(), multiQueue.getNextQueueIndex(queueType1).get()) - Assertions.assertEquals((list2.size + 1).toLong(), multiQueue.getNextQueueIndex(queueType2).get()) + Assertions.assertEquals((list1.size + 1).toLong(), multiQueue.getNextSubQueueIndex(subQueue1).get()) + Assertions.assertEquals((list2.size + 1).toLong(), multiQueue.getNextSubQueueIndex(subQueue2).get()) } } /** - * Ensure [MultiQueue.getQueueForType] returns the list of [QueueMessage]s always ordered by their [QueueMessage.id]. + * Ensure [MultiQueue.getSubQueue] returns the list of [QueueMessage]s always ordered by their [QueueMessage.id]. * * This also ensures they are assigned the `id` in the order they are enqueued. */ @Test - fun testGetQueueForType_ordered() + fun testGetqueue_ordered() { Assertions.assertTrue(multiQueue.isEmpty()) - val queueType = "testGetQueueForType_ordered" + val subQueue = "testGetqueue_ordered" - val list = listOf(QueueMessage(81248, queueType), QueueMessage("test data", queueType), QueueMessage(false, queueType)) + val list = listOf(QueueMessage(81248, subQueue), QueueMessage("test data", subQueue), QueueMessage(false, subQueue)) Assertions.assertTrue(multiQueue.addAll(list)) - val queue = multiQueue.getQueueForType(queueType) + val queue = multiQueue.getSubQueue(subQueue) Assertions.assertEquals(list.size, queue.size) var previousIndex: Long? = null list.zip(queue).forEach { pair -> @@ -353,22 +353,22 @@ abstract class MultiQueueTest } /** - * Ensure [MultiQueue.getQueueForType] returns the list of [QueueMessage]s always ordered by their [QueueMessage.id]. + * Ensure [MultiQueue.getSubQueue] returns the list of [QueueMessage]s always ordered by their [QueueMessage.id]. * Even when messages are changed and re-enqueued we need to make sure the returned message order is retained. */ @Test - fun testGetQueueForType_reordered() + fun testGetqueue_reordered() { Assertions.assertTrue(multiQueue.isEmpty()) - val queueType = "testGetQueueForType_reordered" + val subQueue = "testGetqueue_reordered" - val list = listOf(QueueMessage(81248, queueType), QueueMessage("test data", queueType), QueueMessage(false, queueType)) + val list = listOf(QueueMessage(81248, subQueue), QueueMessage("test data", subQueue), QueueMessage(false, subQueue)) Assertions.assertTrue(multiQueue.addAll(list)) // Force an object change, which for some mechanisms would re-enqueue it at the end // We will re-retrieve the queue and ensure they are in order to test that the ordering is correct // even after the object is changed - var queue = multiQueue.getQueueForType(queueType) + var queue = multiQueue.getSubQueue(subQueue) Assertions.assertEquals(list.size, queue.size) val firstMessage = queue.first() Assertions.assertEquals(list[0].uuid, firstMessage.uuid) @@ -376,7 +376,7 @@ abstract class MultiQueueTest firstMessage.payload = newData multiQueue.persistMessage(firstMessage) - queue = multiQueue.getQueueForType(queueType) + queue = multiQueue.getSubQueue(subQueue) var previousIndex: Long? = null list.zip(queue).forEach { pair -> Assertions.assertEquals(pair.first.uuid, pair.second.uuid) @@ -394,16 +394,16 @@ abstract class MultiQueueTest } /** - * Ensure that calls to [MultiQueue.getQueueForType] with a [MultiQueueAuthenticator.getReservedSubQueues] as an + * Ensure that calls to [MultiQueue.getSubQueue] with a [MultiQueueAuthenticator.getReservedSubQueues] as an * argument will throw [IllegalSubQueueIdentifierException]. */ @Test - fun testGetQueueForType_reservedSubQueue() + fun testGetqueue_reservedSubQueue() { - doWithAuthType(RestrictionMode.HYBRID) { + doWithRestrictedMode(RestrictionMode.HYBRID) { authenticator.getReservedSubQueues().forEach { reservedSubQueueIdentifier -> Assertions.assertThrows(IllegalSubQueueIdentifierException::class.java) { - multiQueue.getQueueForType(reservedSubQueueIdentifier) + multiQueue.getSubQueue(reservedSubQueueIdentifier) } } } @@ -416,7 +416,7 @@ abstract class MultiQueueTest fun testAddAll_containsAll_removeAll() { Assertions.assertTrue(multiQueue.isEmpty()) - val list = listOf(QueueMessage(81273648, "type"), QueueMessage("test test test", "type")) + val list = listOf(QueueMessage(81273648, "testAddAll_containsAll_removeAll"), QueueMessage("test test test", "testAddAll_containsAll_removeAll")) Assertions.assertTrue(multiQueue.addAll(list)) Assertions.assertFalse(multiQueue.isEmpty()) Assertions.assertEquals(2, multiQueue.size) @@ -436,7 +436,7 @@ abstract class MultiQueueTest @Test fun testAddAll_throwsDuplicateException() { - val list = listOf(QueueMessage(81273648, "type"), QueueMessage("test test test", "type")) + val list = listOf(QueueMessage(81273648, "testAddAll_throwsDuplicateException"), QueueMessage("test test test", "testAddAll_throwsDuplicateException")) Assertions.assertTrue(multiQueue.add(list[1])) Assertions.assertFalse(multiQueue.addAll(list)) Assertions.assertEquals(list.size, multiQueue.size) @@ -447,15 +447,15 @@ abstract class MultiQueueTest * Otherwise, if it does exist make sure that the correct entry is returned and that it is removed. */ @Test - fun testPollForType() + fun testPollForSubQueue() { Assertions.assertTrue(multiQueue.isEmpty()) - val message = QueueMessage(Payload("poll for type", 89, true, PayloadEnum.B), "poll-type") + val message = QueueMessage(Payload("poll for type", 89, true, PayloadEnum.B), "testPollForSubQueue") - Assertions.assertFalse(multiQueue.pollForType(message.type).isPresent) + Assertions.assertFalse(multiQueue.pollSubQueue(message.subQueue).isPresent) Assertions.assertTrue(multiQueue.add(message)) Assertions.assertFalse(multiQueue.isEmpty()) - val polledMessage = multiQueue.pollForType(message.type).get() + val polledMessage = multiQueue.pollSubQueue(message.subQueue).get() Assertions.assertEquals(message, polledMessage) Assertions.assertTrue(multiQueue.isEmpty()) } @@ -465,68 +465,68 @@ abstract class MultiQueueTest * Otherwise, if it does exist make sure that the correct entry is returned. */ @Test - fun testPeekForType() + fun testPeekForSubQueue() { Assertions.assertTrue(multiQueue.isEmpty()) - val message = QueueMessage(Payload("peek for type", 1121, false, PayloadEnum.C), "peek-type") + val message = QueueMessage(Payload("peek for type", 1121, false, PayloadEnum.C), "testPeekForSubQueue") - Assertions.assertFalse(multiQueue.peekForType(message.type).isPresent) + Assertions.assertFalse(multiQueue.peekSubQueue(message.subQueue).isPresent) Assertions.assertTrue(multiQueue.add(message)) Assertions.assertFalse(multiQueue.isEmpty()) - val peekedMessage = multiQueue.peekForType(message.type).get() + val peekedMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertEquals(message, peekedMessage) Assertions.assertFalse(multiQueue.isEmpty()) } /** - * Ensure that [MultiQueue.isEmptyForType] operates as expected when entries exist and don't exist for a specific type. + * Ensure that [MultiQueue.isEmptySubQueue] operates as expected when entries exist and don't exist for a specific sub-queue. */ @Test - fun testIsEmptyForType() + fun testIsEmptyForSubQueue() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "type" + val subQueue = "testIsEmptyForSubQueue" val data = "test data" - val message = QueueMessage(data, type) + val message = QueueMessage(data, subQueue) Assertions.assertTrue(multiQueue.add(message)) Assertions.assertFalse(multiQueue.isEmpty()) - Assertions.assertFalse(multiQueue.isEmptyForType(type)) - Assertions.assertTrue(multiQueue.isEmptyForType("another-type")) + Assertions.assertFalse(multiQueue.isEmptySubQueue(subQueue)) + Assertions.assertTrue(multiQueue.isEmptySubQueue("testIsEmptyForSubQueue-another")) } /** - * Ensure that only the specific entries are removed when [MultiQueue.clearForTypeInternal] is called. + * Ensure that only the specific entries are removed when [MultiQueue.clearSubQueueInternal] is called. */ @Test - fun testClearForType() + fun testClearForSubQueue() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "clear-for-type" - val list = listOf(QueueMessage(81273648, type), QueueMessage("test test test", type)) + val subQueue = "testClearForSubQueue" + val list = listOf(QueueMessage(81273648, subQueue), QueueMessage("test test test", subQueue)) Assertions.assertTrue(multiQueue.addAll(list)) - val singleEntryType = "single-entry-type" - val message = QueueMessage("test message", singleEntryType) + val singleEntrySubQueue = "testClearForSubQueue2" + val message = QueueMessage("test message", singleEntrySubQueue) Assertions.assertTrue(multiQueue.add(message)) Assertions.assertEquals(3, multiQueue.size) - multiQueue.clearForTypeInternal(type) + multiQueue.clearSubQueueInternal(subQueue) Assertions.assertEquals(1, multiQueue.size) - multiQueue.clearForTypeInternal(singleEntryType) + multiQueue.clearSubQueueInternal(singleEntrySubQueue) Assertions.assertTrue(multiQueue.isEmpty()) } /** - * Ensure that no change is made when the specific type has no entries. + * Ensure that no change is made when the specific sub-queue has no entries. */ @Test - fun testClearForType_DoesNotExist() + fun testClearSubQueue_DoesNotExist() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "clear-for-type-does-not-exist" - multiQueue.clearForTypeInternal(type) + val subQueue = "testClearSubQueue_DoesNotExist" + multiQueue.clearSubQueueInternal(subQueue) Assertions.assertTrue(multiQueue.isEmpty()) } @@ -537,11 +537,11 @@ abstract class MultiQueueTest fun testRetainAll() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "type1" - val type2 = "type2" + val subQueue = "testRetainAll1" + val subQueue2 = "testRetainAll2" val data = Payload("some payload", 1, true, PayloadEnum.A) val data2 = Payload("some more data", 2, false, PayloadEnum.B) - val list = listOf(QueueMessage(data, type), QueueMessage(data, type2), QueueMessage(data2, type), QueueMessage(data2, type2)) + val list = listOf(QueueMessage(data, subQueue), QueueMessage(data, subQueue2), QueueMessage(data2, subQueue), QueueMessage(data2, subQueue2)) Assertions.assertTrue(multiQueue.addAll(list)) Assertions.assertEquals(4, multiQueue.size) @@ -550,9 +550,9 @@ abstract class MultiQueueTest toRetain.addAll(list.subList(0, 2)) Assertions.assertEquals(2, toRetain.size) // No elements of this type to cover all branches of code - val type3 = "type3" - val type3Message = QueueMessage(Payload("type3 data", 3, false, PayloadEnum.C), type3) - toRetain.add(type3Message) + val subQueue3 = "testRetainAll3" + val message3 = QueueMessage(Payload("data 3", 3, false, PayloadEnum.C), subQueue3) + toRetain.add(message3) Assertions.assertEquals(3, toRetain.size) Assertions.assertTrue(multiQueue.retainAll(toRetain)) @@ -574,14 +574,14 @@ abstract class MultiQueueTest fun testPersistMessage() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "test-persist" + val subQueue = "testPersistMessage" val data = Payload("some payload", 1, true, PayloadEnum.A) val data2 = Payload("some more data", 2, false, PayloadEnum.B) - val message = QueueMessage(data, type) + val message = QueueMessage(data, subQueue) Assertions.assertTrue(multiQueue.add(message)) - val persistedMessage = multiQueue.peekForType(message.type) + val persistedMessage = multiQueue.peekSubQueue(message.subQueue) Assertions.assertTrue(persistedMessage.isPresent) val messageToUpdate = persistedMessage.get() Assertions.assertEquals(message, messageToUpdate) @@ -601,7 +601,7 @@ abstract class MultiQueueTest multiQueue.persistMessage(messageToUpdate) - val reRetrievedMessage = multiQueue.peekForType(message.type) + val reRetrievedMessage = multiQueue.peekSubQueue(message.subQueue) Assertions.assertTrue(reRetrievedMessage.isPresent) Assertions.assertEquals(messageToUpdate, reRetrievedMessage.get()) } @@ -613,7 +613,7 @@ abstract class MultiQueueTest @Test fun testPersistMessage_messageHasNullID() { - val message = QueueMessage("payload", "type") + val message = QueueMessage("payload", "testPersistMessage_messageHasNullID") Assertions.assertNull(message.id) if (multiQueue !is InMemoryMultiQueue) @@ -626,16 +626,16 @@ abstract class MultiQueueTest } /** - * Test [MultiQueue.getAssignedMessagesForType] returns only messages with a non-null [QueueMessage.assignedTo] property. + * Test [MultiQueue.getAssignedMessagesInSubQueue] returns only messages with a non-null [QueueMessage.assignedTo] property. */ @Test - fun testGetAssignedMessagesForType_noAssignedTo() + fun testGetAssignedMessagesForSubQueue_noAssignedTo() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "test-assigned-messages-for-type" - val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), type) - val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), type) - val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), type) + val subQueue = "testGetAssignedMessagesForSubQueue_noAssignedTo" + val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), subQueue) + val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), subQueue) + val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), subQueue) // Assign message 1 val assignedTo = "me" @@ -651,11 +651,11 @@ abstract class MultiQueueTest multiQueue.persistMessage(message2) // Ensure all messages are in the queue - val messagesInSubQueue = multiQueue.getQueueForType(type) + val messagesInSubQueue = multiQueue.getSubQueue(subQueue) Assertions.assertEquals(3, messagesInSubQueue.size) // Check only messages 1 and 2 are returned in the assigned queue - val assignedMessages = multiQueue.getAssignedMessagesForType(type, null) + val assignedMessages = multiQueue.getAssignedMessagesInSubQueue(subQueue, null) Assertions.assertEquals(2, assignedMessages.size) val list = ArrayList() @@ -666,17 +666,18 @@ abstract class MultiQueueTest } /** - * Test [MultiQueue.getAssignedMessagesForType] returns only messages with the matching [QueueMessage.assignedTo] property. + * Test [MultiQueue.getAssignedMessagesInSubQueue] returns only messages with the matching [QueueMessage.assignedTo] property. */ @Test - fun testGetAssignedMessagesForType_withAssignedTo() + fun testGetAssignedMessagesForSubQueue_withAssignedTo() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "test-assigned-messages-for-type" - val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), type) - val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), type) - val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), type) - val message4 = QueueMessage(Payload("some more data data data", 4, false, PayloadEnum.A), type) + Assertions.assertTrue(multiQueue.isEmpty()) + val subQueue = "testGetAssignedMessagesForSubQueue_withAssignedTo" + val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), subQueue) + val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), subQueue) + val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), subQueue) + val message4 = QueueMessage(Payload("some more data data data", 4, false, PayloadEnum.A), subQueue) // Assign message 1, 2 and 3 val assignedTo = "me" @@ -695,11 +696,11 @@ abstract class MultiQueueTest multiQueue.persistMessage(message2) // Ensure all messages are in the queue - val messagesInSubQueue = multiQueue.getQueueForType(type) + val messagesInSubQueue = multiQueue.getSubQueue(subQueue) Assertions.assertEquals(4, messagesInSubQueue.size) // Check only messages 1 and 2 are assigned to 'assignedTo' - val assignedMessages = multiQueue.getAssignedMessagesForType(type, assignedTo) + val assignedMessages = multiQueue.getAssignedMessagesInSubQueue(subQueue, assignedTo) Assertions.assertEquals(2, assignedMessages.size) val list = ArrayList() @@ -711,17 +712,17 @@ abstract class MultiQueueTest } /** - * Test [MultiQueue.getUnassignedMessagesForType] returns only messages with a `null` [QueueMessage.assignedTo] property. + * Test [MultiQueue.getUnassignedMessagesInSubQueue] returns only messages with a `null` [QueueMessage.assignedTo] property. */ @Test - fun testGetUnassignedMessagesForType() + fun testGetUnassignedMessagesForSubQueue() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "test-unassigned-messages-for-type" - val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), type) - val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), type) - val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), type) - val message4 = QueueMessage(Payload("some more data data data", 4, true, PayloadEnum.A), type) + val subQueue = "testGetUnassignedMessagesForSubQueue" + val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), subQueue) + val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), subQueue) + val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), subQueue) + val message4 = QueueMessage(Payload("some more data data data", 4, true, PayloadEnum.A), subQueue) val assignedTo = "you" message.assignedTo = assignedTo @@ -739,11 +740,11 @@ abstract class MultiQueueTest multiQueue.persistMessage(message3) // Ensure all messages are in the queue - val messagesInSubQueue = multiQueue.getQueueForType(type) + val messagesInSubQueue = multiQueue.getSubQueue(subQueue) Assertions.assertEquals(4, messagesInSubQueue.size) // Check only messages 3 and 4 are returned in the unassigned queue - val assignedMessages = multiQueue.getUnassignedMessagesForType(type) + val assignedMessages = multiQueue.getUnassignedMessagesInSubQueue(subQueue) Assertions.assertEquals(2, assignedMessages.size) val list = ArrayList() @@ -755,21 +756,21 @@ abstract class MultiQueueTest } /** - * Test [MultiQueue.getOwnersAndKeysMapForType] to ensure that the provided map is populated properly with the correct entries + * Test [MultiQueue.getOwnersAndKeysMapForSubQueue] to ensure that the provided map is populated properly with the correct entries * for the current [MultiQueue] state. */ @Test - fun testGetOwnersAndKeysMapForType() + fun testGetOwnersAndKeysMapForSubQueue() { val responseMap = HashMap>() Assertions.assertTrue(multiQueue.isEmpty()) - val type = "test-get-owners-and-keys-map-for-type" - val type2 = "test-get-owners-and-keys-map-for-type2" - val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), type) - val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), type) - val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), type2) - val message4 = QueueMessage(Payload("some more data data data", 4, true, PayloadEnum.A), type) + val subQueue = "test-get-owners-and-keys-map-for-subqueue" + val subQueue2 = "test-get-owners-and-keys-map-for-subqueue2" + val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), subQueue) + val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), subQueue) + val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), subQueue2) + val message4 = QueueMessage(Payload("some more data data data", 4, true, PayloadEnum.A), subQueue) val assignedTo = "assigned1" val assignedTo2 = "assigned2" @@ -783,7 +784,7 @@ abstract class MultiQueueTest Assertions.assertTrue(multiQueue.add(message3)) Assertions.assertTrue(multiQueue.add(message4)) - multiQueue.getOwnersAndKeysMapForType(type, responseMap) + multiQueue.getOwnersAndKeysMapForSubQueue(subQueue, responseMap) Assertions.assertEquals(2, responseMap.keys.size) val listOfKeys = ArrayList() @@ -792,13 +793,13 @@ abstract class MultiQueueTest Assertions.assertTrue(listOfKeys.contains(assignedTo)) Assertions.assertTrue(listOfKeys.contains(assignedTo2)) - val typesForAssignedTo = responseMap[assignedTo] - Assertions.assertEquals(1, typesForAssignedTo!!.size) - Assertions.assertEquals(type, typesForAssignedTo.iterator().next()) + val subQueuesForAssignedTo = responseMap[assignedTo] + Assertions.assertEquals(1, subQueuesForAssignedTo!!.size) + Assertions.assertEquals(subQueue, subQueuesForAssignedTo.iterator().next()) - val typesForAssignedTo2 = responseMap[assignedTo2] - Assertions.assertEquals(1, typesForAssignedTo2!!.size) - Assertions.assertEquals(type, typesForAssignedTo2.iterator().next()) + val subQueuesForAssignedTo2 = responseMap[assignedTo2] + Assertions.assertEquals(1, subQueuesForAssignedTo2!!.size) + Assertions.assertEquals(subQueue, subQueuesForAssignedTo2.iterator().next()) } /** @@ -806,15 +807,15 @@ abstract class MultiQueueTest * for the current [MultiQueue] state. */ @Test - fun testGetOwnersAndKeysMap_withQueueType() + fun testGetOwnersAndKeysMap_inSubQueue() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "test-get-owners-and-keys-map" - val type2 = "test-get-owners-and-keys-map2" - val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), type) - val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), type) - val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), type2) - val message4 = QueueMessage(Payload("some more data data data", 4, true, PayloadEnum.A), type) + val subQueue = "testGetOwnersAndKeysMap_inSubQueue" + val subQueue2 = "testGetOwnersAndKeysMap_inSubQueue2" + val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), subQueue) + val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), subQueue) + val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), subQueue2) + val message4 = QueueMessage(Payload("some more data data data", 4, true, PayloadEnum.A), subQueue) val assignedTo = "assigned1" val assignedTo2 = "assigned2" @@ -828,7 +829,7 @@ abstract class MultiQueueTest Assertions.assertTrue(multiQueue.add(message3)) Assertions.assertTrue(multiQueue.add(message4)) - val responseMap = multiQueue.getOwnersAndKeysMap(type) + val responseMap = multiQueue.getOwnersAndKeysMap(subQueue) Assertions.assertEquals(2, responseMap.keys.size) val listOfKeys = responseMap.keys.toList() @@ -836,13 +837,13 @@ abstract class MultiQueueTest Assertions.assertTrue(listOfKeys.contains(assignedTo)) Assertions.assertTrue(listOfKeys.contains(assignedTo2)) - val typesForAssignedTo = responseMap[assignedTo] - Assertions.assertEquals(1, typesForAssignedTo!!.size) - Assertions.assertEquals(type, typesForAssignedTo.iterator().next()) + val subQueuesForAssignedTo = responseMap[assignedTo] + Assertions.assertEquals(1, subQueuesForAssignedTo!!.size) + Assertions.assertEquals(subQueue, subQueuesForAssignedTo.iterator().next()) - val typesForAssignedTo2 = responseMap[assignedTo2] - Assertions.assertEquals(1, typesForAssignedTo2!!.size) - Assertions.assertEquals(type, typesForAssignedTo2.iterator().next()) + val subQueuesForAssignedTo2 = responseMap[assignedTo2] + Assertions.assertEquals(1, subQueuesForAssignedTo2!!.size) + Assertions.assertEquals(subQueue, subQueuesForAssignedTo2.iterator().next()) } /** @@ -850,19 +851,19 @@ abstract class MultiQueueTest * for the current [MultiQueue] state. */ @Test - fun testGetOwnersAndKeysMap_withoutQueueType() + fun testGetOwnersAndKeysMap_notInSubQueue() { Assertions.assertTrue(multiQueue.isEmpty()) - val type = "test-get-owners-and-keys-map" - val type2 = "test-get-owners-and-keys-map2" - val type3 = "test-get-owners-and-keys-map3" - val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), type) - val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), type) - val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), type2) - val message4 = QueueMessage(Payload("some more data data data", 4, true, PayloadEnum.A), type) - val message5 = QueueMessage(Payload("just data", 5, true, PayloadEnum.C), type3) - val message6 = QueueMessage(Payload("just more data", 6, false, PayloadEnum.B), type2) - val message7 = QueueMessage(Payload("just more and more data", 7, false, PayloadEnum.A), type) + val subQueue = "test-get-owners-and-keys-map" + val subQueue2 = "test-get-owners-and-keys-map2" + val subQueue3 = "test-get-owners-and-keys-map3" + val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), subQueue) + val message2 = QueueMessage(Payload("some more data", 2, false, PayloadEnum.B), subQueue) + val message3 = QueueMessage(Payload("some more data data", 3, false, PayloadEnum.C), subQueue2) + val message4 = QueueMessage(Payload("some more data data data", 4, true, PayloadEnum.A), subQueue) + val message5 = QueueMessage(Payload("just data", 5, true, PayloadEnum.C), subQueue3) + val message6 = QueueMessage(Payload("just more data", 6, false, PayloadEnum.B), subQueue2) + val message7 = QueueMessage(Payload("just more and more data", 7, false, PayloadEnum.A), subQueue) val assignedTo = "assigned1" val assignedTo2 = "assigned2" @@ -892,19 +893,19 @@ abstract class MultiQueueTest Assertions.assertTrue(listOfKeys.contains(assignedTo2)) Assertions.assertTrue(listOfKeys.contains(assignedTo3)) - val typesForAssignedTo = responseMap[assignedTo]!!.toList() - Assertions.assertEquals(1, typesForAssignedTo.size) - Assertions.assertTrue(typesForAssignedTo.contains(type)) + val subQueuesForAssignedTo = responseMap[assignedTo]!!.toList() + Assertions.assertEquals(1, subQueuesForAssignedTo.size) + Assertions.assertTrue(subQueuesForAssignedTo.contains(subQueue)) - val typesForAssignedTo2 = responseMap[assignedTo2]!!.toList() - Assertions.assertEquals(2, typesForAssignedTo2.size) - Assertions.assertTrue(typesForAssignedTo2.contains(type)) - Assertions.assertTrue(typesForAssignedTo2.contains(type2)) + val subQueuesForAssignedTo2 = responseMap[assignedTo2]!!.toList() + Assertions.assertEquals(2, subQueuesForAssignedTo2.size) + Assertions.assertTrue(subQueuesForAssignedTo2.contains(subQueue)) + Assertions.assertTrue(subQueuesForAssignedTo2.contains(subQueue2)) - val typesForAssignedTo3 = responseMap[assignedTo3]!!.toList() - Assertions.assertEquals(2, typesForAssignedTo3.size) - Assertions.assertTrue(typesForAssignedTo3.contains(type2)) - Assertions.assertTrue(typesForAssignedTo3.contains(type3)) + val subQueuesForAssignedTo3 = responseMap[assignedTo3]!!.toList() + Assertions.assertEquals(2, subQueuesForAssignedTo3.size) + Assertions.assertTrue(subQueuesForAssignedTo3.contains(subQueue2)) + Assertions.assertTrue(subQueuesForAssignedTo3.contains(subQueue3)) } /** @@ -913,8 +914,8 @@ abstract class MultiQueueTest @Test fun testGetMessageByUUID_matchingMessage() { - val type = "testGetMessageByUUID_matchingMessage" - val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), type) + val subQueue = "testGetMessageByUUID_matchingMessage" + val message = QueueMessage(Payload("some payload", 1, true, PayloadEnum.A), subQueue) Assertions.assertTrue(multiQueue.add(message)) val retrievedMessage = multiQueue.getMessageByUUID(message.uuid) @@ -944,12 +945,12 @@ abstract class MultiQueueTest } /** - * Ensure that we cannot add a new [QueueMessage] with [QueueMessage.type] set to any of the [MultiQueueAuthenticator.getReservedSubQueues] entries. + * Ensure that we cannot add a new [QueueMessage] with [QueueMessage.subQueue] set to any of the [MultiQueueAuthenticator.getReservedSubQueues] entries. */ @Test fun testAddReservedSubQueue() { - doWithAuthType(RestrictionMode.RESTRICTED) { + doWithRestrictedMode(RestrictionMode.RESTRICTED) { authenticator.getReservedSubQueues().forEach { reservedSubQueueIdentifier -> val message = QueueMessage("Data", reservedSubQueueIdentifier) Assertions.assertThrows(IllegalSubQueueIdentifierException::class.java) { @@ -966,7 +967,7 @@ abstract class MultiQueueTest @Test fun testKeysWithReservedSubQueueUsage() { - doWithAuthType(RestrictionMode.HYBRID) { + doWithRestrictedMode(RestrictionMode.HYBRID) { var keys = multiQueue.keys() authenticator.getReservedSubQueues().forEach { reservedSubQueueIdentifier -> Assertions.assertFalse(keys.contains(reservedSubQueueIdentifier)) @@ -986,17 +987,17 @@ abstract class MultiQueueTest } /** - * Perform the provided [function] with the [RestrictionMode] set to [authenticationType]. + * Perform the provided [function] with the [RestrictionMode] set to [restrictionMode]. * Once completed the [RestrictionMode] will be set back to its initial value. * - * @param authenticationType the [RestrictionMode] to be set while the [function] is being called + * @param restrictionMode the [RestrictionMode] to be set while the [function] is being called * @param function the function to call with the provided [RestrictionMode] being active * @return `T` the result of the [function] */ - private fun doWithAuthType(authenticationType: RestrictionMode, function: Supplier): T + private fun doWithRestrictedMode(restrictionMode: RestrictionMode, function: Supplier): T { - val previousAuthType = authenticator.getAuthenticationType() - authenticator.setAuthenticationType(authenticationType) + val previousRestrictedMode = authenticator.getRestrictionMode() + authenticator.setRestrictionMode(restrictionMode) try { @@ -1004,7 +1005,7 @@ abstract class MultiQueueTest } finally { - authenticator.setAuthenticationType(previousAuthType) + authenticator.setRestrictionMode(previousRestrictedMode) } } @@ -1024,7 +1025,7 @@ abstract class MultiQueueTest { Assertions.assertThrows(UnsupportedOperationException::class.java) { - multiQueue.offer(QueueMessage(Payload("test data", 13, false, PayloadEnum.C), "test type")) + multiQueue.offer(QueueMessage(Payload("test data", 13, false, PayloadEnum.C), "test sub-queue")) } }, { diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt index d19a5e2..c00c9f6 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/cache/redis/RedisStandAloneMultiQueueTest.kt @@ -111,22 +111,22 @@ class RedisStandAloneMultiQueueTest: MultiQueueTest() val prefix = redisMultiQueue.getPrefix() - val type = "removePrefix" - val type2 = "removePrefix2" - Assertions.assertTrue(redisMultiQueue.add(QueueMessage("data", type))) - Assertions.assertTrue(redisMultiQueue.add(QueueMessage("data2", type2))) + val subQueue = "removePrefix" + val subQueue2 = "removePrefix2" + Assertions.assertTrue(redisMultiQueue.add(QueueMessage("data", subQueue))) + Assertions.assertTrue(redisMultiQueue.add(QueueMessage("data2", subQueue2))) val keys = redisMultiQueue.keys() - Assertions.assertTrue(keys.contains("$prefix$type")) - Assertions.assertTrue(keys.contains("$prefix$type2")) + Assertions.assertTrue(keys.contains("$prefix$subQueue")) + Assertions.assertTrue(keys.contains("$prefix$subQueue2")) keys.forEach { key -> Assertions.assertTrue(key.startsWith(prefix)) } val removedPrefix = redisMultiQueue.removePrefix(keys) - Assertions.assertFalse(removedPrefix.contains("$prefix$type")) - Assertions.assertFalse(removedPrefix.contains("$prefix$type2")) + Assertions.assertFalse(removedPrefix.contains("$prefix$subQueue")) + Assertions.assertFalse(removedPrefix.contains("$prefix$subQueue2")) removedPrefix.forEach { key -> Assertions.assertFalse(key.startsWith(prefix)) } - Assertions.assertTrue(removedPrefix.contains(type)) - Assertions.assertTrue(removedPrefix.contains(type2)) + Assertions.assertTrue(removedPrefix.contains(subQueue)) + Assertions.assertTrue(removedPrefix.contains(subQueue2)) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMockMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMockMultiQueueTest.kt index bc4e64a..da7f0cc 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMockMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/inmemory/InMemoryMockMultiQueueTest.kt @@ -39,7 +39,7 @@ class InMemoryMockMultiQueueTest @Test fun testPerformAdd_returnsFalse() { - val message = QueueMessage(null, "type") + val message = QueueMessage(null, "testPerformAdd_returnsFalse") Mockito.`when`(multiQueue.addInternal(message)).thenReturn(false) Mockito.`when`(multiQueue.containsUUID(message.uuid)).thenReturn(Optional.empty()) Assertions.assertFalse(multiQueue.add(message)) @@ -67,7 +67,7 @@ class InMemoryMockMultiQueueTest @Test fun testRetainAll_removeFails() { - val message = QueueMessage("payload", "type-string") + val message = QueueMessage("payload", "testRetainAll_removeFails") Mockito.`when`(multiQueue.remove(message)).thenReturn(false) Assertions.assertTrue(multiQueue.add(message)) diff --git a/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt b/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt index b10391a..775645b 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/queue/nosql/mongo/MongoMultiQueueTest.kt @@ -95,8 +95,6 @@ class MongoMultiQueueTest: MultiQueueTest() /** * Check the container is running before each test as it's required for the methods to access the [MongoMultiQueue]. - * - * We will call [MongoMultiQueue.initialiseQueueIndex] here because we pass in the [MessageQueueSettings.MULTI_QUEUE_LAZY_INITIALISE] in the [DataMongoTest] annotation. */ @BeforeEach fun beforeEach() diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt index fd7c828..e4b8505 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/AuthControllerTest.kt @@ -87,49 +87,49 @@ class AuthControllerTest @Test fun testRestrictSubQueue_inNoneMode() { - val queueType = "testRestrictSubQueue_inNoneMode" - Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) + val subQueue = "testRestrictSubQueue_inNoneMode" + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getRestrictionMode()) mockMvc.perform( - MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${subQueue}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isNoContent) } /** * Ensure [AuthController.restrictSubQueue] returns [org.springframework.http.HttpStatus.CONFLICT] when the - * requested queue type requested is already restricted. + * requested sub-queue requested is already restricted. */ @Test fun testRestrictSubQueue_alreadyRestricted() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRestrictSubQueue_alreadyRestricted" - Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(queueType)) - Assertions.assertTrue(multiQueueAuthenticator.isRestricted(queueType)) + val subQueue = "testRestrictSubQueue_alreadyRestricted" + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) mockMvc.perform( - MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${subQueue}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isConflict) } /** * Ensure [AuthController.restrictSubQueue] returns [org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR] - * when the requested queue type fails to be restricted. + * when the requested sub-queue fails to be restricted. */ @Test fun testRestrictSubQueue_wasNotAdded() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRestrictSubQueue_wasNotAdded" - Mockito.doReturn(false).`when`(multiQueueAuthenticator).addRestrictedEntry(queueType) + val subQueue = "testRestrictSubQueue_wasNotAdded" + Mockito.doReturn(false).`when`(multiQueueAuthenticator).addRestrictedEntry(subQueue) mockMvc.perform( - MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${subQueue}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isInternalServerError) } @@ -141,32 +141,32 @@ class AuthControllerTest @Test fun testRestrictSubQueue_tokenGenerationFailure() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRestrictSubQueue_tokenGenerationFailure" - Mockito.doReturn(Optional.empty()).`when`(jwtTokenProvider).createTokenForSubQueue(queueType) + val subQueue = "testRestrictSubQueue_tokenGenerationFailure" + Mockito.doReturn(Optional.empty()).`when`(jwtTokenProvider).createTokenForSubQueue(subQueue) mockMvc.perform( - MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${subQueue}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isInternalServerError) } /** * Ensure [AuthController.restrictSubQueue] returns [org.springframework.http.HttpStatus.OK] and a valid - * [AuthResponse] when the requested queue type is restricted successfully. + * [AuthResponse] when the requested sub-queue is restricted successfully. */ @Test fun testRestrictSubQueue_tokenGenerated() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRestrictSubQueue_tokenGenerated" + val subQueue = "testRestrictSubQueue_tokenGenerated" val mvcResult: MvcResult = mockMvc.perform( - MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${subQueue}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isCreated) .andReturn() @@ -174,7 +174,7 @@ class AuthControllerTest val authResponse = gson.fromJson(mvcResult.response.contentAsString, AuthResponse::class.java) Assertions.assertNotNull(authResponse.token) Assertions.assertNotNull(authResponse.correlationId) - Assertions.assertEquals(queueType, authResponse.subQueue) + Assertions.assertEquals(subQueue, authResponse.subQueue) } /** @@ -185,13 +185,13 @@ class AuthControllerTest @Test fun testRestrictSubQueue_inRestrictedMode() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRestrictSubQueue_inRestrictedMode" + val subQueue = "testRestrictSubQueue_inRestrictedMode" val mvcResult: MvcResult = mockMvc.perform( - MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.post("${AuthController.AUTH_PATH}/${subQueue}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isCreated) .andReturn() @@ -199,7 +199,7 @@ class AuthControllerTest val authResponse = gson.fromJson(mvcResult.response.contentAsString, AuthResponse::class.java) Assertions.assertNotNull(authResponse.token) Assertions.assertNotNull(authResponse.correlationId) - Assertions.assertEquals(queueType, authResponse.subQueue) + Assertions.assertEquals(subQueue, authResponse.subQueue) } /** @@ -209,11 +209,11 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_inNoneMode() { - val queueType = "testRemoveRestrictionFromSubQueue_inNoneMode" + val subQueue = "testRemoveRestrictionFromSubQueue_inNoneMode" - Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getRestrictionMode()) mockMvc.perform( - MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${subQueue}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isAccepted) } @@ -225,16 +225,16 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_invalidToken() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRemoveRestrictionFromSubQueue_invalidToken" - val invalidQueueType = "invalidQueueType" - val token = jwtTokenProvider.createTokenForSubQueue(queueType) + val subQueue = "testRemoveRestrictionFromSubQueue_invalidToken" + val invalidsubQueue = "invalidsubQueue" + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) Assertions.assertTrue(token.isPresent) mockMvc.perform( - MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${invalidQueueType}") + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${invalidsubQueue}") .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isForbidden) @@ -248,13 +248,13 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_withoutAuthToken() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRemoveRestrictionFromSubQueue_withoutAuthToken" + val subQueue = "testRemoveRestrictionFromSubQueue_withoutAuthToken" mockMvc.perform( - MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${subQueue}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) } @@ -266,17 +266,17 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_validTokenButNotRestricted() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRemoveRestrictionFromSubQueue_validToken" - val token = jwtTokenProvider.createTokenForSubQueue(queueType) + val subQueue = "testRemoveRestrictionFromSubQueue_validToken" + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) Assertions.assertTrue(token.isPresent) - Assertions.assertFalse(multiQueueAuthenticator.isRestricted(queueType)) + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) mockMvc.perform( - MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${subQueue}") .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isNoContent) @@ -290,20 +290,20 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_failedToRemoveRestriction() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRemoveRestrictionFromSubQueue_failedToRemoveRestriction" - val token = jwtTokenProvider.createTokenForSubQueue(queueType) + val subQueue = "testRemoveRestrictionFromSubQueue_failedToRemoveRestriction" + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) Assertions.assertTrue(token.isPresent) - Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(queueType)) - Assertions.assertTrue(multiQueueAuthenticator.isRestricted(queueType)) + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) - Mockito.doReturn(false).`when`(multiQueueAuthenticator).removeRestriction(queueType) + Mockito.doReturn(false).`when`(multiQueueAuthenticator).removeRestriction(subQueue) mockMvc.perform( - MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${subQueue}") .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isInternalServerError) @@ -317,30 +317,30 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_removeButDontClearQueue() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRemoveRestrictionFromSubQueue_removeButDontClearQueue" - val token = jwtTokenProvider.createTokenForSubQueue(queueType) + val subQueue = "testRemoveRestrictionFromSubQueue_removeButDontClearQueue" + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) Assertions.assertTrue(token.isPresent) - Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(queueType)) - Assertions.assertTrue(multiQueueAuthenticator.isRestricted(queueType)) + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) multiQueue.clear() try { - Assertions.assertTrue(multiQueue.add(QueueMessage("a payload", queueType))) + Assertions.assertTrue(multiQueue.add(QueueMessage("a payload", subQueue))) Assertions.assertEquals(1, multiQueue.size) mockMvc.perform( - MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}") + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${subQueue}") .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) Assertions.assertEquals(1, multiQueue.size) - Assertions.assertFalse(multiQueueAuthenticator.isRestricted(queueType)) + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) } finally { @@ -356,30 +356,30 @@ class AuthControllerTest @Test fun testRemoveRestrictionFromSubQueue_removeAndClearQueue() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) - val queueType = "testRemoveRestrictionFromSubQueue_removeAndClearQueue" - val token = jwtTokenProvider.createTokenForSubQueue(queueType) + val subQueue = "testRemoveRestrictionFromSubQueue_removeAndClearQueue" + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) Assertions.assertTrue(token.isPresent) - Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(queueType)) - Assertions.assertTrue(multiQueueAuthenticator.isRestricted(queueType)) + Assertions.assertTrue(multiQueueAuthenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(multiQueueAuthenticator.isRestricted(subQueue)) multiQueue.clear() try { - Assertions.assertTrue(multiQueue.add(QueueMessage("a payload", queueType))) + Assertions.assertTrue(multiQueue.add(QueueMessage("a payload", subQueue))) Assertions.assertEquals(1, multiQueue.size) mockMvc.perform( - MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${queueType}?${RestParameters.CLEAR_QUEUE}=true") + MockMvcRequestBuilders.delete("${AuthController.AUTH_PATH}/${subQueue}?${RestParameters.CLEAR_QUEUE}=true") .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) Assertions.assertEquals(0, multiQueue.size) - Assertions.assertFalse(multiQueueAuthenticator.isRestricted(queueType)) + Assertions.assertFalse(multiQueueAuthenticator.isRestricted(subQueue)) } finally { @@ -394,8 +394,8 @@ class AuthControllerTest @Test fun testGetRestrictedSubQueueIdentifiers_inNoneMode() { - Mockito.doReturn(RestrictionMode.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.NONE).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.NONE, multiQueueAuthenticator.getRestrictionMode()) mockMvc.perform(MockMvcRequestBuilders.get(AuthController.AUTH_PATH) .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -410,8 +410,8 @@ class AuthControllerTest @Test fun testGetRestrictedSubQueueIdentifiers_notInNoneMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, multiQueueAuthenticator.getRestrictionMode()) val restrictedIdentifiers = setOf("testGetRestrictedSubQueueIdentifiers_inNoneMode1", "testGetRestrictedSubQueueIdentifiers_inNoneMode2", "testGetRestrictedSubQueueIdentifiers_inNoneMode3", "testGetRestrictedSubQueueIdentifiers_inNoneMode4", "testGetRestrictedSubQueueIdentifiers_inNoneMode5") diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt index 5bbb6d5..b6f2aed 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/MessageQueueControllerTest.kt @@ -90,53 +90,53 @@ class MessageQueueControllerTest } /** - * Test [MessageQueueController.getQueueTypeInfo] to ensure the correct information is returned for the specified - * `queueType`. + * Test [MessageQueueController.getSubQueueInfo] to ensure the correct information is returned for the specified + * `sub-queue`. */ @Test - fun testGetQueueTypeInfo() + fun testGetSubQueueInfo() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val queueType = "testGetQueueTypeInfo" - Assertions.assertEquals(0, multiQueue.getQueueForType(queueType).size) - mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_TYPE + "/" + queueType) + val subQueue = "testGetSubQueueInfo" + Assertions.assertEquals(0, multiQueue.getSubQueue(subQueue).size) + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_TYPE + "/" + subQueue) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) .andExpect(MockMvcResultMatchers.content().json("0")) - val message = createQueueMessage(type = queueType) + val message = createQueueMessage(subQueue = subQueue) Assertions.assertTrue(multiQueue.add(message)) - Assertions.assertEquals(1, multiQueue.getQueueForType(queueType).size) + Assertions.assertEquals(1, multiQueue.getSubQueue(subQueue).size) - mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_TYPE + "/" + queueType) + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_TYPE + "/" + subQueue) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) .andExpect(MockMvcResultMatchers.content().json("1")) } /** - * Test [MessageQueueController.getAllQueueTypeInfo] to ensure that information for all `queue type`s is returned - * when no `queue type` is specified. + * Test [MessageQueueController.getAllQueueInfo] to ensure that information for all `sub-queue`s is returned + * when no `sub-queue` is specified. */ @Test - fun testGetAllQueueTypeInfo() + fun testGetAllSubQueueInfo() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_TYPE) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) .andExpect(MockMvcResultMatchers.content().json("0")) - val message = createQueueMessage(type = "testGetAllQueueTypeInfo_type1") - val message2 = createQueueMessage(type = "testGetAllQueueTypeInfo_type2") + val message = createQueueMessage(subQueue = "testGetAllSubQueueInfo1") + val message2 = createQueueMessage(subQueue = "testGetAllSubQueueInfo2") Assertions.assertTrue(multiQueue.add(message)) Assertions.assertTrue(multiQueue.add(message2)) - Assertions.assertEquals(1, multiQueue.getQueueForType(message.type).size) - Assertions.assertEquals(1, multiQueue.getQueueForType(message2.type).size) + Assertions.assertEquals(1, multiQueue.getSubQueue(message.subQueue).size) + Assertions.assertEquals(1, multiQueue.getSubQueue(message2.subQueue).size) Assertions.assertEquals(2, multiQueue.size) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_TYPE) @@ -152,9 +152,9 @@ class MessageQueueControllerTest @Test fun testGetEntry() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testGetEntry") + val message = createQueueMessage(subQueue = "testGetEntry") Assertions.assertTrue(multiQueue.add(message)) @@ -168,8 +168,8 @@ class MessageQueueControllerTest val deserialisedPayload = gson.fromJson(gson.toJson(messageResponse.message.payload), Payload::class.java) Assertions.assertEquals(message.payload, deserialisedPayload) Assertions.assertNull(messageResponse.message.assignedTo) - Assertions.assertEquals(message.type, messageResponse.message.type) - Assertions.assertEquals(message.type, messageResponse.queueType) + Assertions.assertEquals(message.subQueue, messageResponse.message.subQueue) + Assertions.assertEquals(message.subQueue, messageResponse.subQueue) Assertions.assertNotNull(messageResponse.message.uuid) } @@ -180,7 +180,7 @@ class MessageQueueControllerTest @Test fun testGetEntry_ResponseBody_NotExists() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val uuid = "invalid-not-found-uuid" mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + uuid) @@ -195,17 +195,17 @@ class MessageQueueControllerTest @Test fun testGetEntry_usingHybridMode_withRestrictedSubQueue() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) val entries = initialiseMapWithEntries() - val type1 = entries.second[0] + val subQueue1 = entries.second[0] val message1 = entries.first[0] - val type1Token = jwtTokenProvider.createTokenForSubQueue(type1) - Assertions.assertTrue(type1Token.isPresent) - Assertions.assertTrue(authenticator.addRestrictedEntry(type1)) - Assertions.assertTrue(authenticator.isRestricted(type1)) + val subQueue1Token = jwtTokenProvider.createTokenForSubQueue(subQueue1) + Assertions.assertTrue(subQueue1Token.isPresent) + Assertions.assertTrue(authenticator.addRestrictedEntry(subQueue1)) + Assertions.assertTrue(authenticator.isRestricted(subQueue1)) // Make sure we cannot access without a token mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message1.uuid) @@ -214,7 +214,7 @@ class MessageQueueControllerTest // Checking entry is retrieve with provided token val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message1.uuid) - .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${type1Token.get()}") + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${subQueue1Token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -224,17 +224,17 @@ class MessageQueueControllerTest val deserialisedPayload = gson.fromJson(gson.toJson(messageResponse.message.payload), Payload::class.java) Assertions.assertEquals(message1.payload, deserialisedPayload) Assertions.assertNull(messageResponse.message.assignedTo) - Assertions.assertEquals(message1.type, messageResponse.message.type) - Assertions.assertEquals(message1.type, messageResponse.queueType) + Assertions.assertEquals(message1.subQueue, messageResponse.message.subQueue) + Assertions.assertEquals(message1.subQueue, messageResponse.subQueue) Assertions.assertNotNull(messageResponse.message.uuid) - val type2 = entries.second[1] + val subQueue2 = entries.second[1] val message2 = entries.first[1] - Assertions.assertFalse(authenticator.isRestricted(type2)) + Assertions.assertFalse(authenticator.isRestricted(subQueue2)) // Check un-restricted entry is still accessible without a token val mvcResult2: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message2.uuid) - .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${type1Token.get()}") + .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${subQueue1Token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -244,8 +244,8 @@ class MessageQueueControllerTest val deserialisedPayload2 = gson.fromJson(gson.toJson(messageResponse2.message.payload), Payload::class.java) Assertions.assertEquals(message2.payload, deserialisedPayload2) Assertions.assertNull(messageResponse2.message.assignedTo) - Assertions.assertEquals(message2.type, messageResponse2.message.type) - Assertions.assertEquals(message2.type, messageResponse2.queueType) + Assertions.assertEquals(message2.subQueue, messageResponse2.message.subQueue) + Assertions.assertEquals(message2.subQueue, messageResponse2.subQueue) Assertions.assertNotNull(messageResponse2.message.uuid) } @@ -256,9 +256,9 @@ class MessageQueueControllerTest @Test fun testCreateQueueEntry_withProvidedDefaults() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testCreateQueueEntry_withProvidedDefaults", assignedTo = "user-1") + val message = createQueueMessage(subQueue = "testCreateQueueEntry_withProvidedDefaults", assignedTo = "user-1") val mvcResult: MvcResult = mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) .contentType(MediaType.APPLICATION_JSON_VALUE) @@ -271,13 +271,13 @@ class MessageQueueControllerTest val deserialisedPayload = gson.fromJson(gson.toJson(messageResponse.message.payload), Payload::class.java) Assertions.assertEquals(message.payload, deserialisedPayload) Assertions.assertEquals(message.assignedTo, messageResponse.message.assignedTo) - Assertions.assertEquals(message.type, messageResponse.message.type) - Assertions.assertEquals(message.type, messageResponse.queueType) + Assertions.assertEquals(message.subQueue, messageResponse.message.subQueue) + Assertions.assertEquals(message.subQueue, messageResponse.subQueue) Assertions.assertEquals(message.uuid, messageResponse.message.uuid) - val createdMessage = multiQueue.peekForType(message.type).get() + val createdMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertEquals(message.assignedTo, createdMessage.assignedTo) - Assertions.assertEquals(message.type, createdMessage.type) + Assertions.assertEquals(message.subQueue, createdMessage.subQueue) Assertions.assertEquals(message.uuid, createdMessage.uuid) } @@ -288,9 +288,9 @@ class MessageQueueControllerTest @Test fun testCreateQueueEntry_withOutDefaults() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testCreateQueueEntry_withOutDefaults") + val message = createQueueMessage(subQueue = "testCreateQueueEntry_withOutDefaults") val mvcResult: MvcResult = mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) .contentType(MediaType.APPLICATION_JSON_VALUE) @@ -303,13 +303,13 @@ class MessageQueueControllerTest val deserialisedPayload = gson.fromJson(gson.toJson(messageResponse.message.payload), Payload::class.java) Assertions.assertEquals(message.payload, deserialisedPayload) Assertions.assertNull(messageResponse.message.assignedTo) - Assertions.assertEquals(message.type, messageResponse.message.type) - Assertions.assertEquals(message.type, messageResponse.queueType) + Assertions.assertEquals(message.subQueue, messageResponse.message.subQueue) + Assertions.assertEquals(message.subQueue, messageResponse.subQueue) Assertions.assertNotNull(messageResponse.message.uuid) - val createdMessage = multiQueue.peekForType(message.type).get() + val createdMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertNull(createdMessage.assignedTo) - Assertions.assertEquals(message.type, createdMessage.type) + Assertions.assertEquals(message.subQueue, createdMessage.subQueue) Assertions.assertEquals(message.uuid, createdMessage.uuid) } @@ -320,9 +320,9 @@ class MessageQueueControllerTest @Test fun testCreateEntry_Conflict() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testCreateEntry_Conflict") + val message = createQueueMessage(subQueue = "testCreateEntry_Conflict") Assertions.assertTrue(multiQueue.add(message)) @@ -339,9 +339,9 @@ class MessageQueueControllerTest @Test fun testCreateQueueEntry_withBlankAssignedTo() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testCreateQueueEntry_withAssignedButNoAssignedTo") + val message = createQueueMessage(subQueue = "testCreateQueueEntry_withAssignedButNoAssignedTo") message.assignedTo = " " val mvcResult: MvcResult = mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) @@ -361,15 +361,15 @@ class MessageQueueControllerTest @Test fun testCreateEntry_inHybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testCreateEntry_inHybridMode") + val message = createQueueMessage(subQueue = "testCreateEntry_inHybridMode") - Assertions.assertTrue(authenticator.addRestrictedEntry(message.type)) - Assertions.assertTrue(authenticator.isRestricted(message.type)) + Assertions.assertTrue(authenticator.addRestrictedEntry(message.subQueue)) + Assertions.assertTrue(authenticator.isRestricted(message.subQueue)) - val token = jwtTokenProvider.createTokenForSubQueue(message.type) + val token = jwtTokenProvider.createTokenForSubQueue(message.subQueue) Assertions.assertTrue(token.isPresent) mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) @@ -383,8 +383,8 @@ class MessageQueueControllerTest .content(gson.toJson(message))) .andExpect(MockMvcResultMatchers.status().isCreated) - val message2 = createQueueMessage(type = "testCreateEntry_inHybridMode2") - Assertions.assertFalse(authenticator.isRestricted(message2.type)) + val message2 = createQueueMessage(subQueue = "testCreateEntry_inHybridMode2") + Assertions.assertFalse(authenticator.isRestricted(message2.subQueue)) mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) .contentType(MediaType.APPLICATION_JSON_VALUE) @@ -399,7 +399,7 @@ class MessageQueueControllerTest @Test fun testGetKeys() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val entries = initialiseMapWithEntries() @@ -411,12 +411,12 @@ class MessageQueueControllerTest val keys = gson.fromJson(mvcResult.response.contentAsString, List::class.java) Assertions.assertFalse(keys.isNullOrEmpty()) Assertions.assertEquals(entries.second.size, keys.size) - entries.second.forEach { type -> Assertions.assertTrue(keys.contains(type)) } + entries.second.forEach { subQueue -> Assertions.assertTrue(keys.contains(subQueue)) } val mapKeys = multiQueue.keys(true) Assertions.assertFalse(mapKeys.isEmpty()) Assertions.assertEquals(entries.second.size, mapKeys.size) - entries.second.forEach { type -> Assertions.assertTrue(mapKeys.contains(type)) } + entries.second.forEach { subQueue -> Assertions.assertTrue(mapKeys.contains(subQueue)) } } /** @@ -426,7 +426,7 @@ class MessageQueueControllerTest @Test fun testGetKeys_excludeEmpty() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val entries = initialiseMapWithEntries() Assertions.assertTrue(multiQueue.remove(entries.first[0])) @@ -441,27 +441,27 @@ class MessageQueueControllerTest val keys = gson.fromJson(mvcResult.response.contentAsString, List::class.java) Assertions.assertFalse(keys.isNullOrEmpty()) Assertions.assertEquals(2, keys.size) - entries.second.subList(2, 3).forEach { type -> Assertions.assertTrue(keys.contains(type)) } + entries.second.subList(2, 3).forEach { subQueue -> Assertions.assertTrue(keys.contains(subQueue)) } val mapKeys = multiQueue.keys(false) Assertions.assertFalse(mapKeys.isEmpty()) Assertions.assertEquals(2, mapKeys.size) - entries.second.subList(2, 3).forEach { type -> Assertions.assertTrue(mapKeys.contains(type)) } + entries.second.subList(2, 3).forEach { subQueue -> Assertions.assertTrue(mapKeys.contains(subQueue)) } } /** - * Test [MessageQueueController.getAll] to ensure that all entries are returned from all `queueTypes` when no - * explicit `queueType` is provided. + * Test [MessageQueueController.getAll] to ensure that all entries are returned from all `sub-queues` when no + * explicit `sub-queue` is provided. * This also checks the returned object has a `non-null` value in the payload since the `detailed` flag is set to * `true`. */ @Test fun testGetAll() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val entries = initialiseMapWithEntries() - val type = entries.first[0].type + val subQueue = entries.first[0].subQueue val detailed = true val mvcResult: MvcResult = mockMvc.perform(get("${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}/${MessageQueueController.ENDPOINT_ALL}?${RestParameters.DETAILED}=$detailed") @@ -473,32 +473,32 @@ class MessageQueueControllerTest val keys = gson.fromJson>>(mvcResult.response.contentAsString, mapType) Assertions.assertNotNull(keys) Assertions.assertEquals(entries.second.size, keys.keys.size) - entries.second.forEach { typeString -> Assertions.assertTrue(keys.keys.contains(typeString)) } + entries.second.forEach { subQueueId -> Assertions.assertTrue(keys.keys.contains(subQueueId)) } keys.values.forEach { detailList -> Assertions.assertEquals(1, detailList.size) } - Assertions.assertEquals(entries.first[0].removePayload(detailed).uuid, keys[type]!![0].uuid) + Assertions.assertEquals(entries.first[0].removePayload(detailed).uuid, keys[subQueue]!![0].uuid) // Since we passed in true for the detailed flag, ensure the payload is equal - val payloadObject = gson.fromJson(keys[type]!![0].payload.toString(), Payload::class.java) + val payloadObject = gson.fromJson(keys[subQueue]!![0].payload.toString(), Payload::class.java) Assertions.assertEquals(entries.first[0].payload, payloadObject) - Assertions.assertEquals(entries.first[0].removePayload(detailed).assignedTo, keys[type]!![0].assignedTo) - Assertions.assertEquals(entries.first[0].removePayload(detailed).type, keys[type]!![0].type) + Assertions.assertEquals(entries.first[0].removePayload(detailed).assignedTo, keys[subQueue]!![0].assignedTo) + Assertions.assertEquals(entries.first[0].removePayload(detailed).subQueue, keys[subQueue]!![0].subQueue) } /** - * Test [MessageQueueController.getAll] to ensure that all entries are returned from the `queueType` when an - * explicit `queueType` is provided. + * Test [MessageQueueController.getAll] to ensure that all entries are returned from the `sub-queue` when an + * explicit `sub-queue` is provided. * This also checks the returned object has `null` in the payload since the `detailed` flag is not provided. */ @Test - fun testGetAll_SpecificQueueType() + fun testGetAll_SpecificSubQueue() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val entries = initialiseMapWithEntries() - val type = entries.first[0].type + val subQueue = entries.first[0].subQueue val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ALL) .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, type)) + .param(RestParameters.SUB_QUEUE, subQueue)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -506,13 +506,13 @@ class MessageQueueControllerTest val keys = gson.fromJson>>(mvcResult.response.contentAsString, mapType) Assertions.assertNotNull(keys) Assertions.assertEquals(1, keys.keys.size) - Assertions.assertTrue(keys.keys.contains(type)) + Assertions.assertTrue(keys.keys.contains(subQueue)) keys.values.forEach { detailList -> Assertions.assertEquals(1, detailList.size) } - Assertions.assertEquals(entries.first[0].removePayload(false).uuid, keys[type]!![0].uuid) + Assertions.assertEquals(entries.first[0].removePayload(false).uuid, keys[subQueue]!![0].uuid) // Since we did not pass a detailed flag value, ensure the payload is a placeholder value Assertions.assertEquals("***", entries.first[0].removePayload(false).payload) - Assertions.assertEquals(entries.first[0].removePayload(false).assignedTo, keys[type]!![0].assignedTo) - Assertions.assertEquals(entries.first[0].removePayload(false).type, keys[type]!![0].type) + Assertions.assertEquals(entries.first[0].removePayload(false).assignedTo, keys[subQueue]!![0].assignedTo) + Assertions.assertEquals(entries.first[0].removePayload(false).subQueue, keys[subQueue]!![0].subQueue) } /** @@ -522,24 +522,24 @@ class MessageQueueControllerTest @Test fun testGetAll_inHybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) - val queueType = "testGetAll_inHybridMode" - val messages = listOf(createQueueMessage(queueType), createQueueMessage(queueType)) + val subQueue = "testGetAll_inHybridMode" + val messages = listOf(createQueueMessage(subQueue), createQueueMessage(subQueue)) messages.forEach { message -> Assertions.assertTrue(multiQueue.add(message)) } - Assertions.assertTrue(authenticator.addRestrictedEntry(queueType)) - Assertions.assertTrue(authenticator.isRestricted(queueType)) + Assertions.assertTrue(authenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(authenticator.isRestricted(subQueue)) - val token = jwtTokenProvider.createTokenForSubQueue(queueType) + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) Assertions.assertTrue(token.isPresent) val entries = initialiseMapWithEntries() - entries.second.forEach { type -> Assertions.assertFalse(authenticator.isRestricted(type)) } + entries.second.forEach { subQueueId -> Assertions.assertFalse(authenticator.isRestricted(subQueueId)) } val detailed = true - // Ensure the message in the restricted queue type are not returned + // Ensure the message in the restricted sub-queue are not returned var mvcResult: MvcResult = mockMvc.perform(get("${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}/${MessageQueueController.ENDPOINT_ALL}?${RestParameters.DETAILED}=$detailed") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isOk) @@ -550,8 +550,8 @@ class MessageQueueControllerTest Assertions.assertNotNull(keys) Assertions.assertEquals(entries.second.size, keys.keys.size) - Assertions.assertFalse(keys.keys.contains(queueType)) - Assertions.assertNull(keys[queueType]) + Assertions.assertFalse(keys.keys.contains(subQueue)) + Assertions.assertNull(keys[subQueue]) // After providing the token we should see the messages for the restricted queue mvcResult = mockMvc.perform(get("${MessageQueueController.MESSAGE_QUEUE_BASE_PATH}/${MessageQueueController.ENDPOINT_ALL}?${RestParameters.DETAILED}=$detailed") @@ -564,8 +564,8 @@ class MessageQueueControllerTest Assertions.assertNotNull(keys) Assertions.assertEquals(entries.second.size + 1, keys.keys.size) - Assertions.assertTrue(keys.keys.contains(queueType)) - Assertions.assertNotNull(keys[queueType]) + Assertions.assertTrue(keys.keys.contains(subQueue)) + Assertions.assertNotNull(keys[subQueue]) } /** @@ -573,30 +573,30 @@ class MessageQueueControllerTest * and all messages are requested for a restricted queue are not accessible unless a token is provided. */ @Test - fun testGetAll_SpecificQueueType_inHybridMode() + fun testGetAll_SpecificSubQueue_inHybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) - val queueType = "testGetAll_SpecificQueueType_inHybridMode" - val messages = listOf(createQueueMessage(queueType), createQueueMessage(queueType)) + val subQueue = "testGetAll_SpecificSubQueue_inHybridMode" + val messages = listOf(createQueueMessage(subQueue), createQueueMessage(subQueue)) messages.forEach { message -> Assertions.assertTrue(multiQueue.add(message)) } - Assertions.assertTrue(authenticator.addRestrictedEntry(queueType)) - Assertions.assertTrue(authenticator.isRestricted(queueType)) + Assertions.assertTrue(authenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(authenticator.isRestricted(subQueue)) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ALL) .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, queueType)) + .param(RestParameters.SUB_QUEUE, subQueue)) .andExpect(MockMvcResultMatchers.status().isForbidden) - val token = jwtTokenProvider.createTokenForSubQueue(queueType) + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) Assertions.assertTrue(token.isPresent) val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ALL) .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, queueType)) + .param(RestParameters.SUB_QUEUE, subQueue)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -605,9 +605,9 @@ class MessageQueueControllerTest Assertions.assertNotNull(keys) Assertions.assertEquals(1, keys.keys.size) - Assertions.assertTrue(keys.keys.contains(queueType)) - Assertions.assertNotNull(keys[queueType]) - Assertions.assertEquals(2, keys[queueType]!!.size) + Assertions.assertTrue(keys.keys.contains(subQueue)) + Assertions.assertNotNull(keys[subQueue]) + Assertions.assertEquals(2, keys[subQueue]!!.size) } /** @@ -617,7 +617,7 @@ class MessageQueueControllerTest @Test fun testGetOwned_NoneOwned() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val entries = initialiseMapWithEntries() val assignedTo = "my-assigned-to-identifier" @@ -625,7 +625,7 @@ class MessageQueueControllerTest val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_OWNED) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo) - .param(RestParameters.QUEUE_TYPE, entries.first[0].type)) + .param(RestParameters.SUB_QUEUE, entries.first[0].subQueue)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -641,12 +641,12 @@ class MessageQueueControllerTest @Test fun testGetOwned_SomeOwned() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "my-assigned-to-identifier" - val type = "testGetOwned_SomeOwned" - val message1 = createQueueMessage(assignedTo = assignedTo, type = type) - val message2 = createQueueMessage(assignedTo = assignedTo, type = type) + val subQueue = "testGetOwned_SomeOwned" + val message1 = createQueueMessage(assignedTo = assignedTo, subQueue = subQueue) + val message2 = createQueueMessage(assignedTo = assignedTo, subQueue = subQueue) Assertions.assertTrue(multiQueue.add(message1)) Assertions.assertTrue(multiQueue.add(message2)) @@ -654,7 +654,7 @@ class MessageQueueControllerTest val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_OWNED) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo) - .param(RestParameters.QUEUE_TYPE, type)) + .param(RestParameters.SUB_QUEUE, subQueue)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -663,8 +663,8 @@ class MessageQueueControllerTest Assertions.assertTrue(owned.isNotEmpty()) owned.forEach { message -> Assertions.assertTrue(message.message.uuid == message1.uuid || message.message.uuid == message2.uuid) - Assertions.assertEquals(type, message.queueType) - Assertions.assertEquals(type, message.message.type) + Assertions.assertEquals(subQueue, message.subQueue) + Assertions.assertEquals(subQueue, message.message.subQueue) Assertions.assertEquals(assignedTo, message.message.assignedTo) } } @@ -676,34 +676,34 @@ class MessageQueueControllerTest @Test fun testGetOwned_SomeOwned_inHybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) val assignedTo = "my-assigned-to-identifier" - val type = "testGetOwned_SomeOwned_inHybridMode" - val message1 = createQueueMessage(assignedTo = assignedTo, type = type) - val message2 = createQueueMessage(assignedTo = assignedTo, type = type) + val subQueue = "testGetOwned_SomeOwned_inHybridMode" + val message1 = createQueueMessage(assignedTo = assignedTo, subQueue = subQueue) + val message2 = createQueueMessage(assignedTo = assignedTo, subQueue = subQueue) Assertions.assertTrue(multiQueue.add(message1)) Assertions.assertTrue(multiQueue.add(message2)) - Assertions.assertTrue(authenticator.addRestrictedEntry(type)) - Assertions.assertTrue(authenticator.isRestricted(type)) + Assertions.assertTrue(authenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(authenticator.isRestricted(subQueue)) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_OWNED) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo) - .param(RestParameters.QUEUE_TYPE, type)) + .param(RestParameters.SUB_QUEUE, subQueue)) .andExpect(MockMvcResultMatchers.status().isForbidden) - val token = jwtTokenProvider.createTokenForSubQueue(type) + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) Assertions.assertTrue(token.isPresent) val mvcResult: MvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_OWNED) .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo) - .param(RestParameters.QUEUE_TYPE, type)) + .param(RestParameters.SUB_QUEUE, subQueue)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -712,8 +712,8 @@ class MessageQueueControllerTest Assertions.assertTrue(owned.isNotEmpty()) owned.forEach { message -> Assertions.assertTrue(message.message.uuid == message1.uuid || message.message.uuid == message2.uuid) - Assertions.assertEquals(type, message.queueType) - Assertions.assertEquals(type, message.message.type) + Assertions.assertEquals(subQueue, message.subQueue) + Assertions.assertEquals(subQueue, message.message.subQueue) Assertions.assertEquals(assignedTo, message.message.assignedTo) } } @@ -725,7 +725,7 @@ class MessageQueueControllerTest @Test fun testAssignMessage_doesNotExist() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val uuid = UUID.randomUUID().toString() val assignedTo = "assigned" @@ -742,10 +742,10 @@ class MessageQueueControllerTest @Test fun testAssignMessage_messageIsAssigned() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assigned" - val message = createQueueMessage(type = "testAssignMessage_messageIsAssigned") + val message = createQueueMessage(subQueue = "testAssignMessage_messageIsAssigned") Assertions.assertNull(message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) @@ -759,7 +759,7 @@ class MessageQueueControllerTest Assertions.assertEquals(assignedTo, messageResponse.message.assignedTo) Assertions.assertEquals(message.uuid, messageResponse.message.uuid) - val assignedMessage = multiQueue.peekForType(message.type).get() + val assignedMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertEquals(assignedTo, assignedMessage.assignedTo) Assertions.assertEquals(message.uuid, assignedMessage.uuid) } @@ -771,23 +771,23 @@ class MessageQueueControllerTest @Test fun testAssignMessage_messageIsAssigned_inHybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) val assignedTo = "assigned" - val message = createQueueMessage(type = "testAssignMessage_messageIsAssigned_inHybridMode") + val message = createQueueMessage(subQueue = "testAssignMessage_messageIsAssigned_inHybridMode") Assertions.assertNull(message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) - Assertions.assertTrue(authenticator.addRestrictedEntry(message.type)) - Assertions.assertTrue(authenticator.isRestricted(message.type)) + Assertions.assertTrue(authenticator.addRestrictedEntry(message.subQueue)) + Assertions.assertTrue(authenticator.isRestricted(message.subQueue)) mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_ASSIGN) .contentType(MediaType.APPLICATION_JSON_VALUE) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isForbidden) - val token = jwtTokenProvider.createTokenForSubQueue(message.type) + val token = jwtTokenProvider.createTokenForSubQueue(message.subQueue) Assertions.assertTrue(token.isPresent) val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_ASSIGN) @@ -801,7 +801,7 @@ class MessageQueueControllerTest Assertions.assertEquals(assignedTo, messageResponse.message.assignedTo) Assertions.assertEquals(message.uuid, messageResponse.message.uuid) - val assignedMessage = multiQueue.peekForType(message.type).get() + val assignedMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertEquals(assignedTo, assignedMessage.assignedTo) Assertions.assertEquals(message.uuid, assignedMessage.uuid) } @@ -814,10 +814,10 @@ class MessageQueueControllerTest @Test fun testAssignMessage_alreadyAssignedToSameID() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assigned" - val message = createQueueMessage(type = "testAssignMessage_alreadyAssignedToSameID", assignedTo = assignedTo) + val message = createQueueMessage(subQueue = "testAssignMessage_alreadyAssignedToSameID", assignedTo = assignedTo) Assertions.assertEquals(assignedTo, message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) @@ -832,7 +832,7 @@ class MessageQueueControllerTest Assertions.assertEquals(message.assignedTo, messageResponse.message.assignedTo) Assertions.assertEquals(message.uuid, messageResponse.message.uuid) - val assignedMessage = multiQueue.peekForType(message.type).get() + val assignedMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertEquals(assignedTo, assignedMessage.assignedTo) Assertions.assertEquals(message.uuid, assignedMessage.uuid) } @@ -844,16 +844,16 @@ class MessageQueueControllerTest @Test fun testAssignMessage_alreadyAssignedToOtherID() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assignee" - val message = createQueueMessage(type = "testAssignMessage_alreadyAssignedToOtherID", assignedTo = assignedTo) + val message = createQueueMessage(subQueue = "testAssignMessage_alreadyAssignedToOtherID", assignedTo = assignedTo) Assertions.assertEquals(assignedTo, message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) // Check the message is set correctly - var assignedMessage = multiQueue.peekForType(message.type).get() + var assignedMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertEquals(assignedTo, assignedMessage.assignedTo) Assertions.assertEquals(message.uuid, assignedMessage.uuid) @@ -864,29 +864,29 @@ class MessageQueueControllerTest .andExpect(MockMvcResultMatchers.status().isConflict) // Check the message is still assigned to the correct ID - assignedMessage = multiQueue.peekForType(message.type).get() + assignedMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertEquals(assignedTo, assignedMessage.assignedTo) Assertions.assertEquals(message.uuid, assignedMessage.uuid) } /** * Test [MessageQueueController.getNext] to ensure [HttpStatus.NO_CONTENT] is returned when there are no - * [QueueMessage]s available for the provided `queueType`. + * [QueueMessage]s available for the provided `sub-queue`. */ @Test fun testGetNext_noNewMessages() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assignee" - val type = "testGetNext_noNewMessages" + val subQueue = "testGetNext_noNewMessages" mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT) .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, type) + .param(RestParameters.SUB_QUEUE, subQueue) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isNoContent) - Assertions.assertTrue(multiQueue.getQueueForType(type).isEmpty()) + Assertions.assertTrue(multiQueue.getSubQueue(subQueue).isEmpty()) } /** @@ -896,21 +896,21 @@ class MessageQueueControllerTest @Test fun testGetNext_noNewUnAssignedMessages() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assignee" - val type = "testGetNext_noNewUnAssignedMessages" - val message = createQueueMessage(type = type, assignedTo = assignedTo) - val message2 = createQueueMessage(type = type, assignedTo = assignedTo) + val subQueue = "testGetNext_noNewUnAssignedMessages" + val message = createQueueMessage(subQueue = subQueue, assignedTo = assignedTo) + val message2 = createQueueMessage(subQueue = subQueue, assignedTo = assignedTo) Assertions.assertTrue(multiQueue.add(message)) Assertions.assertTrue(multiQueue.add(message2)) - Assertions.assertFalse(multiQueue.getQueueForType(type).isEmpty()) + Assertions.assertFalse(multiQueue.getSubQueue(subQueue).isEmpty()) mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT) .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, type) + .param(RestParameters.SUB_QUEUE, subQueue) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isNoContent) } @@ -922,23 +922,23 @@ class MessageQueueControllerTest @Test fun testGetNext() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assignee" - val type = "testGetNext" - val message = createQueueMessage(type = type, assignedTo = assignedTo) - val message2 = createQueueMessage(type = type) + val subQueue = "testGetNext" + val message = createQueueMessage(subQueue = subQueue, assignedTo = assignedTo) + val message2 = createQueueMessage(subQueue = subQueue) Assertions.assertTrue(multiQueue.add(message)) Assertions.assertTrue(multiQueue.add(message2)) - val storedMessage2 = multiQueue.getQueueForType(type).stream().filter{ m -> m.uuid == message2.uuid }.findFirst().get() + val storedMessage2 = multiQueue.getSubQueue(subQueue).stream().filter{ m -> m.uuid == message2.uuid }.findFirst().get() Assertions.assertNull(storedMessage2.assignedTo) Assertions.assertEquals(message2.uuid, storedMessage2.uuid) val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT) .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, type) + .param(RestParameters.SUB_QUEUE, subQueue) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -947,7 +947,7 @@ class MessageQueueControllerTest Assertions.assertEquals(assignedTo, messageResponse.message.assignedTo) Assertions.assertEquals(message2.uuid, messageResponse.message.uuid) - val assignedMessage2 = multiQueue.getQueueForType(type).stream().filter{ m -> m.uuid == message2.uuid }.findFirst().get() + val assignedMessage2 = multiQueue.getSubQueue(subQueue).stream().filter{ m -> m.uuid == message2.uuid }.findFirst().get() Assertions.assertEquals(assignedTo, assignedMessage2.assignedTo) Assertions.assertEquals(message2.uuid, assignedMessage2.uuid) } @@ -959,37 +959,37 @@ class MessageQueueControllerTest @Test fun testGetNext_inHybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) val assignedTo = "assignee" - val type = "testGetNext_inHybridMode" - val message = createQueueMessage(type = type, assignedTo = assignedTo) - val message2 = createQueueMessage(type = type) + val subQueue = "testGetNext_inHybridMode" + val message = createQueueMessage(subQueue = subQueue, assignedTo = assignedTo) + val message2 = createQueueMessage(subQueue = subQueue) Assertions.assertTrue(multiQueue.add(message)) Assertions.assertTrue(multiQueue.add(message2)) - Assertions.assertTrue(authenticator.addRestrictedEntry(type)) - Assertions.assertTrue(authenticator.isRestricted(type)) + Assertions.assertTrue(authenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(authenticator.isRestricted(subQueue)) - val storedMessage2 = multiQueue.getQueueForType(type).stream().filter{ m -> m.uuid == message2.uuid }.findFirst().get() + val storedMessage2 = multiQueue.getSubQueue(subQueue).stream().filter{ m -> m.uuid == message2.uuid }.findFirst().get() Assertions.assertNull(storedMessage2.assignedTo) Assertions.assertEquals(message2.uuid, storedMessage2.uuid) mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT) .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, type) + .param(RestParameters.SUB_QUEUE, subQueue) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isForbidden) - val token = jwtTokenProvider.createTokenForSubQueue(type) + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) Assertions.assertTrue(token.isPresent) val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT) .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, type) + .param(RestParameters.SUB_QUEUE, subQueue) .param(RestParameters.ASSIGNED_TO, assignedTo)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -998,7 +998,7 @@ class MessageQueueControllerTest Assertions.assertEquals(assignedTo, messageResponse.message.assignedTo) Assertions.assertEquals(message2.uuid, messageResponse.message.uuid) - val assignedMessage2 = multiQueue.getQueueForType(type).stream().filter{ m -> m.uuid == message2.uuid }.findFirst().get() + val assignedMessage2 = multiQueue.getSubQueue(subQueue).stream().filter{ m -> m.uuid == message2.uuid }.findFirst().get() Assertions.assertEquals(assignedTo, assignedMessage2.assignedTo) Assertions.assertEquals(message2.uuid, assignedMessage2.uuid) } @@ -1010,7 +1010,7 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_doesNotExist() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val uuid = UUID.randomUUID().toString() mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + uuid + MessageQueueController.ENDPOINT_RELEASE) @@ -1025,10 +1025,10 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_messageIsReleased() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assignee" - val message = createQueueMessage(type = "testReleaseMessage_messageIsReleased", assignedTo = assignedTo) + val message = createQueueMessage(subQueue = "testReleaseMessage_messageIsReleased", assignedTo = assignedTo) Assertions.assertEquals(assignedTo, message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) @@ -1043,7 +1043,7 @@ class MessageQueueControllerTest Assertions.assertNull(messageResponse.message.assignedTo) Assertions.assertEquals(message.uuid, messageResponse.message.uuid) - val updatedMessage = multiQueue.peekForType(message.type).get() + val updatedMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertNull(updatedMessage.assignedTo) Assertions.assertEquals(message.uuid, updatedMessage.uuid) } @@ -1055,17 +1055,17 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_messageIsReleased_inHybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) val assignedTo = "assignee" - val message = createQueueMessage(type = "testReleaseMessage_messageIsReleased_inHybridMode", assignedTo = assignedTo) + val message = createQueueMessage(subQueue = "testReleaseMessage_messageIsReleased_inHybridMode", assignedTo = assignedTo) Assertions.assertEquals(assignedTo, message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) - Assertions.assertTrue(authenticator.addRestrictedEntry(message.type)) - Assertions.assertTrue(authenticator.isRestricted(message.type)) + Assertions.assertTrue(authenticator.addRestrictedEntry(message.subQueue)) + Assertions.assertTrue(authenticator.isRestricted(message.subQueue)) mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_RELEASE) .contentType(MediaType.APPLICATION_JSON_VALUE) @@ -1073,7 +1073,7 @@ class MessageQueueControllerTest .andExpect(MockMvcResultMatchers.status().isForbidden) - val token = jwtTokenProvider.createTokenForSubQueue(message.type) + val token = jwtTokenProvider.createTokenForSubQueue(message.subQueue) Assertions.assertTrue(token.isPresent) val mvcResult: MvcResult = mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid + MessageQueueController.ENDPOINT_RELEASE) @@ -1087,7 +1087,7 @@ class MessageQueueControllerTest Assertions.assertNull(messageResponse.message.assignedTo) Assertions.assertEquals(message.uuid, messageResponse.message.uuid) - val updatedMessage = multiQueue.peekForType(message.type).get() + val updatedMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertNull(updatedMessage.assignedTo) Assertions.assertEquals(message.uuid, updatedMessage.uuid) } @@ -1099,10 +1099,10 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_messageIsReleased_withoutAssignedToInQuery() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assigned" - val message = createQueueMessage(type = "testReleaseMessage_messageIsReleased_withoutAssignedToInQuery", assignedTo = assignedTo) + val message = createQueueMessage(subQueue = "testReleaseMessage_messageIsReleased_withoutAssignedToInQuery", assignedTo = assignedTo) Assertions.assertEquals(assignedTo, message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) @@ -1116,7 +1116,7 @@ class MessageQueueControllerTest Assertions.assertNull(messageResponse.message.assignedTo) Assertions.assertEquals(message.uuid, messageResponse.message.uuid) - val updatedMessage = multiQueue.peekForType(message.type).get() + val updatedMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertNull(updatedMessage.assignedTo) Assertions.assertEquals(message.uuid, updatedMessage.uuid) } @@ -1128,9 +1128,9 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_alreadyReleased() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testReleaseMessage_alreadyReleased") + val message = createQueueMessage(subQueue = "testReleaseMessage_alreadyReleased") Assertions.assertNull(message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) @@ -1144,7 +1144,7 @@ class MessageQueueControllerTest Assertions.assertEquals(message.uuid, messageResponse.message.uuid) // Ensure the message is updated in the queue too - val updatedMessage = multiQueue.peekForType(message.type).get() + val updatedMessage = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertNull(updatedMessage.assignedTo) Assertions.assertEquals(message.uuid, updatedMessage.uuid) } @@ -1157,10 +1157,10 @@ class MessageQueueControllerTest @Test fun testReleaseMessage_cannotBeReleasedWithMisMatchingID() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assigned" - val message = createQueueMessage(type = "testReleaseMessage_cannotBeReleasedWithMisMatchingID", assignedTo = assignedTo) + val message = createQueueMessage(subQueue = "testReleaseMessage_cannotBeReleasedWithMisMatchingID", assignedTo = assignedTo) Assertions.assertEquals(assignedTo, message.assignedTo) Assertions.assertTrue(multiQueue.add(message)) @@ -1171,7 +1171,7 @@ class MessageQueueControllerTest .param(RestParameters.ASSIGNED_TO, wrongAssignedTo)) .andExpect(MockMvcResultMatchers.status().isConflict) - val assignedEntry = multiQueue.peekForType(message.type).get() + val assignedEntry = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertEquals(assignedTo, assignedEntry.assignedTo) } @@ -1182,7 +1182,7 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_notFound() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val uuid = UUID.randomUUID().toString() @@ -1198,9 +1198,9 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_removeExistingEntry() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testRemoveMessage_removed") + val message = createQueueMessage(subQueue = "testRemoveMessage_removed") Assertions.assertTrue(multiQueue.add(message)) Assertions.assertTrue(multiQueue.containsUUID(message.uuid).isPresent) @@ -1209,7 +1209,7 @@ class MessageQueueControllerTest .andExpect(MockMvcResultMatchers.status().isOk) Assertions.assertFalse(multiQueue.containsUUID(message.uuid).isPresent) - Assertions.assertTrue(multiQueue.getQueueForType(message.type).isEmpty()) + Assertions.assertTrue(multiQueue.getSubQueue(message.subQueue).isEmpty()) } /** @@ -1219,21 +1219,21 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_removeExistingEntry_inHybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testRemoveMessage_removeExistingEntry_inHybridMode") + val message = createQueueMessage(subQueue = "testRemoveMessage_removeExistingEntry_inHybridMode") Assertions.assertTrue(multiQueue.add(message)) Assertions.assertTrue(multiQueue.containsUUID(message.uuid).isPresent) - Assertions.assertTrue(authenticator.addRestrictedEntry(message.type)) - Assertions.assertTrue(authenticator.isRestricted(message.type)) + Assertions.assertTrue(authenticator.addRestrictedEntry(message.subQueue)) + Assertions.assertTrue(authenticator.isRestricted(message.subQueue)) mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isForbidden) - val token = jwtTokenProvider.createTokenForSubQueue(message.type) + val token = jwtTokenProvider.createTokenForSubQueue(message.subQueue) Assertions.assertTrue(token.isPresent) mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid) @@ -1242,7 +1242,7 @@ class MessageQueueControllerTest .andExpect(MockMvcResultMatchers.status().isOk) Assertions.assertFalse(multiQueue.containsUUID(message.uuid).isPresent) - Assertions.assertTrue(multiQueue.getQueueForType(message.type).isEmpty()) + Assertions.assertTrue(multiQueue.getSubQueue(message.subQueue).isEmpty()) } /** @@ -1252,7 +1252,7 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_doesNotExist() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val uuid = UUID.randomUUID().toString() Assertions.assertFalse(multiQueue.containsUUID(uuid).isPresent) @@ -1271,10 +1271,10 @@ class MessageQueueControllerTest @Test fun testRemoveMessage_assignedToAnotherID() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assignee" - val message = createQueueMessage(type = "testRemoveMessage_assignedToAnotherID", assignedTo = assignedTo) + val message = createQueueMessage(subQueue = "testRemoveMessage_assignedToAnotherID", assignedTo = assignedTo) Assertions.assertTrue(multiQueue.add(message)) val wrongAssignedTo = "wrong-assignee" @@ -1283,27 +1283,27 @@ class MessageQueueControllerTest .param(RestParameters.ASSIGNED_TO, wrongAssignedTo)) .andExpect(MockMvcResultMatchers.status().isForbidden) - val assignedEntry = multiQueue.peekForType(message.type).get() + val assignedEntry = multiQueue.peekSubQueue(message.subQueue).get() Assertions.assertEquals(assignedTo, assignedEntry.assignedTo) } /** - * Test [MessageQueueController.getOwners] with a provided `queueType` parameter to ensure the appropriate map is + * Test [MessageQueueController.getOwners] with a provided `sub-queue` parameter to ensure the appropriate map is * provided in the response and [HttpStatus.OK] is returned. */ @Test - fun testGetOwners_withQueueType() + fun testGetOwners_inSubQueue() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assignedTo" val assignedTo2 = "assignedTo2" - val type = "testGetOwners" + val subQueue = "testGetOwners" - val message = createQueueMessage(type = type, assignedTo = assignedTo) - val message2 = createQueueMessage(type = type, assignedTo = assignedTo2) - val message3 = createQueueMessage(type = type, assignedTo = assignedTo2) + val message = createQueueMessage(subQueue = subQueue, assignedTo = assignedTo) + val message2 = createQueueMessage(subQueue = subQueue, assignedTo = assignedTo2) + val message3 = createQueueMessage(subQueue = subQueue, assignedTo = assignedTo2) Assertions.assertTrue(multiQueue.add(message)) Assertions.assertTrue(multiQueue.add(message2)) @@ -1311,7 +1311,7 @@ class MessageQueueControllerTest val mvcResult = mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_OWNERS) .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, type)) + .param(RestParameters.SUB_QUEUE, subQueue)) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn() @@ -1323,31 +1323,31 @@ class MessageQueueControllerTest val valuesInAssignedTo = owners[assignedTo] Assertions.assertTrue(valuesInAssignedTo is ArrayList<*>) - Assertions.assertTrue((valuesInAssignedTo as ArrayList<*>).contains(type)) + Assertions.assertTrue((valuesInAssignedTo as ArrayList<*>).contains(subQueue)) val valuesInAssignedTo2 = owners[assignedTo2] Assertions.assertTrue(valuesInAssignedTo2 is ArrayList<*>) - Assertions.assertTrue((valuesInAssignedTo2 as ArrayList<*>).contains(type)) + Assertions.assertTrue((valuesInAssignedTo2 as ArrayList<*>).contains(subQueue)) } /** - * Test [MessageQueueController.getOwners] without a provided `queueType` parameter to ensure the appropriate map + * Test [MessageQueueController.getOwners] without a provided `sub-queue` parameter to ensure the appropriate map * is provided in the response and [HttpStatus.OK] is returned. */ @Test - fun testGetOwners_withoutQueueType() + fun testGetOwners_notInSubQueue() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assignedTo" val assignedTo2 = "assignedTo2" - val type = "testGetOwners" - val type2 = "testGetOwners2" + val subQueue = "testGetOwners" + val subQueue2 = "testGetOwners2" - val message = createQueueMessage(type = type, assignedTo = assignedTo) - val message2 = createQueueMessage(type = type2, assignedTo = assignedTo) - val message3 = createQueueMessage(type = type2, assignedTo = assignedTo2) + val message = createQueueMessage(subQueue = subQueue, assignedTo = assignedTo) + val message2 = createQueueMessage(subQueue = subQueue2, assignedTo = assignedTo) + val message3 = createQueueMessage(subQueue = subQueue2, assignedTo = assignedTo2) Assertions.assertTrue(multiQueue.add(message)) Assertions.assertTrue(multiQueue.add(message2)) @@ -1366,12 +1366,12 @@ class MessageQueueControllerTest val valuesInAssignedTo = owners[assignedTo] Assertions.assertTrue(valuesInAssignedTo is ArrayList<*>) - Assertions.assertTrue((valuesInAssignedTo as ArrayList<*>).contains(type)) - Assertions.assertTrue(valuesInAssignedTo.contains(type2)) + Assertions.assertTrue((valuesInAssignedTo as ArrayList<*>).contains(subQueue)) + Assertions.assertTrue(valuesInAssignedTo.contains(subQueue2)) val valuesInAssignedTo2 = owners[assignedTo2] Assertions.assertTrue(valuesInAssignedTo2 is ArrayList<*>) - Assertions.assertTrue((valuesInAssignedTo2 as ArrayList<*>).contains(type2)) + Assertions.assertTrue((valuesInAssignedTo2 as ArrayList<*>).contains(subQueue2)) } /** @@ -1381,7 +1381,7 @@ class MessageQueueControllerTest @Test fun testGetPerformHealthCheck() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_HEALTH_CHECK) .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -1396,9 +1396,9 @@ class MessageQueueControllerTest @Test fun testCorrelationId_randomIdOnSuccess() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testCorrelationId_providedId") + val message = createQueueMessage(subQueue = "testCorrelationId_providedId") val mvcResult: MvcResult = mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) .contentType(MediaType.APPLICATION_JSON_VALUE) @@ -1418,9 +1418,9 @@ class MessageQueueControllerTest @Test fun testCorrelationId_providedId() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val message = createQueueMessage(type = "testCorrelationId_providedId") + val message = createQueueMessage(subQueue = "testCorrelationId_providedId") val correlationId = "my-correlation-id-123456" val mvcResult: MvcResult = mockMvc.perform(post(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY) @@ -1441,10 +1441,10 @@ class MessageQueueControllerTest @Test fun testCorrelationId_randomIdOnError() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val assignedTo = "assignee" - val message = createQueueMessage(type = "testCorrelationId_randomIdOnError", assignedTo = assignedTo) + val message = createQueueMessage(subQueue = "testCorrelationId_randomIdOnError", assignedTo = assignedTo) Assertions.assertTrue(multiQueue.add(message)) val wrongAssignedTo = "wrong-assignee" @@ -1464,12 +1464,12 @@ class MessageQueueControllerTest /** * Ensure that [MessageQueueController.deleteKeys] will only delete keys by the specified - * [RestParameters.QUEUE_TYPE] when it is provided and that other sub queues are not cleared. + * [RestParameters.SUB_QUEUE] when it is provided and that other sub-queues are not cleared. */ @Test fun testDeleteKeys_singleKey() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) val subQueue1 = "testDeleteKeys_singleKey1" var messages = listOf(createQueueMessage(subQueue1), createQueueMessage(subQueue1), createQueueMessage(subQueue1)) @@ -1488,7 +1488,7 @@ class MessageQueueControllerTest mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, subQueue1)) + .param(RestParameters.SUB_QUEUE, subQueue1)) .andExpect(MockMvcResultMatchers.status().isNoContent) Assertions.assertEquals(2, multiQueue.size) @@ -1503,8 +1503,8 @@ class MessageQueueControllerTest @Test fun testDeleteKeys_singleKey_inHybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) val subQueue1 = "testDeleteKeys_singleKey_inHybridMode1" var messages = listOf(createQueueMessage(subQueue1), createQueueMessage(subQueue1), createQueueMessage(subQueue1)) @@ -1526,7 +1526,7 @@ class MessageQueueControllerTest mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, subQueue1)) + .param(RestParameters.SUB_QUEUE, subQueue1)) .andExpect(MockMvcResultMatchers.status().isNoContent) Assertions.assertEquals(2, multiQueue.size) @@ -1535,7 +1535,7 @@ class MessageQueueControllerTest mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, subQueue2)) + .param(RestParameters.SUB_QUEUE, subQueue2)) .andExpect(MockMvcResultMatchers.status().isForbidden) val token = jwtTokenProvider.createTokenForSubQueue(subQueue2) @@ -1544,7 +1544,7 @@ class MessageQueueControllerTest mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") .contentType(MediaType.APPLICATION_JSON_VALUE) - .param(RestParameters.QUEUE_TYPE, subQueue2)) + .param(RestParameters.SUB_QUEUE, subQueue2)) .andExpect(MockMvcResultMatchers.status().isNoContent) Assertions.assertEquals(0, multiQueue.size) @@ -1554,23 +1554,23 @@ class MessageQueueControllerTest /** * Ensure that [MessageQueueController.deleteKeys] will only delete all keys/queues when the provided - * [RestParameters.QUEUE_TYPE] is `null`. + * [RestParameters.SUB_QUEUE] is `null`. */ @Test fun testDeleteKeys_allKeys() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val (messages, types) = initialiseMapWithEntries() + val (messages, subQueues) = initialiseMapWithEntries() Assertions.assertEquals(messages.size, multiQueue.size) - types.forEach { type -> Assertions.assertTrue(multiQueue.keys().contains(type)) } + subQueues.forEach { subQueue -> Assertions.assertTrue(multiQueue.keys().contains(subQueue)) } mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isNoContent) Assertions.assertTrue(multiQueue.isEmpty()) - types.forEach { type -> Assertions.assertFalse(multiQueue.keys().contains(type)) } + subQueues.forEach { subQueue -> Assertions.assertFalse(multiQueue.keys().contains(subQueue)) } } /** @@ -1580,25 +1580,25 @@ class MessageQueueControllerTest @Test fun testDeleteKeys_allKeys_inHybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.HYBRID).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.HYBRID, authenticator.getRestrictionMode()) - val (messages, types) = initialiseMapWithEntries() + val (messages, subQueues) = initialiseMapWithEntries() Assertions.assertEquals(messages.size, multiQueue.size) - types.forEach { type -> Assertions.assertTrue(multiQueue.keys().contains(type)) } + subQueues.forEach { subQueue -> Assertions.assertTrue(multiQueue.keys().contains(subQueue)) } - Assertions.assertTrue(authenticator.addRestrictedEntry(types[0])) - Assertions.assertTrue(authenticator.isRestricted(types[0])) + Assertions.assertTrue(authenticator.addRestrictedEntry(subQueues[0])) + Assertions.assertTrue(authenticator.isRestricted(subQueues[0])) mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isPartialContent) Assertions.assertEquals(1, multiQueue.size) - Assertions.assertTrue(multiQueue.keys().contains(types[0])) - types.subList(1, types.size - 1).forEach { type -> Assertions.assertFalse(multiQueue.keys().contains(type)) } + Assertions.assertTrue(multiQueue.keys().contains(subQueues[0])) + subQueues.subList(1, subQueues.size - 1).forEach { subQueue -> Assertions.assertFalse(multiQueue.keys().contains(subQueue)) } - val token = jwtTokenProvider.createTokenForSubQueue(types[0]) + val token = jwtTokenProvider.createTokenForSubQueue(subQueues[0]) Assertions.assertTrue(token.isPresent) mockMvc.perform(delete(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_KEYS) @@ -1607,7 +1607,7 @@ class MessageQueueControllerTest .andExpect(MockMvcResultMatchers.status().isNoContent) Assertions.assertTrue(multiQueue.isEmpty()) - types.forEach { type -> Assertions.assertFalse(multiQueue.keys().contains(type)) } + subQueues.forEach { subQueue -> Assertions.assertFalse(multiQueue.keys().contains(subQueue)) } } /** @@ -1619,7 +1619,7 @@ class MessageQueueControllerTest @Test fun testGetPerformHealthCheck_failureResponse() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) Mockito.doThrow(RuntimeException("Failed to perform health check.")).`when`(multiQueue).performHealthCheckInternal() @@ -1637,9 +1637,9 @@ class MessageQueueControllerTest @Test fun testCreateMessage_addFails() { - Assertions.assertEquals(RestrictionMode.NONE, authenticator.getAuthenticationType()) + Assertions.assertEquals(RestrictionMode.NONE, authenticator.getRestrictionMode()) - val message = QueueMessage("payload", "type") + val message = QueueMessage("payload", "testCreateMessage_addFails") Mockito.doReturn(false).`when`(multiQueue).add(message) @@ -1656,8 +1656,8 @@ class MessageQueueControllerTest @Test fun testRestrictedModeMakesAllEndpointsInaccessibleWithoutAToken() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, authenticator.getRestrictionMode()) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + UUID.randomUUID().toString()) .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -1681,7 +1681,7 @@ class MessageQueueControllerTest .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) - mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT + "?" + RestParameters.QUEUE_TYPE +"=someType&" + RestParameters.ASSIGNED_TO + "=me") + mockMvc.perform(put(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_NEXT + "?" + RestParameters.SUB_QUEUE +"=someType&" + RestParameters.ASSIGNED_TO + "=me") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) @@ -1689,7 +1689,7 @@ class MessageQueueControllerTest .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) - mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_OWNED + "?" + RestParameters.QUEUE_TYPE +"=someType&" + RestParameters.ASSIGNED_TO + "=me") + mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_OWNED + "?" + RestParameters.SUB_QUEUE +"=someType&" + RestParameters.ASSIGNED_TO + "=me") .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) } @@ -1701,11 +1701,11 @@ class MessageQueueControllerTest @Test fun testGetEntry_inRestrictedMode() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getAuthenticationType() - Assertions.assertEquals(RestrictionMode.RESTRICTED, authenticator.getAuthenticationType()) + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(authenticator).getRestrictionMode() + Assertions.assertEquals(RestrictionMode.RESTRICTED, authenticator.getRestrictionMode()) - val type = "testRestrictedMode_getByUUID" - val message = createQueueMessage(type) + val subQueue = "testGetEntry_inRestrictedMode" + val message = createQueueMessage(subQueue) Assertions.assertTrue(multiQueue.add(message)) @@ -1713,7 +1713,7 @@ class MessageQueueControllerTest .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) - val token = jwtTokenProvider.createTokenForSubQueue(type) + val token = jwtTokenProvider.createTokenForSubQueue(subQueue) Assertions.assertTrue(token.isPresent) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid) @@ -1721,8 +1721,8 @@ class MessageQueueControllerTest .contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(MockMvcResultMatchers.status().isUnauthorized) - Assertions.assertTrue(authenticator.addRestrictedEntry(type)) - Assertions.assertTrue(authenticator.isRestricted(type)) + Assertions.assertTrue(authenticator.addRestrictedEntry(subQueue)) + Assertions.assertTrue(authenticator.isRestricted(subQueue)) mockMvc.perform(get(MessageQueueController.MESSAGE_QUEUE_BASE_PATH + "/" + MessageQueueController.ENDPOINT_ENTRY + "/" + message.uuid) .header(JwtAuthenticationFilter.AUTHORIZATION_HEADER, "${JwtAuthenticationFilter.BEARER_HEADER_VALUE}${token.get()}") @@ -1733,36 +1733,36 @@ class MessageQueueControllerTest /** * A helper method which creates `4` [QueueMessage] objects and inserts them into the [MultiQueue]. * - * @return a [Pair] containing the [List] of [QueueMessage] and their related matching [List] of [String] `queueTypes` in order. + * @return a [Pair] containing the [List] of [QueueMessage] and their related matching [List] of [String] `sub-queue` IDs in order. */ private fun initialiseMapWithEntries(): Pair, List> { - val types = listOf("type1", "type2", "type3", "type4") - val message = createQueueMessage(type = types[0]) - val message2 = createQueueMessage(type = types[1]) - val message3 = createQueueMessage(type = types[2], assignedTo = "assignee") - val message4 = createQueueMessage(type = types[3]) + val subQueues = listOf("type1", "type2", "type3", "type4") + val message = createQueueMessage(subQueue = subQueues[0]) + val message2 = createQueueMessage(subQueue = subQueues[1]) + val message3 = createQueueMessage(subQueue = subQueues[2], assignedTo = "assignee") + val message4 = createQueueMessage(subQueue = subQueues[3]) Assertions.assertTrue(multiQueue.add(message)) Assertions.assertTrue(multiQueue.add(message2)) Assertions.assertTrue(multiQueue.add(message3)) Assertions.assertTrue(multiQueue.add(message4)) - return Pair(listOf(message, message2, message3, message4), types) + return Pair(listOf(message, message2, message3, message4), subQueues) } /** * A helper method to create a [QueueMessage] that can be easily re-used between each test. * - * @param type the `queueType` to assign to the created [QueueMessage] + * @param subQueue the `subQueue` to set in to the created [QueueMessage] * @param assignedTo the [QueueMessage.assignedTo] value to set * @return a [QueueMessage] initialised with multiple parameters */ - private fun createQueueMessage(type: String, assignedTo: String? = null): QueueMessage + private fun createQueueMessage(subQueue: String, assignedTo: String? = null): QueueMessage { val uuid = UUID.randomUUID().toString() val payload = Payload("test", 12, true, PayloadEnum.C) - val message = QueueMessage(payload = payload, type = type) + val message = QueueMessage(payload = payload, subQueue = subQueue) message.uuid = UUID.fromString(uuid).toString() message.assignedTo = assignedTo diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt index d49d120..8421e58 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/controller/SettingsControllerTest.kt @@ -66,7 +66,7 @@ class SettingsControllerTest */ private fun testGetSettings_defaultValues(authenticationType: RestrictionMode) { - Assertions.assertEquals(authenticationType, multiQueueAuthenticator.getAuthenticationType()) + Assertions.assertEquals(authenticationType, multiQueueAuthenticator.getRestrictionMode()) val mvcResult: MvcResult = mockMvc.perform(MockMvcRequestBuilders.get(SettingsController.SETTINGS_PATH) .contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -74,8 +74,8 @@ class SettingsControllerTest .andReturn() val settings = gson.fromJson(mvcResult.response.contentAsString, MessageQueueSettings::class.java) - Assertions.assertEquals(StorageMedium.IN_MEMORY.toString(), settings.multiQueueType) - Assertions.assertEquals(RestrictionMode.NONE.toString(), settings.multiQueueAuthentication) + Assertions.assertEquals(StorageMedium.IN_MEMORY.toString(), settings.storageMedium) + Assertions.assertEquals(RestrictionMode.NONE.toString(), settings.restrictionMode) Assertions.assertTrue(settings.redisPrefix.isEmpty()) Assertions.assertEquals(MessageQueueSettings.REDIS_ENDPOINT_DEFAULT, settings.redisEndpoint) @@ -99,7 +99,7 @@ class SettingsControllerTest @Test fun testGetSettings_noneMode() { - Mockito.doReturn(RestrictionMode.NONE).`when`(multiQueueAuthenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.NONE).`when`(multiQueueAuthenticator).getRestrictionMode() testGetSettings_defaultValues(RestrictionMode.NONE) } @@ -110,7 +110,7 @@ class SettingsControllerTest @Test fun testGetSettings_hybridMode() { - Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.HYBRID).`when`(multiQueueAuthenticator).getRestrictionMode() testGetSettings_defaultValues(RestrictionMode.HYBRID) } @@ -121,7 +121,7 @@ class SettingsControllerTest @Test fun testGetSettings_restrictedMode() { - Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getAuthenticationType() + Mockito.doReturn(RestrictionMode.RESTRICTED).`when`(multiQueueAuthenticator).getRestrictionMode() testGetSettings_defaultValues(RestrictionMode.RESTRICTED) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt index f7f6267..77f392d 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/rest/response/RestResponseExceptionHandlerTest.kt @@ -104,13 +104,13 @@ class RestResponseExceptionHandlerTest { val correlationId = UUID.randomUUID().toString() MDC.put(CorrelationIdFilter.CORRELATION_ID, correlationId) - val type = "testHandleIllegalSubQueueIdentifierException" - val exception = IllegalSubQueueIdentifierException(type) + val subQueue = "testHandleIllegalSubQueueIdentifierException" + val exception = IllegalSubQueueIdentifierException(subQueue) val response = responseHandler.handleIllegalSubQueueIdentifierException(exception) Assertions.assertEquals(HttpStatus.BAD_REQUEST, response.statusCode) Assertions.assertNotNull(response.body) - Assertions.assertTrue(response.body!!.message!!.contains(type)) + Assertions.assertTrue(response.body!!.message!!.contains(subQueue)) Assertions.assertEquals(correlationId, response.body!!.correlationId) } } diff --git a/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt b/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt index 22cb8fa..9f1cc79 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsDefaultTest.kt @@ -42,8 +42,8 @@ class MessageQueueSettingsDefaultTest fun testDefaults() { Assertions.assertNotNull(messageQueueSettings) - Assertions.assertEquals(MessageQueueSettings.STORAGE_MEDIUM_DEFAULT, messageQueueSettings.multiQueueType) - Assertions.assertEquals(MessageQueueSettings.RESTRICTION_MODE_DEFAULT, messageQueueSettings.multiQueueAuthentication) + Assertions.assertEquals(MessageQueueSettings.STORAGE_MEDIUM_DEFAULT, messageQueueSettings.storageMedium) + Assertions.assertEquals(MessageQueueSettings.RESTRICTION_MODE_DEFAULT, messageQueueSettings.restrictionMode) Assertions.assertEquals(MessageQueueSettings.REDIS_ENDPOINT_DEFAULT, messageQueueSettings.redisEndpoint) Assertions.assertEquals("", messageQueueSettings.redisPrefix) diff --git a/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsTest.kt b/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsTest.kt index 8f56377..e95c07a 100644 --- a/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsTest.kt +++ b/src/test/kotlin/au/kilemon/messagequeue/settings/MessageQueueSettingsTest.kt @@ -50,7 +50,7 @@ class MessageQueueSettingsTest fun testValues() { Assertions.assertNotNull(messageQueueSettings) - Assertions.assertEquals("REDIS", messageQueueSettings.multiQueueType) + Assertions.assertEquals("REDIS", messageQueueSettings.storageMedium) Assertions.assertEquals("123.123.123.123", messageQueueSettings.redisEndpoint) Assertions.assertEquals("redis", messageQueueSettings.redisPrefix) Assertions.assertEquals("master", messageQueueSettings.redisMasterName)