Skip to content

Commit

Permalink
Added vulnerability permission (#2303)
Browse files Browse the repository at this point in the history
* Added vulnerability permission
  • Loading branch information
Cheshiriks authored Jul 10, 2023
1 parent 4bb142a commit d453f65
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.saveourtool.save.backend.controllers.vulnerability

import com.saveourtool.save.backend.security.VulnerabilityPermissionEvaluator
import com.saveourtool.save.backend.service.vulnerability.VulnerabilityService
import com.saveourtool.save.backend.utils.hasRole
import com.saveourtool.save.configs.ApiSwaggerSupport
Expand All @@ -12,6 +13,7 @@ import com.saveourtool.save.entities.vulnerability.VulnerabilityProjectDto
import com.saveourtool.save.entities.vulnerability.VulnerabilityStatus
import com.saveourtool.save.filters.VulnerabilityFilter
import com.saveourtool.save.info.UserInfo
import com.saveourtool.save.permission.Permission
import com.saveourtool.save.utils.*
import com.saveourtool.save.v1
import io.swagger.v3.oas.annotations.Operation
Expand Down Expand Up @@ -41,6 +43,7 @@ typealias VulnerabilityDtoList = List<VulnerabilityDto>
@RequestMapping(path = ["/api/$v1/vulnerabilities"])
class VulnerabilityController(
private val vulnerabilityService: VulnerabilityService,
private val vulnerabilityPermissionEvaluator: VulnerabilityPermissionEvaluator,
) {
@PostMapping("/by-filters")
@Operation(
Expand Down Expand Up @@ -253,9 +256,12 @@ class VulnerabilityController(
fun saveDate(
@RequestBody vulnerabilityDateDto: VulnerabilityDateDto,
authentication: Authentication,
): Mono<StringResponse> = blockingToMono {
vulnerabilityService.saveDate(vulnerabilityDateDto, authentication)
}
): Mono<StringResponse> = vulnerabilityDateDto.vulnerabilityName.toMono()
.filter {
vulnerabilityPermissionEvaluator.hasPermission(authentication, it, Permission.DELETE)
}
.switchIfEmptyToResponseException(HttpStatus.FORBIDDEN) { "Permissions required for comment deletion were not granted." }
.flatMap { blockingToMono { vulnerabilityService.saveDate(vulnerabilityDateDto, authentication) } }
.switchIfErrorToConflict {
"Date with type ${vulnerabilityDateDto.type} is already present in ${vulnerabilityDateDto.vulnerabilityName} vulnerability"
}
Expand All @@ -274,9 +280,12 @@ class VulnerabilityController(
fun deleteDate(
@RequestBody vulnerabilityDateDto: VulnerabilityDateDto,
authentication: Authentication,
): Mono<StringResponse> = vulnerabilityDateDto.toMono()
// TODO: add permission check
.flatMap { blockingToMono { vulnerabilityService.deleteDate(it) } }
): Mono<StringResponse> = vulnerabilityDateDto.vulnerabilityName.toMono()
.filter {
vulnerabilityPermissionEvaluator.hasPermission(authentication, it, Permission.DELETE)
}
.switchIfEmptyToResponseException(HttpStatus.FORBIDDEN) { "Permissions required for comment deletion were not granted." }
.flatMap { blockingToMono { vulnerabilityService.deleteDate(vulnerabilityDateDto) } }
.map { ResponseEntity.ok("Date was successfully deleted from vulnerability") }

@DeleteMapping("/delete-project")
Expand All @@ -289,11 +298,16 @@ class VulnerabilityController(
fun deleteProject(
@RequestParam projectName: String,
@RequestParam vulnerabilityName: String,
): Mono<StringResponse> = blockingToMono {
vulnerabilityService.deleteProject(projectName, vulnerabilityName)
}.map {
ResponseEntity.ok("Project $projectName was successfully deleted from vulnerability $vulnerabilityName")
}
authentication: Authentication,
): Mono<StringResponse> = vulnerabilityName.toMono()
.filter {
vulnerabilityPermissionEvaluator.hasPermission(authentication, vulnerabilityName, Permission.DELETE)
}
.switchIfEmptyToResponseException(HttpStatus.FORBIDDEN) { "Permissions required for comment deletion were not granted." }
.flatMap { blockingToMono { vulnerabilityService.deleteProject(projectName, vulnerabilityName) } }
.map {
ResponseEntity.ok("Project $projectName was successfully deleted from vulnerability $vulnerabilityName")
}

@PostMapping("/save-user")
@Operation(
Expand All @@ -308,10 +322,13 @@ class VulnerabilityController(
fun saveUser(
@RequestBody userName: String,
@RequestBody vulnerabilityName: String,
): Mono<StringResponse> = blockingToMono {
// TODO: add permission check
vulnerabilityService.saveUser(userName, vulnerabilityName)
}
authentication: Authentication,
): Mono<StringResponse> = vulnerabilityName.toMono()
.filter {
vulnerabilityPermissionEvaluator.hasPermission(authentication, vulnerabilityName, Permission.DELETE)
}
.switchIfEmptyToResponseException(HttpStatus.FORBIDDEN) { "Permissions required for comment deletion were not granted." }
.flatMap { blockingToMono { vulnerabilityService.saveUser(userName, vulnerabilityName) } }
.switchIfErrorToConflict {
"User with name $userName is already present in $vulnerabilityName vulnerability"
}
Expand All @@ -329,9 +346,13 @@ class VulnerabilityController(
fun deleteUser(
@RequestBody userName: String,
@RequestBody vulnerabilityName: String,
): Mono<StringResponse> = blockingToMono {
vulnerabilityService.deleteUser(userName, vulnerabilityName)
}.map {
ResponseEntity.ok("User $userName was successfully deleted from vulnerability $vulnerabilityName")
}
authentication: Authentication,
): Mono<StringResponse> = vulnerabilityName.toMono()
.filter {
vulnerabilityPermissionEvaluator.hasPermission(authentication, vulnerabilityName, Permission.DELETE)
}
.switchIfEmptyToResponseException(HttpStatus.FORBIDDEN) { "Permissions required for comment deletion were not granted." }
.flatMap { blockingToMono { vulnerabilityService.deleteUser(userName, vulnerabilityName) } }
.switchIfEmptyToNotFound { "Could not find user." }
.map { StringResponse.ok("Successfully deleted user from vulnerability.") }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.saveourtool.save.backend.security

import com.saveourtool.save.authservice.utils.AuthenticationDetails
import com.saveourtool.save.backend.service.vulnerability.VulnerabilityService
import com.saveourtool.save.backend.utils.hasRole
import com.saveourtool.save.domain.Role

import com.saveourtool.save.permission.Permission
import com.saveourtool.save.utils.orNotFound
import org.springframework.security.core.Authentication
import org.springframework.stereotype.Component

/**
* Class that is capable of assessing user permissions.
*/
@Component
class VulnerabilityPermissionEvaluator(
private val vulnerabilityService: VulnerabilityService,
) {
/**
* Check permission for user to read, write and delete vulnerabilities by its [vulnerabilityName]
*
* @param authentication
* @param vulnerabilityName
* @param permission
* @return true if user with [authentication] has [permission] for [vulnerabilityName]
*/
fun hasPermission(
authentication: Authentication?,
vulnerabilityName: String,
permission: Permission,
): Boolean {
authentication ?: return false

return when {
authentication.hasRole(Role.SUPER_ADMIN) -> true
permission == Permission.READ -> true
else -> hasFullPermission(vulnerabilityName, authentication)
}
}

/**
* @param vulnerabilityName
* @param authentication
* @return check permission
*/
fun hasFullPermission(vulnerabilityName: String, authentication: Authentication): Boolean {
val vulnerability = vulnerabilityService.findByName(vulnerabilityName).orNotFound { "Not found vulnerability $vulnerabilityName" }
val linkUsers = vulnerabilityService.getUsers(vulnerability.requiredId()).map { it.user.name }

return vulnerability.userId == (authentication.details as AuthenticationDetails).id || authentication.name in linkUsers
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ class VulnerabilityService(
*/
fun findByNameAndStatus(name: String, status: VulnerabilityStatus) = vulnerabilityRepository.findByNameAndStatus(name, status)

/**
* @param name name of vulnerability
* @return vulnerability by name
*/
fun findByName(name: String) = vulnerabilityRepository.findByName(name)

/**
* @param userName creator of vulnerability
* @param status status of vulnerability
Expand Down Expand Up @@ -364,6 +370,12 @@ class VulnerabilityService(
lnkVulnerabilityUserRepository.deleteByUserNameAndVulnerabilityId(userName, vulnerability.requiredId())
}

/**
* @param vulnerabilityId
* @return list users
*/
fun getUsers(vulnerabilityId: Long) = lnkVulnerabilityUserRepository.findByVulnerabilityId(vulnerabilityId)

/**
* @param name name of project
* @param vulnerabilityName name of vulnerability
Expand Down

0 comments on commit d453f65

Please sign in to comment.