feat(api): add support for API keys in REST API via X-API-Key header

This commit is contained in:
Gauthier Roebroeck 2025-02-05 14:05:33 +08:00
parent 6fa976fffa
commit 64b192cee2
2 changed files with 77 additions and 0 deletions

View file

@ -159,6 +159,8 @@ class SecurityConfiguration(
)
}
http.addFilterBefore(restAuthenticationFilter(), AnonymousAuthenticationFilter::class.java)
return http.build()
}
@ -249,6 +251,12 @@ class SecurityConfiguration(
HeaderApiKeyAuthenticationConverter("X-Auth-User", tokenEncoder, userAgentWebAuthenticationDetailsSource),
)
fun restAuthenticationFilter(): Filter =
ApiKeyAuthenticationFilter(
apiKeyAuthenticationProvider(),
HeaderApiKeyAuthenticationConverter("X-API-Key", tokenEncoder, userAgentWebAuthenticationDetailsSource),
)
fun apiKeyAuthenticationProvider(): AuthenticationManager =
ProviderManager(apiKeyAuthenticationProvider).apply {
setAuthenticationEventPublisher(authenticationEventPublisher)

View file

@ -0,0 +1,69 @@
package org.gotson.komga.interfaces.api.rest
import org.gotson.komga.domain.model.KomgaUser
import org.gotson.komga.domain.persistence.KomgaUserRepository
import org.gotson.komga.domain.service.KomgaUserLifecycle
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
@SpringBootTest
@AutoConfigureMockMvc(printOnlyOnFailure = false)
class ApiKeyTest(
@Autowired private val mockMvc: MockMvc,
@Autowired private val userRepository: KomgaUserRepository,
@Autowired private val komgaUserLifecycle: KomgaUserLifecycle,
) {
private val user1 =
KomgaUser(
"user@example.org",
"password",
)
private lateinit var apiKey: String
@BeforeAll
fun setup() {
userRepository.insert(user1)
apiKey = komgaUserLifecycle.createApiKey(user1, "test")!!.key
}
@AfterAll
fun teardown() {
komgaUserLifecycle.deleteUser(user1)
}
@Test
fun `when getting user information then unauthorized is thrown`() {
mockMvc
.get("/api/v2/users/me")
.andExpect {
status { isUnauthorized() }
}
}
@Test
fun `given invalid api key in X-API-Key header when getting user information then unauthorized is thrown`() {
mockMvc
.get("/api/v2/users/me") {
header("x-api-key", "abc123")
}.andExpect {
status { isUnauthorized() }
}
}
@Test
fun `given api key in X-API-Key header when getting user information then returns OK`() {
mockMvc
.get("/api/v2/users/me") {
header("x-api-key", apiKey)
}.andExpect {
status { isOk() }
jsonPath("email") { value(user1.email) }
}
}
}