From b0645710c55df91c4095afbd2e9924d9ca67ff29 Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Fri, 2 May 2025 10:27:08 +0200 Subject: [PATCH 01/10] Update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a062262..93418c2 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ KickerELO is a web application for displaying Elo ratings for foosball (table soccer) games. It uses **Spring Boot** for the backend, **Vaadin** for the frontend, and **MariaDB** as the database. +This fork implements a single sign-on implementation for Authentik using (OIDC). + ## Requirements - **Java 23** or later From 7021df1953491281d22ec184087df4e2f44cc1e0 Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Fri, 2 May 2025 10:42:25 +0200 Subject: [PATCH 02/10] First try in oidc implementation --- .gitignore | 2 ++ pom.xml | 4 ++++ .../kickerelo/layout/KickerAppLayout.java | 23 +++++++++++++++++++ .../resources/application-prod.properties | 10 +++++++- .../resources/application-test.properties | 10 +++++++- 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index fac9f1f..b7a847d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ !**/src/test/**/target/ +data.mv.db +src/main/bundles ### IntelliJ IDEA ### .idea/modules.xml diff --git a/pom.xml b/pom.xml index ef2bdd1..cf6098d 100644 --- a/pom.xml +++ b/pom.xml @@ -68,6 +68,10 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-oauth2-client + diff --git a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java index ee8a1e8..176a842 100644 --- a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java +++ b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java @@ -14,6 +14,11 @@ import com.vaadin.flow.dom.Style; import com.vaadin.flow.router.Layout; import org.kickerelo.kickerelo.views.*; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.authentication.AnonymousAuthenticationToken; + + @Layout @JsModule("./prefers-color-scheme.js") public class KickerAppLayout extends AppLayout { @@ -26,6 +31,24 @@ public class KickerAppLayout extends AppLayout { addToNavbar(drawerToggle, title); + // Add login/logout button + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth != null && auth.isAuthenticated() && !(auth instanceof AnonymousAuthenticationToken)) { + Anchor logoutLink = new Anchor("/logout", "Logout (" + auth.getName() + ")"); + logoutLink.getElement().getStyle() + .set("margin-left", "auto") + .set("margin-right", "10px") + .set("align-self", "center"); + addToNavbar(logoutLink); + } else { + Anchor loginLink = new Anchor("/oauth2/authorization/oidc", "Login"); + loginLink.getElement().getStyle() + .set("margin-left", "auto") + .set("margin-right", "10px") + .set("align-self", "center"); + addToNavbar(loginLink); + } + SideNav general = new SideNav("Allgemein"); general.setCollapsible(true); general.addItem(new SideNavItem("Spielerliste", PlayerListView.class, VaadinIcon.GROUP.create()), diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 292a868..2dfcd30 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -8,4 +8,12 @@ spring.datasource.password=${DATABASE_PASSWORD} spring.datasource.driver-class-name=org.mariadb.jdbc.Driver spring.jpa.hibernate.ddl-auto=validate spring.jpa.show-sql=false -spring.jpa.open-in-view=false \ No newline at end of file +spring.jpa.open-in-view=false + +# == OIDC Configuration == +spring.security.oauth2.client.registration.oidc.client-id=client-id +spring.security.oauth2.client.registration.oidc.client-secret=client-secret +spring.security.oauth2.client.registration.oidc.scope=openid,profile,email +spring.security.oauth2.client.registration.oidc.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} + +spring.security.oauth2.client.provider.oidc.issuer-uri=https://auth.fs.cs.uni-frankfurt.de/application/o/oidc/ diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 9306521..0eece6b 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -7,4 +7,12 @@ spring.datasource.driver-class-name=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.hibernate.ddl-auto=update -spring.jpa.show-sql=true \ No newline at end of file +spring.jpa.show-sql=true + +# == OIDC Configuration == +spring.security.oauth2.client.registration.oidc.client-id=client-id +spring.security.oauth2.client.registration.oidc.client-secret=client-secret +spring.security.oauth2.client.registration.oidc.scope=openid,profile,email +spring.security.oauth2.client.registration.oidc.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} + +spring.security.oauth2.client.provider.oidc.issuer-uri=https://auth.fs.cs.uni-frankfurt.de/application/o/oidc/ From 72bda504aad3b2e6e69defe94c4ee91926b12c8f Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Sun, 11 May 2025 17:17:28 +0200 Subject: [PATCH 03/10] Add secrets --- .gitignore | 4 +++ .../kickerelo/layout/KickerAppLayout.java | 28 ++++++++++--------- .../resources/application-test.properties | 6 ++-- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index b7a847d..77c7396 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,10 @@ target/ data.mv.db src/main/bundles +# for secrets +.env +.vscode + ### IntelliJ IDEA ### .idea/modules.xml .idea/jarRepositories.xml diff --git a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java index 176a842..9e8f39c 100644 --- a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java +++ b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java @@ -33,20 +33,22 @@ public class KickerAppLayout extends AppLayout { // Add login/logout button Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth != null && auth.isAuthenticated() && !(auth instanceof AnonymousAuthenticationToken)) { - Anchor logoutLink = new Anchor("/logout", "Logout (" + auth.getName() + ")"); - logoutLink.getElement().getStyle() - .set("margin-left", "auto") - .set("margin-right", "10px") - .set("align-self", "center"); - addToNavbar(logoutLink); + boolean isAuthenticated = auth != null && auth.isAuthenticated() && !(auth instanceof AnonymousAuthenticationToken); + + if (isAuthenticated) { + Anchor logoutLink = new Anchor("/logout", "Logout (" + auth.getName() + ")"); + logoutLink.getElement().getStyle() + .set("margin-left", "auto") + .set("margin-right", "10px") + .set("align-self", "center"); + addToNavbar(logoutLink); } else { - Anchor loginLink = new Anchor("/oauth2/authorization/oidc", "Login"); - loginLink.getElement().getStyle() - .set("margin-left", "auto") - .set("margin-right", "10px") - .set("align-self", "center"); - addToNavbar(loginLink); + Anchor loginLink = new Anchor("/oauth2/authorization/oidc", "Login"); + loginLink.getElement().getStyle() + .set("margin-left", "auto") + .set("margin-right", "10px") + .set("align-self", "center"); + addToNavbar(loginLink); } SideNav general = new SideNav("Allgemein"); diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 0eece6b..314bb7d 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -10,9 +10,9 @@ spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true # == OIDC Configuration == -spring.security.oauth2.client.registration.oidc.client-id=client-id -spring.security.oauth2.client.registration.oidc.client-secret=client-secret +spring.security.oauth2.client.registration.oidc.client-id=${OIDC_CLIENT_ID} +spring.security.oauth2.client.registration.oidc.client-secret=${OIDC_CLIENT_SECRET} spring.security.oauth2.client.registration.oidc.scope=openid,profile,email spring.security.oauth2.client.registration.oidc.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} -spring.security.oauth2.client.provider.oidc.issuer-uri=https://auth.fs.cs.uni-frankfurt.de/application/o/oidc/ +spring.security.oauth2.client.provider.oidc.issuer-uri=${OIDC_ISSUER_URI} From c47a83e8d402c91011637c364a2163c3de841d58 Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Sun, 11 May 2025 19:23:49 +0200 Subject: [PATCH 04/10] Add connection to fs auth provider, redirect not tested --- pom.xml | 5 ++ .../kickerelo/config/SecurityConfig.java | 50 +++++++++++++++++++ .../kickerelo/layout/KickerAppLayout.java | 9 ++++ .../kickerelo/kickerelo/views/AdminView.java | 2 +- .../kickerelo/kickerelo/views/Chart1vs1.java | 2 + .../kickerelo/kickerelo/views/Chart2vs2.java | 3 ++ .../kickerelo/views/Enter1vs1View.java | 2 +- .../kickerelo/views/Enter2vs2View.java | 2 +- .../kickerelo/views/Graph1vs1View.java | 2 +- .../kickerelo/views/Graph2vs2View.java | 2 +- .../kickerelo/views/History1vs1View.java | 2 +- .../kickerelo/views/History2vs2View.java | 2 +- .../kickerelo/views/PlayerListView.java | 2 +- .../kickerelo/views/Stat2vs2View.java | 2 +- .../resources/application-prod.properties | 7 +-- .../resources/application-test.properties | 4 +- 16 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java diff --git a/pom.xml b/pom.xml index cf6098d..1e60e6e 100644 --- a/pom.xml +++ b/pom.xml @@ -72,6 +72,11 @@ org.springframework.boot spring-boot-starter-oauth2-client + + io.github.cdimascio + dotenv-java + 3.0.0 + diff --git a/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java new file mode 100644 index 0000000..d744c86 --- /dev/null +++ b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java @@ -0,0 +1,50 @@ +package org.kickerelo.kickerelo.config; + +import io.github.cdimascio.dotenv.Dotenv; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +public class SecurityConfig { + + private final Dotenv dotenv = Dotenv.load(); + + @Bean + public ClientRegistrationRepository clientRegistrationRepository() { + ClientRegistration oidcRegistration = ClientRegistration.withRegistrationId("oidc") + .clientId(dotenv.get("OIDC_CLIENT_ID")) + .clientSecret(dotenv.get("OIDC_CLIENT_SECRET")) + .scope("openid", "profile", "email") + .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) + .authorizationUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/authorize/") + .tokenUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/token/") + .userInfoUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/userinfo/") + .userNameAttributeName("sub") + .clientName("OIDC") + .redirectUri(dotenv.get("OIDC_REDIRECT_URI")) + .build(); + + return new InMemoryClientRegistrationRepository(oidcRegistration); + } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests(auth -> auth + .requestMatchers("/oauth2/**").permitAll() // Allow all OAuth2 requests + .anyRequest().permitAll() // Allow all requests + ) + .oauth2Login() + .and() + .logout(logout -> logout.logoutSuccessUrl("/")) + .csrf(csrf -> csrf.disable()); + + return http.build(); + } +} diff --git a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java index 617b7f0..a0638eb 100644 --- a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java +++ b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java @@ -67,6 +67,15 @@ public class KickerAppLayout extends AppLayout { new SideNavItem("Historie", History2vs2View.class, VaadinIcon.RECORDS.create()), new SideNavItem("Statistik", Stat2vs2View.class, VaadinIcon.ABACUS.create())); + // add additional nav item if user is logged in + if (isAuthenticated) { + SideNav nav3 = new SideNav("Admin"); + nav3.setCollapsible(true); + nav3.addItem(new SideNavItem("Delete Internet", AdminView.class, VaadinIcon.COG.create()), + new SideNavItem("Current User: " + auth.getName(), AdminView.class, VaadinIcon.COG.create())); + +} + Image githubLogo = new Image("github-mark.png", "Github"); githubLogo.setHeight("30px"); diff --git a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java index 5098cbb..99692f1 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java +++ b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java @@ -12,7 +12,7 @@ import org.kickerelo.kickerelo.exception.InvalidDataException; import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; import org.kickerelo.kickerelo.service.KickerEloService; -@Route("admin") +@Route("app/admin") public class AdminView extends VerticalLayout { public AdminView(KickerEloService service) { H2 subheader = new H2("Verwaltung"); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java b/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java index 48e7df3..571db32 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java @@ -16,6 +16,7 @@ import com.github.appreciated.apexcharts.config.yaxis.Title; import com.github.appreciated.apexcharts.helper.Series; import com.vaadin.flow.component.UI; import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.router.Route; import com.vaadin.flow.server.VaadinService; import com.vaadin.flow.theme.lumo.Lumo; import org.kickerelo.kickerelo.data.Spieler; @@ -24,6 +25,7 @@ import org.kickerelo.kickerelo.util.Spieler1vs1EloComparator; import java.math.BigDecimal; import java.util.List; +@Route(value = "app/chart1vs1") public class Chart1vs1 extends ApexChartsBuilder { public Chart1vs1(List l) { Theme theme = new Theme(); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java b/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java index 696e0cd..db986e9 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java @@ -12,11 +12,14 @@ import com.github.appreciated.apexcharts.config.theme.Mode; import com.github.appreciated.apexcharts.config.theme.Monochrome; import com.github.appreciated.apexcharts.config.xaxis.Labels; import com.github.appreciated.apexcharts.helper.Series; +import com.vaadin.flow.router.Route; + import org.kickerelo.kickerelo.data.Spieler; import org.kickerelo.kickerelo.util.Spieler2vs2EloComparator; import java.util.List; +@Route(value = "app/chart1vs1") public class Chart2vs2 extends ApexChartsBuilder { public Chart2vs2(List l) { Theme theme = new Theme(); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java b/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java index 016d00d..7973903 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java @@ -14,7 +14,7 @@ import org.kickerelo.kickerelo.exception.NoSuchPlayerException; import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; import org.kickerelo.kickerelo.service.KickerEloService; -@Route(value = "enter1vs1") +@Route(value = "app/enter1vs1") public class Enter1vs1View extends VerticalLayout { public Enter1vs1View(KickerEloService eloService) { diff --git a/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java index 23829bc..ce753b3 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java @@ -14,7 +14,7 @@ import org.kickerelo.kickerelo.exception.NoSuchPlayerException; import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; import org.kickerelo.kickerelo.service.KickerEloService; -@Route(value = "enter2vs2") +@Route(value = "app/enter2vs2") public class Enter2vs2View extends VerticalLayout { public Enter2vs2View(KickerEloService eloService) { H2 subheading = new H2("2 vs 2 Ergebnis"); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java b/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java index 6d86fc6..2582416 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java @@ -7,7 +7,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.Route; import org.kickerelo.kickerelo.repository.SpielerRepository; -@Route("graph1vs1") +@Route("app/graph1vs1") public class Graph1vs1View extends VerticalLayout { ApexCharts chart1vs1; diff --git a/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java index 26ad677..968c0a9 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java @@ -7,7 +7,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.Route; import org.kickerelo.kickerelo.repository.SpielerRepository; -@Route("graph2vs2") +@Route("app/graph2vs2") public class Graph2vs2View extends VerticalLayout { ApexCharts chart2vs2; public Graph2vs2View(SpielerRepository repo) { diff --git a/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java b/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java index 2c1344f..7d84869 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java @@ -18,7 +18,7 @@ import org.kickerelo.kickerelo.repository.Ergebnis1vs1Repository; import java.util.List; -@Route("history1vs1") +@Route("app/history1vs1") public class History1vs1View extends VerticalLayout { List res; public History1vs1View(Ergebnis1vs1Repository repo) { diff --git a/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java index 5daeb45..f956e43 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java @@ -19,7 +19,7 @@ import org.kickerelo.kickerelo.repository.Ergebnis2vs2Repository; import java.util.List; -@Route("history2vs2") +@Route("app/history2vs2") public class History2vs2View extends VerticalLayout { public History2vs2View(Ergebnis2vs2Repository repo) { setSizeFull(); diff --git a/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java b/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java index 205dbae..e012df0 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java +++ b/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java @@ -11,7 +11,7 @@ import org.kickerelo.kickerelo.service.KickerEloService; import java.util.List; -@Route("") +@Route("app") public class PlayerListView extends VerticalLayout { public PlayerListView(KickerEloService eloService) { setSizeFull(); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java index 7bfa90e..3c0c0ee 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java @@ -12,7 +12,7 @@ import org.kickerelo.kickerelo.service.KickerEloService; import org.kickerelo.kickerelo.service.Stat2vs2Service; import org.kickerelo.kickerelo.util.Position; -@Route("stat2vs2") +@Route("app/stat2vs2") public class Stat2vs2View extends VerticalLayout { Stat2vs2Service stat2vs2Service; KickerEloService kickerEloService; diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 2dfcd30..2fa27fb 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -11,9 +11,10 @@ spring.jpa.show-sql=false spring.jpa.open-in-view=false # == OIDC Configuration == -spring.security.oauth2.client.registration.oidc.client-id=client-id -spring.security.oauth2.client.registration.oidc.client-secret=client-secret +spring.security.oauth2.client.registration.oidc.client-id=${OIDC_CLIENT_ID} +spring.security.oauth2.client.registration.oidc.client-secret=${OIDC_CLIENT_SECRET} spring.security.oauth2.client.registration.oidc.scope=openid,profile,email spring.security.oauth2.client.registration.oidc.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} +spring.security.oauth2.client.provider.oidc.issuer-uri=${OIDC_ISSUER_URI} -spring.security.oauth2.client.provider.oidc.issuer-uri=https://auth.fs.cs.uni-frankfurt.de/application/o/oidc/ +vaadin.urlMapping=/* diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 314bb7d..386b42a 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -1,5 +1,6 @@ server.port=${PORT:8080} logging.level.org.atmosphere = warn +logging.level.org.springframework.security=DEBUG spring.mustache.check-template-location = false spring.datasource.url=jdbc:h2:file:./data @@ -14,5 +15,6 @@ spring.security.oauth2.client.registration.oidc.client-id=${OIDC_CLIENT_ID} spring.security.oauth2.client.registration.oidc.client-secret=${OIDC_CLIENT_SECRET} spring.security.oauth2.client.registration.oidc.scope=openid,profile,email spring.security.oauth2.client.registration.oidc.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} - spring.security.oauth2.client.provider.oidc.issuer-uri=${OIDC_ISSUER_URI} + +vaadin.urlMapping=/app/* From a2624384442bcb6fda9dc6e4cdb422b96c847521 Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Sat, 31 May 2025 18:26:26 +0200 Subject: [PATCH 05/10] Working prototype This commit implements the oidc compatibility with the caveat of having every subsite under the app path. For that, there is also a redirection handler to redirect the home page to the app home page. --- pom.xml | 9 ++-- .../kickerelo/KickerEloApplication.java | 8 +-- .../kickerelo/config/SecurityConfig.java | 54 +++++++++---------- .../kickerelo/layout/KickerAppLayout.java | 4 +- .../kickerelo/util/RedirectController.java | 12 +++++ .../kickerelo/kickerelo/views/AdminView.java | 45 ++++++++++++++-- .../kickerelo/kickerelo/views/Chart1vs1.java | 16 ++---- .../kickerelo/kickerelo/views/Chart2vs2.java | 12 ++--- .../kickerelo/views/Enter1vs1View.java | 11 ++-- .../kickerelo/views/Enter2vs2View.java | 11 ++-- .../kickerelo/views/Graph1vs1View.java | 3 +- .../kickerelo/views/Graph2vs2View.java | 3 +- .../kickerelo/views/History1vs1View.java | 9 ++-- .../kickerelo/views/History2vs2View.java | 9 ++-- .../kickerelo/views/PlayerListView.java | 9 ++-- .../kickerelo/views/Stat2vs2View.java | 9 ++-- .../resources/application-prod.properties | 2 +- .../resources/application-test.properties | 5 +- 18 files changed, 139 insertions(+), 92 deletions(-) create mode 100644 src/main/java/org/kickerelo/kickerelo/util/RedirectController.java diff --git a/pom.xml b/pom.xml index 1e60e6e..30e336f 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,10 @@ org.springframework.boot spring-boot-starter-data-jpa + + org.springframework.boot + spring-boot-starter-web + com.vaadin vaadin-spring-boot-starter @@ -72,11 +76,6 @@ org.springframework.boot spring-boot-starter-oauth2-client - - io.github.cdimascio - dotenv-java - 3.0.0 - diff --git a/src/main/java/org/kickerelo/kickerelo/KickerEloApplication.java b/src/main/java/org/kickerelo/kickerelo/KickerEloApplication.java index 0252816..d9ce578 100644 --- a/src/main/java/org/kickerelo/kickerelo/KickerEloApplication.java +++ b/src/main/java/org/kickerelo/kickerelo/KickerEloApplication.java @@ -1,13 +1,14 @@ package org.kickerelo.kickerelo; -import com.vaadin.flow.component.page.AppShellConfigurator; -import com.vaadin.flow.server.PWA; -import com.vaadin.flow.theme.Theme; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import com.vaadin.flow.component.page.AppShellConfigurator; +import com.vaadin.flow.server.PWA; +import com.vaadin.flow.theme.Theme; + @SpringBootApplication @EntityScan(basePackages = "org.kickerelo.kickerelo.data") @@ -19,5 +20,4 @@ public class KickerEloApplication implements AppShellConfigurator { public static void main(String[] args) { SpringApplication.run(KickerEloApplication.class, args); } - } diff --git a/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java index d744c86..edf3291 100644 --- a/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java +++ b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java @@ -1,47 +1,45 @@ package org.kickerelo.kickerelo.config; -import io.github.cdimascio.dotenv.Dotenv; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; -import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.web.SecurityFilterChain; @Configuration public class SecurityConfig { - private final Dotenv dotenv = Dotenv.load(); + // unnecessary, because already configured in application.properties + // private final Dotenv dotenv = Dotenv.load(); + // @Bean + // public ClientRegistrationRepository clientRegistrationRepository() { + // ClientRegistration oidcRegistration = ClientRegistration.withRegistrationId("oidc") + // .clientId(dotenv.get("OIDC_CLIENT_ID")) + // .clientSecret(dotenv.get("OIDC_CLIENT_SECRET")) + // .scope("openid", "profile", "email") + // .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) + // .authorizationUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/authorize/") + // .tokenUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/token/") + // .userInfoUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/userinfo/") + // .userNameAttributeName("sub") + // .clientName("OIDC") + // .redirectUri(dotenv.get("OIDC_REDIRECT_URI")) + // .build(); - @Bean - public ClientRegistrationRepository clientRegistrationRepository() { - ClientRegistration oidcRegistration = ClientRegistration.withRegistrationId("oidc") - .clientId(dotenv.get("OIDC_CLIENT_ID")) - .clientSecret(dotenv.get("OIDC_CLIENT_SECRET")) - .scope("openid", "profile", "email") - .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) - .authorizationUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/authorize/") - .tokenUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/token/") - .userInfoUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/userinfo/") - .userNameAttributeName("sub") - .clientName("OIDC") - .redirectUri(dotenv.get("OIDC_REDIRECT_URI")) - .build(); - - return new InMemoryClientRegistrationRepository(oidcRegistration); - } + // return new InMemoryClientRegistrationRepository(oidcRegistration); + // } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth - .requestMatchers("/oauth2/**").permitAll() // Allow all OAuth2 requests - .anyRequest().permitAll() // Allow all requests - ) - .oauth2Login() - .and() + .requestMatchers("/app/admin/**").authenticated() // Nur authentifizierte User + .anyRequest().permitAll() + ) + .oauth2Login(org.springframework.security.config.Customizer.withDefaults()) + // .oauth2Login(oauth -> oauth + // .defaultSuccessUrl("/app/app/admin", true) + // ) + //.and() .logout(logout -> logout.logoutSuccessUrl("/")) .csrf(csrf -> csrf.disable()); diff --git a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java index a0638eb..e8aa77b 100644 --- a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java +++ b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java @@ -35,8 +35,8 @@ public class KickerAppLayout extends AppLayout { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); boolean isAuthenticated = auth != null && auth.isAuthenticated() && !(auth instanceof AnonymousAuthenticationToken); - if (isAuthenticated) { - Anchor logoutLink = new Anchor("/logout", "Logout (" + auth.getName() + ")"); + if (isAuthenticated && auth != null && auth.getPrincipal() instanceof org.springframework.security.oauth2.core.oidc.user.OidcUser oidcUser) { + Anchor logoutLink = new Anchor("/logout", "Logout (" + oidcUser.getPreferredUsername() + ")"); logoutLink.getElement().getStyle() .set("margin-left", "auto") .set("margin-right", "10px") diff --git a/src/main/java/org/kickerelo/kickerelo/util/RedirectController.java b/src/main/java/org/kickerelo/kickerelo/util/RedirectController.java new file mode 100644 index 0000000..039d28a --- /dev/null +++ b/src/main/java/org/kickerelo/kickerelo/util/RedirectController.java @@ -0,0 +1,12 @@ +package org.kickerelo.kickerelo.util; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class RedirectController { + @GetMapping("/") + public String redirectToApp() { + return "redirect:/app/app"; + } +} diff --git a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java index 99692f1..7831347 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java +++ b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java @@ -1,21 +1,55 @@ package org.kickerelo.kickerelo.views; +import org.kickerelo.kickerelo.exception.DuplicatePlayerException; +import org.kickerelo.kickerelo.exception.InvalidDataException; +import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; +import org.kickerelo.kickerelo.service.KickerEloService; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.core.oidc.user.OidcUser; +import java.util.List; + import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.html.H2; +import com.vaadin.flow.component.html.Paragraph; import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.notification.NotificationVariant; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.exception.DuplicatePlayerException; -import org.kickerelo.kickerelo.exception.InvalidDataException; -import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; -import org.kickerelo.kickerelo.service.KickerEloService; @Route("app/admin") public class AdminView extends VerticalLayout { public AdminView(KickerEloService service) { - H2 subheader = new H2("Verwaltung"); + // Zeige den aktuell authentifizierten Benutzer + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth != null && auth.getPrincipal() instanceof OidcUser oidcUser) { + String username = oidcUser.getPreferredUsername(); + Object groupsObj = oidcUser.getClaims().getOrDefault("groups", List.of()); + List listOfGroups; + if (groupsObj instanceof List groupsList) { + listOfGroups = groupsList.stream() + .filter(String.class::isInstance) + .map(String.class::cast) + .toList(); + } else { + listOfGroups = List.of(); + } + add(new Paragraph("Angemeldet als: " + username)); + add(new Paragraph("Gruppen: " + listOfGroups.toString())); + + if (listOfGroups.contains("Kicker Admin")) { + add(new Paragraph("Du bist Admin!")); + } else { + if (listOfGroups.contains("Kicker User")) { + add(new Paragraph("Du bist kein Admin, aber ein kickerelo User!")); + } else { + add(new Paragraph("Du bist gar nichts!")); + } + } + } else { + add(new Paragraph("Niemand ist angemeldet")); + } TextField spielername = new TextField("Spielername"); spielername.addClassName("bordered"); @@ -41,6 +75,7 @@ public class AdminView extends VerticalLayout { service.recalculateAll1vs1(); Notification.show("Recalculating finished").addThemeVariants(NotificationVariant.LUMO_SUCCESS); }); + Button recalc2vs2Button = new Button("2 vs 2 Elo neu berechnen", e -> { Notification.show("Recalculating Elo").addThemeVariants(NotificationVariant.LUMO_WARNING); service.recalculateAll2vs2(); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java b/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java index 571db32..7f109ae 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Chart1vs1.java @@ -1,5 +1,10 @@ package org.kickerelo.kickerelo.views; +import java.util.List; + +import org.kickerelo.kickerelo.data.Spieler; +import org.kickerelo.kickerelo.util.Spieler1vs1EloComparator; + import com.github.appreciated.apexcharts.ApexChartsBuilder; import com.github.appreciated.apexcharts.config.Theme; import com.github.appreciated.apexcharts.config.builder.ChartBuilder; @@ -11,19 +16,8 @@ import com.github.appreciated.apexcharts.config.chart.zoom.ZoomType; import com.github.appreciated.apexcharts.config.theme.Mode; import com.github.appreciated.apexcharts.config.theme.Monochrome; import com.github.appreciated.apexcharts.config.xaxis.Labels; -import com.github.appreciated.apexcharts.config.xaxis.labels.Style; -import com.github.appreciated.apexcharts.config.yaxis.Title; import com.github.appreciated.apexcharts.helper.Series; -import com.vaadin.flow.component.UI; -import com.vaadin.flow.component.button.Button; import com.vaadin.flow.router.Route; -import com.vaadin.flow.server.VaadinService; -import com.vaadin.flow.theme.lumo.Lumo; -import org.kickerelo.kickerelo.data.Spieler; -import org.kickerelo.kickerelo.util.Spieler1vs1EloComparator; - -import java.math.BigDecimal; -import java.util.List; @Route(value = "app/chart1vs1") public class Chart1vs1 extends ApexChartsBuilder { diff --git a/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java b/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java index db986e9..24e6e86 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Chart2vs2.java @@ -1,5 +1,10 @@ package org.kickerelo.kickerelo.views; +import java.util.List; + +import org.kickerelo.kickerelo.data.Spieler; +import org.kickerelo.kickerelo.util.Spieler2vs2EloComparator; + import com.github.appreciated.apexcharts.ApexChartsBuilder; import com.github.appreciated.apexcharts.config.Theme; import com.github.appreciated.apexcharts.config.builder.ChartBuilder; @@ -14,12 +19,7 @@ import com.github.appreciated.apexcharts.config.xaxis.Labels; import com.github.appreciated.apexcharts.helper.Series; import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.data.Spieler; -import org.kickerelo.kickerelo.util.Spieler2vs2EloComparator; - -import java.util.List; - -@Route(value = "app/chart1vs1") +@Route(value = "app/chart2vs2") public class Chart2vs2 extends ApexChartsBuilder { public Chart2vs2(List l) { Theme theme = new Theme(); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java b/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java index 7973903..ca94328 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java @@ -1,5 +1,11 @@ package org.kickerelo.kickerelo.views; +import org.kickerelo.kickerelo.exception.DuplicatePlayerException; +import org.kickerelo.kickerelo.exception.InvalidDataException; +import org.kickerelo.kickerelo.exception.NoSuchPlayerException; +import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; +import org.kickerelo.kickerelo.service.KickerEloService; + import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.html.H2; @@ -8,11 +14,6 @@ import com.vaadin.flow.component.notification.NotificationVariant; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.IntegerField; import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.exception.DuplicatePlayerException; -import org.kickerelo.kickerelo.exception.InvalidDataException; -import org.kickerelo.kickerelo.exception.NoSuchPlayerException; -import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; -import org.kickerelo.kickerelo.service.KickerEloService; @Route(value = "app/enter1vs1") public class Enter1vs1View extends VerticalLayout { diff --git a/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java index ce753b3..3f97e52 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java @@ -1,5 +1,11 @@ package org.kickerelo.kickerelo.views; +import org.kickerelo.kickerelo.exception.DuplicatePlayerException; +import org.kickerelo.kickerelo.exception.InvalidDataException; +import org.kickerelo.kickerelo.exception.NoSuchPlayerException; +import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; +import org.kickerelo.kickerelo.service.KickerEloService; + import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.html.H2; @@ -8,11 +14,6 @@ import com.vaadin.flow.component.notification.NotificationVariant; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.IntegerField; import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.exception.DuplicatePlayerException; -import org.kickerelo.kickerelo.exception.InvalidDataException; -import org.kickerelo.kickerelo.exception.NoSuchPlayerException; -import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; -import org.kickerelo.kickerelo.service.KickerEloService; @Route(value = "app/enter2vs2") public class Enter2vs2View extends VerticalLayout { diff --git a/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java b/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java index 2582416..9ed689e 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java @@ -1,11 +1,12 @@ package org.kickerelo.kickerelo.views; +import org.kickerelo.kickerelo.repository.SpielerRepository; + import com.github.appreciated.apexcharts.ApexCharts; import com.vaadin.flow.component.Unit; import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.repository.SpielerRepository; @Route("app/graph1vs1") public class Graph1vs1View extends VerticalLayout { diff --git a/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java index 968c0a9..19d9f64 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java @@ -1,11 +1,12 @@ package org.kickerelo.kickerelo.views; +import org.kickerelo.kickerelo.repository.SpielerRepository; + import com.github.appreciated.apexcharts.ApexCharts; import com.vaadin.flow.component.Unit; import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.repository.SpielerRepository; @Route("app/graph2vs2") public class Graph2vs2View extends VerticalLayout { diff --git a/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java b/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java index 7d84869..6ccaf52 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java @@ -1,5 +1,10 @@ package org.kickerelo.kickerelo.views; +import java.util.List; + +import org.kickerelo.kickerelo.data.Ergebnis1vs1; +import org.kickerelo.kickerelo.repository.Ergebnis1vs1Repository; + import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.GridSortOrder; import com.vaadin.flow.component.grid.dataview.GridListDataView; @@ -13,10 +18,6 @@ import com.vaadin.flow.data.provider.SortDirection; import com.vaadin.flow.data.renderer.LocalDateTimeRenderer; import com.vaadin.flow.data.value.ValueChangeMode; import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.data.Ergebnis1vs1; -import org.kickerelo.kickerelo.repository.Ergebnis1vs1Repository; - -import java.util.List; @Route("app/history1vs1") public class History1vs1View extends VerticalLayout { diff --git a/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java index f956e43..aae20be 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java @@ -1,5 +1,10 @@ package org.kickerelo.kickerelo.views; +import java.util.List; + +import org.kickerelo.kickerelo.data.Ergebnis2vs2; +import org.kickerelo.kickerelo.repository.Ergebnis2vs2Repository; + import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.GridSortOrder; import com.vaadin.flow.component.grid.dataview.GridListDataView; @@ -14,10 +19,6 @@ import com.vaadin.flow.data.provider.SortDirection; import com.vaadin.flow.data.renderer.LocalDateTimeRenderer; import com.vaadin.flow.data.value.ValueChangeMode; import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.data.Ergebnis2vs2; -import org.kickerelo.kickerelo.repository.Ergebnis2vs2Repository; - -import java.util.List; @Route("app/history2vs2") public class History2vs2View extends VerticalLayout { diff --git a/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java b/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java index e012df0..30eff60 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java +++ b/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java @@ -1,15 +1,16 @@ package org.kickerelo.kickerelo.views; +import java.util.List; + +import org.kickerelo.kickerelo.data.Spieler; +import org.kickerelo.kickerelo.service.KickerEloService; + import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.GridSortOrder; import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.data.provider.SortDirection; import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.data.Spieler; -import org.kickerelo.kickerelo.service.KickerEloService; - -import java.util.List; @Route("app") public class PlayerListView extends VerticalLayout { diff --git a/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java index 3c0c0ee..132881d 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java @@ -1,5 +1,10 @@ package org.kickerelo.kickerelo.views; +import org.kickerelo.kickerelo.data.Spieler; +import org.kickerelo.kickerelo.service.KickerEloService; +import org.kickerelo.kickerelo.service.Stat2vs2Service; +import org.kickerelo.kickerelo.util.Position; + import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.html.NativeLabel; @@ -7,10 +12,6 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.progressbar.ProgressBar; import com.vaadin.flow.component.progressbar.ProgressBarVariant; import com.vaadin.flow.router.Route; -import org.kickerelo.kickerelo.data.Spieler; -import org.kickerelo.kickerelo.service.KickerEloService; -import org.kickerelo.kickerelo.service.Stat2vs2Service; -import org.kickerelo.kickerelo.util.Position; @Route("app/stat2vs2") public class Stat2vs2View extends VerticalLayout { diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 2fa27fb..deec540 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -17,4 +17,4 @@ spring.security.oauth2.client.registration.oidc.scope=openid,profile,email spring.security.oauth2.client.registration.oidc.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} spring.security.oauth2.client.provider.oidc.issuer-uri=${OIDC_ISSUER_URI} -vaadin.urlMapping=/* +vaadin.urlMapping=/app/* diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 386b42a..8898ffb 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -13,8 +13,9 @@ spring.jpa.show-sql=true # == OIDC Configuration == spring.security.oauth2.client.registration.oidc.client-id=${OIDC_CLIENT_ID} spring.security.oauth2.client.registration.oidc.client-secret=${OIDC_CLIENT_SECRET} -spring.security.oauth2.client.registration.oidc.scope=openid,profile,email -spring.security.oauth2.client.registration.oidc.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} +spring.security.oauth2.client.registration.oidc.scope=openid,email,profile +spring.security.oauth2.client.registration.oidc.redirect-uri=${OIDC_REDIRECT_URI} +spring.security.oauth2.client.provider.oidc.jwk-set-uri=${OIDC_JWK_SET_URI} spring.security.oauth2.client.provider.oidc.issuer-uri=${OIDC_ISSUER_URI} vaadin.urlMapping=/app/* From f0bf51bf4e7d5338afda55c99aedb159a94b7090 Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Sat, 31 May 2025 18:55:34 +0200 Subject: [PATCH 06/10] Small cleanup --- .../kickerelo/config/SecurityConfig.java | 21 ------------------- .../kickerelo/layout/KickerAppLayout.java | 9 -------- 2 files changed, 30 deletions(-) diff --git a/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java index edf3291..06d7747 100644 --- a/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java +++ b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java @@ -7,27 +7,6 @@ import org.springframework.security.web.SecurityFilterChain; @Configuration public class SecurityConfig { - - // unnecessary, because already configured in application.properties - // private final Dotenv dotenv = Dotenv.load(); - // @Bean - // public ClientRegistrationRepository clientRegistrationRepository() { - // ClientRegistration oidcRegistration = ClientRegistration.withRegistrationId("oidc") - // .clientId(dotenv.get("OIDC_CLIENT_ID")) - // .clientSecret(dotenv.get("OIDC_CLIENT_SECRET")) - // .scope("openid", "profile", "email") - // .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) - // .authorizationUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/authorize/") - // .tokenUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/token/") - // .userInfoUri(dotenv.get("OIDC_ISSUER_BASE_URI") + "application/o/userinfo/") - // .userNameAttributeName("sub") - // .clientName("OIDC") - // .redirectUri(dotenv.get("OIDC_REDIRECT_URI")) - // .build(); - - // return new InMemoryClientRegistrationRepository(oidcRegistration); - // } - @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http diff --git a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java index e8aa77b..1d3d2c1 100644 --- a/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java +++ b/src/main/java/org/kickerelo/kickerelo/layout/KickerAppLayout.java @@ -67,15 +67,6 @@ public class KickerAppLayout extends AppLayout { new SideNavItem("Historie", History2vs2View.class, VaadinIcon.RECORDS.create()), new SideNavItem("Statistik", Stat2vs2View.class, VaadinIcon.ABACUS.create())); - // add additional nav item if user is logged in - if (isAuthenticated) { - SideNav nav3 = new SideNav("Admin"); - nav3.setCollapsible(true); - nav3.addItem(new SideNavItem("Delete Internet", AdminView.class, VaadinIcon.COG.create()), - new SideNavItem("Current User: " + auth.getName(), AdminView.class, VaadinIcon.COG.create())); - -} - Image githubLogo = new Image("github-mark.png", "Github"); githubLogo.setHeight("30px"); From 0ed96cbae2ed6b229cf41a2655e87e4ee1a275fc Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Sun, 8 Jun 2025 18:13:37 +0200 Subject: [PATCH 07/10] Fix access even when logged in --- README.md | 4 +- .../kickerelo/config/SecurityConfig.java | 26 ++++++------- .../kickerelo/util/RedirectController.java | 2 +- .../kickerelo/kickerelo/views/AdminView.java | 37 +++++++++++++------ .../kickerelo/views/Enter1vs1View.java | 2 +- .../kickerelo/views/Enter2vs2View.java | 2 +- .../kickerelo/views/Graph1vs1View.java | 2 +- .../kickerelo/views/Graph2vs2View.java | 2 +- .../kickerelo/views/History1vs1View.java | 2 +- .../kickerelo/views/History2vs2View.java | 2 +- .../kickerelo/views/PlayerListView.java | 2 +- .../kickerelo/views/Stat2vs2View.java | 2 +- 12 files changed, 48 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 6b3bf55..2cb3d0e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ # KickerELO KickerELO is a web application for displaying Elo ratings for foosball (table soccer) games. -It uses **Spring Boot** for the backend, **Vaadin** for the frontend, and **MariaDB** as the database. - -This fork implements a single sign-on implementation for Authentik using (OIDC). +It uses **Spring Boot** for the backend, **Vaadin** for the frontend, and **MariaDB** as the database. It is compatible with any OpenID Connect (OIDC) provider. ## Requirements diff --git a/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java index 06d7747..2cca3ce 100644 --- a/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java +++ b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java @@ -1,27 +1,25 @@ package org.kickerelo.kickerelo.config; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.web.SecurityFilterChain; + +import com.vaadin.flow.spring.security.VaadinWebSecurity; @Configuration -public class SecurityConfig { - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { +class SecurityConfiguration extends VaadinWebSecurity { + + @Override + protected void configure(HttpSecurity http) throws Exception { + + // super.configure(http); + http .authorizeHttpRequests(auth -> auth - .requestMatchers("/app/admin/**").authenticated() // Nur authentifizierte User - .anyRequest().permitAll() - ) + .requestMatchers("/app/admin/**", "/app/admin", "/app/app/admin/**", "/app/app/admin").hasAuthority("Kicker Admin") + .anyRequest().permitAll() + ) .oauth2Login(org.springframework.security.config.Customizer.withDefaults()) - // .oauth2Login(oauth -> oauth - // .defaultSuccessUrl("/app/app/admin", true) - // ) - //.and() .logout(logout -> logout.logoutSuccessUrl("/")) .csrf(csrf -> csrf.disable()); - - return http.build(); } } diff --git a/src/main/java/org/kickerelo/kickerelo/util/RedirectController.java b/src/main/java/org/kickerelo/kickerelo/util/RedirectController.java index 039d28a..25b54b1 100644 --- a/src/main/java/org/kickerelo/kickerelo/util/RedirectController.java +++ b/src/main/java/org/kickerelo/kickerelo/util/RedirectController.java @@ -7,6 +7,6 @@ import org.springframework.web.bind.annotation.GetMapping; public class RedirectController { @GetMapping("/") public String redirectToApp() { - return "redirect:/app/app"; + return "redirect:/app"; } } diff --git a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java index 7831347..574029e 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java +++ b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java @@ -1,5 +1,7 @@ package org.kickerelo.kickerelo.views; +import java.util.List; + import org.kickerelo.kickerelo.exception.DuplicatePlayerException; import org.kickerelo.kickerelo.exception.InvalidDataException; import org.kickerelo.kickerelo.exception.PlayerNameNotSetException; @@ -7,19 +9,32 @@ import org.kickerelo.kickerelo.service.KickerEloService; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.core.oidc.user.OidcUser; -import java.util.List; import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.html.Paragraph; import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.notification.NotificationVariant; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.Route; -@Route("app/admin") +@Route("admin") public class AdminView extends VerticalLayout { + + public void beforeEnter(BeforeEnterEvent event) { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth == null || !(auth.getPrincipal() instanceof OidcUser oidcUser)) { + event.rerouteTo(""); + return; + } + + var groups = oidcUser.getClaimAsStringList("groups"); + if (groups == null || !groups.contains("Kicker Admin")) { + event.rerouteTo(""); + } + } + public AdminView(KickerEloService service) { // Zeige den aktuell authentifizierten Benutzer Authentication auth = SecurityContextHolder.getContext().getAuthentication(); @@ -36,19 +51,19 @@ public class AdminView extends VerticalLayout { listOfGroups = List.of(); } add(new Paragraph("Angemeldet als: " + username)); - add(new Paragraph("Gruppen: " + listOfGroups.toString())); - if (listOfGroups.contains("Kicker Admin")) { - add(new Paragraph("Du bist Admin!")); + if (!listOfGroups.contains("Kicker Admin")) { + add(new Paragraph("Du bist nicht berechtigt, diese Seite zu sehen.")); + getUI().ifPresent(ui -> ui.navigate("")); + return; } else { - if (listOfGroups.contains("Kicker User")) { - add(new Paragraph("Du bist kein Admin, aber ein kickerelo User!")); - } else { - add(new Paragraph("Du bist gar nichts!")); - } + add(new Paragraph("Willkommen im Admin-Bereich!")); } } else { add(new Paragraph("Niemand ist angemeldet")); + add(new Paragraph("Du bist nicht berechtigt, diese Seite zu sehen.")); + getUI().ifPresent(ui -> ui.navigate("")); + return; } TextField spielername = new TextField("Spielername"); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java b/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java index dd5437d..3123aac 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Enter1vs1View.java @@ -16,7 +16,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.IntegerField; import com.vaadin.flow.router.Route; -@Route(value = "app/enter1vs1") +@Route("enter1vs1") public class Enter1vs1View extends VerticalLayout { public Enter1vs1View(KickerEloService eloService) { diff --git a/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java index f6278df..3bba582 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Enter2vs2View.java @@ -16,7 +16,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.IntegerField; import com.vaadin.flow.router.Route; -@Route(value = "app/enter2vs2") +@Route("enter2vs2") public class Enter2vs2View extends VerticalLayout { public Enter2vs2View(KickerEloService eloService) { H2 subheading = new H2("2 vs 2 Ergebnis"); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java b/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java index aeb89a7..63e94cc 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Graph1vs1View.java @@ -10,7 +10,7 @@ import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.Route; -@Route("app/graph1vs1") +@Route("graph1vs1") public class Graph1vs1View extends VerticalLayout { public Graph1vs1View(SpielerRepository repo) { diff --git a/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java index 4932a7c..068ca9f 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Graph2vs2View.java @@ -10,7 +10,7 @@ import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.Route; -@Route("app/graph2vs2") +@Route("graph2vs2") public class Graph2vs2View extends VerticalLayout { public Graph2vs2View(SpielerRepository repo) { diff --git a/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java b/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java index dfc0001..5680b1f 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/History1vs1View.java @@ -19,7 +19,7 @@ import com.vaadin.flow.data.renderer.LocalDateTimeRenderer; import com.vaadin.flow.data.value.ValueChangeMode; import com.vaadin.flow.router.Route; -@Route("app/history1vs1") +@Route("history1vs1") public class History1vs1View extends HistoryView { private final Ergebnis1vs1Repository repo; diff --git a/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java index d6e2b3c..bf0f2b3 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/History2vs2View.java @@ -21,7 +21,7 @@ import com.vaadin.flow.data.value.ValueChangeMode; import com.vaadin.flow.router.Route; -@Route("app/history2vs2") +@Route("history2vs2") public class History2vs2View extends HistoryView { private final Ergebnis2vs2Repository repo; diff --git a/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java b/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java index 30eff60..7f61a0f 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java +++ b/src/main/java/org/kickerelo/kickerelo/views/PlayerListView.java @@ -12,7 +12,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.data.provider.SortDirection; import com.vaadin.flow.router.Route; -@Route("app") +@Route("/") public class PlayerListView extends VerticalLayout { public PlayerListView(KickerEloService eloService) { setSizeFull(); diff --git a/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java b/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java index 1eb05ae..d30d4c3 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java +++ b/src/main/java/org/kickerelo/kickerelo/views/Stat2vs2View.java @@ -15,7 +15,7 @@ import com.vaadin.flow.component.progressbar.ProgressBar; import com.vaadin.flow.component.progressbar.ProgressBarVariant; import com.vaadin.flow.router.Route; -@Route("app/stat2vs2") +@Route("stat2vs2") public class Stat2vs2View extends VerticalLayout { Stat2vs2Service stat2vs2Service; KickerEloService kickerEloService; From 8ff8ccae0f24f80d02e1b9dce2d94d7400e6197c Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Sun, 8 Jun 2025 18:19:20 +0200 Subject: [PATCH 08/10] Update application-prod.properties --- src/main/resources/application-prod.properties | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 9a9210e..ca0774f 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -13,8 +13,9 @@ spring.jpa.open-in-view=false # == OIDC Configuration == spring.security.oauth2.client.registration.oidc.client-id=${OIDC_CLIENT_ID} spring.security.oauth2.client.registration.oidc.client-secret=${OIDC_CLIENT_SECRET} -spring.security.oauth2.client.registration.oidc.scope=openid,profile,email -spring.security.oauth2.client.registration.oidc.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} +spring.security.oauth2.client.registration.oidc.scope=openid,email,profile +spring.security.oauth2.client.registration.oidc.redirect-uri=${OIDC_REDIRECT_URI} +spring.security.oauth2.client.provider.oidc.jwk-set-uri=${OIDC_JWK_SET_URI} spring.security.oauth2.client.provider.oidc.issuer-uri=${OIDC_ISSUER_URI} vaadin.urlMapping=/app/* From 5df6605bef10632c1bceaf21da0b74db33479a2c Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Thu, 12 Jun 2025 15:37:14 +0200 Subject: [PATCH 09/10] Ignore login when in test env --- .../kickerelo/kickerelo/views/AdminView.java | 84 +++++++++++-------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java index 574029e..4607447 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java +++ b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java @@ -22,48 +22,66 @@ import com.vaadin.flow.router.Route; @Route("admin") public class AdminView extends VerticalLayout { - public void beforeEnter(BeforeEnterEvent event) { - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth == null || !(auth.getPrincipal() instanceof OidcUser oidcUser)) { - event.rerouteTo(""); - return; - } + private final org.springframework.core.env.Environment environment; - var groups = oidcUser.getClaimAsStringList("groups"); - if (groups == null || !groups.contains("Kicker Admin")) { - event.rerouteTo(""); + // Methode zum Prüfen, ob das "test"-Profil aktiv ist + private boolean isTestProfileActive() { + for (String profile : environment.getActiveProfiles()) { + System.out.println("Active profile: " + profile); + if ("prod".equals(profile)) { + return true; + } + } + return false; + } + + public void beforeEnter(BeforeEnterEvent event) { + if (!isTestProfileActive()) { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth == null || !(auth.getPrincipal() instanceof OidcUser oidcUser)) { + event.rerouteTo(""); + return; + } + + var groups = oidcUser.getClaimAsStringList("groups"); + if (groups == null || !groups.contains("Kicker Admin")) { + event.rerouteTo(""); + } } } - public AdminView(KickerEloService service) { - // Zeige den aktuell authentifizierten Benutzer - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth != null && auth.getPrincipal() instanceof OidcUser oidcUser) { - String username = oidcUser.getPreferredUsername(); - Object groupsObj = oidcUser.getClaims().getOrDefault("groups", List.of()); - List listOfGroups; - if (groupsObj instanceof List groupsList) { - listOfGroups = groupsList.stream() - .filter(String.class::isInstance) - .map(String.class::cast) - .toList(); - } else { - listOfGroups = List.of(); - } - add(new Paragraph("Angemeldet als: " + username)); + public AdminView(KickerEloService service, org.springframework.core.env.Environment environment) { + this.environment = environment; + + if (!isTestProfileActive()) { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth != null && auth.getPrincipal() instanceof OidcUser oidcUser) { + String username = oidcUser.getPreferredUsername(); + Object groupsObj = oidcUser.getClaims().getOrDefault("groups", List.of()); + List listOfGroups; + if (groupsObj instanceof List groupsList) { + listOfGroups = groupsList.stream() + .filter(String.class::isInstance) + .map(String.class::cast) + .toList(); + } else { + listOfGroups = List.of(); + } + add(new Paragraph("Angemeldet als: " + username)); - if (!listOfGroups.contains("Kicker Admin")) { + if (!listOfGroups.contains("Kicker Admin")) { + add(new Paragraph("Du bist nicht berechtigt, diese Seite zu sehen.")); + getUI().ifPresent(ui -> ui.navigate("")); + return; + } else { + add(new Paragraph("Willkommen im Admin-Bereich!")); + } + } else { + add(new Paragraph("Niemand ist angemeldet")); add(new Paragraph("Du bist nicht berechtigt, diese Seite zu sehen.")); getUI().ifPresent(ui -> ui.navigate("")); return; - } else { - add(new Paragraph("Willkommen im Admin-Bereich!")); } - } else { - add(new Paragraph("Niemand ist angemeldet")); - add(new Paragraph("Du bist nicht berechtigt, diese Seite zu sehen.")); - getUI().ifPresent(ui -> ui.navigate("")); - return; } TextField spielername = new TextField("Spielername"); From ebb6a8cae69a0dcae10423d33ad78e0eb819d60c Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Thu, 12 Jun 2025 17:48:55 +0200 Subject: [PATCH 10/10] Fix reviews --- .../kickerelo/kickerelo/views/AdminView.java | 69 +++++++++---------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java index 4607447..f000dc7 100644 --- a/src/main/java/org/kickerelo/kickerelo/views/AdminView.java +++ b/src/main/java/org/kickerelo/kickerelo/views/AdminView.java @@ -27,26 +27,46 @@ public class AdminView extends VerticalLayout { // Methode zum Prüfen, ob das "test"-Profil aktiv ist private boolean isTestProfileActive() { for (String profile : environment.getActiveProfiles()) { - System.out.println("Active profile: " + profile); - if ("prod".equals(profile)) { + if ("test".equals(profile)) { return true; } } return false; } - public void beforeEnter(BeforeEnterEvent event) { - if (!isTestProfileActive()) { - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth == null || !(auth.getPrincipal() instanceof OidcUser oidcUser)) { - event.rerouteTo(""); - return; + private boolean isAuthentikated() { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth != null && auth.getPrincipal() instanceof OidcUser oidcUser) { + Object groupsObj = oidcUser.getClaims().getOrDefault("groups", List.of()); + List listOfGroups; + if (groupsObj instanceof List groupsList) { + listOfGroups = groupsList.stream() + .filter(String.class::isInstance) + .map(String.class::cast) + .toList(); + } else { + listOfGroups = List.of(); } - var groups = oidcUser.getClaimAsStringList("groups"); - if (groups == null || !groups.contains("Kicker Admin")) { - event.rerouteTo(""); - } + return listOfGroups.contains("Kicker Admin"); + } else { + return false; + } + } + + public void beforeEnter(BeforeEnterEvent event) { + if (isTestProfileActive()) { + return; // Skip authentication check in test profile + } + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth == null || !(auth.getPrincipal() instanceof OidcUser oidcUser)) { + event.rerouteTo(""); + return; + } + + var groups = oidcUser.getClaimAsStringList("groups"); + if (groups == null || !groups.contains("Kicker Admin")) { + event.rerouteTo(""); } } @@ -54,30 +74,7 @@ public class AdminView extends VerticalLayout { this.environment = environment; if (!isTestProfileActive()) { - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth != null && auth.getPrincipal() instanceof OidcUser oidcUser) { - String username = oidcUser.getPreferredUsername(); - Object groupsObj = oidcUser.getClaims().getOrDefault("groups", List.of()); - List listOfGroups; - if (groupsObj instanceof List groupsList) { - listOfGroups = groupsList.stream() - .filter(String.class::isInstance) - .map(String.class::cast) - .toList(); - } else { - listOfGroups = List.of(); - } - add(new Paragraph("Angemeldet als: " + username)); - - if (!listOfGroups.contains("Kicker Admin")) { - add(new Paragraph("Du bist nicht berechtigt, diese Seite zu sehen.")); - getUI().ifPresent(ui -> ui.navigate("")); - return; - } else { - add(new Paragraph("Willkommen im Admin-Bereich!")); - } - } else { - add(new Paragraph("Niemand ist angemeldet")); + if (!isAuthentikated()) { add(new Paragraph("Du bist nicht berechtigt, diese Seite zu sehen.")); getUI().ifPresent(ui -> ui.navigate("")); return;