mirror of
https://github.com/pcvolkmer/etl-processor.git
synced 2025-04-19 17:26:51 +00:00
feat: add basic support for OIDC login
This commit is contained in:
parent
f71a775e12
commit
17e04a3f89
@ -58,6 +58,7 @@ dependencies {
|
|||||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
|
implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
|
||||||
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.thymeleaf.extras:thymeleaf-extras-springsecurity6")
|
implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity6")
|
||||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||||
implementation("org.springframework.kafka:spring-kafka")
|
implementation("org.springframework.kafka:spring-kafka")
|
||||||
|
@ -86,7 +86,8 @@ data class KafkaTargetProperties(
|
|||||||
data class SecurityConfigProperties(
|
data class SecurityConfigProperties(
|
||||||
val adminUser: String?,
|
val adminUser: String?,
|
||||||
val adminPassword: String?,
|
val adminPassword: String?,
|
||||||
val enableTokens: Boolean = false
|
val enableTokens: Boolean = false,
|
||||||
|
val enableOidc: Boolean = false
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
const val NAME = "app.security"
|
const val NAME = "app.security"
|
||||||
|
@ -24,21 +24,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
|||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.core.Ordered
|
|
||||||
import org.springframework.core.annotation.Order
|
|
||||||
import org.springframework.http.HttpMethod
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
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.configuration.EnableWebSecurity
|
||||||
import org.springframework.security.config.annotation.web.invoke
|
import org.springframework.security.config.annotation.web.invoke
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy
|
|
||||||
import org.springframework.security.core.userdetails.User
|
import org.springframework.security.core.userdetails.User
|
||||||
import org.springframework.security.core.userdetails.UserDetails
|
import org.springframework.security.core.userdetails.UserDetails
|
||||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories
|
import org.springframework.security.crypto.factory.PasswordEncoderFactories
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder
|
import org.springframework.security.crypto.password.PasswordEncoder
|
||||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||||
import org.springframework.security.web.SecurityFilterChain
|
import org.springframework.security.web.SecurityFilterChain
|
||||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
@ -82,6 +76,30 @@ class AppSecurityConfiguration(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ConditionalOnProperty(value = ["app.security.enable-oidc"], havingValue = "true")
|
||||||
|
fun filterChainOidc(http: HttpSecurity, passwordEncoder: PasswordEncoder): SecurityFilterChain {
|
||||||
|
http {
|
||||||
|
authorizeRequests {
|
||||||
|
authorize("/configs/**", hasRole("ADMIN"))
|
||||||
|
authorize("/mtbfile/**", hasAnyRole("MTBFILE"))
|
||||||
|
authorize(anyRequest, permitAll)
|
||||||
|
}
|
||||||
|
httpBasic {
|
||||||
|
realmName = "ETL-Processor"
|
||||||
|
}
|
||||||
|
formLogin {
|
||||||
|
loginPage = "/login"
|
||||||
|
}
|
||||||
|
oauth2Login {
|
||||||
|
loginPage = "/login"
|
||||||
|
}
|
||||||
|
csrf { disable() }
|
||||||
|
}
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(value = ["app.security.enable-oidc"], havingValue = "false", matchIfMissing = true)
|
||||||
fun filterChain(http: HttpSecurity, passwordEncoder: PasswordEncoder): SecurityFilterChain {
|
fun filterChain(http: HttpSecurity, passwordEncoder: PasswordEncoder): SecurityFilterChain {
|
||||||
http {
|
http {
|
||||||
authorizeRequests {
|
authorizeRequests {
|
||||||
|
@ -19,14 +19,29 @@
|
|||||||
|
|
||||||
package dev.dnpm.etl.processor.web
|
package dev.dnpm.etl.processor.web
|
||||||
|
|
||||||
|
import dev.dnpm.etl.processor.config.SecurityConfigProperties
|
||||||
|
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties
|
||||||
import org.springframework.stereotype.Controller
|
import org.springframework.stereotype.Controller
|
||||||
|
import org.springframework.ui.Model
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
|
import java.security.Principal
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
class LoginController {
|
class LoginController(
|
||||||
|
private val securityConfigProperties: SecurityConfigProperties,
|
||||||
|
private val oAuth2ClientProperties: OAuth2ClientProperties?
|
||||||
|
) {
|
||||||
|
|
||||||
@GetMapping(path = ["/login"])
|
@GetMapping(path = ["/login"])
|
||||||
fun login(): String {
|
fun login(principal: Principal?, model: Model): String {
|
||||||
|
if (securityConfigProperties.enableOidc) {
|
||||||
|
model.addAttribute(
|
||||||
|
"oidcLogins",
|
||||||
|
oAuth2ClientProperties?.registration?.map { (key, value) -> Pair(key, value.clientName) }.orEmpty()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
model.addAttribute("oidcLogins", emptyList<Pair<String, String>>())
|
||||||
|
}
|
||||||
return "login"
|
return "login"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +209,14 @@ form.samplecode-input input:focus-visible {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-form form hr,
|
||||||
|
.token-form form hr {
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.login-form button,
|
.login-form button,
|
||||||
|
.login-form a.btn,
|
||||||
.token-form button {
|
.token-form button {
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
background: var(--bg-blue);
|
background: var(--bg-blue);
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
<a th:href="@{/login}">Login</a>
|
<a th:href="@{/login}">Login</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="login" sec:authorize="isAuthenticated()">
|
<li class="login" sec:authorize="isAuthenticated()">
|
||||||
|
<span>
|
||||||
|
<span>👤</span>
|
||||||
|
<span sec:authentication="name">?</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
<a th:href="@{/logout}">Abmelden</a>
|
<a th:href="@{/logout}">Abmelden</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -13,9 +13,11 @@
|
|||||||
<div class="centered notification error" th:if="${param.error}">Anmeldung nicht erfolgreich</div>
|
<div class="centered notification error" th:if="${param.error}">Anmeldung nicht erfolgreich</div>
|
||||||
<div class="centered notification success" th:if="${param.logout}">Sie haben sich abgemeldet</div>
|
<div class="centered notification success" th:if="${param.logout}">Sie haben sich abgemeldet</div>
|
||||||
<form method="post" th:action="@{/login}">
|
<form method="post" th:action="@{/login}">
|
||||||
<input type="text" id="username" name="username" class="form-control" placeholder="Username" required="" autofocus="">
|
<input type="text" id="username" name="username" class="form-control" placeholder="Username" required="" autofocus="" />
|
||||||
<input type="password" id="password" name="password" class="form-control" placeholder="Password" required="">
|
<input type="password" id="password" name="password" class="form-control" placeholder="Password" required="" />
|
||||||
<button type="submit">Anmelden</button>
|
<button type="submit">Anmelden</button>
|
||||||
|
<hr th:if="${not oidcLogins.isEmpty()}" />
|
||||||
|
<a th:each="oidcLogin : ${oidcLogins}" class="btn" th:href="@{/oauth2/authorization/{provider}(provider=${oidcLogin.component1()})}">OIDC Login - [[ ${oidcLogin.component2()} ]]</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user