fix: Add missing classes

This commit is contained in:
Jim Martens 2024-08-30 16:20:54 +02:00
parent b1439615bc
commit 06ce3e34b0
No known key found for this signature in database
GPG Key ID: CE04D842C9A68949
22 changed files with 357 additions and 13 deletions

View File

@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="MainApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" nameIsGenerated="true">
<envs>
<env name="CLIENT_SECRET" value="GQNAuOqPjtXUGBuu1rEbNrWYdnoAzFwM" />
</envs>
<module name="routing.server.main" />
<option name="SPRING_BOOT_MAIN_CLASS" value="de.hbt.routing.MainApplication" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -0,0 +1,38 @@
plugins {
id("hbt.jib")
}
dependencies {
implementation(project(":server"))
}
jib {
from {
image = "amazoncorretto:" + properties["projectSourceCompatibility"] + "-alpine"
platforms {
platform {
architecture = "amd64"
os = "linux"
}
platform {
architecture = "arm64"
os = "linux"
}
}
}
to {
image = "hbt/routing"
tags = setOf(
"latest",
properties["version"].toString().replace("+", "-"))
auth {
username = System.getenv("USERNAME")
password = System.getenv("PASSWORD")
}
}
container {
mainClass = "de.hbt.routing.MainApplicationKt"
jvmFlags = listOf("-XX:+UseContainerSupport",
"-XX:MaxRAMPercentage=75.0")
}
}

View File

@ -2,10 +2,8 @@ package de.hbt.routing
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.data.mongodb.config.EnableMongoAuditing
import org.springframework.scheduling.annotation.EnableScheduling
@EnableMongoAuditing
@EnableScheduling
@SpringBootApplication(scanBasePackages = ["de.hbt.support", "de.hbt.routing"])
open class MainApplication

View File

@ -0,0 +1,39 @@
package de.hbt.routing.configuration
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType
import io.swagger.v3.oas.annotations.security.OAuthFlow
import io.swagger.v3.oas.annotations.security.OAuthFlows
import io.swagger.v3.oas.annotations.security.SecurityScheme
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.info.Info
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@SecurityScheme(name = "bearerAuth", type = SecuritySchemeType.HTTP, scheme = "bearer", bearerFormat = "JWT")
@SecurityScheme(
name = "oauth2",
type = SecuritySchemeType.OAUTH2,
flows = OAuthFlows(
implicit = OAuthFlow(
authorizationUrl = "https://id.2martens.de/realms/2martens/protocol/openid-connect/auth",
tokenUrl = "https://id.2martens.de/realms/2martens/protocol/openid-connect/token"
)
)
)
@Configuration
open class OpenApiConfiguration {
@Bean
open fun customOpenAPI(
@Value("\${openapi.description}") apiDescription: String,
@Value("\${openapi.version}") apiVersion: String, @Value("\${openapi.title}") apiTitle: String
): OpenAPI {
return OpenAPI()
.info(
Info()
.title(apiTitle)
.version(apiVersion)
.description(apiDescription)
)
}
}

View File

@ -0,0 +1,15 @@
package de.hbt.routing.configuration
import de.hbt.routing.property.ServiceProperties
import de.hbt.support.property.HealthCheckProperties
import de.hbt.support.property.RestTemplateTimeoutProperties
import de.hbt.support.property.StatusProbeProperties
import de.hbt.support.property.TimeProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Configuration
@Configuration
@EnableConfigurationProperties(RestTemplateTimeoutProperties::class,
StatusProbeProperties::class, TimeProperties::class,
HealthCheckProperties::class, ServiceProperties::class)
open class PropertyConfiguration

View File

@ -0,0 +1,29 @@
package de.hbt.routing.configuration
import de.hbt.support.interceptor.HeaderInterceptorRest
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
import org.springframework.web.servlet.config.annotation.CorsRegistry
import org.springframework.web.servlet.config.annotation.InterceptorRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Configuration
open class WebConfiguration(private val headerInterceptorRest: HeaderInterceptorRest) : WebMvcConfigurer {
override fun addInterceptors(registry: InterceptorRegistry) {
registry.addInterceptor(headerInterceptorRest)
}
override fun addCorsMappings(registry: CorsRegistry) {
val registration = registry.addMapping("/**")
registration.allowedMethods(
HttpMethod.GET.name(), HttpMethod.POST.name(),
HttpMethod.PUT.name(), HttpMethod.HEAD.name(),
HttpMethod.DELETE.name()
)
registration.allowCredentials(true)
registration.allowedOrigins(
"http://localhost:4200",
"https://timetable.2martens.de"
)
}
}

View File

@ -0,0 +1,95 @@
package de.hbt.routing.configuration
import de.hbt.support.security.SpringPolicyEnforcerFilter
import org.keycloak.adapters.authorization.spi.ConfigurationResolver
import org.keycloak.adapters.authorization.spi.HttpRequest
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.EnforcementMode
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig
import org.keycloak.util.JsonSerialization
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
import org.springframework.security.config.Customizer
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer
import org.springframework.security.oauth2.jwt.JwtDecoder
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter
import org.springframework.security.web.SecurityFilterChain
import java.io.IOException
@Configuration
@EnableWebSecurity
open class WebSecurityConfiguration {
@Value("\${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
private lateinit var jwkSetUri: String
@Value("#{environment.CLIENT_SECRET}")
private lateinit var clientSecret: String
@Bean
@Throws(Exception::class)
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http
.csrf { it.disable() }
.authorizeHttpRequests { it.requestMatchers(*PERMITTED_PATHS.toTypedArray<String>()).permitAll() }
.authorizeHttpRequests { it.requestMatchers(HttpMethod.OPTIONS).permitAll() }
.authorizeHttpRequests { it.anyRequest().authenticated() }
.oauth2ResourceServer { obj: OAuth2ResourceServerConfigurer<HttpSecurity?> -> obj.jwt(Customizer.withDefaults()) }
.addFilterAfter(createPolicyEnforcerFilter(), BearerTokenAuthenticationFilter::class.java)
return http.build()
}
@Bean
open fun jwtDecoder(): JwtDecoder {
return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build()
}
private fun createPolicyEnforcerFilter(): SpringPolicyEnforcerFilter {
return SpringPolicyEnforcerFilter(object : ConfigurationResolver {
override fun resolve(request: HttpRequest): PolicyEnforcerConfig {
return try {
val policyEnforcerConfig = JsonSerialization.readValue(
javaClass.getResourceAsStream("/policy-enforcer.json"), PolicyEnforcerConfig::class.java
)
policyEnforcerConfig.credentials = mapOf(Pair("secret", clientSecret))
if (request.method == HttpMethod.OPTIONS.name()) {
// always allow options request
policyEnforcerConfig.enforcementMode = EnforcementMode.DISABLED
} else {
policyEnforcerConfig.paths = PATHS
}
policyEnforcerConfig
} catch (e: IOException) {
throw RuntimeException(e)
}
}
})
}
companion object {
private val PERMITTED_PATHS: Collection<String> = listOf(
"/routing/healthCheck",
"/actuator/**",
"/doc/v1/routing/**",
"/api-docs/v1/routing/**",
"/error",
"/routing/version",
)
private val PATHS = buildPathConfigs()
private fun buildPathConfigs(): List<PathConfig> {
val paths: MutableList<PathConfig> = mutableListOf()
for (path in PERMITTED_PATHS) {
val pathConfig = PathConfig()
pathConfig.path = path.replace("**", "*")
pathConfig.enforcementMode = EnforcementMode.DISABLED
paths.add(pathConfig)
}
return paths
}
}
}

View File

@ -0,0 +1,11 @@
package de.hbt.routing.property
import io.swagger.v3.oas.annotations.media.Schema
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.cloud.context.config.annotation.RefreshScope
@RefreshScope
@ConfigurationProperties(prefix = "de.hbt.routing")
@Schema(description = "Properties, to configure this Application")
class ServiceProperties {
}

View File

@ -0,0 +1,5 @@
spring:
config:
import:
- "classpath:config/routing.yaml"
- "optional:configserver:${CONFIGSERVER_SCHEME:http}://${CONFIGSERVER_HOST:localhost}:${CONFIGSERVER_PORT:8888}${CONFIGSERVER_PREFIX:/config}"

View File

@ -26,6 +26,9 @@ management:
http.server.requests: true
spring:
cloud:
config:
name: routing
main:
banner-mode: off
profiles:
@ -33,14 +36,13 @@ spring:
# data.mongodb:
# uri: ${MONGODB_CONNECTION_STRING}
# auto-index-creation: true
# security:
# oauth2:
# resourceserver:
# jwt:
# jwk-set-uri: ${KEYCLOAK_URL:https://id.2martens.de}/realms/${KEYCLOAK_REALM:2martens}/protocol/openid-connect/certs
# application:
# name: timetable
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: ${KEYCLOAK_URL:https://id.2martens.de}/realms/${KEYCLOAK_REALM:2martens}/protocol/openid-connect/certs
application:
name: routing
springdoc:
swagger-ui:
display-request-duration: true
@ -74,7 +76,6 @@ resttemplate:
readTimeoutRestTemplateInMillis: 5000
connectionRestTemplateTimeoutInMillis: 5000
de.hbt.routing:
de.hbt.support.health.greeting: "Good morning"
time:

View File

@ -0,0 +1,2 @@
de.hbt.support.health:
greeting: "Moin %s, you are test"

View File

@ -0,0 +1,7 @@
de.hbt.routing:
statusprobe:
scheduleDuration: 60
maxKafkaFailureDuration: 5
maxBlobFailureCount: 5
maxFailurePercent: 50
de.hbt.support.health.greeting: "Hello %s, on millenium"

View File

@ -0,0 +1,6 @@
{
"realm": "2martens",
"auth-server-url": "https://id.2martens.de",
"resource": "routing",
"http-method-as-scope": true
}

View File

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en">
<th:block th:insert="~{errorIncludes :: head}"/>
<body>
<th:block th:insert="~{errorIncludes :: mainText}"/>
<th:block th:insert="~{errorIncludes :: footer}"/>
</body>
</html>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en">
<th:block th:insert="~{errorIncludes :: head}" />
<body>
<th:block th:insert="~{errorIncludes :: mainText}" />
<p>The requested URL <code th:text="${path}"></code> was not found on this server.</p>
<th:block th:insert="~{errorIncludes :: footer}" />
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en">
<head th:fragment="head">
<title>Error <th:block th:text="${status}"/> (<th:block th:text="${error}"/>)</title>
<style>
@media (prefers-color-scheme: dark) {
html{background:#000000;color:#ffffff;font:15px/22px arial,sans-serif}
}
@media (prefers-color-scheme: light) {
html{background:#ffffff;color:#000000;font:15px/22px arial,sans-serif}
}
body{margin:50px}
h1,footer{margin:20px 0}
p{margin:0}
code{font-family: monospace,monospace}
.foot{color:#777777;font-size:80%}
</style>
</head>
<body>
<th:block th:fragment="mainText">
<h1>TSW Timetable</h1>
<p>
<b th:text="${status}"></b> <th:block th:text="${error}" />
</p>
</th:block>
<footer class="foot" th:fragment="footer"><th:block th:text="${footerString}" /></footer>
</body>
</html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en">
<head th:fragment="head">
<title th:text="${version}"></title>
<style>
@media (prefers-color-scheme: dark) {
html{background:#000000;color:#ffffff;font:15px/22px arial,sans-serif}
}
@media (prefers-color-scheme: light) {
html{background:#ffffff;color:#000000;font:15px/22px arial,sans-serif}
}
body{margin:50px}
h1,footer{margin:20px 0}
p{margin:0}
code{font-family: monospace,monospace}
.foot{color:#777777;font-size:80%}
</style>
</head>
<body style="font-family:sans-serif; line-height: 1.4em;">
<h2>
<th:block th:text="${version}"/>
</h2>
<p>
Hostname:
<th:block th:text="${hostname}"/>
</p>
<p>
<th:block th:each="item : ${manifest}">
<th:block th:text="${item}"/>
<br/>
</th:block>
</p>
<footer class="foot" th:fragment="footer">
<th:block th:text="${footerString}"/>
</footer>
</body>
</html>

View File

@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping(value = ["/timetable"])
@RequestMapping(value = ["/routing"])
class HealthCheckController(private val properties: HealthCheckProperties) {

View File

@ -53,7 +53,7 @@ class RestHealthIndicator(
}
companion object {
private const val URL_PATH = "/timetable/healthCheck"
private const val URL_PATH = "/routing/healthCheck"
private const val GET_PARAMETER = "message="
}
}

View File

@ -3,8 +3,10 @@ package de.hbt.support.property
import io.swagger.v3.oas.annotations.media.Schema
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.ConstructorBinding
import org.springframework.cloud.context.config.annotation.RefreshScope
import java.time.ZoneId
@RefreshScope
@ConfigurationProperties(prefix = "time")
@Schema(description = "Properties to configure time")
data class TimeProperties @ConstructorBinding constructor(

View File

@ -10,4 +10,5 @@ dependencies {
implementation(libs.spring.openapi)
implementation(libs.bundles.spring.boot.security)
implementation(libs.spring.cloud.starter.config)
}

View File

@ -1,6 +1,7 @@
val projectname: String = providers.gradleProperty("projectname").get()
rootProject.name = projectname
include("deploy")
include("support")
include("server")