Skip to content

Commit

Permalink
Using only user.name in internal authentication
Browse files Browse the repository at this point in the history
### What's done:

It's part of #2336
  • Loading branch information
nulls committed Jul 20, 2023
1 parent c08c6bf commit cf44cc3
Show file tree
Hide file tree
Showing 15 changed files with 111 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.saveourtool.save.authservice.repository

import com.saveourtool.save.authservice.utils.toUserEntity
import com.saveourtool.save.entities.User
import com.saveourtool.save.utils.orNotFound
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
import org.springframework.stereotype.Component

/**
* Repository for [com.saveourtool.save.entities.User] using _original_login_
*/
@Component
class AuthenticationOriginalLoginRepository(
private val namedParameterJdbcTemplate: NamedParameterJdbcTemplate,
) {
/**
* @param name name of user
* @param source source of user
* @return user or null if no results have been found
*/
fun findByNameAndSource(name: String, source: String): User? = namedParameterJdbcTemplate.queryForList(
"SELECT * FROM save_cloud.user WHERE id = (select user_id from save_cloud.original_login where name = :name AND source = :source)",
mapOf("name" to name, "source" to source)
)
.firstOrNull()
?.toUserEntity()

/**
* @param name name of user
* @param source source of user
* @return user or exception if no results have been found
*/
fun getByNameAndSource(name: String, source: String): User = findByNameAndSource(name, source)
.orNotFound { "There is no user with name $name and source $source" }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.saveourtool.save.authservice.repository

import com.saveourtool.save.authservice.utils.toUserEntity
import com.saveourtool.save.entities.User
import com.saveourtool.save.utils.orNotFound
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
Expand All @@ -17,39 +18,18 @@ class AuthenticationUserRepository(
* @param source source of user
* @return user or null if no results have been found
*/
fun findByNameAndSource(name: String, source: String): User? {
val record = namedParameterJdbcTemplate.queryForList(
"SELECT * FROM save_cloud.user WHERE name = :name AND source = :source",
mapOf("name" to name, "source" to source)
).singleOrNull()
?: namedParameterJdbcTemplate.queryForList(
"SELECT * FROM save_cloud.user WHERE id = (select user_id from save_cloud.original_login where name = :name AND source = :source)",
mapOf("name" to name, "source" to source)
).singleOrNull()
.orNotFound {
"There is no user with name $name and source $source"
}
return record.toUserEntity()
}
fun findByNameAndSource(name: String, source: String): User? = namedParameterJdbcTemplate.queryForList(
"SELECT * FROM save_cloud.user WHERE name = :name AND source = :source",
mapOf("name" to name, "source" to source)
).singleOrNull()?.toUserEntity()

private fun Map<String, Any>.toUserEntity(): User {
val record = this
return User(
name = record["name"] as String?,
password = record["password"] as String?,
role = record["role"] as String?,
source = record["source"] as String,
email = record["email"] as String?,
avatar = record["avatar"] as String?,
company = record["company"] as String?,
location = record["location"] as String?,
linkedin = record["linkedin"] as String?,
gitHub = record["git_hub"] as String?,
twitter = record["twitter"] as String?,
isActive = record["is_active"] as Boolean,
rating = record["rating"] as Long,
).apply {
this.id = record["id"] as Long
/**
* @param name name of user
* @param source source of user
* @return user or null if no results have been found
*/
fun getByNameAndSource(name: String, source: String): User = findByNameAndSource(name, source)
.orNotFound {
"There is no user with name $name and source $source"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.saveourtool.save.authservice.service

import com.saveourtool.save.authservice.repository.AuthenticationOriginalLoginRepository
import com.saveourtool.save.authservice.repository.AuthenticationUserRepository
import com.saveourtool.save.authservice.utils.getIdentitySourceAwareUserDetails
import com.saveourtool.save.utils.AUTH_SEPARATOR
import com.saveourtool.save.utils.blockingToMono
import org.springframework.context.annotation.Primary
import org.springframework.security.core.userdetails.ReactiveUserDetailsService
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Service
import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.toMono

/**
* A service that provides `UserDetails`
Expand All @@ -17,15 +18,18 @@ import reactor.kotlin.core.publisher.toMono
@Primary
class AuthenticationUserDetailsService(
private val authenticationUserRepository: AuthenticationUserRepository,
private val authenticationOriginalLoginRepository: AuthenticationOriginalLoginRepository,
) : ReactiveUserDetailsService {
/**
* @param userNameAndSource
* @return IdentitySourceAwareUserDetails retrieved from UserDetails
*/
override fun findByUsername(userNameAndSource: String): Mono<UserDetails> {
val (name, source) = userNameAndSource.split(AUTH_SEPARATOR)
return {
authenticationUserRepository.findByNameAndSource(name, source)
}.toMono().getIdentitySourceAwareUserDetails(name)
return blockingToMono {
authenticationUserRepository.findByNameAndSource(name, source) ?:
authenticationOriginalLoginRepository.findByNameAndSource(name, source)
}
.getIdentitySourceAwareUserDetails(name)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,24 @@ fun roleHierarchy(): RoleHierarchy = mapOf(
.let {
RoleHierarchyImpl().apply { setHierarchy(it) }
}

/**
* @return entity [User] created from [Map]
*/
internal fun Map<String, Any>.toUserEntity(): User = User(
name = this["name"] as String?,
password = this["password"] as String?,
role = this["role"] as String?,
source = this["source"] as String,
email = this["email"] as String?,
avatar = this["avatar"] as String?,
company = this["company"] as String?,
location = this["location"] as String?,
linkedin = this["linkedin"] as String?,
gitHub = this["git_hub"] as String?,
twitter = this["twitter"] as String?,
isActive = this["is_active"] as Boolean,
rating = this["rating"] as Long,
).apply {
this.id = this@toUserEntity["id"] as Long
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.saveourtool.save.backend.controllers

import com.saveourtool.save.backend.ByteBufferFluxResponse
import com.saveourtool.save.backend.service.OrganizationService
import com.saveourtool.save.backend.service.UserDetailsService
import com.saveourtool.save.backend.service.UserService
import com.saveourtool.save.backend.storage.AvatarKey
import com.saveourtool.save.backend.storage.AvatarStorage
import com.saveourtool.save.configs.ApiSwaggerSupport
Expand Down Expand Up @@ -38,7 +38,7 @@ import kotlin.time.toJavaDuration
internal class AvatarController(
private val avatarStorage: AvatarStorage,
private val organizationService: OrganizationService,
private val userDetailsService: UserDetailsService,
private val userService: UserService,
) {
/**
* @param partMono image to be uploaded
Expand Down Expand Up @@ -81,7 +81,7 @@ internal class AvatarController(
blockingToMono {
when (type) {
AvatarType.ORGANIZATION -> organizationService.updateAvatarVersion(owner)
AvatarType.USER -> userDetailsService.updateAvatarVersion(owner)
AvatarType.USER -> userService.updateAvatarVersion(owner)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.saveourtool.save.backend.controllers
import com.saveourtool.save.authservice.utils.userId
import com.saveourtool.save.backend.repository.OriginalLoginRepository
import com.saveourtool.save.backend.repository.UserRepository
import com.saveourtool.save.backend.service.UserDetailsService
import com.saveourtool.save.backend.service.UserService
import com.saveourtool.save.backend.utils.toMonoOrNotFound
import com.saveourtool.save.configs.RequiresAuthorizationSourceHeader
import com.saveourtool.save.domain.Role
Expand Down Expand Up @@ -37,7 +37,7 @@ import reactor.kotlin.core.publisher.toMono
@RequestMapping(path = ["/api/$v1/users"])
class UsersDetailsController(
private val userRepository: UserRepository,
private val userDetailsService: UserDetailsService,
private val userService: UserService,
private val originalLoginRepository: OriginalLoginRepository,
) {
/**
Expand Down Expand Up @@ -106,7 +106,7 @@ class UsersDetailsController(
.map {
val user: User = userRepository.findByName(newUserInfo.oldName ?: newUserInfo.name).orNotFound()
val response = if (user.id == authentication.userId()) {
userDetailsService.saveUser(user.apply {
userService.saveUser(user.apply {
name = newUserInfo.name
email = newUserInfo.email
company = newUserInfo.company
Expand Down Expand Up @@ -160,7 +160,7 @@ class UsersDetailsController(
@GetMapping("/global-role")
@PreAuthorize("isAuthenticated()")
fun getSelfGlobalRole(authentication: Authentication): Mono<Role> =
Mono.just(userDetailsService.getGlobalRole(authentication))
Mono.just(userService.getGlobalRole(authentication))

/**
* @param name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.saveourtool.save.backend.controllers.internal

import com.saveourtool.save.authservice.utils.IdentitySourceAwareUserDetails
import com.saveourtool.save.backend.repository.OriginalLoginRepository
import com.saveourtool.save.backend.service.UserDetailsService
import com.saveourtool.save.backend.service.UserService
import com.saveourtool.save.entities.User
import com.saveourtool.save.utils.IdentitySourceAwareUserDetailsMixin
import com.saveourtool.save.utils.StringResponse
Expand All @@ -27,7 +27,7 @@ import reactor.core.publisher.Mono
@RestController
@RequestMapping("/internal/users")
class UsersController(
private val userService: UserDetailsService,
private val userService: UserService,
private val originalLoginRepository: OriginalLoginRepository,
) {
private val logger = LoggerFactory.getLogger(javaClass)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import kotlin.NoSuchElementException
class LnkUserOrganizationService(
private val lnkUserOrganizationRepository: LnkUserOrganizationRepository,
private val userRepository: UserRepository,
private val userDetailsService: UserDetailsService,
private val userService: UserService,
) {
/**
* @param organization
Expand Down Expand Up @@ -172,7 +172,7 @@ class LnkUserOrganizationService(
*/
fun getGlobalRoleOrOrganizationRole(authentication: Authentication, organization: Organization): Role {
val selfId = authentication.userId()
val selfGlobalRole = userDetailsService.getGlobalRole(authentication)
val selfGlobalRole = userService.getGlobalRole(authentication)
val selfOrganizationRole = findRoleByUserIdAndOrganization(selfId, organization)
return getHighestRole(selfOrganizationRole, selfGlobalRole)
}
Expand All @@ -184,7 +184,7 @@ class LnkUserOrganizationService(
*/
fun getGlobalRoleOrOrganizationRole(authentication: Authentication, organizationName: String): Role {
val selfId = authentication.userId()
val selfGlobalRole = userDetailsService.getGlobalRole(authentication)
val selfGlobalRole = userService.getGlobalRole(authentication)
val selfOrganizationRole = findRoleByUserIdAndOrganizationName(selfId, organizationName)
return getHighestRole(selfOrganizationRole, selfGlobalRole)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import org.springframework.stereotype.Service
class LnkUserProjectService(
private val lnkUserProjectRepository: LnkUserProjectRepository,
private val userRepository: UserRepository,
private val userDetailsService: UserDetailsService,
private val userService: UserService,
) {
/**
* @param project
Expand Down Expand Up @@ -130,7 +130,7 @@ class LnkUserProjectService(
*/
fun getGlobalRoleOrProjectRole(authentication: Authentication, project: Project): Role {
val selfId = authentication.userId()
val selfGlobalRole = userDetailsService.getGlobalRole(authentication)
val selfGlobalRole = userService.getGlobalRole(authentication)
val selfOrganizationRole = findRoleByUserIdAndProject(selfId, project)
return getHighestRole(selfOrganizationRole, selfGlobalRole)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,33 @@ import com.saveourtool.save.domain.UserSaveStatus
import com.saveourtool.save.entities.OriginalLogin
import com.saveourtool.save.entities.User
import com.saveourtool.save.utils.AvatarType
import com.saveourtool.save.utils.blockingToMono
import com.saveourtool.save.utils.orNotFound

import org.springframework.security.core.Authentication
import org.springframework.security.core.userdetails.ReactiveUserDetailsService
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.toMono

import java.util.*

/**
* A service that provides `UserDetails`
* A service that provides access to [UserRepository] and [OriginalLoginRepository]
*/
@Service
class UserDetailsService(
class UserService(
private val userRepository: UserRepository,
private val originalLoginRepository: OriginalLoginRepository,
) : ReactiveUserDetailsService {
override fun findByUsername(username: String): Mono<UserDetails> = {
userRepository.findByName(username) ?: originalLoginRepository.findByName(username)?.user
}.toMono().getIdentitySourceAwareUserDetails(username)

) {
/**
* @param username
* @param source source (where the user identity is coming from)
* @return IdentitySourceAwareUserDetails retrieved from UserDetails
*/
fun findByUsernameAndSource(username: String, source: String) =
{ originalLoginRepository.findByNameAndSource(username, source) }
.toMono()
.map { it.user }
.getIdentitySourceAwareUserDetails(username, source)
fun findByUsernameAndSource(username: String, source: String) = blockingToMono {
originalLoginRepository.findByNameAndSource(username, source)
}
.map { it.user }
.getIdentitySourceAwareUserDetails(username, source)

/**
* @param name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ import kotlin.io.path.*
@EnableConfigurationProperties(ConfigProperties::class)
@MockBeans(
MockBean(OrganizationService::class),
MockBean(UserDetailsService::class),
MockBean(UserService::class),
MockBean(ExecutionService::class),
MockBean(AgentService::class),
MockBean(ProjectPermissionEvaluator::class),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ import java.util.concurrent.TimeUnit
OrganizationService::class,
OrganizationPermissionEvaluator::class,
LnkUserOrganizationService::class,
UserDetailsService::class,
UserService::class,
NoopWebSecurityConfig::class,
GitService::class,
TestSuitesSourceService::class,
TestSuitesService::class,
WebConfig::class,
ProjectPermissionEvaluator::class,
LnkUserProjectService::class,
UserDetailsService::class,
UserService::class,
S11nTestConfig::class,
)
@MockBeans(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.saveourtool.save.authservice.security.ConvertingAuthenticationManager
import com.saveourtool.save.authservice.service.AuthenticationUserDetailsService
import com.saveourtool.save.backend.repository.OriginalLoginRepository
import com.saveourtool.save.backend.repository.UserRepository
import com.saveourtool.save.backend.service.UserDetailsService
import com.saveourtool.save.backend.service.UserService
import com.saveourtool.save.authservice.utils.AuthenticationDetails
import com.saveourtool.save.entities.User
import org.junit.jupiter.api.Assertions
Expand All @@ -25,7 +25,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
@Import(
UserDetailsService::class,
UserService::class,
ConvertingAuthenticationManager::class,
AuthenticationUserDetailsService::class,
AuthenticationUserRepository::class,
Expand Down
Loading

0 comments on commit cf44cc3

Please sign in to comment.