feat: As an user I want to see only the projects I created
This commit is contained in:
parent
b6ec78ef49
commit
056e4532fa
|
@ -5,7 +5,10 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority
|
|||
import org.springframework.security.core.GrantedAuthority
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
|
||||
class Appuser internal constructor() : UserDetails {
|
||||
class Appuser internal constructor(sub: String, username: String, val token: String) : UserDetails {
|
||||
|
||||
var userSub = sub
|
||||
var userName = username
|
||||
|
||||
override fun getAuthorities(): Collection<GrantedAuthority> {
|
||||
return listOf("user").stream().map {
|
||||
|
@ -17,12 +20,17 @@ class Appuser internal constructor() : UserDetails {
|
|||
}.collect(Collectors.toList())
|
||||
}
|
||||
|
||||
|
||||
fun getSub(): String {
|
||||
return userSub
|
||||
}
|
||||
|
||||
override fun getPassword(): String {
|
||||
return "n/a"
|
||||
}
|
||||
|
||||
override fun getUsername(): String {
|
||||
return "n/a"
|
||||
return userName
|
||||
}
|
||||
|
||||
override fun isAccountNonExpired(): Boolean {
|
||||
|
|
|
@ -9,20 +9,17 @@ import org.springframework.security.core.GrantedAuthority
|
|||
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||
import org.springframework.security.oauth2.jwt.Jwt
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.kotlin.core.publisher.toMono
|
||||
import java.util.stream.Collectors
|
||||
|
||||
class AppuserJwtAuthConverter(private val appuserDetailsService: UserAccountDetailsService) :
|
||||
class AppuserJwtAuthConverter :
|
||||
Converter<Jwt, Mono<AbstractAuthenticationToken>> {
|
||||
|
||||
override fun convert(jwt: Jwt): Mono<AbstractAuthenticationToken> {
|
||||
val authorities = extractAuthorities(jwt)
|
||||
// val sub = extractSub(jwt)
|
||||
val sub = extractSub(jwt)
|
||||
val username = extractUserName(jwt)
|
||||
return appuserDetailsService
|
||||
.findByUsername(username)
|
||||
.map { user ->
|
||||
UsernamePasswordAuthenticationToken(user, "n/a", authorities);
|
||||
}
|
||||
return UsernamePasswordAuthenticationToken(Appuser(sub, username, jwt.tokenValue!!), "n/a", authorities).toMono()
|
||||
}
|
||||
|
||||
private fun extractSub(jwt: Jwt): String {
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package com.securityc4po.api.configuration.security
|
||||
|
||||
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
|
||||
|
||||
@Service
|
||||
class UserAccountDetailsService : ReactiveUserDetailsService {
|
||||
override fun findByUsername(username: String): Mono<UserDetails> {
|
||||
return Appuser().toMono()
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ import org.springframework.web.cors.CorsConfiguration
|
|||
@EnableReactiveMethodSecurity
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
class WebSecurityConfiguration(private val userAccountDetailsService: UserAccountDetailsService) {
|
||||
class WebSecurityConfiguration {
|
||||
|
||||
@Value("\${external.issuer-uri}")
|
||||
var externalIssuerUri: String? = null
|
||||
|
@ -60,7 +60,7 @@ class WebSecurityConfiguration(private val userAccountDetailsService: UserAccoun
|
|||
|
||||
@Bean
|
||||
fun appuserJwtAuthenticationConverter(): AppuserJwtAuthConverter {
|
||||
return AppuserJwtAuthConverter(userAccountDetailsService)
|
||||
return AppuserJwtAuthConverter()
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -24,7 +24,8 @@ data class Project(
|
|||
val state: PentestState,
|
||||
val version: String,
|
||||
var projectPentests: List<ProjectPentest> = emptyList(),
|
||||
val createdBy: String
|
||||
@Indexed(background = true, unique = false)
|
||||
var createdBy: String
|
||||
)
|
||||
|
||||
fun buildProject(body: ProjectRequestBody, projectEntity: ProjectEntity): Project {
|
||||
|
@ -159,6 +160,21 @@ fun ProjectRequestBody.toProject(): Project {
|
|||
// ToDo: Update version in backend automatically
|
||||
version = "1.0",
|
||||
// ToDo: Should be changed to SUB from Token after adding AUTH Header
|
||||
createdBy = UUID.randomUUID().toString()
|
||||
createdBy = ""
|
||||
)
|
||||
}
|
||||
|
||||
fun ProjectRequestBody.toNewProject(userId: String): Project {
|
||||
return Project(
|
||||
id = UUID.randomUUID().toString(),
|
||||
client = this.client,
|
||||
title = this.title,
|
||||
createdAt = Instant.now().toString(),
|
||||
tester = this.tester,
|
||||
summary = this.summary,
|
||||
state = this.state,
|
||||
// ToDo: Update version in backend automatically
|
||||
version = "1.0",
|
||||
createdBy = userId
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,11 +4,13 @@ import com.securityc4po.api.configuration.BC_BAD_CAST_TO_ABSTRACT_COLLECTION
|
|||
import com.securityc4po.api.extensions.getLoggerFor
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
|
||||
import com.securityc4po.api.ResponseBody
|
||||
import com.securityc4po.api.configuration.security.Appuser
|
||||
import com.securityc4po.api.pentest.PentestDeletionService
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.kotlin.core.publisher.switchIfEmpty
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/projects")
|
||||
|
@ -24,8 +26,12 @@ class ProjectController(private val projectService: ProjectService, private val
|
|||
var logger = getLoggerFor<ProjectController>()
|
||||
|
||||
@GetMapping
|
||||
fun getProjects(): Mono<ResponseEntity<List<ResponseBody>>> {
|
||||
return projectService.getProjects().map { projectList ->
|
||||
fun getProjects(
|
||||
@AuthenticationPrincipal user: Appuser
|
||||
): Mono<ResponseEntity<List<ResponseBody>>> {
|
||||
|
||||
println("controller " + user.getSub())
|
||||
return projectService.getProjects(user.getSub()).map { projectList ->
|
||||
projectList.map {
|
||||
it.toProjectResponseBody()
|
||||
}
|
||||
|
@ -37,9 +43,10 @@ class ProjectController(private val projectService: ProjectService, private val
|
|||
|
||||
@GetMapping("/{projectId}")
|
||||
fun getCompletedProjectById(
|
||||
@PathVariable(value = "projectId") projectId: String
|
||||
@PathVariable(value = "projectId") projectId: String,
|
||||
@AuthenticationPrincipal user: Appuser
|
||||
): Mono<ResponseEntity<ResponseBody>> {
|
||||
return projectService.getProjectById(projectId).map {
|
||||
return projectService.getProjectById(projectId, user.getSub()).map {
|
||||
it.toProjectCompletedPentestResponseBody()
|
||||
}.map {
|
||||
if (it.isEmpty()) ResponseEntity.noContent().build()
|
||||
|
@ -49,9 +56,10 @@ class ProjectController(private val projectService: ProjectService, private val
|
|||
|
||||
@GetMapping("/evaluation/{projectId}")
|
||||
fun getProjectById(
|
||||
@PathVariable(value = "projectId") projectId: String
|
||||
@PathVariable(value = "projectId") projectId: String,
|
||||
@AuthenticationPrincipal user: Appuser
|
||||
): Mono<ResponseEntity<ResponseBody>> {
|
||||
return projectService.getProjectById(projectId).map {
|
||||
return projectService.getProjectById(projectId, user.getSub()).map {
|
||||
it.toProjectEvaluatedPentestResponseBody()
|
||||
}.map {
|
||||
if (it.isEmpty()) ResponseEntity.noContent().build()
|
||||
|
@ -61,9 +69,10 @@ class ProjectController(private val projectService: ProjectService, private val
|
|||
|
||||
@PostMapping
|
||||
fun saveProject(
|
||||
@RequestBody body: ProjectRequestBody
|
||||
@RequestBody body: ProjectRequestBody,
|
||||
@AuthenticationPrincipal user: Appuser
|
||||
): Mono<ResponseEntity<ResponseBody>> {
|
||||
return this.projectService.saveProject(body).map {
|
||||
return this.projectService.saveProject(body, user.getSub()).map {
|
||||
ResponseEntity.accepted().body(it.toProjectResponseBody())
|
||||
}
|
||||
}
|
||||
|
@ -88,9 +97,10 @@ class ProjectController(private val projectService: ProjectService, private val
|
|||
@PatchMapping("/{id}")
|
||||
fun updateProject(
|
||||
@PathVariable(value = "id") id: String,
|
||||
@AuthenticationPrincipal user: Appuser,
|
||||
@RequestBody body: ProjectRequestBody
|
||||
): Mono<ResponseEntity<ResponseBody>> {
|
||||
return this.projectService.updateProject(id, body).map {
|
||||
return this.projectService.updateProject(id, body, user.getSub()).map {
|
||||
ResponseEntity.accepted().body(it.toProjectResponseBody())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@ class ProjectService(private val projectRepository: ProjectRepository) {
|
|||
* @throws [EntityNotFoundException] if there are no [Project]s in collection
|
||||
* @return list of [Project]
|
||||
*/
|
||||
fun getProjects(): Mono<List<Project>> {
|
||||
return projectRepository.findAll().collectList().map {
|
||||
fun getProjects(userSub: String): Mono<List<Project>> {
|
||||
return projectRepository.findAll().filter { project -> project.data.createdBy == userSub }.collectList().map {
|
||||
it.map { projectEntity -> projectEntity.toProject() }
|
||||
}.switchIfEmpty {
|
||||
val msg = "Projects not found."
|
||||
|
@ -41,8 +41,8 @@ class ProjectService(private val projectRepository: ProjectRepository) {
|
|||
* @throws [EntityNotFoundException] if there is no [Project] in collection
|
||||
* @return [Project]
|
||||
*/
|
||||
fun getProjectById(projectId: String): Mono<Project> {
|
||||
return projectRepository.findProjectById(projectId).map {
|
||||
fun getProjectById(projectId: String, userSub: String): Mono<Project> {
|
||||
return projectRepository.findProjectById(projectId).filter { project -> project.data.createdBy == userSub }.map {
|
||||
it.toProject()
|
||||
}.switchIfEmpty {
|
||||
val msg = "Project not found."
|
||||
|
@ -59,7 +59,7 @@ class ProjectService(private val projectRepository: ProjectRepository) {
|
|||
* @throws [TransactionInterruptedException] if the [Project] could not be stored
|
||||
* @return saved [Project]
|
||||
*/
|
||||
fun saveProject(body: ProjectRequestBody): Mono<Project> {
|
||||
fun saveProject(body: ProjectRequestBody, userSub: String): Mono<Project> {
|
||||
validate(
|
||||
require = body.isValid(),
|
||||
logging = { logger.warn("Project not valid.") },
|
||||
|
@ -68,6 +68,7 @@ class ProjectService(private val projectRepository: ProjectRepository) {
|
|||
)
|
||||
)
|
||||
val project = body.toProject()
|
||||
project.createdBy = userSub
|
||||
val projectEntity = ProjectEntity(project)
|
||||
return projectRepository.insert(projectEntity).map {
|
||||
it.toProject()
|
||||
|
@ -110,7 +111,7 @@ class ProjectService(private val projectRepository: ProjectRepository) {
|
|||
* @throws [TransactionInterruptedException] if the [Project] could not be updated
|
||||
* @return updated [Project]
|
||||
*/
|
||||
fun updateProject(id: String, body: ProjectRequestBody): Mono<Project> {
|
||||
fun updateProject(id: String, body: ProjectRequestBody, userSub: String): Mono<Project> {
|
||||
validate(
|
||||
require = body.isValid(),
|
||||
logging = { logger.warn("Project not valid.") },
|
||||
|
|
|
@ -74,6 +74,7 @@ abstract class BaseContainerizedTest {
|
|||
|
||||
var token = "n/a"
|
||||
var tokenAdmin = "n/a"
|
||||
var adminSub = "n/a"
|
||||
var tokenUser = "n/a"
|
||||
|
||||
fun getAccessToken(username: String, password: String, clientId: String, realm: String): String {
|
||||
|
|
|
@ -98,7 +98,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
|
|||
projectPentests = emptyList<ProjectPentest>(),
|
||||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
val projectTwo = Project(
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
|
@ -110,7 +110,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
|
|||
projectPentests = emptyList<ProjectPentest>(),
|
||||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
|
||||
private fun getProjectsResponse() = listOf(
|
||||
|
@ -245,7 +245,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
|
|||
projectPentests = emptyList<ProjectPentest>(),
|
||||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -315,7 +315,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
|
|||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
projectPentests = emptyList<ProjectPentest>(),
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -331,7 +331,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
|
|||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
projectPentests = emptyList<ProjectPentest>(),
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
val projectTwo = Project(
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
|
@ -343,7 +343,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
|
|||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
projectPentests = emptyList<ProjectPentest>(),
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
// persist test data in database
|
||||
mongoTemplate.save(ProjectEntity(projectOne))
|
||||
|
@ -352,11 +352,13 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
|
|||
|
||||
private fun configureAdminToken() {
|
||||
tokenAdmin = getAccessToken("test_admin", "test", "c4po_local", "c4po_realm_local")
|
||||
adminSub = getSubClaim(tokenAdmin)
|
||||
}
|
||||
|
||||
private fun cleanUp() {
|
||||
mongoTemplate.findAllAndRemove(Query(), ProjectEntity::class.java)
|
||||
|
||||
tokenAdmin = "n/a"
|
||||
adminSub = "n/a"
|
||||
}
|
||||
}
|
|
@ -57,6 +57,8 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
inner class GetProjects {
|
||||
@Test
|
||||
fun `requesting projects successfully`() {
|
||||
println("test " + adminSub)
|
||||
|
||||
webTestClient.get().uri("/projects")
|
||||
.header("Authorization", "Bearer $tokenAdmin")
|
||||
.exchange()
|
||||
|
@ -74,7 +76,7 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
summary = "Lorem Ipsum",
|
||||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
val projectTwo = Project(
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
|
@ -85,7 +87,7 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
summary = "Lorem Ipsum",
|
||||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
|
||||
private fun getProjects() = listOf(
|
||||
|
@ -109,8 +111,7 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
.jsonPath("$.client").isEqualTo("Novatec")
|
||||
.jsonPath("$.title").isEqualTo("log4j Pentest")
|
||||
.jsonPath("$.tester").isEqualTo("Stipe")
|
||||
// ToDo: Should be changed to SUB from Token after adding AUTH Header
|
||||
/*.jsonPath("$.createdBy").isEqualTo("f8aab31f-4925-4242-a6fa-f98135b4b032")*/
|
||||
.jsonPath("$.createdBy").isEqualTo("8f725a10-bdf5-4530-a185-4627fb092d78")
|
||||
}
|
||||
|
||||
val project = Project(
|
||||
|
@ -122,7 +123,7 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
summary = "",
|
||||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
createdBy = "a8891ad2-5cf5-4519-a89e-9ef8eec9e10c"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -157,7 +158,7 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
tester = "Elliot",
|
||||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -185,7 +186,7 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
tester = "Stipe_updated",
|
||||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
createdBy = "a8891ad2-5cf5-4519-a89e-9ef8eec9e10c"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -200,7 +201,7 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
summary = "Lorem Ipsum",
|
||||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
val projectTwo = Project(
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
|
@ -211,7 +212,7 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
summary = "Lorem Ipsum",
|
||||
state = PentestState.NEW,
|
||||
version = "1.0",
|
||||
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
|
||||
createdBy = "8f725a10-bdf5-4530-a185-4627fb092d78"
|
||||
)
|
||||
// persist test data in database
|
||||
mongoTemplate.save(ProjectEntity(projectOne))
|
||||
|
@ -220,11 +221,13 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
|
||||
private fun configureAdminToken() {
|
||||
tokenAdmin = getAccessToken("test_admin", "test", "c4po_local", "c4po_realm_local")
|
||||
adminSub = getSubClaim(tokenAdmin)
|
||||
}
|
||||
|
||||
private fun cleanUp() {
|
||||
mongoTemplate.findAllAndRemove(Query(), ProjectEntity::class.java)
|
||||
|
||||
tokenAdmin = "n/a"
|
||||
adminSub = "n/a"
|
||||
}
|
||||
}
|
|
@ -72,7 +72,7 @@
|
|||
"status": "PAUSED"
|
||||
}
|
||||
],
|
||||
"createdBy": "2b4615ec-2f58-4d6a-8543-0c764d64455a"
|
||||
"createdBy": "16a52c3d-998b-4f2d-badb-1f369d95a690"
|
||||
},
|
||||
"_class": "com.securityc4po.api.project.ProjectEntity"
|
||||
},{
|
||||
|
@ -91,7 +91,7 @@
|
|||
"state": "NEW",
|
||||
"version": "1.0",
|
||||
"projectPentests": [],
|
||||
"createdBy": "5e741fe5-591f-48d1-afef-4e59ff5d8f78"
|
||||
"createdBy": "16a52c3d-998b-4f2d-badb-1f369d95a690"
|
||||
},
|
||||
"_class": "com.securityc4po.api.project.ProjectEntity"
|
||||
},{
|
||||
|
@ -467,7 +467,7 @@
|
|||
"status": "PAUSED"
|
||||
}
|
||||
],
|
||||
"createdBy": "20c3059c-0b3c-4d74-9449-472bd87f3544"
|
||||
"createdBy": "16a52c3d-998b-4f2d-badb-1f369d95a690"
|
||||
},
|
||||
"_class": "com.securityc4po.api.project.ProjectEntity"
|
||||
}]
|
|
@ -27,7 +27,11 @@ class ReportController(private val apiService: APIService, private val reportSer
|
|||
"/{projectId}/pdf/{reportLanguage}",
|
||||
produces = [MediaType.APPLICATION_PDF_VALUE]
|
||||
)
|
||||
fun downloadPentestReportPDF(@PathVariable(value = "projectId") projectId: String, @PathVariable(value = "reportLanguage") reportLanguage: String, @AuthenticationPrincipal user: Appuser): Mono<ResponseEntity<ByteArray>> {
|
||||
fun downloadPentestReportPDF(
|
||||
@PathVariable(value = "projectId") projectId: String,
|
||||
@PathVariable(value = "reportLanguage") reportLanguage: String,
|
||||
@AuthenticationPrincipal user: Appuser
|
||||
): Mono<ResponseEntity<ByteArray>> {
|
||||
return this.apiService.requestProjectReportDataById(projectId, user.token).flatMap {projectReport ->
|
||||
this.reportService.createReport(projectReport, "pdf", reportLanguage).map { reportClassLoaderFilePath ->
|
||||
ResponseEntity.ok().body(reportClassLoaderFilePath)
|
||||
|
|
Loading…
Reference in New Issue