feat: As a developer, I want to have spring security added to the reporting microservice
This commit is contained in:
parent
88b3647295
commit
280948c470
|
@ -837,4 +837,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -11,4 +11,4 @@ class UserAccountDetailsService : ReactiveUserDetailsService {
|
||||||
override fun findByUsername(username: String): Mono<UserDetails> {
|
override fun findByUsername(username: String): Mono<UserDetails> {
|
||||||
return Appuser().toMono()
|
return Appuser().toMono()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,10 +63,10 @@ dependencies {
|
||||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
||||||
|
|
||||||
/*implementation("org.springframework.boot:spring-boot-starter-security")
|
implementation("org.springframework.boot:spring-boot-starter-security")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
|
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
||||||
api("org.springframework.security:spring-security-jwt:1.1.1.RELEASE")*/
|
api("org.springframework.security:spring-security-jwt:1.1.1.RELEASE")
|
||||||
|
|
||||||
/* Reporting */
|
/* Reporting */
|
||||||
implementation("net.sf.jasperreports:jasperreports:6.20.0")
|
implementation("net.sf.jasperreports:jasperreports:6.20.0")
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"header": [],
|
"header": [],
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8888/auth/realms/c4po_realm_local/.well-known/openid-configuration",
|
"raw": "http://localhost:8080/auth/realms/c4po_realm_local/.well-known/openid-configuration",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
],
|
],
|
||||||
"port": "8888",
|
"port": "8080",
|
||||||
"path": [
|
"path": [
|
||||||
"auth",
|
"auth",
|
||||||
"realms",
|
"realms",
|
||||||
|
@ -75,12 +75,12 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8888/auth/realms/c4po_realm_local/protocol/openid-connect/token",
|
"raw": "http://localhost:8080/auth/realms/c4po_realm_local/protocol/openid-connect/token",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
],
|
],
|
||||||
"port": "8888",
|
"port": "8080",
|
||||||
"path": [
|
"path": [
|
||||||
"auth",
|
"auth",
|
||||||
"realms",
|
"realms",
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package com.securityc4po.reporting.configuration.security
|
package com.securityc4po.reporting.configuration.security
|
||||||
class Appuser {}
|
|
||||||
|
|
||||||
/*import org.springframework.security.core.GrantedAuthority
|
import org.springframework.security.core.GrantedAuthority
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||||
import org.springframework.security.core.userdetails.UserDetails
|
import org.springframework.security.core.userdetails.UserDetails
|
||||||
import java.util.stream.Collectors
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
class Appuser internal constructor(val token: String) : UserDetails {
|
class Appuser internal constructor() : UserDetails {
|
||||||
|
|
||||||
override fun getAuthorities(): Collection<GrantedAuthority> {
|
override fun getAuthorities(): Collection<GrantedAuthority> {
|
||||||
return listOf("user").stream().map {
|
return listOf("user").stream().map {
|
||||||
|
@ -21,7 +20,7 @@ class Appuser internal constructor(val token: String) : UserDetails {
|
||||||
override fun getPassword(): String {
|
override fun getPassword(): String {
|
||||||
return "n/a"
|
return "n/a"
|
||||||
}
|
}
|
||||||
d
|
|
||||||
override fun getUsername(): String {
|
override fun getUsername(): String {
|
||||||
return "n/a"
|
return "n/a"
|
||||||
}
|
}
|
||||||
|
@ -45,4 +44,4 @@ class Appuser internal constructor(val token: String) : UserDetails {
|
||||||
companion object {
|
companion object {
|
||||||
private val ROLE_PREFIX = "ROLE_"
|
private val ROLE_PREFIX = "ROLE_"
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.securityc4po.reporting.configuration.security
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
|
import org.springframework.core.convert.converter.Converter
|
||||||
|
import org.springframework.security.authentication.AbstractAuthenticationToken
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||||
|
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 java.util.stream.Collectors
|
||||||
|
|
||||||
|
class AppuserJwtAuthConverter(private val appuserDetailsService: UserAccountDetailsService) :
|
||||||
|
Converter<Jwt, Mono<AbstractAuthenticationToken>> {
|
||||||
|
|
||||||
|
override fun convert(jwt: Jwt): Mono<AbstractAuthenticationToken> {
|
||||||
|
val authorities = extractAuthorities(jwt)
|
||||||
|
// val sub = extractSub(jwt)
|
||||||
|
val username = extractUserName(jwt)
|
||||||
|
return appuserDetailsService
|
||||||
|
.findByUsername(username)
|
||||||
|
.map { user ->
|
||||||
|
UsernamePasswordAuthenticationToken(user, "n/a", authorities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractSub(jwt: Jwt): String {
|
||||||
|
val sub = jwt.getClaims().get(SUB).toString()
|
||||||
|
if (sub.isEmpty() || sub.equals("null")) {
|
||||||
|
return "n/a"
|
||||||
|
}
|
||||||
|
return sub
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractUserName(jwt: Jwt): String {
|
||||||
|
val username = jwt.getClaims().get(USERNAME).toString()
|
||||||
|
if (username.isEmpty() || username.equals("null")) {
|
||||||
|
return "n/a"
|
||||||
|
}
|
||||||
|
return username
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractAuthorities(jwt: Jwt): Collection<GrantedAuthority> {
|
||||||
|
return this.getScopes(jwt).stream().map { authority ->
|
||||||
|
ROLE_PREFIX + authority.toUpperCase()
|
||||||
|
}.map {
|
||||||
|
SimpleGrantedAuthority(it)
|
||||||
|
}.collect(Collectors.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getScopes(jwt: Jwt): Collection<String> {
|
||||||
|
val mapper = ObjectMapper()
|
||||||
|
val scopes = jwt.getClaims().get(GROUPS_CLAIM).toString()
|
||||||
|
val roleStringValue = mapper.readTree(scopes).get("roles").toString()
|
||||||
|
val roles = mapper.readValue<Collection<String>>(roleStringValue)
|
||||||
|
if (!roles.isEmpty()) {
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val GROUPS_CLAIM = "realm_access"
|
||||||
|
private val ROLE_PREFIX = "ROLE_"
|
||||||
|
private val SUB = "sub"
|
||||||
|
private val USERNAME = "username"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.securityc4po.reporting.configuration.security
|
||||||
|
|
||||||
|
import org.modelmapper.ModelMapper
|
||||||
|
import org.modelmapper.convention.MatchingStrategies
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class ModelmapperCfg {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun modelMapper(): ModelMapper {
|
||||||
|
val modelMapper = ModelMapper()
|
||||||
|
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT)
|
||||||
|
return modelMapper
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.securityc4po.reporting.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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.securityc4po.reporting.configuration.security
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.context.annotation.Profile
|
||||||
|
import org.springframework.http.HttpMethod
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity
|
||||||
|
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||||
|
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2TokenValidator
|
||||||
|
import org.springframework.security.oauth2.jwt.Jwt
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtValidators
|
||||||
|
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder
|
||||||
|
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder
|
||||||
|
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders
|
||||||
|
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||||
|
import org.springframework.web.cors.CorsConfiguration
|
||||||
|
|
||||||
|
@EnableWebFluxSecurity
|
||||||
|
@EnableReactiveMethodSecurity
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan
|
||||||
|
class WebSecurityConfiguration(private val userAccountDetailsService: UserAccountDetailsService) {
|
||||||
|
|
||||||
|
@Value("\${external.issuer-uri}")
|
||||||
|
var externalIssuerUri: String? = null
|
||||||
|
|
||||||
|
@Value("\${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
|
||||||
|
var internalIssuerUri: String? = null
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun setSecurityWebFilterChains(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||||
|
http.cors().configurationSource {
|
||||||
|
CorsConfiguration().apply {
|
||||||
|
this.applyPermitDefaultValues()
|
||||||
|
this.addAllowedMethod(HttpMethod.DELETE)
|
||||||
|
this.addAllowedMethod(HttpMethod.PATCH)
|
||||||
|
this.addAllowedMethod(HttpMethod.POST)
|
||||||
|
this.addAllowedMethod(HttpMethod.GET)
|
||||||
|
this.addAllowedMethod(HttpMethod.PUT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.and()
|
||||||
|
.csrf()
|
||||||
|
.disable()
|
||||||
|
.authorizeExchange()
|
||||||
|
.pathMatchers(HttpMethod.GET, "/v1/reports/**").authenticated()
|
||||||
|
.pathMatchers("/actuator/**").permitAll()
|
||||||
|
/*.pathMatchers("/docs/SecurityC4PO.html").permitAll()*/
|
||||||
|
.anyExchange().authenticated()
|
||||||
|
.and()
|
||||||
|
.oauth2ResourceServer()
|
||||||
|
.jwt()
|
||||||
|
.jwtAuthenticationConverter(appuserJwtAuthenticationConverter())
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun appuserJwtAuthenticationConverter(): AppuserJwtAuthConverter {
|
||||||
|
return AppuserJwtAuthConverter(userAccountDetailsService)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Profile("COMPOSE")
|
||||||
|
fun jwtDecoder(): ReactiveJwtDecoder {
|
||||||
|
val jwtDecoder = ReactiveJwtDecoders.fromIssuerLocation(internalIssuerUri) as NimbusReactiveJwtDecoder
|
||||||
|
val withIssuer: OAuth2TokenValidator<Jwt> = JwtValidators.createDefaultWithIssuer(externalIssuerUri)
|
||||||
|
jwtDecoder.setJwtValidator(withIssuer)
|
||||||
|
return jwtDecoder
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,19 +2,19 @@ package com.securityc4po.reporting.report
|
||||||
|
|
||||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
|
import com.securityc4po.reporting.configuration.security.Appuser
|
||||||
import com.securityc4po.reporting.extensions.getLoggerFor
|
import com.securityc4po.reporting.extensions.getLoggerFor
|
||||||
import com.securityc4po.reporting.remote.APIService
|
import com.securityc4po.reporting.remote.APIService
|
||||||
import com.securityc4po.reporting.remote.model.ProjectReport
|
import com.securityc4po.reporting.remote.model.ProjectReport
|
||||||
import org.apache.pdfbox.io.IOUtils
|
import org.springframework.http.HttpHeaders
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.http.ResponseEntity.notFound
|
import org.springframework.http.ResponseEntity.notFound
|
||||||
|
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||||
import org.springframework.web.bind.annotation.*
|
import org.springframework.web.bind.annotation.*
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.kotlin.core.publisher.switchIfEmpty
|
import reactor.kotlin.core.publisher.switchIfEmpty
|
||||||
import java.io.File
|
import java.io.File
|
||||||
// import com.securityc4po.reporting.configuration.security.Appuser
|
|
||||||
// import org.springframework.security.core.annotation.AuthenticationPrincipal
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/reports")
|
@RequestMapping("/reports")
|
||||||
|
@ -32,18 +32,16 @@ class ReportController(private val apiService: APIService, private val reportSer
|
||||||
"/{projectId}/pdf",
|
"/{projectId}/pdf",
|
||||||
produces = [MediaType.APPLICATION_PDF_VALUE]
|
produces = [MediaType.APPLICATION_PDF_VALUE]
|
||||||
)
|
)
|
||||||
fun downloadPentestReportPDF(@PathVariable(value = "projectId") projectId: String/*, @AuthenticationPrincipal user: Appuser*/): Mono<ResponseEntity<ByteArray>> {
|
fun downloadPentestReportPDF(@PathVariable(value = "projectId") projectId: String, @AuthenticationPrincipal user: Appuser): Mono<ResponseEntity<ByteArray>> {
|
||||||
// Todo: Create Report with Jasper
|
// Todo: Create Report with Jasper
|
||||||
// this.apiService.requestProjectDataById(projectId, user.token)
|
// this.apiService.requestProjectDataById(projectId, user.token)
|
||||||
val jsonProjectReportString: String =
|
val jsonProjectReportString: String =
|
||||||
File("./src/test/resources/ProjectReportData.json").readText(Charsets.UTF_8)
|
File("./src/test/resources/ProjectReportData.json").readText(Charsets.UTF_8)
|
||||||
val jsonProjectReportCollection: ProjectReport =
|
val jsonProjectReportCollection: ProjectReport =
|
||||||
jacksonObjectMapper().readValue<ProjectReport>(jsonProjectReportString)
|
jacksonObjectMapper().readValue<ProjectReport>(jsonProjectReportString)
|
||||||
return this.reportService.createReport(jsonProjectReportCollection, "pdf").map { reportClassLoaderFilePatch ->
|
// Setup headers
|
||||||
val reportRessourceStream = ReportController::class.java.getResourceAsStream(reportClassLoaderFilePatch)
|
return this.reportService.createReport(jsonProjectReportCollection, "pdf").map { reportClassLoaderFilePath ->
|
||||||
// Todo: Fix Error with IOUtils.toByteArray(reportRessourceStream) on first start of application
|
ResponseEntity.ok().body(reportClassLoaderFilePath)
|
||||||
val response = IOUtils.toByteArray(reportRessourceStream)
|
|
||||||
ResponseEntity.ok().body(response)
|
|
||||||
}.switchIfEmpty {
|
}.switchIfEmpty {
|
||||||
Mono.just(notFound().build<ByteArray>())
|
Mono.just(notFound().build<ByteArray>())
|
||||||
}.doOnSuccess {
|
}.doOnSuccess {
|
||||||
|
|
|
@ -5,13 +5,16 @@ import com.securityc4po.reporting.remote.model.*
|
||||||
import net.sf.jasperreports.engine.*
|
import net.sf.jasperreports.engine.*
|
||||||
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource
|
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource
|
||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
|
import org.apache.pdfbox.io.MemoryUsageSetting
|
||||||
import org.apache.pdfbox.multipdf.PDFMergerUtility
|
import org.apache.pdfbox.multipdf.PDFMergerUtility
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import org.springframework.util.ResourceUtils
|
import org.springframework.util.ResourceUtils
|
||||||
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.kotlin.core.publisher.toMono
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
/*
|
/*
|
||||||
* This Service makes use of the created Jasper Templates
|
* This Service makes use of the created Jasper Templates
|
||||||
|
@ -23,8 +26,10 @@ class ReportService {
|
||||||
|
|
||||||
private val reportCoverDesignTemplate = "./src/main/resources/jasper/reports/c4po_cover.jrxml"
|
private val reportCoverDesignTemplate = "./src/main/resources/jasper/reports/c4po_cover.jrxml"
|
||||||
private val reportContentDesignTemplate = "./src/main/resources/jasper/reports/c4po_content.jrxml"
|
private val reportContentDesignTemplate = "./src/main/resources/jasper/reports/c4po_content.jrxml"
|
||||||
private val reportStateOfConfidentialityDesignTemplate = "./src/main/resources/jasper/reports/c4po_state_of_confidentiality.jrxml"
|
private val reportStateOfConfidentialityDesignTemplate =
|
||||||
private val reportExecutiveSummaryDesignTemplate = "./src/main/resources/jasper/reports/c4po_executive_summary.jrxml"
|
"./src/main/resources/jasper/reports/c4po_state_of_confidentiality.jrxml"
|
||||||
|
private val reportExecutiveSummaryDesignTemplate =
|
||||||
|
"./src/main/resources/jasper/reports/c4po_executive_summary.jrxml"
|
||||||
private val reportPentestsDesignTemplate = "./src/main/resources/jasper/reports/c4po_pentests.jrxml"
|
private val reportPentestsDesignTemplate = "./src/main/resources/jasper/reports/c4po_pentests.jrxml"
|
||||||
private val reportAppendenciesDesignTemplate = "./src/main/resources/jasper/reports/c4po_appendencies.jrxml"
|
private val reportAppendenciesDesignTemplate = "./src/main/resources/jasper/reports/c4po_appendencies.jrxml"
|
||||||
|
|
||||||
|
@ -33,39 +38,31 @@ class ReportService {
|
||||||
|
|
||||||
// Path where the created Reports are saved
|
// Path where the created Reports are saved
|
||||||
private val reportDestination = "./src/main/resources/jasper/reportPDFs/"
|
private val reportDestination = "./src/main/resources/jasper/reportPDFs/"
|
||||||
|
|
||||||
// Path where the completed Report is saved
|
// Path where the completed Report is saved
|
||||||
private val reportFileDestination = "./src/main/resources/jasper/finalReport/"
|
private val reportFileDestination = "./src/main/resources/jasper/finalReport/"
|
||||||
|
|
||||||
// Path where the completed Report can be found by class loader
|
// Path where the completed Report can be found by class loader
|
||||||
private val reportFileForClassLoader = "/jasper/finalReport/"
|
private val reportFileForClassLoader = "/jasper/finalReport/"
|
||||||
|
|
||||||
fun createReport(projectReportCollection: ProjectReport, reportFormat: String): Mono<String> {
|
fun createReport(projectReportCollection: ProjectReport, reportFormat: String): Mono<ByteArray> {
|
||||||
val C4POPentestReport: PDFMergerUtility = PDFMergerUtility()
|
// Setup Filepath destination
|
||||||
val reportFilePathDestination: String = reportFileDestination + projectReportCollection.title.replace(" ", "_") + "_report.pdf"
|
val reportFilePathDestination: String =
|
||||||
val reportFilePathForClassLoader: String = reportFileForClassLoader + projectReportCollection.title.replace(" ", "_") + "_report.pdf"
|
reportFileDestination + projectReportCollection.title.replace(" ", "_") + "_report.pdf"
|
||||||
|
// Setup PDFMergerUtility
|
||||||
|
val mergedC4POPentestReport: PDFMergerUtility = PDFMergerUtility()
|
||||||
|
// Setup ByteArrayOutputStream for "on the fly" file generation
|
||||||
|
val pdfDocOutputstream = ByteArrayOutputStream()
|
||||||
// Try to create report files & merge them together
|
// Try to create report files & merge them together
|
||||||
return try {
|
return createPentestReportFiles(projectReportCollection, reportFormat, mergedC4POPentestReport).collectList().map {
|
||||||
// Create report files
|
// Merge report files
|
||||||
val coverFile: File = createCover(projectReportCollection, reportFormat)
|
mergedC4POPentestReport.destinationFileName = reportFilePathDestination
|
||||||
val contentFile: File = createTableOfContent(projectReportCollection, reportFormat)
|
mergedC4POPentestReport.destinationStream = pdfDocOutputstream
|
||||||
val confidentialityFile: File = createStateOfConfidentiality(projectReportCollection, reportFormat)
|
mergedC4POPentestReport.mergeDocuments(MemoryUsageSetting.setupTempFileOnly())
|
||||||
val summaryFile: File = createExecutiveSummary(projectReportCollection, reportFormat)
|
}.flatMap {
|
||||||
val pentestFiles: List<File> = createPentestReports(projectReportCollection, reportFormat)
|
return@flatMap Mono.just(pdfDocOutputstream.toByteArray())
|
||||||
val appendenciesFile: File = createAppendencies(reportFormat)
|
}.doOnError {
|
||||||
// Add files to [C4POPentestReport]
|
|
||||||
C4POPentestReport.addSource(coverFile)
|
|
||||||
C4POPentestReport.addSource(contentFile)
|
|
||||||
C4POPentestReport.addSource(confidentialityFile)
|
|
||||||
C4POPentestReport.addSource(summaryFile)
|
|
||||||
// Merge every Pentestreport file in List of File
|
|
||||||
pentestFiles.forEach { pentestFile -> C4POPentestReport.addSource(pentestFile) }
|
|
||||||
C4POPentestReport.addSource(appendenciesFile)
|
|
||||||
// Save completed report
|
|
||||||
C4POPentestReport.destinationFileName = reportFilePathDestination
|
|
||||||
C4POPentestReport.mergeDocuments()
|
|
||||||
reportFilePathForClassLoader.toMono()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logger.error("Report generation failed.")
|
logger.error("Report generation failed.")
|
||||||
Mono.just("")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +75,32 @@ class ReportService {
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.error("Report file cleanup failed with exception: ", e)
|
logger.error("Report file cleanup failed with exception: ", e)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createPentestReportFiles(
|
||||||
|
projectReportCollection: ProjectReport,
|
||||||
|
reportFormat: String,
|
||||||
|
mergedC4POPentestReport: PDFMergerUtility
|
||||||
|
): Flux<Unit> {
|
||||||
|
return Flux.just(
|
||||||
|
// Create report files
|
||||||
|
createCover(projectReportCollection, reportFormat),
|
||||||
|
createTableOfContent(projectReportCollection, reportFormat),
|
||||||
|
createStateOfConfidentiality(projectReportCollection, reportFormat),
|
||||||
|
createExecutiveSummary(projectReportCollection, reportFormat),
|
||||||
|
createPentestReports(projectReportCollection, reportFormat),
|
||||||
|
createAppendencies(reportFormat)
|
||||||
|
).map { jasperObject ->
|
||||||
|
if (jasperObject is File) {
|
||||||
|
mergedC4POPentestReport.addSource(jasperObject)
|
||||||
|
} else if (jasperObject is List<*>) {
|
||||||
|
jasperObject.forEach { jasperFile ->
|
||||||
|
if (jasperFile is File) {
|
||||||
|
mergedC4POPentestReport.addSource(jasperFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createCover(projectReportCollection: ProjectReport, reportFormat: String): File {
|
private fun createCover(projectReportCollection: ProjectReport, reportFormat: String): File {
|
||||||
|
@ -284,7 +306,7 @@ class ReportService {
|
||||||
// Create File
|
// Create File
|
||||||
var finalFile: File = File(reportDefaultPdf)
|
var finalFile: File = File(reportDefaultPdf)
|
||||||
return if (reportFormat.equals("pdf")) {
|
return if (reportFormat.equals("pdf")) {
|
||||||
JasperExportManager.exportReportToPdfFile(jasperPrintContent,reportDestination + "D_ExecutiveSummary.pdf")
|
JasperExportManager.exportReportToPdfFile(jasperPrintContent, reportDestination + "D_ExecutiveSummary.pdf")
|
||||||
finalFile = File(reportDestination + "D_ExecutiveSummary.pdf")
|
finalFile = File(reportDestination + "D_ExecutiveSummary.pdf")
|
||||||
finalFile
|
finalFile
|
||||||
} else {
|
} else {
|
||||||
|
@ -311,16 +333,18 @@ class ReportService {
|
||||||
// val pentestCommentsDataSource =
|
// val pentestCommentsDataSource =
|
||||||
// Setup Parameter & add Sub-datasets
|
// Setup Parameter & add Sub-datasets
|
||||||
val parameters = HashMap<String, Any>()
|
val parameters = HashMap<String, Any>()
|
||||||
parameters["PentestFindingsDataSource"] = if (projectReportCollection.projectPentestReport[i].findings.isNotEmpty()) {
|
parameters["PentestFindingsDataSource"] =
|
||||||
JRBeanCollectionDataSource(projectReportCollection.projectPentestReport[i].findings)
|
if (projectReportCollection.projectPentestReport[i].findings.isNotEmpty()) {
|
||||||
} else {
|
JRBeanCollectionDataSource(projectReportCollection.projectPentestReport[i].findings)
|
||||||
JRBeanCollectionDataSource(emptyList<Finding>())
|
} else {
|
||||||
}
|
JRBeanCollectionDataSource(emptyList<Finding>())
|
||||||
parameters["PentestCommentsDataSource"] = if (projectReportCollection.projectPentestReport[i].comments.isNotEmpty()) {
|
}
|
||||||
JRBeanCollectionDataSource(projectReportCollection.projectPentestReport[i].comments)
|
parameters["PentestCommentsDataSource"] =
|
||||||
} else {
|
if (projectReportCollection.projectPentestReport[i].comments.isNotEmpty()) {
|
||||||
JRBeanCollectionDataSource(emptyList<Comment>())
|
JRBeanCollectionDataSource(projectReportCollection.projectPentestReport[i].comments)
|
||||||
}
|
} else {
|
||||||
|
JRBeanCollectionDataSource(emptyList<Comment>())
|
||||||
|
}
|
||||||
// Fill Reports
|
// Fill Reports
|
||||||
// Print one report for each objective and merge them together afterwards
|
// Print one report for each objective and merge them together afterwards
|
||||||
val jasperPrintPentests: JasperPrint =
|
val jasperPrintPentests: JasperPrint =
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
## IdentityProvider (Keycloak) ##
|
||||||
|
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://c4po-keycloak:8080/auth/realms/c4po_realm_local
|
||||||
|
keycloakhost=c4po-keycloak
|
||||||
|
keycloak.client.url=http://c4po-keycloak:8080
|
||||||
|
keycloak.client.realm.path=auth/realms/c4po_realm_local/
|
|
@ -0,0 +1,4 @@
|
||||||
|
## IdentityProvider (Keycloak) ##
|
||||||
|
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/auth/realms/c4po_realm_local
|
||||||
|
keycloakhost=localhost
|
||||||
|
keycloak.client.url=http://localhost:8080/
|
|
@ -0,0 +1,3 @@
|
||||||
|
## IdentityProvider (Keycloak) ##
|
||||||
|
keycloak.client.url=http://localhost:9999
|
||||||
|
keycloak.client.realm.path=auth/realms/c4po_realm_local/
|
|
@ -20,10 +20,11 @@ api.client.findings.path=pentests/findings
|
||||||
api.client.comments.path=pentests/comments
|
api.client.comments.path=pentests/comments
|
||||||
|
|
||||||
## IdentityProvider (Keycloak) ##
|
## IdentityProvider (Keycloak) ##
|
||||||
# spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8888/auth/realms/c4po_realm_local
|
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/auth/realms/c4po_realm_local
|
||||||
# keycloakhost=localhost
|
external.issuer-uri=http://localhost:8080/auth/realms/c4po_realm_local
|
||||||
# keycloak.client.url=http://localhost:8888
|
keycloakhost=localhost
|
||||||
# keycloak.client.realm.path=auth/realms/c4po_realm_local/
|
keycloak.client.url=http://localhost:8080
|
||||||
|
keycloak.client.realm.path=auth/realms/c4po_realm_local/
|
||||||
|
|
||||||
## Total number of pentests listet in the OWASP testing guide
|
## Total number of pentests listet in the OWASP testing guide
|
||||||
## https://owasp.org/www-project-web-security-testing-guide/assets/archive/OWASP_Testing_Guide_v4.pdf
|
## https://owasp.org/www-project-web-security-testing-guide/assets/archive/OWASP_Testing_Guide_v4.pdf
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue