feat: automatic oauth2 user creation

enable via
komga.oauth2-account-creation: true

closes #716
This commit is contained in:
Gauthier Roebroeck 2021-11-30 11:38:59 +08:00
parent fca13a7893
commit fed2294b84
5 changed files with 35 additions and 14 deletions

1
.gitignore vendored
View file

@ -49,3 +49,4 @@ nbdist/
/komga/src/main/resources/public/ /komga/src/main/resources/public/
/komga/artemis/ /komga/artemis/
/komga/lucene/ /komga/lucene/
application-oauth2.yml

View file

@ -1,26 +1,26 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="komga [bootRun] dev,localdb,noclaim" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="komga [bootRun] dev,localdb,noclaim,oauth2" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings> <ExternalSystemSettings>
<option name="env"> <option name="env">
<map> <map>
<entry key="SPRING_PROFILES_ACTIVE" value="dev,localdb,noclaim" /> <entry key="SPRING_PROFILES_ACTIVE" value="dev,localdb,noclaim,oauth2" />
</map> </map>
</option> </option>
<option name="executionName" /> <option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" /> <option name="scriptParameters" value="bootRun" />
<option name="taskDescriptions"> <option name="taskDescriptions">
<list /> <list />
</option> </option>
<option name="taskNames"> <option name="taskNames">
<list> <list />
<option value="bootRun" />
</list>
</option> </option>
<option name="vmOptions" value="" /> <option name="vmOptions" />
</ExternalSystemSettings> </ExternalSystemSettings>
<GradleScriptDebugEnabled>true</GradleScriptDebugEnabled> <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" /> <method v="2" />
</configuration> </configuration>
</component> </component>

View file

@ -32,6 +32,8 @@ class KomgaProperties {
var nativeWebp: Boolean = true var nativeWebp: Boolean = true
var oauth2AccountCreation: Boolean = false
var database = Database() var database = Database()
var cors = Cors() var cors = Cors()

View file

@ -1,6 +1,11 @@
package org.gotson.komga.infrastructure.security.oauth2 package org.gotson.komga.infrastructure.security.oauth2
import mu.KotlinLogging
import org.apache.commons.lang3.RandomStringUtils
import org.gotson.komga.domain.model.KomgaUser
import org.gotson.komga.domain.persistence.KomgaUserRepository import org.gotson.komga.domain.persistence.KomgaUserRepository
import org.gotson.komga.domain.service.KomgaUserLifecycle
import org.gotson.komga.infrastructure.configuration.KomgaProperties
import org.gotson.komga.infrastructure.security.KomgaPrincipal import org.gotson.komga.infrastructure.security.KomgaPrincipal
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
@ -13,9 +18,13 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException
import org.springframework.security.oauth2.core.oidc.user.OidcUser import org.springframework.security.oauth2.core.oidc.user.OidcUser
import org.springframework.security.oauth2.core.user.OAuth2User import org.springframework.security.oauth2.core.user.OAuth2User
private val logger = KotlinLogging.logger {}
@Configuration @Configuration
class KomgaOAuth2UserServiceConfiguration( class KomgaOAuth2UserServiceConfiguration(
private val userRepository: KomgaUserRepository, private val userRepository: KomgaUserRepository,
private val userLifecycle: KomgaUserLifecycle,
private val komgaProperties: KomgaProperties,
) { ) {
@Bean @Bean
@ -34,9 +43,10 @@ class KomgaOAuth2UserServiceConfiguration(
val email = oAuth2User.getAttribute<String>("email") val email = oAuth2User.getAttribute<String>("email")
?: throw OAuth2AuthenticationException("ERR_1024") ?: throw OAuth2AuthenticationException("ERR_1024")
userRepository.findByEmailIgnoreCaseOrNull(email)?.let { val existingUser = userRepository.findByEmailIgnoreCaseOrNull(email)
KomgaPrincipal(it, oAuth2User = oAuth2User) ?: tryCreateNewUser(email)
} ?: throw OAuth2AuthenticationException("ERR_1025")
KomgaPrincipal(existingUser, oAuth2User = oAuth2User)
} }
} }
@ -48,9 +58,16 @@ class KomgaOAuth2UserServiceConfiguration(
if (!oidcUser.emailVerified) throw OAuth2AuthenticationException("ERR_1026") if (!oidcUser.emailVerified) throw OAuth2AuthenticationException("ERR_1026")
userRepository.findByEmailIgnoreCaseOrNull(oidcUser.email)?.let { val existingUser = userRepository.findByEmailIgnoreCaseOrNull(oidcUser.email)
KomgaPrincipal(it, oidcUser) ?: tryCreateNewUser(oidcUser.email)
} ?: throw OAuth2AuthenticationException("ERR_1025")
KomgaPrincipal(existingUser, oidcUser)
} }
} }
private fun tryCreateNewUser(email: String) =
if (komgaProperties.oauth2AccountCreation) {
logger.info { "Creating new user from OAuth2 login: $email" }
userLifecycle.createUser(KomgaUser(email, RandomStringUtils.randomAlphanumeric(12), roleAdmin = false))
} else throw OAuth2AuthenticationException("ERR_1025")
} }

View file

@ -12,6 +12,7 @@ komga:
# file-hashing: false # file-hashing: false
# delete-empty-collections: true # delete-empty-collections: true
# delete-empty-read-lists: true # delete-empty-read-lists: true
oauth2-account-creation: false
spring: spring:
artemis: artemis:
embedded: embedded: