Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added user permissions in cosv service #2556

Merged
merged 5 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.saveourtool.save.backend.security

import com.saveourtool.save.authservice.utils.username
import com.saveourtool.save.backend.service.LnkUserOrganizationService
import com.saveourtool.save.backend.repository.LnkUserOrganizationRepository
import com.saveourtool.save.entities.OrganizationStatus
import com.saveourtool.save.info.UserPermissions
import com.saveourtool.save.info.UserPermissionsInOrganization
import org.springframework.security.core.Authentication
Expand All @@ -12,7 +13,7 @@ import org.springframework.stereotype.Component
*/
@Component
class UserPermissionEvaluator(
private var lnkUserOrganizationService: LnkUserOrganizationService,
private var lnkUserOrganizationRepository: LnkUserOrganizationRepository,
) {
/**
* @param authentication
Expand All @@ -21,7 +22,21 @@ class UserPermissionEvaluator(
fun getUserPermissions(
authentication: Authentication,
): UserPermissions {
val lnkOrganizations = lnkUserOrganizationService.getOrganizationsByUserNameAndCreatedStatus(authentication.username())
val lnkOrganizations = lnkUserOrganizationRepository.findByUserNameAndOrganizationStatus(authentication.username(), OrganizationStatus.CREATED)

return UserPermissions(
lnkOrganizations.associate { it.organization.name to UserPermissionsInOrganization(it.organization.canCreateContests, it.organization.canBulkUpload) },
)
}

/**
* @param userName
* @return UserPermissions
*/
fun getUserPermissionsByName(
userName: String,
): UserPermissions {
val lnkOrganizations = lnkUserOrganizationRepository.findByUserNameAndOrganizationStatus(userName, OrganizationStatus.CREATED)

return UserPermissions(
lnkOrganizations.associate { it.organization.name to UserPermissionsInOrganization(it.organization.canCreateContests, it.organization.canBulkUpload) },
Expand All @@ -37,7 +52,8 @@ class UserPermissionEvaluator(
authentication: Authentication,
organizationName: String,
): UserPermissions {
val lnkOrganization = lnkUserOrganizationService.getOrganizationsByUserNameAndCreatedStatusAndOrganizationName(authentication.username(), organizationName)
val lnkOrganization = lnkUserOrganizationRepository.findByUserNameAndOrganizationStatusAndOrganizationName(authentication.username(), OrganizationStatus.CREATED,
organizationName)

val isPermittedCreateContest = lnkOrganization?.organization?.canCreateContests ?: false
val isPermittedToBulkUpload = lnkOrganization?.organization?.canBulkUpload ?: false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.saveourtool.save.backend.service

import com.saveourtool.save.backend.security.UserPermissionEvaluator
import com.saveourtool.save.backend.service.vulnerability.VulnerabilityService
import com.saveourtool.save.entities.Organization
import com.saveourtool.save.entities.User
import com.saveourtool.save.entities.vulnerabilities.Vulnerability
import com.saveourtool.save.entities.vulnerability.VulnerabilityDto
import org.springframework.security.core.Authentication
import org.springframework.stereotype.Service

/**
Expand All @@ -15,6 +17,7 @@ class BackendForCosvService(
private val vulnerabilityService: VulnerabilityService,
private val organizationService: OrganizationService,
private val userDetailsService: UserDetailsService,
private val userPermissionEvaluator: UserPermissionEvaluator,
) : IBackendService {
override fun findVulnerabilityByName(name: String): Vulnerability? = vulnerabilityService.findByName(name)

Expand All @@ -23,4 +26,8 @@ class BackendForCosvService(
override fun getOrganizationByName(name: String): Organization = organizationService.getByName(name)

override fun getUserByName(name: String): User = userDetailsService.getByName(name)

override fun getUserPermissionsByOrganizationName(authentication: Authentication, organizationName: String) = userPermissionEvaluator.getUserPermissionsByOrganizationName(
authentication, organizationName
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.saveourtool.save.backend.repository.LnkUserProjectRepository
import com.saveourtool.save.backend.repository.OriginalLoginRepository
import com.saveourtool.save.backend.repository.UserRepository
import com.saveourtool.save.backend.security.UserPermissionEvaluator
import com.saveourtool.save.backend.storage.AvatarKey
import com.saveourtool.save.backend.storage.AvatarStorage
import com.saveourtool.save.domain.Role
Expand Down Expand Up @@ -35,6 +36,7 @@
private val lnkUserOrganizationRepository: LnkUserOrganizationRepository,
private val lnkUserProjectRepository: LnkUserProjectRepository,
private val avatarStorage: AvatarStorage,
private val userPermissionEvaluator: UserPermissionEvaluator,
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
) {
/**
* @param username
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,13 @@ import kotlinx.serialization.Serializable
@Serializable
data class UserPermissions(
val inOrganizations: Map<String, UserPermissionsInOrganization> = emptyMap(),
)
) {
companion object {
/**
* Value that represents an empty [UserPermissions]
*/
val empty = UserPermissions(
inOrganizations = emptyMap(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.saveourtool.save.entities.Organization
import com.saveourtool.save.entities.User
import com.saveourtool.save.entities.vulnerabilities.Vulnerability
import com.saveourtool.save.entities.vulnerability.VulnerabilityDto
import com.saveourtool.save.info.UserPermissions
import org.springframework.security.core.Authentication

/**
* Interface for service to get required info for COSV from backend
Expand Down Expand Up @@ -39,4 +41,11 @@ interface IBackendService {
* @return found [User] by name
*/
fun getUserByName(name: String): User

/**
* @param authentication
* @param organizationName name of organization
* @return found [UserPermissions] by organizationName
*/
fun getUserPermissionsByOrganizationName(authentication: Authentication, organizationName: String): UserPermissions
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import com.saveourtool.save.entities.vulnerability.*
import com.saveourtool.save.utils.*

import com.saveourtool.osv4k.*
import org.springframework.http.HttpStatus
import org.springframework.security.core.Authentication
import org.springframework.stereotype.Service
import org.springframework.web.server.ResponseStatusException
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.toMono
Expand Down Expand Up @@ -47,6 +49,7 @@ class CosvService(
* @param authentication who uploads [inputStream]
* @param organizationName to which is uploaded
* @return save's vulnerability identifiers
* @throws ResponseStatusException
*/
@OptIn(ExperimentalSerializationApi::class)
fun decodeAndSave(
Expand All @@ -56,6 +59,12 @@ class CosvService(
): Flux<String> {
val user = backendService.getUserByName(authentication.name)
val organization = backendService.getOrganizationByName(organizationName)
val userPermissions = backendService.getUserPermissionsByOrganizationName(authentication, organizationName)

if (userPermissions.inOrganizations[organizationName]?.canDoBulkUpload != true) {
throw ResponseStatusException(HttpStatus.FORBIDDEN, "You do not have permission to upload COSV files on behalf of this organization: $organizationName")
Cheshiriks marked this conversation as resolved.
Show resolved Hide resolved
}

return inputStreams.flatMap { inputStream ->
decode(json.decodeFromStream<JsonElement>(inputStream), user, organization)
}.save(user)
Expand All @@ -68,6 +77,7 @@ class CosvService(
* @param authentication who uploads [content]
* @param organizationName to which is uploaded
* @return save's vulnerability identifiers
* @throws ResponseStatusException
*/
fun decodeAndSave(
content: String,
Expand All @@ -76,6 +86,12 @@ class CosvService(
): Flux<String> {
val user = backendService.getUserByName(authentication.name)
val organization = backendService.getOrganizationByName(organizationName)
val userPermissions = backendService.getUserPermissionsByOrganizationName(authentication, organizationName)

if (userPermissions.inOrganizations[organizationName]?.canDoBulkUpload != true) {
throw ResponseStatusException(HttpStatus.FORBIDDEN, "You do not have permission to upload COSV file on behalf of this organization: $organizationName")
}

return decode(json.parseToJsonElement(content), user, organization).save(user)
}

Expand Down
Loading