feat: added mongodb to microservice and docker compose
This commit is contained in:
parent
dfc5e1a934
commit
47dd096da6
|
@ -0,0 +1,4 @@
|
|||
.DS_Store
|
||||
# Volumes
|
||||
/security-c4po-cfg/volumes/keycloak/data/*
|
||||
/security-c4po-cfg/volumes/mongodb/data/*
|
23
c4po.sh
23
c4po.sh
|
@ -1,11 +1,17 @@
|
|||
#!/bin/bash
|
||||
docker_reg="c4po.io"
|
||||
baseDir=$(pwd)
|
||||
|
||||
composeDir=$baseDir"/security-c4po-cfg"
|
||||
keycloakVolume="security-c4po-cfg/volumes/keycloak/data/*"
|
||||
mongoVolume="security-c4po-cfg/volumes/mongodb/data/*"
|
||||
|
||||
composeKeycloak=$baseDir"/security-c4po-cfg/kc/docker-compose.keycloak.yml"
|
||||
composeDatabase=$baseDir"/security-c4po-cfg/mongodb/docker-compose.mongodb.yml"
|
||||
composeFrontend=$baseDir"/security-c4po-cfg/frontend/docker-compose.frontend.yml"
|
||||
composeBackend=$baseDir"/security-c4po-cfg/backend/docker-compose.backend.yml"
|
||||
|
||||
compose=$baseDir"/security-c4po-cfg/docker-compose.yml"
|
||||
|
||||
echo -e "
|
||||
_______ _______ _______ _ _ ______ _____ _______ __ __
|
||||
|______ |______ | | | |_____/ | | \_/
|
||||
|
@ -18,12 +24,13 @@ ______| |______ |_____ |_____| | \_ __|__ | | _/_/_/ _/
|
|||
|
||||
echo "-------------CLEAN UP Container---------------"
|
||||
echo -e "\n"
|
||||
#docker rm -f security-c4po-keycloak
|
||||
#docker rm -f security-c4po-postgres-keycloak
|
||||
docker rm -f security-c4po-api
|
||||
docker rm -f security-c4po-angular
|
||||
rm -r ${keycloakVolume}
|
||||
docker rm -f c4po-keycloak
|
||||
docker rm -f c4po-keycloak-postgres
|
||||
docker rm -f c4po-db
|
||||
docker rm -f c4po-api
|
||||
docker rm -f c4po-angular
|
||||
echo -e "\n"
|
||||
|
||||
echo "-----------------Start Build------------------"
|
||||
echo -e "\n"
|
||||
echo " - Backend: "
|
||||
|
@ -32,7 +39,9 @@ echo -e "\n"
|
|||
echo " - Frontend: "
|
||||
docker-compose -f ${composeFrontend} build
|
||||
echo -e "\n"
|
||||
# docker-compose -f ${compose} up
|
||||
|
||||
echo "------------Start Docker Container------------"
|
||||
echo -e "\n"
|
||||
docker-compose -f ${composeKeycloak} -f ${composeBackend} -f ${composeFrontend} up
|
||||
docker-compose -f ${composeKeycloak} -f ${composeDatabase} -f ${composeBackend} -f ${composeFrontend} up
|
||||
# docker-compose -f ${compose} up
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
HELP.md
|
||||
.gradle
|
||||
*.DS_Store
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
FROM openjdk:11-jre
|
||||
ENV TZ=Europe/Berlin
|
||||
RUN groupadd -g 9999 security-c4po-api && \
|
||||
useradd -r -u 9999 -g security-c4po-api security-c4po-api
|
||||
RUN mkdir /data
|
||||
RUN chown security-c4po-api:security-c4po-api /data
|
||||
USER security-c4po-api
|
||||
|
||||
# GET CURRENT STAGE
|
||||
ARG STAGE
|
||||
ENV ENV_STAGE=$STAGE
|
||||
|
||||
# COPY PACKAGE INTO IMAGE
|
||||
COPY ./build/libs/security-c4po-api-0.0.1-SNAPSHOT.jar .
|
||||
COPY ./build/libs/security-c4po-api-0.0.1-SNAPSHOT.jar /
|
||||
USER security-c4po-api
|
||||
EXPOSE 8443
|
||||
|
||||
# RUN JAVA
|
||||
CMD [ "java", "-jar", "security-c4po-api-0.0.1-SNAPSHOT.jar" ]
|
||||
# CMD [ "java", "-jar", "security-c4po-api-0.0.1-SNAPSHOT.jar" ]
|
||||
ENTRYPOINT [ "java", "-jar", "-Dspring.profiles.active=${ENV_STAGE}", "security-c4po-api-0.0.1-SNAPSHOT.jar" ]
|
||||
|
|
|
@ -36,6 +36,8 @@ repositories {
|
|||
mavenCentral()
|
||||
}
|
||||
|
||||
apply(plugin = "org.asciidoctor.jvm.convert")
|
||||
|
||||
dependencyCheck {
|
||||
autoUpdate = true
|
||||
cveValidForHours = 1
|
||||
|
@ -59,28 +61,33 @@ val snippetsDir = file("build/generated-snippets")
|
|||
|
||||
dependencies {
|
||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-joda:2.11.3")
|
||||
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions:1.1.1")
|
||||
implementation("javax.websocket:javax.websocket-api:1.1")
|
||||
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")
|
||||
|
||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
||||
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions:1.1.1")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
/*implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")*/
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
implementation("com.github.spotbugs:spotbugs-annotations:4.1.2")
|
||||
|
||||
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
||||
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
|
||||
implementation("com.auth0:java-jwt:3.18.1")
|
||||
implementation("org.modelmapper:modelmapper:2.3.2")
|
||||
|
||||
api("org.springframework.boot:spring-boot-starter-test")
|
||||
api("org.springframework.security:spring-security-jwt:1.1.1.RELEASE")
|
||||
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0")
|
||||
testImplementation("io.projectreactor:reactor-test")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.1")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.3.1")
|
||||
testImplementation("org.springframework.cloud:spring-cloud-contract-wiremock:2.1.0.RELEASE")
|
||||
testImplementation("org.springframework.restdocs:spring-restdocs-webtestclient")
|
||||
testImplementation("com.github.spotbugs:spotbugs-annotations:4.1.2")
|
||||
testApi("org.testcontainers:junit-jupiter:1.15.2")
|
||||
}
|
||||
|
||||
jacoco {
|
||||
|
|
|
@ -5,7 +5,11 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority
|
|||
import org.springframework.security.core.GrantedAuthority
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
|
||||
class Appuser : UserDetails {
|
||||
class Appuser internal constructor(
|
||||
val sub: String,
|
||||
val extractedUsername: String,
|
||||
val token: String
|
||||
) : UserDetails {
|
||||
|
||||
override fun getAuthorities(): Collection<GrantedAuthority> {
|
||||
return listOf("user").stream().map {
|
||||
|
|
|
@ -9,19 +9,33 @@ 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
|
||||
|
||||
/** JWT converter that takes the roles from 'groups' claim of JWT token. */
|
||||
class AppuserJwtAuthConverter(
|
||||
private val appuserDetailsService: UserAccountDetailsService) : Converter<Jwt, Mono<AbstractAuthenticationToken>> {
|
||||
class AppuserJwtAuthConverter : Converter<Jwt, Mono<AbstractAuthenticationToken>> {
|
||||
|
||||
override fun convert(jwt: Jwt): Mono<AbstractAuthenticationToken> {
|
||||
val authorities = extractAuthorities(jwt)
|
||||
return appuserDetailsService
|
||||
.findByUsername(jwt.getClaimAsString("sub"))
|
||||
.map { u ->
|
||||
UsernamePasswordAuthenticationToken(u, "n/a", authorities);
|
||||
}
|
||||
val sub = extractSub(jwt)
|
||||
val username = extractUserName(jwt)
|
||||
return UsernamePasswordAuthenticationToken(Appuser(sub, username, jwt.tokenValue!!), "n/a", authorities).toMono()
|
||||
}
|
||||
|
||||
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> {
|
||||
|
@ -35,19 +49,18 @@ class AppuserJwtAuthConverter(
|
|||
private fun getScopes(jwt: Jwt): Collection<String> {
|
||||
val mapper = ObjectMapper()
|
||||
val scopes = jwt.getClaims().get(GROUPS_CLAIM).toString()
|
||||
if (scopes != null) {
|
||||
val roleStringValue = mapper.readTree(scopes).get("roles").toString()
|
||||
val roles = mapper.readValue<Collection<String>>(roleStringValue)
|
||||
if (!roles.isEmpty()){
|
||||
return roles
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +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()
|
||||
}
|
||||
}
|
|
@ -1,18 +1,18 @@
|
|||
package com.securityc4po.api.configuration.security
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.Lazy
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.web.cors.CorsConfiguration
|
||||
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.web.server.SecurityWebFilterChain
|
||||
import org.springframework.web.cors.CorsConfiguration
|
||||
|
||||
@Configuration
|
||||
@EnableWebFluxSecurity
|
||||
@EnableReactiveMethodSecurity
|
||||
class WebSecurityConfiguration(private val userAccountDetailsService: UserAccountDetailsService) {
|
||||
class WebSecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
|
@ -43,6 +43,6 @@ class WebSecurityConfiguration(private val userAccountDetailsService: UserAccoun
|
|||
|
||||
@Bean
|
||||
fun appuserJwtAuthenticationConverter(): AppuserJwtAuthConverter {
|
||||
return AppuserJwtAuthConverter(userAccountDetailsService)
|
||||
return AppuserJwtAuthConverter()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,35 +2,27 @@ package com.securityc4po.api.project
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat
|
||||
import com.securityc4po.api.ResponseBody
|
||||
import org.springframework.data.mongodb.core.index.Indexed
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
data class Project(
|
||||
/*
|
||||
* @Indexed(background = true, unique = true)
|
||||
* Can be used after adding deps for mongodb
|
||||
*/
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
|
||||
val client: String,
|
||||
|
||||
val title: String,
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
/* Change to Instant after database integration */
|
||||
val createdAt: String,
|
||||
|
||||
val tester: String? = null,
|
||||
|
||||
val logo: String? = null
|
||||
@Indexed(background = true, unique = true)
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
val client: String,
|
||||
val title: String,
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
val createdAt: String = Instant.now().toString(),
|
||||
val tester: String? = null,
|
||||
val logo: String? = null
|
||||
)
|
||||
|
||||
fun Project.toProjectResponseBody(): ResponseBody {
|
||||
return kotlin.collections.mapOf(
|
||||
return mapOf(
|
||||
"id" to id,
|
||||
"client" to client,
|
||||
"title" to title,
|
||||
"createdAt" to createdAt.toString(),
|
||||
"createdAt" to createdAt,
|
||||
"tester" to tester,
|
||||
"logo" to logo
|
||||
)
|
||||
|
|
|
@ -4,9 +4,9 @@ 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 org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/projects")
|
||||
|
@ -22,8 +22,13 @@ class ProjectController(private val projectService: ProjectService) {
|
|||
var logger = getLoggerFor<ProjectController>()
|
||||
|
||||
@GetMapping
|
||||
fun getProjects(): List<Project> {
|
||||
return projectService.getProjects()
|
||||
fun getProjects(): Mono<ResponseEntity<List<ResponseBody>>> {
|
||||
return projectService.getProjects().map {
|
||||
it.map {
|
||||
it.toProjectResponseBody()
|
||||
}
|
||||
}.map {
|
||||
ResponseEntity.ok(it)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,26 @@
|
|||
package com.securityc4po.api.project
|
||||
|
||||
import com.securityc4po.api.BaseEntity
|
||||
import org.springframework.data.mongodb.core.mapping.Document
|
||||
|
||||
/*
|
||||
* @Document(collection = "project")
|
||||
* Can be used after adding deps for mongodb
|
||||
*/
|
||||
@Document(collection = "projects")
|
||||
open class ProjectEntity(
|
||||
data: Project
|
||||
) : BaseEntity<Project>(data)
|
||||
|
||||
fun ProjectEntity.toProject() : Project {
|
||||
return Project(
|
||||
this.data.id,
|
||||
this.data.client,
|
||||
this.data.title,
|
||||
this.data.createdAt,
|
||||
this.data.tester,
|
||||
this.data.logo
|
||||
)
|
||||
}
|
||||
|
||||
fun List<ProjectEntity>.toProjects(): List<Project> {
|
||||
return this.map {
|
||||
it.toProject()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.securityc4po.api.project
|
||||
|
||||
import org.springframework.data.mongodb.repository.Query
|
||||
import org.springframework.data.mongodb.repository.ReactiveMongoRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@Repository
|
||||
interface ProjectRepository: ReactiveMongoRepository<ProjectEntity, String> {
|
||||
|
||||
@Query("{'data._id' : ?0}")
|
||||
fun findProjectById(id: String): Mono<ProjectEntity>
|
||||
}
|
|
@ -1,39 +1,22 @@
|
|||
package com.securityc4po.api.project
|
||||
|
||||
import com.securityc4po.api.extensions.getLoggerFor
|
||||
import org.junit.BeforeClass
|
||||
import org.springframework.stereotype.Service
|
||||
import reactor.core.publisher.Flux
|
||||
/* Remove after database is integrated */
|
||||
import java.io.File
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@Service
|
||||
class ProjectService() {
|
||||
class ProjectService(private val projectRepository: ProjectRepository) {
|
||||
|
||||
var logger = getLoggerFor<ProjectService>()
|
||||
|
||||
/* Remove after database is integrated */
|
||||
val mapper = jacksonObjectMapper()
|
||||
|
||||
@BeforeClass
|
||||
fun init() {
|
||||
mapper.registerKotlinModule()
|
||||
mapper.registerModule(JavaTimeModule())
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all [Project]s
|
||||
*
|
||||
* @return list of [Project]
|
||||
*/
|
||||
fun getProjects(): List<Project> {
|
||||
val jsonProjectsString: String = File("./src/main/resources/mocks/projects.json").readText(Charsets.UTF_8)
|
||||
val jsonProjectList: List<Project> = mapper.readValue<List<Project>>(jsonProjectsString)
|
||||
/* After database integration the return should be Flux of ProjectEntity */
|
||||
return jsonProjectList;
|
||||
fun getProjects(): Mono<List<Project>> {
|
||||
return projectRepository.findAll().collectList().map {
|
||||
it.map { projectEntity -> projectEntity.toProject() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
## IdentityProvider (Keycloak) ##
|
||||
# spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8888/auth/realms/c4po_realm_local
|
||||
# keycloakhost=localhost
|
||||
# keycloak.client.url=http://localhost:8888/
|
||||
|
||||
## Database (MONGODB) Config ##
|
||||
#spring.data.mongodb.host=c4po-db
|
||||
spring.data.mongodb.host=localhost
|
||||
spring.data.mongodb.port=27017
|
|
@ -0,0 +1,8 @@
|
|||
## IdentityProvider (Keycloak) ##
|
||||
# spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8888/auth/realms/c4po_realm_local
|
||||
# keycloakhost=localhost
|
||||
# keycloak.client.url=http://localhost:8888/
|
||||
|
||||
## Database (MONGODB) Config ##
|
||||
spring.data.mongodb.host=localhost
|
||||
spring.data.mongodb.port=27017
|
|
@ -1,6 +1,7 @@
|
|||
## General Properties ##
|
||||
spring.main.web-application-type=reactive
|
||||
# spring.main.web-application-type=reactive
|
||||
spring.main.allow-bean-definition-overriding=true
|
||||
spring.jackson.default-property-inclusion=non_null
|
||||
|
||||
## Server Config ##
|
||||
server.port=8443
|
||||
|
@ -11,13 +12,12 @@ management.endpoint.health.enabled=true
|
|||
management.endpoints.web.exposure.include=info, health, metrics
|
||||
|
||||
## Database (MONGODB) Config ##
|
||||
# spring.data.mongodb.database=C4PO
|
||||
# spring.data.mongodb.host=localhost
|
||||
# spring.data.mongodb.port=27017
|
||||
# spring.main.allow-bean-definition-overriding=true
|
||||
# spring.data.mongodb.auto-index-creation=true
|
||||
spring.data.mongodb.database=c4po
|
||||
spring.data.mongodb.auto-index-creation=true
|
||||
|
||||
## IdentityProvider (Keycloak for tests) ##
|
||||
## IdentityProvider (Keycloak) ##
|
||||
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8888/auth/realms/c4po_realm_local
|
||||
keycloakhost=localhost
|
||||
keycloak.client.url=http://localhost:8888/
|
||||
keycloak.client.url=http://localhost:8888/
|
||||
# keycloak.client.realm.path=auth/realms/c4po_realm_local/
|
||||
idp.jwt.claim.name.user=username
|
|
@ -1,9 +1,105 @@
|
|||
package com.securityc4po.api
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import com.github.dockerjava.api.model.ExposedPort
|
||||
import com.github.dockerjava.api.model.PortBinding
|
||||
import com.github.dockerjava.api.model.Ports
|
||||
import com.nimbusds.jwt.JWTParser
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock
|
||||
import org.springframework.http.HttpEntity
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.test.context.TestPropertySource
|
||||
import org.springframework.util.LinkedMultiValueMap
|
||||
import org.springframework.web.client.RestTemplate
|
||||
import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper
|
||||
import org.testcontainers.containers.GenericContainer
|
||||
import org.testcontainers.images.builder.ImageFromDockerfile
|
||||
import org.testcontainers.utility.DockerImageName
|
||||
import org.testcontainers.utility.MountableFile
|
||||
import java.nio.file.Paths
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
@AutoConfigureWireMock(port = 0)
|
||||
@TestPropertySource(properties = [
|
||||
"spring.data.mongodb.port=10002",
|
||||
"spring.data.mongodb.authentication-database=admin",
|
||||
"spring.data.mongodb.password=test",
|
||||
"spring.data.mongodb.username=testuser",
|
||||
"MONGO_DB_MAX_CONNECTION_IDLE_TIME=PT25M",
|
||||
"DATA_REFRESH_THRESHOLD_DURATION=PT30M",
|
||||
"CLEANUP_BATCH_SIZE_FOR_SELECTING_EXPIRED_USERS=100"
|
||||
])
|
||||
abstract class BaseContainerizedTest {
|
||||
@Value("\${keycloakhost}")
|
||||
var keycloakhost: String? = null
|
||||
|
||||
companion object {
|
||||
val mongoDbContainer = KGenericContainer(ImageFromDockerfile("c4poapibasecontainerizedtest").withDockerfileFromBuilder {
|
||||
it.from("mongo")
|
||||
it.env("MONGO_INITDB_ROOT_USERNAME", "root")
|
||||
it.env("MONGO_INITDB_ROOT_PASSWORD", "cjwkbencowepoc324pon2mop3mp4")
|
||||
it.env("MONGO_INITDB_DATABASE", "admin")
|
||||
it.add("insert-mongodb-user.js", "/docker-entrypoint-initdb.d")
|
||||
}.withFileFromPath("insert-mongodb-user.js", Paths.get(MountableFile.forClasspathResource("insert-mongodb-user.js", 700).resolvedPath))
|
||||
).apply {
|
||||
withCreateContainerCmdModifier {
|
||||
it.hostConfig?.withPortBindings(PortBinding(Ports.Binding.bindPort(10002), ExposedPort(27017)))
|
||||
}
|
||||
start()
|
||||
}
|
||||
|
||||
val keycloakContainer = KGenericContainerFromImage(DockerImageName.parse("jboss/keycloak:6.0.1")).apply {
|
||||
withEnv("KEYCLOAK_USER", "admin")
|
||||
withEnv("KEYCLOAK_PASSWORD", "admin")
|
||||
withEnv("KEYCLOAK_IMPORT", "/tmp/realm.json")
|
||||
withEnv("DB_VENDOR", "h2")
|
||||
withCreateContainerCmdModifier {
|
||||
it.hostConfig?.withPortBindings(PortBinding(Ports.Binding.bindPort(8888), ExposedPort(8080)))
|
||||
}
|
||||
withCopyFileToContainer(MountableFile.forClasspathResource("outdated_realm-export.json", 700), "/tmp/realm.json")
|
||||
withCopyFileToContainer(MountableFile.forClasspathResource("create-keycloak-user.sh", 700),
|
||||
"/opt/jboss/create-keycloak-user.sh")
|
||||
start()
|
||||
println("== Inserting users must wait until Keycloak is started completely ==")
|
||||
execInContainer("sh", "/opt/jboss/create-keycloak-user.sh")
|
||||
}
|
||||
}
|
||||
|
||||
var token = "n/a"
|
||||
var tokenAdmin = "n/a"
|
||||
var tokenUser = "n/a"
|
||||
var keycloakHost: String? = null
|
||||
|
||||
fun getAccessToken(username: String, password: String, clientId: String, realm: String): String {
|
||||
keycloakHost = "http://" + keycloakhost + ":" + keycloakContainer.getMappedPort(8080)
|
||||
val restTemplate = RestTemplate()
|
||||
val headers = HttpHeaders()
|
||||
headers.contentType = MediaType.APPLICATION_FORM_URLENCODED
|
||||
|
||||
val map = LinkedMultiValueMap<Any, Any>()
|
||||
map.add("grant_type", "password")
|
||||
map.add("client_id", clientId)
|
||||
map.add("username", username)
|
||||
map.add("password", password)
|
||||
map.add("client_secret", "secret")
|
||||
val responseString = restTemplate.postForObject("$keycloakHost/auth/realms/$realm/protocol/openid-connect/token",
|
||||
HttpEntity<Any>(map, headers), String::class.java)
|
||||
val token = ObjectMapper().readValue(responseString, KeyCloakToken::class.java)
|
||||
return token.access_token!!
|
||||
}
|
||||
|
||||
fun getSubClaim(token: String): String {
|
||||
val jwt = JWTParser.parse(token)
|
||||
val scopes = ObjectMapper().readValue(jwt.jwtClaimsSet.toJSONObject().toJSONString(), HashMap::class.java)
|
||||
return scopes["sub"] as String
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class KeyCloakToken(val access_token: String? = null)
|
||||
|
||||
class KGenericContainerFromImage(imageName: DockerImageName) : GenericContainer<KGenericContainerFromImage>(imageName)
|
||||
class KGenericContainer(dockerFile: ImageFromDockerfile) : GenericContainer<KGenericContainer>(dockerFile)
|
||||
}
|
|
@ -28,7 +28,7 @@ abstract class BaseDocumentationIntTest : BaseContainerizedTest() {
|
|||
@BeforeEach
|
||||
fun setupDocs(restDocumentation: RestDocumentationContextProvider) {
|
||||
webTestClient = WebTestClient.bindToServer()
|
||||
.baseUrl("com.securityc4po.api.http://localhost:$port")
|
||||
.baseUrl("http://localhost:$port")
|
||||
.filter(documentationConfiguration(restDocumentation))
|
||||
.responseTimeout(Duration.ofMillis(10000))
|
||||
.build()
|
||||
|
|
|
@ -8,4 +8,4 @@ import org.springframework.test.context.junit.jupiter.SpringExtension
|
|||
@ExtendWith(SpringExtension::class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@DirtiesContext
|
||||
abstract class BaseIntTest : BaseContainerizedTest() { }
|
||||
abstract class BaseIntTest : BaseContainerizedTest()
|
|
@ -9,6 +9,7 @@ import org.junit.jupiter.api.Nested
|
|||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock
|
||||
import org.springframework.data.mongodb.core.MongoTemplate
|
||||
import org.springframework.restdocs.operation.preprocess.Preprocessors
|
||||
import org.springframework.restdocs.payload.JsonFieldType
|
||||
import org.springframework.restdocs.payload.PayloadDocumentation
|
||||
|
@ -18,8 +19,8 @@ import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
|
|||
@SuppressFBWarnings(SIC_INNER_SHOULD_BE_STATIC)
|
||||
class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||
|
||||
/*@Autowired
|
||||
lateinit var mongoTemplate: MongoTemplate*/
|
||||
@Autowired
|
||||
lateinit var mongoTemplate: MongoTemplate
|
||||
|
||||
@BeforeEach
|
||||
fun init() {
|
||||
|
|
|
@ -5,38 +5,54 @@ import com.securityc4po.api.BaseIntTest
|
|||
import com.securityc4po.api.configuration.SIC_INNER_SHOULD_BE_STATIC
|
||||
import com.securityc4po.api.configuration.URF_UNREAD_FIELD
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
|
||||
import io.netty.handler.ssl.SslContextBuilder
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.web.server.LocalServerPort
|
||||
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock
|
||||
import org.springframework.data.mongodb.core.MongoTemplate
|
||||
import org.springframework.data.mongodb.core.query.Query
|
||||
import org.springframework.test.context.TestPropertySource
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import org.springframework.util.ResourceUtils
|
||||
import reactor.netty.http.client.HttpClient
|
||||
import java.time.Duration
|
||||
|
||||
@AutoConfigureWireMock(port = 0)
|
||||
@SuppressFBWarnings(SIC_INNER_SHOULD_BE_STATIC, URF_UNREAD_FIELD, "Unread field will become used after database implementation")
|
||||
/*@TestPropertySource(
|
||||
properties = [
|
||||
"keycloak.client.url=http://localhost:${'$'}{wiremock.server.port}"
|
||||
]
|
||||
)*/
|
||||
@SuppressFBWarnings(
|
||||
SIC_INNER_SHOULD_BE_STATIC,
|
||||
URF_UNREAD_FIELD,
|
||||
"Unread field will become used after database implementation"
|
||||
)
|
||||
class ProjectControllerIntTest : BaseIntTest() {
|
||||
|
||||
@LocalServerPort
|
||||
private var port = 0
|
||||
|
||||
@Autowired
|
||||
lateinit var mongoTemplate: MongoTemplate
|
||||
|
||||
private lateinit var webTestClient: WebTestClient
|
||||
|
||||
@BeforeEach
|
||||
fun setupWebClient() {
|
||||
webTestClient = WebTestClient.bindToServer()
|
||||
.baseUrl("http://localhost:$port")
|
||||
.responseTimeout(Duration.ofMillis(10000))
|
||||
.build()
|
||||
.baseUrl("http://localhost:$port")
|
||||
.responseTimeout(Duration.ofMillis(10000))
|
||||
.build()
|
||||
}
|
||||
|
||||
/*@Autowired
|
||||
lateinit var mongoTemplate: MongoTemplate*/
|
||||
|
||||
@BeforeEach
|
||||
fun init() {
|
||||
cleanUp()
|
||||
configureAdminToken()
|
||||
persistBasicTestScenario()
|
||||
}
|
||||
|
||||
|
@ -44,63 +60,67 @@ class ProjectControllerIntTest : BaseIntTest() {
|
|||
inner class GetProjects {
|
||||
@Test
|
||||
fun `requesting projects successfully`() {
|
||||
/* Implement after the implementation of database */
|
||||
|
||||
/*webTestClient.get().uri("/v1/projects")
|
||||
.header("")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
.expectHeader().doesNotExist("")
|
||||
.expectBody().json(Json.write(getProjects()))*/
|
||||
webTestClient.get().uri("/v1/projects")
|
||||
.header("Authorization", "Bearer $tokenAdmin")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
.expectHeader().valueEquals("Application-Name", "security-c4po-api")
|
||||
.expectBody().json(Json.write(getProjects()))
|
||||
}
|
||||
|
||||
val projectOne = Project(
|
||||
id = "4f6567a8-76fd-487b-8602-f82d0ca4d1f9",
|
||||
client = "E Corp",
|
||||
title = "Some Mock API (v1.0) Scanning",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Novatester",
|
||||
logo = "Insert'E_Corp.png'BASE64Encoded"
|
||||
id = "4f6567a8-76fd-487b-8602-f82d0ca4d1f9",
|
||||
client = "E Corp",
|
||||
title = "Some Mock API (v1.0) Scanning",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Novatester",
|
||||
logo = "Insert'E_Corp.png'BASE64Encoded"
|
||||
)
|
||||
val projectTwo = Project(
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
client = "Allsafe",
|
||||
title = "CashMyData (iOS)",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Elliot",
|
||||
logo = "Insert'Allsafe.png'BASE64Encoded"
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
client = "Allsafe",
|
||||
title = "CashMyData (iOS)",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Elliot",
|
||||
logo = "Insert'Allsafe.png'BASE64Encoded"
|
||||
)
|
||||
|
||||
private fun getProjects() = listOf(
|
||||
projectOne.toProjectResponseBody(),
|
||||
projectTwo.toProjectResponseBody()
|
||||
projectOne.toProjectResponseBody(),
|
||||
projectTwo.toProjectResponseBody()
|
||||
)
|
||||
}
|
||||
|
||||
private fun cleanUp() {
|
||||
/*mongoTemplate.findAllAndRemove(Query(), Project::class.java)*/
|
||||
mongoTemplate.findAllAndRemove(Query(), Project::class.java)
|
||||
|
||||
tokenAdmin = "n/a"
|
||||
}
|
||||
|
||||
private fun persistBasicTestScenario() {
|
||||
// setup test data
|
||||
val projectOne = Project(
|
||||
id = "4f6567a8-76fd-487b-8602-f82d0ca4d1f9",
|
||||
client = "E Corp",
|
||||
title = "Some Mock API (v1.0) Scanning",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Novatester",
|
||||
logo = "Insert'E_Corp.png'BASE64Encoded"
|
||||
id = "4f6567a8-76fd-487b-8602-f82d0ca4d1f9",
|
||||
client = "E Corp",
|
||||
title = "Some Mock API (v1.0) Scanning",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Novatester",
|
||||
logo = "Insert'E_Corp.png'BASE64Encoded"
|
||||
)
|
||||
val projectTwo = Project(
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
client = "Allsafe",
|
||||
title = "CashMyData (iOS)",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Elliot",
|
||||
logo = "Insert'Allsafe.png'BASE64Encoded"
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
client = "Allsafe",
|
||||
title = "CashMyData (iOS)",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Elliot",
|
||||
logo = "Insert'Allsafe.png'BASE64Encoded"
|
||||
)
|
||||
cleanUp()
|
||||
/*mongoTemplate.save(ProjectEntity(projectOne))
|
||||
mongoTemplate.save(ProjectEntity(projectTwo))*/
|
||||
mongoTemplate.save(ProjectEntity(projectOne))
|
||||
mongoTemplate.save(ProjectEntity(projectTwo))
|
||||
}
|
||||
|
||||
private fun configureAdminToken() {
|
||||
tokenAdmin = getAccessToken("test_admin", "test", "c4po_local", "c4po_realm_local")
|
||||
}
|
||||
}
|
|
@ -12,7 +12,9 @@ class ProjectServiceTest {
|
|||
|
||||
private val log = mock<Logger>()
|
||||
|
||||
private val cut = ProjectService().apply {
|
||||
private val projectRepository = mock<ProjectRepository>()
|
||||
|
||||
private val cut = ProjectService(projectRepository).apply {
|
||||
this.logger = log
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
cd keycloak/bin
|
||||
sleep 20
|
||||
./kcadm.sh config credentials --server http://localhost:8080/auth --realm master --user admin --password admin
|
||||
|
||||
USERID=$(./kcadm.sh create users -r c4po_realm_local -s username=test_admin \
|
||||
-s email=Test.Admin@heros.com \
|
||||
-s firstName=test \
|
||||
-s lastName=admin \
|
||||
-s attributes.lang="de-DE" \
|
||||
-s attributes.datenumberformat="en-US" \
|
||||
-o --fields id | jq '.id' | tr -d '"')
|
||||
|
||||
./kcadm.sh update users/$USERID/reset-password -r c4po_realm_test -s type=password -s value=test -s temporary=false -n
|
||||
./kcadm.sh add-roles --uusername test_admin --rolename c4po_admin -r c4po_realm_test
|
||||
./kcadm.sh add-roles -r c4po_realm_test --uusername test_admin --cclientid realm-management --rolename create-client --rolename view-users
|
||||
|
||||
USERID=$(./kcadm.sh create users -r c4po_realm_local -s username=test_user \
|
||||
-s email=Test.User@heros.com \
|
||||
-s firstName=test \
|
||||
-s lastName=user \
|
||||
-s attributes.lang="de-DE" \
|
||||
-s attributes.datenumberformat="en-US" \
|
||||
-o --fields id | jq '.id' | tr -d '"')
|
||||
|
||||
./kcadm.sh update users/$USERID/reset-password -r c4po_realm_test -s type=password -s value=test -s temporary=false -n
|
||||
./kcadm.sh add-roles --uusername test_user --rolename c4po_user -r c4po_realm_test
|
||||
./kcadm.sh add-roles -r c4po_realm_test --uusername test_user --cclientid realm-management --rolename create-client --rolename view-users
|
|
@ -0,0 +1,12 @@
|
|||
db.createUser(
|
||||
{
|
||||
user: "testuser",
|
||||
pwd: "test",
|
||||
roles: [
|
||||
{
|
||||
role: "readWrite",
|
||||
db: "c4po"
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
cd keycloak/bin
|
||||
sleep 20
|
||||
./kcadm.sh config credentials --server http://localhost:8888/auth --realm master --user admin --password admin
|
||||
|
||||
USERID=$(./kcadm.sh create users -r c4po_realm_local -s username=test_admin \
|
||||
-s email=Troy.Stewart@heros.com \
|
||||
-s firstName=test \
|
||||
-s lastName=admin \
|
||||
-s attributes.lang="de-DE" \
|
||||
-s attributes.datenumberformat="en-US" \
|
||||
-o --fields id | jq '.id' | tr -d '"')
|
||||
|
||||
./kcadm.sh update users/$USERID/reset-password -r c4po_realm_test -s type=password -s value=test -s temporary=false -n
|
||||
./kcadm.sh add-roles --uusername test_admin --rolename c4po_admin -r c4po_realm_test
|
||||
./kcadm.sh add-roles -r c4po_realm_test --uusername test_admin --cclientid realm-management --rolename create-client --rolename view-users
|
||||
|
||||
USERID=$(./kcadm.sh create users -r c4po_realm_local -s username=test_user \
|
||||
-s email=Troy.Stewart@heros.com \
|
||||
-s firstName=test \
|
||||
-s lastName=user \
|
||||
-s attributes.lang="de-DE" \
|
||||
-s attributes.datenumberformat="en-US" \
|
||||
-o --fields id | jq '.id' | tr -d '"')
|
||||
|
||||
./kcadm.sh update users/$USERID/reset-password -r c4po_realm_test -s type=password -s value=test -s temporary=false -n
|
||||
./kcadm.sh add-roles --uusername test_user --rolename c4po_user -r c4po_realm_test
|
||||
./kcadm.sh add-roles -r c4po_realm_test --uusername test_user --cclientid realm-management --rolename create-client --rolename view-users
|
|
@ -4,13 +4,18 @@ services:
|
|||
c4po-api:
|
||||
build: '../../security-c4po-api'
|
||||
image: security-c4po-api:latest
|
||||
container_name: security-c4po-api
|
||||
container_name: c4po-api
|
||||
environment:
|
||||
- SPRING_PROFILES_ACTIVE=COMPOSE
|
||||
depends_on:
|
||||
- c4po-db
|
||||
- c4po-keycloak
|
||||
links:
|
||||
- c4po-db
|
||||
- c4po-keycloak
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: "1G"
|
||||
ports:
|
||||
- '8443:8443'
|
||||
|
||||
networks:
|
||||
c4po:
|
||||
- 8443:8443
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
{
|
||||
"id" : "c4po_realm_local",
|
||||
"realm" : "c4po_realm_local",
|
||||
"displayName" : "C4PO",
|
||||
"displayNameHtml" : "<div><span>C4PO</span></div>",
|
||||
"notBefore" : 0,
|
||||
"revokeRefreshToken" : false,
|
||||
"refreshTokenMaxReuse" : 0,
|
||||
|
@ -380,7 +382,7 @@
|
|||
} ],
|
||||
"disableableCredentialTypes" : [ ],
|
||||
"requiredActions" : [ ],
|
||||
"realmRoles" : [ "uma_authorization", "c4po_user", "offline_access", "c4po_admin" ],
|
||||
"realmRoles" : [ "uma_authorization", "c4po_user", "c4po_admin" ],
|
||||
"clientRoles" : {
|
||||
"c4po_local" : [ "user" ],
|
||||
"account" : [ "view-profile", "manage-account" ]
|
||||
|
@ -659,8 +661,8 @@
|
|||
"protocol" : "openid-connect",
|
||||
"attributes" : {
|
||||
"saml.assertion.signature" : "false",
|
||||
"saml.multivalued.roles" : "false",
|
||||
"saml.force.post.binding" : "false",
|
||||
"saml.multivalued.roles" : "false",
|
||||
"saml.encrypt" : "false",
|
||||
"saml.server.signature" : "false",
|
||||
"saml.server.signature.keyinfo.ext" : "false",
|
||||
|
@ -680,7 +682,7 @@
|
|||
}, {
|
||||
"id" : "8badc11a-50e4-44ae-a292-47e3759fcaeb",
|
||||
"clientId" : "security-c4po-api",
|
||||
"rootUrl" : "http://localhost:8443",
|
||||
"rootUrl" : "",
|
||||
"adminUrl" : "",
|
||||
"baseUrl" : "http://localhost:8443/",
|
||||
"surrogateAuthRequired" : false,
|
||||
|
@ -702,8 +704,8 @@
|
|||
"protocol" : "openid-connect",
|
||||
"attributes" : {
|
||||
"saml.assertion.signature" : "false",
|
||||
"saml.multivalued.roles" : "false",
|
||||
"saml.force.post.binding" : "false",
|
||||
"saml.multivalued.roles" : "false",
|
||||
"saml.encrypt" : "false",
|
||||
"saml.server.signature" : "false",
|
||||
"saml.server.signature.keyinfo.ext" : "false",
|
||||
|
@ -1206,7 +1208,7 @@
|
|||
"subType" : "anonymous",
|
||||
"subComponents" : { },
|
||||
"config" : {
|
||||
"allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-user-property-mapper", "saml-role-list-mapper" ]
|
||||
"allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper" ]
|
||||
}
|
||||
}, {
|
||||
"id" : "cc2d0cd7-3d3f-4b0a-ad95-7118f36bf188",
|
||||
|
@ -1238,7 +1240,7 @@
|
|||
"subType" : "authenticated",
|
||||
"subComponents" : { },
|
||||
"config" : {
|
||||
"allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ]
|
||||
"allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper" ]
|
||||
}
|
||||
}, {
|
||||
"id" : "92230e65-7480-44c3-af2d-72ddee758cbc",
|
||||
|
@ -1287,7 +1289,7 @@
|
|||
"internationalizationEnabled" : false,
|
||||
"supportedLocales" : [ ],
|
||||
"authenticationFlows" : [ {
|
||||
"id" : "2c54f19d-5992-447d-a2b3-58953c5a92d9",
|
||||
"id" : "fa5fc78f-19a9-4737-868b-618163f28c79",
|
||||
"alias" : "Account verification options",
|
||||
"description" : "Method with which to verity the existing account",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1307,7 +1309,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "58e457d2-c138-401b-94e6-aa0c89d40be5",
|
||||
"id" : "01735b0f-139f-46e5-bb63-f797a27efa77",
|
||||
"alias" : "Authentication Options",
|
||||
"description" : "Authentication options.",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1333,7 +1335,7 @@
|
|||
"autheticatorFlow" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "ed8a0f0d-c571-4c7c-8177-51ff71e0cb0e",
|
||||
"id" : "a7666cf0-626c-48c4-9e71-e408832de725",
|
||||
"alias" : "Browser - Conditional OTP",
|
||||
"description" : "Flow to determine if the OTP is required for the authentication",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1353,7 +1355,7 @@
|
|||
"autheticatorFlow" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "b12f09d6-8e47-4fa2-80cb-6adece38f970",
|
||||
"id" : "1dfabb7a-efdd-4964-bba5-389cad79b654",
|
||||
"alias" : "Direct Grant - Conditional OTP",
|
||||
"description" : "Flow to determine if the OTP is required for the authentication",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1373,7 +1375,7 @@
|
|||
"autheticatorFlow" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "571ebbe3-1dbd-4c11-a048-431ebe7b9ba0",
|
||||
"id" : "c3b2bf2b-3da8-430d-a9b7-8793c3dc30a3",
|
||||
"alias" : "First broker login - Conditional OTP",
|
||||
"description" : "Flow to determine if the OTP is required for the authentication",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1393,7 +1395,7 @@
|
|||
"autheticatorFlow" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "9efe3906-9789-45d5-bd69-17657e7d0dd1",
|
||||
"id" : "44343bdf-8592-4242-835f-e349943a110b",
|
||||
"alias" : "Handle Existing Account",
|
||||
"description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1413,7 +1415,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "ff2fc973-bd97-49f6-a5b9-234904131b12",
|
||||
"id" : "e72b8fcb-cd8b-4e7a-a057-3446b806b538",
|
||||
"alias" : "Reset - Conditional OTP",
|
||||
"description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1433,7 +1435,7 @@
|
|||
"autheticatorFlow" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "b4b2f650-4ae7-4d26-ae58-59e6074fb067",
|
||||
"id" : "2416145b-4d20-493c-bdf7-419898c002ee",
|
||||
"alias" : "User creation or linking",
|
||||
"description" : "Flow for the existing/non-existing user alternatives",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1454,7 +1456,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "5848478b-6cb0-4460-a0be-9393e8835382",
|
||||
"id" : "b7ff8aad-2daa-4736-8815-f3e8f0df391e",
|
||||
"alias" : "Verify Existing Account by Re-authentication",
|
||||
"description" : "Reauthentication of existing account",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1474,7 +1476,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "79af744f-037e-49b7-b469-4581078db93a",
|
||||
"id" : "8339d3ba-2d0a-4d23-bbfa-a78e4973d3c9",
|
||||
"alias" : "browser",
|
||||
"description" : "browser based authentication",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1506,7 +1508,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "bed9a42e-29ce-42e3-b217-4c82ddc1da60",
|
||||
"id" : "5ece002a-4e62-4d0d-8705-4b116164b424",
|
||||
"alias" : "clients",
|
||||
"description" : "Base authentication for clients",
|
||||
"providerId" : "client-flow",
|
||||
|
@ -1538,7 +1540,7 @@
|
|||
"autheticatorFlow" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "90ed59d7-616e-4db0-b5b7-b02c4778bfe6",
|
||||
"id" : "bd27b0dc-bc87-40b7-a626-491b9955668d",
|
||||
"alias" : "direct grant",
|
||||
"description" : "OpenID Connect Resource Owner Grant",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1564,7 +1566,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "02136f0a-354a-41d6-8a81-82d9d61f8ae1",
|
||||
"id" : "2db79d60-7c9d-4516-80f0-0c5d60349899",
|
||||
"alias" : "docker auth",
|
||||
"description" : "Used by Docker clients to authenticate against the IDP",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1578,7 +1580,7 @@
|
|||
"autheticatorFlow" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "61049b62-3f5e-440e-b3d3-7955c74ce79a",
|
||||
"id" : "25a92fbe-7d4d-46bc-a751-29ef844290a3",
|
||||
"alias" : "first broker login",
|
||||
"description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1599,7 +1601,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "a3416906-b38a-4626-9759-99010c6e27b9",
|
||||
"id" : "26f6a5db-9be8-446c-82d0-6f4e29b5f08d",
|
||||
"alias" : "forms",
|
||||
"description" : "Username, password, otp and other auth forms.",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1619,7 +1621,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "e53c6c19-574d-4ba0-b8b5-55631d71328d",
|
||||
"id" : "05a94701-ad98-4bbc-a162-746a107afba5",
|
||||
"alias" : "http challenge",
|
||||
"description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1639,7 +1641,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "3bc89297-8fa2-45a0-a4f9-64166c5f53f2",
|
||||
"id" : "75347884-d4cb-4eba-9b89-63566d509b92",
|
||||
"alias" : "registration",
|
||||
"description" : "registration flow",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1654,7 +1656,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "7f080e51-3567-498e-ae34-1abeefe07495",
|
||||
"id" : "74e3a2d3-ecda-400d-8bff-0926dc272e4b",
|
||||
"alias" : "registration form",
|
||||
"description" : "registration form",
|
||||
"providerId" : "form-flow",
|
||||
|
@ -1686,7 +1688,7 @@
|
|||
"autheticatorFlow" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "d0fe2454-5b33-47bd-9909-fd81dc62e27b",
|
||||
"id" : "6eae8652-baf7-4a7d-80a4-1711906caec7",
|
||||
"alias" : "reset credentials",
|
||||
"description" : "Reset credentials for a user if they forgot their password or something",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1718,7 +1720,7 @@
|
|||
"autheticatorFlow" : true
|
||||
} ]
|
||||
}, {
|
||||
"id" : "f41e0e59-1927-4f6b-9917-1fffc76ed300",
|
||||
"id" : "6135710b-b019-4117-ba32-578d3d496b2a",
|
||||
"alias" : "saml ecp",
|
||||
"description" : "SAML ECP Profile Authentication Flow",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -1733,13 +1735,13 @@
|
|||
} ]
|
||||
} ],
|
||||
"authenticatorConfig" : [ {
|
||||
"id" : "7328eecb-235e-4d51-aeb8-60f040bdce55",
|
||||
"id" : "3d3735a0-1362-4f0d-9306-bfc727da1b5b",
|
||||
"alias" : "create unique user config",
|
||||
"config" : {
|
||||
"require.password.update.after.registration" : "false"
|
||||
}
|
||||
}, {
|
||||
"id" : "3ca8532e-719d-420c-9c96-684c1195ece6",
|
||||
"id" : "c1f4a15f-8234-4f0f-affa-baf610b001e1",
|
||||
"alias" : "review profile config",
|
||||
"config" : {
|
||||
"update.profile.on.first.login" : "missing"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# cfg for local keycloak
|
||||
DB_VENDOR=postgres
|
||||
DB_ADDR=keycloak-postgres
|
||||
DB_ADDR=c4po-keycloak-postgress
|
||||
DB_PORT=5432
|
||||
DB_USER=c4po_kc_local
|
||||
DB_PASSWORD=Test1234!
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
version: '2'
|
||||
|
||||
volumes:
|
||||
c4po-keycloak-postgres:
|
||||
c4po-db:
|
||||
|
||||
services:
|
||||
# Database
|
||||
c4po-keycloak-postgres:
|
||||
container_name: c4po-keycloak-postgres
|
||||
image: postgres:latest
|
||||
env_file:
|
||||
- cfg/keycloakdb.env
|
||||
ports:
|
||||
- 5433:5432
|
||||
volumes:
|
||||
- /volumes/keycloak/data/:/var/lib/postgres/data
|
||||
networks:
|
||||
- c4po
|
||||
c4po-db:
|
||||
image: mongo:latest
|
||||
container_name: c4po-db
|
||||
volumes:
|
||||
- /volumes/mongodb/data/:/db/data
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: "1G"
|
||||
ports:
|
||||
- 27017:27017
|
||||
networks:
|
||||
- c4po
|
||||
# Authentity Provider
|
||||
c4po-keycloak:
|
||||
container_name: c4po-keycloak
|
||||
depends_on:
|
||||
- c4po-keycloak-postgres
|
||||
links:
|
||||
- c4po-keycloak-postgres
|
||||
image: jboss/keycloak:11.0.3
|
||||
volumes:
|
||||
- /cfg/c4po_realm_export.json/:/tmp/c4po_realm_export.json
|
||||
ports:
|
||||
- 8888:8080
|
||||
env_file:
|
||||
- cfg/keycloak.env
|
||||
networks:
|
||||
- c4po
|
||||
# Services
|
||||
c4po-angular:
|
||||
build: '../security-c4po-angular'
|
||||
image: security-c4po-angular:latest
|
||||
container_name: c4po-angular
|
||||
depends_on:
|
||||
- c4po-keycloak
|
||||
links:
|
||||
- c4po-keycloak
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: "1G"
|
||||
ports:
|
||||
- 4200:4200
|
||||
networks:
|
||||
- c4po
|
||||
|
||||
c4po-api:
|
||||
build: '../security-c4po-api'
|
||||
image: security-c4po-api:latest
|
||||
container_name: c4po-api
|
||||
environment:
|
||||
- SPRING_PROFILES_ACTIVE=COMPOSE
|
||||
depends_on:
|
||||
- c4po-db
|
||||
- c4po-keycloak
|
||||
links:
|
||||
- c4po-db
|
||||
- c4po-keycloak
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: "1G"
|
||||
ports:
|
||||
- 8443:8443
|
||||
networks:
|
||||
- c4po
|
||||
|
||||
networks:
|
||||
c4po:
|
|
@ -4,13 +4,12 @@ services:
|
|||
c4po-angular:
|
||||
build: '../../security-c4po-angular'
|
||||
image: security-c4po-angular:latest
|
||||
container_name: security-c4po-angular
|
||||
container_name: c4po-angular
|
||||
depends_on:
|
||||
- c4po-keycloak
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: "1G"
|
||||
ports:
|
||||
- '4200:4200'
|
||||
|
||||
networks:
|
||||
c4po:
|
||||
- 4200:4200
|
||||
|
|
|
@ -2,23 +2,22 @@ version: '3.1'
|
|||
|
||||
services:
|
||||
c4po-keycloak:
|
||||
container_name: security-c4po-keycloak
|
||||
container_name: c4po-keycloak
|
||||
depends_on:
|
||||
- keycloak-postgres
|
||||
- c4po-keycloak-postgres
|
||||
image: jboss/keycloak:11.0.3
|
||||
volumes:
|
||||
- ../cfg/c4po_realm_export.json:/tmp/c4po_realm_export.json
|
||||
ports:
|
||||
- 8888:8080
|
||||
- 9990:9990
|
||||
env_file:
|
||||
- ../cfg/keycloak.env
|
||||
keycloak-postgres:
|
||||
container_name: security-c4po-postgres-keycloak
|
||||
c4po-keycloak-postgress:
|
||||
container_name: c4po-keycloak-postgres
|
||||
image: postgres:latest
|
||||
env_file:
|
||||
- ../cfg/keycloakdb.env
|
||||
ports:
|
||||
- 5433:5432
|
||||
volumes:
|
||||
- ../volumes/keycloak/data:/var/lib/postgresql/data
|
||||
- ../volumes/keycloak/data:/var/lib/postgres/data
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
version: '3.1'
|
||||
|
||||
services:
|
||||
c4po-db:
|
||||
image: mongo:latest
|
||||
container_name: c4po-db
|
||||
volumes:
|
||||
- ../volumes/mongodb/data:/data/db
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: "1G"
|
||||
ports:
|
||||
- 27017:27017
|
Loading…
Reference in New Issue