diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 8bc0f00..c6b21af 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -25,8 +25,8 @@ processors: console-reports: active: true exclude: - - 'ProjectStatisticsReport' - - 'ComplexityReport' + # - 'ProjectStatisticsReport' + # - 'ComplexityReport' - 'NotificationReport' # - 'FindingsReport' - 'FileBasedFindingsReport' diff --git a/src/main/kotlin/com/kuvaszuptime/kuvasz/config/AdminAuthConfig.kt b/src/main/kotlin/com/kuvaszuptime/kuvasz/config/AdminAuthConfig.kt new file mode 100644 index 0000000..1263965 --- /dev/null +++ b/src/main/kotlin/com/kuvaszuptime/kuvasz/config/AdminAuthConfig.kt @@ -0,0 +1,21 @@ +package com.kuvaszuptime.kuvasz.config + +import com.kuvaszuptime.kuvasz.validation.UsernamePasswordNotEquals +import io.micronaut.context.annotation.ConfigurationProperties +import io.micronaut.context.annotation.Context +import io.micronaut.core.annotation.Introspected +import javax.validation.constraints.NotBlank +import javax.validation.constraints.Size + +@ConfigurationProperties("admin-auth") +@UsernamePasswordNotEquals +@Context +@Introspected +class AdminAuthConfig { + @NotBlank + var username: String? = null + + @NotBlank + @Size(min = 12) + var password: String? = null +} diff --git a/src/main/kotlin/com/kuvaszuptime/kuvasz/config/AppConfig.kt b/src/main/kotlin/com/kuvaszuptime/kuvasz/config/AppConfig.kt deleted file mode 100644 index 9a9fa63..0000000 --- a/src/main/kotlin/com/kuvaszuptime/kuvasz/config/AppConfig.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.kuvaszuptime.kuvasz.config - -import io.micronaut.context.annotation.ConfigurationProperties -import io.micronaut.core.annotation.Introspected - -@ConfigurationProperties("app-config") -@Introspected -class AppConfig { - var user: String? = null - var password: String? = null -} diff --git a/src/main/kotlin/com/kuvaszuptime/kuvasz/handlers/DatabaseEventHandler.kt b/src/main/kotlin/com/kuvaszuptime/kuvasz/handlers/DatabaseEventHandler.kt index a798174..28b4299 100644 --- a/src/main/kotlin/com/kuvaszuptime/kuvasz/handlers/DatabaseEventHandler.kt +++ b/src/main/kotlin/com/kuvaszuptime/kuvasz/handlers/DatabaseEventHandler.kt @@ -1,7 +1,7 @@ package com.kuvaszuptime.kuvasz.handlers -import com.kuvaszuptime.kuvasz.events.UptimeMonitorEvent -import com.kuvaszuptime.kuvasz.events.uptimeStatusNotEquals +import com.kuvaszuptime.kuvasz.models.UptimeMonitorEvent +import com.kuvaszuptime.kuvasz.models.uptimeStatusNotEquals import com.kuvaszuptime.kuvasz.repositories.LatencyLogRepository import com.kuvaszuptime.kuvasz.repositories.UptimeEventRepository import com.kuvaszuptime.kuvasz.services.EventDispatcher diff --git a/src/main/kotlin/com/kuvaszuptime/kuvasz/handlers/LogEventHandler.kt b/src/main/kotlin/com/kuvaszuptime/kuvasz/handlers/LogEventHandler.kt index a25a9b2..d8be24e 100644 --- a/src/main/kotlin/com/kuvaszuptime/kuvasz/handlers/LogEventHandler.kt +++ b/src/main/kotlin/com/kuvaszuptime/kuvasz/handlers/LogEventHandler.kt @@ -1,9 +1,9 @@ package com.kuvaszuptime.kuvasz.handlers -import com.kuvaszuptime.kuvasz.events.MonitorDownEvent -import com.kuvaszuptime.kuvasz.events.MonitorUpEvent -import com.kuvaszuptime.kuvasz.events.RedirectEvent -import com.kuvaszuptime.kuvasz.events.getEndedEventDuration +import com.kuvaszuptime.kuvasz.models.MonitorDownEvent +import com.kuvaszuptime.kuvasz.models.MonitorUpEvent +import com.kuvaszuptime.kuvasz.models.RedirectEvent +import com.kuvaszuptime.kuvasz.models.getEndedEventDuration import com.kuvaszuptime.kuvasz.services.EventDispatcher import com.kuvaszuptime.kuvasz.util.toDurationString import io.micronaut.context.annotation.Context diff --git a/src/main/kotlin/com/kuvaszuptime/kuvasz/events/Event.kt b/src/main/kotlin/com/kuvaszuptime/kuvasz/models/Event.kt similarity index 98% rename from src/main/kotlin/com/kuvaszuptime/kuvasz/events/Event.kt rename to src/main/kotlin/com/kuvaszuptime/kuvasz/models/Event.kt index 462dcc7..41c267d 100644 --- a/src/main/kotlin/com/kuvaszuptime/kuvasz/events/Event.kt +++ b/src/main/kotlin/com/kuvaszuptime/kuvasz/models/Event.kt @@ -1,4 +1,4 @@ -package com.kuvaszuptime.kuvasz.events +package com.kuvaszuptime.kuvasz.models import arrow.core.Option import com.kuvaszuptime.kuvasz.enums.UptimeStatus diff --git a/src/main/kotlin/com/kuvaszuptime/kuvasz/repositories/UptimeEventRepository.kt b/src/main/kotlin/com/kuvaszuptime/kuvasz/repositories/UptimeEventRepository.kt index ae14558..74aa880 100644 --- a/src/main/kotlin/com/kuvaszuptime/kuvasz/repositories/UptimeEventRepository.kt +++ b/src/main/kotlin/com/kuvaszuptime/kuvasz/repositories/UptimeEventRepository.kt @@ -1,9 +1,9 @@ package com.kuvaszuptime.kuvasz.repositories import arrow.core.toOption -import com.kuvaszuptime.kuvasz.events.MonitorDownEvent -import com.kuvaszuptime.kuvasz.events.UptimeMonitorEvent -import com.kuvaszuptime.kuvasz.events.toUptimeStatus +import com.kuvaszuptime.kuvasz.models.MonitorDownEvent +import com.kuvaszuptime.kuvasz.models.UptimeMonitorEvent +import com.kuvaszuptime.kuvasz.models.toUptimeStatus import com.kuvaszuptime.kuvasz.tables.UptimeEvent.UPTIME_EVENT import com.kuvaszuptime.kuvasz.tables.daos.UptimeEventDao import com.kuvaszuptime.kuvasz.tables.pojos.UptimeEventPojo diff --git a/src/main/kotlin/com/kuvaszuptime/kuvasz/security/AdminAuthProvider.kt b/src/main/kotlin/com/kuvaszuptime/kuvasz/security/AdminAuthProvider.kt index 5ebe887..91ce30a 100644 --- a/src/main/kotlin/com/kuvaszuptime/kuvasz/security/AdminAuthProvider.kt +++ b/src/main/kotlin/com/kuvaszuptime/kuvasz/security/AdminAuthProvider.kt @@ -1,6 +1,6 @@ package com.kuvaszuptime.kuvasz.security -import com.kuvaszuptime.kuvasz.config.AppConfig +import com.kuvaszuptime.kuvasz.config.AdminAuthConfig import io.micronaut.http.HttpRequest import io.micronaut.security.authentication.AuthenticationException import io.micronaut.security.authentication.AuthenticationFailed @@ -16,15 +16,15 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class AdminAuthProvider @Inject constructor(private val appConfig: AppConfig) : AuthenticationProvider { +class AdminAuthProvider @Inject constructor(private val authConfig: AdminAuthConfig) : AuthenticationProvider { override fun authenticate( httpRequest: HttpRequest<*>?, authenticationRequest: AuthenticationRequest<*, *> ): Publisher { return Flowable.create({ emitter: FlowableEmitter -> - if (authenticationRequest.identity == appConfig.user && - authenticationRequest.secret == appConfig.password + if (authenticationRequest.identity == authConfig.username && + authenticationRequest.secret == authConfig.password ) { val userDetails = UserDetails( diff --git a/src/main/kotlin/com/kuvaszuptime/kuvasz/services/EventDispatcher.kt b/src/main/kotlin/com/kuvaszuptime/kuvasz/services/EventDispatcher.kt index 08edef6..e0b109d 100644 --- a/src/main/kotlin/com/kuvaszuptime/kuvasz/services/EventDispatcher.kt +++ b/src/main/kotlin/com/kuvaszuptime/kuvasz/services/EventDispatcher.kt @@ -1,9 +1,9 @@ package com.kuvaszuptime.kuvasz.services -import com.kuvaszuptime.kuvasz.events.Event -import com.kuvaszuptime.kuvasz.events.MonitorDownEvent -import com.kuvaszuptime.kuvasz.events.MonitorUpEvent -import com.kuvaszuptime.kuvasz.events.RedirectEvent +import com.kuvaszuptime.kuvasz.models.Event +import com.kuvaszuptime.kuvasz.models.MonitorDownEvent +import com.kuvaszuptime.kuvasz.models.MonitorUpEvent +import com.kuvaszuptime.kuvasz.models.RedirectEvent import io.reactivex.disposables.Disposable import io.reactivex.subjects.PublishSubject import javax.inject.Singleton diff --git a/src/main/kotlin/com/kuvaszuptime/kuvasz/services/UptimeChecker.kt b/src/main/kotlin/com/kuvaszuptime/kuvasz/services/UptimeChecker.kt index 48df1e6..c7dcded 100644 --- a/src/main/kotlin/com/kuvaszuptime/kuvasz/services/UptimeChecker.kt +++ b/src/main/kotlin/com/kuvaszuptime/kuvasz/services/UptimeChecker.kt @@ -1,8 +1,8 @@ package com.kuvaszuptime.kuvasz.services -import com.kuvaszuptime.kuvasz.events.MonitorDownEvent -import com.kuvaszuptime.kuvasz.events.MonitorUpEvent -import com.kuvaszuptime.kuvasz.events.RedirectEvent +import com.kuvaszuptime.kuvasz.models.MonitorDownEvent +import com.kuvaszuptime.kuvasz.models.MonitorUpEvent +import com.kuvaszuptime.kuvasz.models.RedirectEvent import com.kuvaszuptime.kuvasz.repositories.UptimeEventRepository import com.kuvaszuptime.kuvasz.tables.pojos.MonitorPojo import com.kuvaszuptime.kuvasz.util.RawHttpResponse diff --git a/src/main/kotlin/com/kuvaszuptime/kuvasz/validation/UsernamePasswordNotEquals.kt b/src/main/kotlin/com/kuvaszuptime/kuvasz/validation/UsernamePasswordNotEquals.kt new file mode 100644 index 0000000..1148070 --- /dev/null +++ b/src/main/kotlin/com/kuvaszuptime/kuvasz/validation/UsernamePasswordNotEquals.kt @@ -0,0 +1,26 @@ +package com.kuvaszuptime.kuvasz.validation + +import com.kuvaszuptime.kuvasz.config.AdminAuthConfig +import io.micronaut.context.annotation.Factory +import io.micronaut.validation.validator.constraints.ConstraintValidator +import javax.inject.Singleton +import javax.validation.Constraint + +@Retention(AnnotationRetention.RUNTIME) +@Constraint(validatedBy = []) +annotation class UsernamePasswordNotEquals( + val message: String = "Admin username and password should not be equal" +) + +@Factory +class UsernamePasswordValidatorFactory { + + @Singleton + fun usernamePasswordValidator(): ConstraintValidator { + return ConstraintValidator { adminAuthConfig, _, _ -> + if (adminAuthConfig != null) { + adminAuthConfig.username!!.toLowerCase() != adminAuthConfig.password!!.toLowerCase() + } else false + } + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 295e9f1..bb4d8ec 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -15,7 +15,8 @@ datasources: password: 'pass' --- app-config: - user: user - password: pass http-communication-logging: enabled: true +admin-auth: + username: user + password: pass3j4hkhk23hk23k232hk3h232 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ba2ec14..f989a0c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -64,9 +64,10 @@ jooq: sql-dialect: POSTGRES --- app-config: - user: ${ADMIN_USER} - password: ${ADMIN_PASSWORD} http-communication-logging: enabled: ${ENABLE_HTTP_COMMUNICATION_LOG:`false`} log-event-handler: enabled: ${ENABLE_LOG_EVENT_HANDLER:`true`} +admin-auth: + username: ${ADMIN_USER} + password: ${ADMIN_PASSWORD} diff --git a/src/test/kotlin/com/kuvaszuptime/kuvasz/config/AdminAuthConfigTest.kt b/src/test/kotlin/com/kuvaszuptime/kuvasz/config/AdminAuthConfigTest.kt new file mode 100644 index 0000000..2fd7726 --- /dev/null +++ b/src/test/kotlin/com/kuvaszuptime/kuvasz/config/AdminAuthConfigTest.kt @@ -0,0 +1,46 @@ +package com.kuvaszuptime.kuvasz.config + +import io.kotest.assertions.exceptionToMessage +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe +import io.micronaut.context.ApplicationContext +import io.micronaut.context.env.PropertySource +import io.micronaut.context.exceptions.BeanInstantiationException + +class AdminAuthConfigTest : BehaviorSpec({ + given("an AdminAuthConfig bean") { + `when`("password is less than 12 characters long") { + val properties = PropertySource.of( + "test", + mapOf( + "admin-auth.username" to "test-user", + "admin-auth.password" to "tooShortPas" + ) + ) + then("ApplicationContext should throw a BeanInstantiationException") { + val exception = shouldThrow { + ApplicationContext.run(properties) + } + exceptionToMessage(exception).contains("password - size must be between 12") shouldBe true + } + } + + `when`("username or password is blank") { + val properties = PropertySource.of( + "test", + mapOf( + "admin-auth.username" to "", + "admin-auth.password" to "" + ) + ) + then("ApplicationContext should throw a BeanInstantiationException") { + val exception = shouldThrow { + ApplicationContext.run(properties) + } + exceptionToMessage(exception).contains("username - must not be blank") shouldBe true + exceptionToMessage(exception).contains("password - must not be blank") shouldBe true + } + } + } +}) diff --git a/src/test/kotlin/com/kuvaszuptime/kuvasz/events/EventTest.kt b/src/test/kotlin/com/kuvaszuptime/kuvasz/events/EventTest.kt index b21d902..945023a 100644 --- a/src/test/kotlin/com/kuvaszuptime/kuvasz/events/EventTest.kt +++ b/src/test/kotlin/com/kuvaszuptime/kuvasz/events/EventTest.kt @@ -2,6 +2,9 @@ package com.kuvaszuptime.kuvasz.events import arrow.core.Option import com.kuvaszuptime.kuvasz.enums.UptimeStatus +import com.kuvaszuptime.kuvasz.models.MonitorUpEvent +import com.kuvaszuptime.kuvasz.models.continueWhenStateChanges +import com.kuvaszuptime.kuvasz.models.getEndedEventDuration import com.kuvaszuptime.kuvasz.tables.pojos.UptimeEventPojo import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe diff --git a/src/test/kotlin/com/kuvaszuptime/kuvasz/handlers/DatabaseEventHandlerTest.kt b/src/test/kotlin/com/kuvaszuptime/kuvasz/handlers/DatabaseEventHandlerTest.kt index 6468bc9..a72cd3e 100644 --- a/src/test/kotlin/com/kuvaszuptime/kuvasz/handlers/DatabaseEventHandlerTest.kt +++ b/src/test/kotlin/com/kuvaszuptime/kuvasz/handlers/DatabaseEventHandlerTest.kt @@ -3,8 +3,8 @@ package com.kuvaszuptime.kuvasz.handlers import arrow.core.Option import com.kuvaszuptime.kuvasz.DatabaseBehaviorSpec import com.kuvaszuptime.kuvasz.enums.UptimeStatus -import com.kuvaszuptime.kuvasz.events.MonitorDownEvent -import com.kuvaszuptime.kuvasz.events.MonitorUpEvent +import com.kuvaszuptime.kuvasz.models.MonitorDownEvent +import com.kuvaszuptime.kuvasz.models.MonitorUpEvent import com.kuvaszuptime.kuvasz.mocks.createMonitor import com.kuvaszuptime.kuvasz.repositories.LatencyLogRepository import com.kuvaszuptime.kuvasz.repositories.MonitorRepository diff --git a/src/test/kotlin/com/kuvaszuptime/kuvasz/mocks/Auth.kt b/src/test/kotlin/com/kuvaszuptime/kuvasz/mocks/Auth.kt index c4e034f..ebe8fcc 100644 --- a/src/test/kotlin/com/kuvaszuptime/kuvasz/mocks/Auth.kt +++ b/src/test/kotlin/com/kuvaszuptime/kuvasz/mocks/Auth.kt @@ -1,10 +1,10 @@ package com.kuvaszuptime.kuvasz.mocks -import com.kuvaszuptime.kuvasz.config.AppConfig +import com.kuvaszuptime.kuvasz.config.AdminAuthConfig import io.micronaut.security.authentication.UsernamePasswordCredentials -fun generateCredentials(appConfig: AppConfig, valid: Boolean) = +fun generateCredentials(authConfig: AdminAuthConfig, valid: Boolean) = UsernamePasswordCredentials( - appConfig.user, - if (valid) appConfig.password else "bad-pass" + authConfig.username, + if (valid) authConfig.password else "bad-pass" ) diff --git a/src/test/kotlin/com/kuvaszuptime/kuvasz/security/AuthenticationTest.kt b/src/test/kotlin/com/kuvaszuptime/kuvasz/security/AuthenticationTest.kt index 2f26559..05c5d27 100644 --- a/src/test/kotlin/com/kuvaszuptime/kuvasz/security/AuthenticationTest.kt +++ b/src/test/kotlin/com/kuvaszuptime/kuvasz/security/AuthenticationTest.kt @@ -1,6 +1,6 @@ package com.kuvaszuptime.kuvasz.security -import com.kuvaszuptime.kuvasz.config.AppConfig +import com.kuvaszuptime.kuvasz.config.AdminAuthConfig import com.kuvaszuptime.kuvasz.mocks.generateCredentials import com.nimbusds.jwt.JWTParser import com.nimbusds.jwt.SignedJWT @@ -19,7 +19,7 @@ import io.micronaut.test.annotation.MicronautTest @MicronautTest class AuthenticationTest( @Client("/") private val client: RxHttpClient, - private val appConfig: AppConfig + private val authConfig: AdminAuthConfig ) : BehaviorSpec() { init { given("a public endpoint") { @@ -34,7 +34,7 @@ class AuthenticationTest( given("the login endpoint") { `when`("the user provides the right credentials") { - val credentials = generateCredentials(appConfig, valid = true) + val credentials = generateCredentials(authConfig, valid = true) val request = HttpRequest.POST("/login", credentials) val response = client.toBlocking().exchange(request, BearerAccessRefreshToken::class.java) val token = response.body()!! @@ -48,7 +48,7 @@ class AuthenticationTest( } `when`("a user provides bad credentials") { - val credentials = generateCredentials(appConfig, valid = false) + val credentials = generateCredentials(authConfig, valid = false) val request = HttpRequest.POST("/login", credentials) val exception = shouldThrow { client.toBlocking().exchange(request, BearerAccessRefreshToken::class.java) @@ -70,7 +70,7 @@ class AuthenticationTest( } `when`("a user provides the right credentials") { - val credentials = generateCredentials(appConfig, valid = true) + val credentials = generateCredentials(authConfig, valid = true) val loginRequest = HttpRequest.POST("/login", credentials) val loginResponse = client.toBlocking().exchange(loginRequest, BearerAccessRefreshToken::class.java) val token = loginResponse.body()!! diff --git a/src/test/kotlin/com/kuvaszuptime/kuvasz/services/UptimeCheckerTest.kt b/src/test/kotlin/com/kuvaszuptime/kuvasz/services/UptimeCheckerTest.kt index 91f7fca..ac52ca1 100644 --- a/src/test/kotlin/com/kuvaszuptime/kuvasz/services/UptimeCheckerTest.kt +++ b/src/test/kotlin/com/kuvaszuptime/kuvasz/services/UptimeCheckerTest.kt @@ -1,9 +1,9 @@ package com.kuvaszuptime.kuvasz.services import com.kuvaszuptime.kuvasz.DatabaseBehaviorSpec -import com.kuvaszuptime.kuvasz.events.MonitorDownEvent -import com.kuvaszuptime.kuvasz.events.MonitorUpEvent -import com.kuvaszuptime.kuvasz.events.RedirectEvent +import com.kuvaszuptime.kuvasz.models.MonitorDownEvent +import com.kuvaszuptime.kuvasz.models.MonitorUpEvent +import com.kuvaszuptime.kuvasz.models.RedirectEvent import com.kuvaszuptime.kuvasz.mocks.createMonitor import com.kuvaszuptime.kuvasz.repositories.MonitorRepository import com.kuvaszuptime.kuvasz.util.toUri diff --git a/src/test/kotlin/com/kuvaszuptime/kuvasz/testutils/Rx.kt b/src/test/kotlin/com/kuvaszuptime/kuvasz/testutils/Rx.kt index 90bf892..0c74856 100644 --- a/src/test/kotlin/com/kuvaszuptime/kuvasz/testutils/Rx.kt +++ b/src/test/kotlin/com/kuvaszuptime/kuvasz/testutils/Rx.kt @@ -1,6 +1,6 @@ package com.kuvaszuptime.kuvasz.testutils -import com.kuvaszuptime.kuvasz.events.Event +import com.kuvaszuptime.kuvasz.models.Event import io.reactivex.subscribers.TestSubscriber fun T.toSubscriber(testSubscriber: TestSubscriber) = testSubscriber.onNext(this) diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index 18fd062..8d710d2 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -9,7 +9,8 @@ micronaut: secret: testSecretItsVeryVerySecretSecret --- app-config: - user: test-user - password: test-pass http-communication-logging: enabled: true +admin-auth: + username: test-user + password: test-pass-test-pass-test-pass