mirror of
https://github.com/gotson/komga.git
synced 2025-12-22 00:13:30 +01:00
feat(security): add remember-me option
configuration key komga.remember-me.key is necessary to activate the feature removed LoggingBasicAuthFilter.kt, could not make it work along with RememberMe closes #39
This commit is contained in:
parent
f6315f2a3d
commit
003452bd26
4 changed files with 51 additions and 81 deletions
|
|
@ -4,6 +4,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties
|
|||
import org.springframework.stereotype.Component
|
||||
import org.springframework.validation.annotation.Validated
|
||||
import javax.validation.constraints.Min
|
||||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.Positive
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "komga")
|
||||
|
|
@ -25,4 +27,14 @@ class KomgaProperties {
|
|||
@Min(1)
|
||||
var analyzer: Int = 2
|
||||
}
|
||||
|
||||
var rememberMe = RememberMe()
|
||||
|
||||
class RememberMe {
|
||||
@NotBlank
|
||||
var key: String? = null
|
||||
|
||||
@Positive
|
||||
var validity: Int = 1209600 // 2 weeks
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
package org.gotson.komga.infrastructure.security
|
||||
|
||||
import mu.KotlinLogging
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.BadCredentialsException
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.AuthenticationException
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
|
||||
import java.security.Principal
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
private val log = KotlinLogging.logger {}
|
||||
|
||||
class LoggingBasicAuthFilter(
|
||||
authenticationManager: AuthenticationManager
|
||||
) : BasicAuthenticationFilter(authenticationManager) {
|
||||
|
||||
override fun onUnsuccessfulAuthentication(request: HttpServletRequest, response: HttpServletResponse, failed: AuthenticationException) {
|
||||
val cause = when {
|
||||
failed is BadCredentialsException -> "Bad credentials"
|
||||
!failed.message.isNullOrBlank() -> failed.message!!
|
||||
else -> failed.toString()
|
||||
}
|
||||
|
||||
log.info { "Authentication failure: $cause, ${request.extractInfo()}" }
|
||||
}
|
||||
|
||||
override fun onSuccessfulAuthentication(request: HttpServletRequest, response: HttpServletResponse, authResult: Authentication) {
|
||||
val user = when (val p = authResult.principal) {
|
||||
is KomgaPrincipal -> p.user.email
|
||||
is Principal -> p.name
|
||||
else -> p.toString()
|
||||
}
|
||||
|
||||
log.info { "Authentication success for user: $user, ${request.extractInfo()}" }
|
||||
}
|
||||
}
|
||||
|
||||
data class RequestInfo(
|
||||
val ip: String,
|
||||
val userAgent: String?,
|
||||
val method: String,
|
||||
val url: String,
|
||||
val query: String?
|
||||
)
|
||||
|
||||
fun HttpServletRequest.extractInfo() = RequestInfo(
|
||||
ip = getHeader("X-Real-IP") ?: getHeader("X-Forwarded-For") ?: remoteAddr,
|
||||
userAgent = getHeader("User-Agent"),
|
||||
method = method,
|
||||
url = requestURL.toString(),
|
||||
query = queryString
|
||||
)
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package org.gotson.komga.infrastructure.security
|
||||
|
||||
import mu.KotlinLogging
|
||||
import org.gotson.komga.infrastructure.configuration.KomgaProperties
|
||||
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest
|
||||
import org.springframework.boot.autoconfigure.security.servlet.PathRequest
|
||||
|
|
@ -12,18 +13,17 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity
|
|||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.core.session.SessionRegistry
|
||||
import org.springframework.security.core.session.SessionRegistryImpl
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.web.cors.CorsConfiguration
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
class SecurityConfiguration(
|
||||
private val komgaProperties: KomgaProperties,
|
||||
private val komgaUserDetailsLifecycle: UserDetailsService,
|
||||
private val sessionRegistry: SessionRegistry
|
||||
) : WebSecurityConfigurerAdapter() {
|
||||
|
||||
|
|
@ -31,36 +31,45 @@ class SecurityConfiguration(
|
|||
// @formatter:off
|
||||
|
||||
http
|
||||
.addFilterAt(LoggingBasicAuthFilter(this.authenticationManager()), BasicAuthenticationFilter::class.java)
|
||||
.cors()
|
||||
.and()
|
||||
.csrf().disable()
|
||||
.cors()
|
||||
.and()
|
||||
.csrf().disable()
|
||||
|
||||
.authorizeRequests()
|
||||
// restrict all actuator endpoints to ADMIN only
|
||||
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN")
|
||||
.authorizeRequests()
|
||||
// restrict all actuator endpoints to ADMIN only
|
||||
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN")
|
||||
|
||||
// restrict H2 console to ADMIN only
|
||||
.requestMatchers(PathRequest.toH2Console()).hasRole("ADMIN")
|
||||
// restrict H2 console to ADMIN only
|
||||
.requestMatchers(PathRequest.toH2Console()).hasRole("ADMIN")
|
||||
|
||||
// all other endpoints are restricted to authenticated users
|
||||
.antMatchers(
|
||||
"/api/**",
|
||||
"/opds/**"
|
||||
).hasRole("USER")
|
||||
// all other endpoints are restricted to authenticated users
|
||||
.antMatchers(
|
||||
"/api/**",
|
||||
"/opds/**"
|
||||
).hasRole("USER")
|
||||
|
||||
// authorize frames for H2 console
|
||||
.and()
|
||||
.headers().frameOptions().sameOrigin()
|
||||
// authorize frames for H2 console
|
||||
.and()
|
||||
.headers().frameOptions().sameOrigin()
|
||||
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.httpBasic()
|
||||
|
||||
.and()
|
||||
.sessionManagement()
|
||||
.maximumSessions(10)
|
||||
.sessionRegistry(sessionRegistry)
|
||||
.and()
|
||||
.sessionManagement()
|
||||
.maximumSessions(10)
|
||||
.sessionRegistry(sessionRegistry)
|
||||
|
||||
if(!komgaProperties.rememberMe.key.isNullOrBlank()) {
|
||||
logger.info { "RememberMe is active, validity: ${komgaProperties.rememberMe.validity}s" }
|
||||
|
||||
http
|
||||
.rememberMe()
|
||||
.key(komgaProperties.rememberMe.key)
|
||||
.tokenValiditySeconds(komgaProperties.rememberMe.validity)
|
||||
.alwaysRemember(true)
|
||||
.userDetailsService(komgaUserDetailsLifecycle)
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ komga:
|
|||
threads:
|
||||
analyzer: 1
|
||||
filesystem-scanner-force-directory-modified-time: false
|
||||
remember-me:
|
||||
key: changeMe!
|
||||
validity: 2592000 # 1 month
|
||||
# libraries-scan-directory-exclusions:
|
||||
# - "#recycle"
|
||||
# - "@eaDir"
|
||||
|
|
|
|||
Loading…
Reference in a new issue