Skip to content

Commit

Permalink
Add an advanced auth config validation logic (#32)
Browse files Browse the repository at this point in the history
* Add an advanced auth config validation logic

* Make validation to fail if AdminAuthConfig is null
  • Loading branch information
adamkobor authored Aug 6, 2020
1 parent a09277e commit 7cb6c9b
Show file tree
Hide file tree
Showing 21 changed files with 143 additions and 55 deletions.
4 changes: 2 additions & 2 deletions config/detekt/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ processors:
console-reports:
active: true
exclude:
- 'ProjectStatisticsReport'
- 'ComplexityReport'
# - 'ProjectStatisticsReport'
# - 'ComplexityReport'
- 'NotificationReport'
# - 'FindingsReport'
- 'FileBasedFindingsReport'
Expand Down
21 changes: 21 additions & 0 deletions src/main/kotlin/com/kuvaszuptime/kuvasz/config/AdminAuthConfig.kt
Original file line number Diff line number Diff line change
@@ -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
}
11 changes: 0 additions & 11 deletions src/main/kotlin/com/kuvaszuptime/kuvasz/config/AppConfig.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.kuvaszuptime.kuvasz.events
package com.kuvaszuptime.kuvasz.models

import arrow.core.Option
import com.kuvaszuptime.kuvasz.enums.UptimeStatus
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<AuthenticationResponse> {
return Flowable.create({ emitter: FlowableEmitter<AuthenticationResponse> ->
if (authenticationRequest.identity == appConfig.user &&
authenticationRequest.secret == appConfig.password
if (authenticationRequest.identity == authConfig.username &&
authenticationRequest.secret == authConfig.password
) {
val userDetails =
UserDetails(
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<UsernamePasswordNotEquals, AdminAuthConfig> {
return ConstraintValidator { adminAuthConfig, _, _ ->
if (adminAuthConfig != null) {
adminAuthConfig.username!!.toLowerCase() != adminAuthConfig.password!!.toLowerCase()
} else false
}
}
}
5 changes: 3 additions & 2 deletions src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ datasources:
password: 'pass'
---
app-config:
user: user
password: pass
http-communication-logging:
enabled: true
admin-auth:
username: user
password: pass3j4hkhk23hk23k232hk3h232
5 changes: 3 additions & 2 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Original file line number Diff line number Diff line change
@@ -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<BeanInstantiationException> {
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<BeanInstantiationException> {
ApplicationContext.run(properties)
}
exceptionToMessage(exception).contains("username - must not be blank") shouldBe true
exceptionToMessage(exception).contains("password - must not be blank") shouldBe true
}
}
}
})
3 changes: 3 additions & 0 deletions src/test/kotlin/com/kuvaszuptime/kuvasz/events/EventTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions src/test/kotlin/com/kuvaszuptime/kuvasz/mocks/Auth.kt
Original file line number Diff line number Diff line change
@@ -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"
)
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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") {
Expand All @@ -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()!!
Expand All @@ -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<HttpClientResponseException> {
client.toBlocking().exchange(request, BearerAccessRefreshToken::class.java)
Expand All @@ -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()!!
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/test/kotlin/com/kuvaszuptime/kuvasz/testutils/Rx.kt
Original file line number Diff line number Diff line change
@@ -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 : Event> T.toSubscriber(testSubscriber: TestSubscriber<T>) = testSubscriber.onNext(this)
5 changes: 3 additions & 2 deletions src/test/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 7cb6c9b

Please sign in to comment.