diff --git a/src/main/kotlin/de/code_freak/codefreak/auth/AppUser.kt b/src/main/kotlin/de/code_freak/codefreak/auth/AppUser.kt index 00fc91e03..d30e65338 100644 --- a/src/main/kotlin/de/code_freak/codefreak/auth/AppUser.kt +++ b/src/main/kotlin/de/code_freak/codefreak/auth/AppUser.kt @@ -6,13 +6,11 @@ import org.springframework.security.core.userdetails.User as SpringUser class AppUser( val entity: User, roles: Collection, - password: String = "", - firstName: String? = null, - lastName: String? = null + password: String = "" ) : SpringUser( entity.username, password, roles.flatMap { it.allGrantedAuthorities } ) { - val displayName = listOfNotNull(firstName, lastName).ifEmpty { listOf(username) }.joinToString(" ") + val displayName = listOfNotNull(entity.firstName, entity.lastName).ifEmpty { listOf(username) }.joinToString(" ") } diff --git a/src/main/kotlin/de/code_freak/codefreak/auth/LdapUserDetailsContextMapper.kt b/src/main/kotlin/de/code_freak/codefreak/auth/LdapUserDetailsContextMapper.kt index c9232f053..c03c87611 100644 --- a/src/main/kotlin/de/code_freak/codefreak/auth/LdapUserDetailsContextMapper.kt +++ b/src/main/kotlin/de/code_freak/codefreak/auth/LdapUserDetailsContextMapper.kt @@ -1,8 +1,7 @@ package de.code_freak.codefreak.auth import de.code_freak.codefreak.config.AppConfiguration -import de.code_freak.codefreak.entity.User -import de.code_freak.codefreak.repository.UserRepository +import de.code_freak.codefreak.service.UserService import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.ldap.core.DirContextAdapter @@ -16,7 +15,7 @@ import org.springframework.stereotype.Component class LdapUserDetailsContextMapper : UserDetailsContextMapper { @Autowired - private lateinit var userRepository: UserRepository + private lateinit var userService: UserService @Autowired private lateinit var config: AppConfiguration @@ -50,11 +49,11 @@ class LdapUserDetailsContextMapper : UserDetailsContextMapper { } } - val user = userRepository.findByUsernameIgnoreCase(username!!).orElseGet { userRepository.save(User(username)) } + val user = userService.getOrCreateUser(username!!) { + firstName = config.ldap.firstNameAttribute?.let { ctx?.getStringAttribute(it) } + lastName = config.ldap.lastNameAttribute?.let { ctx?.getStringAttribute(it) } + } log.debug("Logging in ${user.username} with roles $roles") - return AppUser(user, roles, - firstName = config.ldap.firstNameAttribute?.let { ctx?.getStringAttribute(it) }, - lastName = config.ldap.lastNameAttribute?.let { ctx?.getStringAttribute(it) } - ) + return AppUser(user, roles) } } diff --git a/src/main/kotlin/de/code_freak/codefreak/auth/lti/LtiAuthenticationProvider.kt b/src/main/kotlin/de/code_freak/codefreak/auth/lti/LtiAuthenticationProvider.kt index 0492599c1..7fbaf01de 100644 --- a/src/main/kotlin/de/code_freak/codefreak/auth/lti/LtiAuthenticationProvider.kt +++ b/src/main/kotlin/de/code_freak/codefreak/auth/lti/LtiAuthenticationProvider.kt @@ -3,14 +3,13 @@ package de.code_freak.codefreak.auth.lti import com.nimbusds.jwt.JWTClaimsSet import de.code_freak.codefreak.auth.AppUser import de.code_freak.codefreak.auth.Role -import de.code_freak.codefreak.entity.User -import de.code_freak.codefreak.repository.UserRepository +import de.code_freak.codefreak.service.UserService import org.mitre.openid.connect.client.OIDCAuthenticationProvider import org.mitre.openid.connect.model.PendingOIDCAuthenticationToken import org.slf4j.LoggerFactory import org.springframework.security.core.Authentication -class LtiAuthenticationProvider(private val userRepository: UserRepository) : OIDCAuthenticationProvider() { +class LtiAuthenticationProvider(private val userService: UserService) : OIDCAuthenticationProvider() { private val log = LoggerFactory.getLogger(this::class.java) @@ -41,13 +40,12 @@ class LtiAuthenticationProvider(private val userRepository: UserRepository) : OI private fun buildAppUser(claims: JWTClaimsSet, roles: List): AppUser { val username = claims.getStringClaim("email") - val user = userRepository.findByUsernameIgnoreCase(username!!).orElseGet { userRepository.save(User(username)) } + val user = userService.getOrCreateUser(username) { + firstName = claims.getStringClaim("given_name") + lastName = claims.getStringClaim("family_name") + } log.debug("Logging in ${user.username} with roles $roles") - return AppUser( - user, roles, - firstName = claims.getStringClaim("given_name"), - lastName = claims.getStringClaim("family_name") - ) + return AppUser(user, roles) } private fun buildAuthorities(claims: JWTClaimsSet): List { diff --git a/src/main/kotlin/de/code_freak/codefreak/config/LtiSecurityConfiguration.kt b/src/main/kotlin/de/code_freak/codefreak/config/LtiSecurityConfiguration.kt index 59ecfecdf..5d3bd5157 100644 --- a/src/main/kotlin/de/code_freak/codefreak/config/LtiSecurityConfiguration.kt +++ b/src/main/kotlin/de/code_freak/codefreak/config/LtiSecurityConfiguration.kt @@ -6,7 +6,7 @@ import de.code_freak.codefreak.auth.lti.IdCodeAuthRequestBuilder import de.code_freak.codefreak.auth.lti.LtiAuthenticationFilter import de.code_freak.codefreak.auth.lti.LtiAuthenticationProvider import de.code_freak.codefreak.auth.lti.LtiAuthenticationSuccessHandler -import de.code_freak.codefreak.repository.UserRepository +import de.code_freak.codefreak.service.UserService import org.mitre.jwt.signer.service.JWTSigningAndValidationService import org.mitre.jwt.signer.service.impl.DefaultJWTSigningAndValidationService import org.mitre.oauth2.model.ClientDetailsEntity @@ -37,7 +37,7 @@ import java.security.KeyStore @Order(1) class LtiSecurityConfiguration( @Autowired appConfiguration: AppConfiguration, - @Autowired val userRepository: UserRepository + @Autowired val userService: UserService ) : WebSecurityConfigurerAdapter() { val config = appConfiguration.lti private val ltiLoginPath = "/lti/login" @@ -68,7 +68,7 @@ class LtiSecurityConfiguration( } override fun configure(auth: AuthenticationManagerBuilder?) { - auth?.authenticationProvider(LtiAuthenticationProvider(userRepository)) + auth?.authenticationProvider(LtiAuthenticationProvider(userService)) } @Bean diff --git a/src/main/kotlin/de/code_freak/codefreak/entity/User.kt b/src/main/kotlin/de/code_freak/codefreak/entity/User.kt index d69256a60..5e4533ae1 100644 --- a/src/main/kotlin/de/code_freak/codefreak/entity/User.kt +++ b/src/main/kotlin/de/code_freak/codefreak/entity/User.kt @@ -3,4 +3,8 @@ package de.code_freak.codefreak.entity import javax.persistence.Entity @Entity -class User(val username: String) : BaseEntity() +class User( + val username: String, + var firstName: String? = null, + var lastName: String? = null +) : BaseEntity() diff --git a/src/main/kotlin/de/code_freak/codefreak/service/SeedDatabaseService.kt b/src/main/kotlin/de/code_freak/codefreak/service/SeedDatabaseService.kt index 24c309d89..d457ae3a5 100644 --- a/src/main/kotlin/de/code_freak/codefreak/service/SeedDatabaseService.kt +++ b/src/main/kotlin/de/code_freak/codefreak/service/SeedDatabaseService.kt @@ -40,9 +40,9 @@ class SeedDatabaseService : ApplicationListener, Ordered private val log = LoggerFactory.getLogger(this::class.java) companion object { - val admin = User("admin") - val teacher = User("teacher") - val student = User("student") + val admin = User("admin", "John", "Admin") + val teacher = User("teacher", "Kim", "Teacher") + val student = User("student", "Alice", "Student") } override fun onApplicationEvent(event: ContextRefreshedEvent) { diff --git a/src/main/kotlin/de/code_freak/codefreak/service/UserService.kt b/src/main/kotlin/de/code_freak/codefreak/service/UserService.kt new file mode 100644 index 000000000..bbd6286af --- /dev/null +++ b/src/main/kotlin/de/code_freak/codefreak/service/UserService.kt @@ -0,0 +1,20 @@ +package de.code_freak.codefreak.service + +import de.code_freak.codefreak.entity.User +import de.code_freak.codefreak.repository.UserRepository +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import javax.transaction.Transactional + +@Service +class UserService : BaseService() { + @Autowired + private lateinit var userRepository: UserRepository + + @Transactional + fun getOrCreateUser(username: String, patch: User.() -> Unit): User { + val user = userRepository.findByUsernameIgnoreCase(username).orElseGet { userRepository.save(User(username)) } + user.patch() + return user + } +} diff --git a/src/main/resources/db/changelog-master.yaml b/src/main/resources/db/changelog-master.yaml index 77d6ef91b..015533ab6 100644 --- a/src/main/resources/db/changelog-master.yaml +++ b/src/main/resources/db/changelog-master.yaml @@ -2,3 +2,6 @@ databaseChangeLog: - include: file: changelogs/20191002162627-initial.yaml relativeToChangelogFile: true +- include: + file: changelogs/20191025095704-user-firstname-and-lastname.yaml + relativeToChangelogFile: true diff --git a/src/main/resources/db/changelogs/20191025095704-user-firstname-and-lastname.yaml b/src/main/resources/db/changelogs/20191025095704-user-firstname-and-lastname.yaml new file mode 100644 index 000000000..3b68a5d17 --- /dev/null +++ b/src/main/resources/db/changelogs/20191025095704-user-firstname-and-lastname.yaml @@ -0,0 +1,14 @@ +databaseChangeLog: +- changeSet: + id: 1571990279058-1 + author: hkasch + changes: + - addColumn: + columns: + - column: + name: first_name + type: varchar(255) + - column: + name: last_name + type: varchar(255) + tableName: user