From 206eee4085d21cfa0f6ed09a36a9188489a401bb Mon Sep 17 00:00:00 2001 From: csimonis Date: Wed, 12 Mar 2025 14:45:40 +0100 Subject: [PATCH] wip --- backend/build.gradle.kts | 4 +-- .../CustomJwtAuthenticationConverter.java | 27 +++++++++++++++++++ .../szut/casino/security/SecurityConfig.java | 25 +++++++++++++++++ .../src/main/resources/application.properties | 11 +------- .../login-success/login-success.component.ts | 2 +- frontend/src/app/service/auth.service.ts | 11 +++----- .../shared/interceptor/http.interceptor.ts | 10 +++---- 7 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 backend/src/main/java/de/szut/casino/security/CustomJwtAuthenticationConverter.java create mode 100644 backend/src/main/java/de/szut/casino/security/SecurityConfig.java diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index 36ecee7..d6397a2 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -47,8 +47,8 @@ dependencies { testImplementation("org.springframework.boot:spring-boot-starter-test") testRuntimeOnly("org.junit.platform:junit-platform-launcher") implementation("org.springframework.boot:spring-boot-starter-security") - implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.3.3") - implementation("org.springframework.boot:spring-boot-starter-oauth2-client") + implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server") + implementation("org.springframework.security:spring-security-oauth2-jose") runtimeOnly("org.postgresql:postgresql") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0") } diff --git a/backend/src/main/java/de/szut/casino/security/CustomJwtAuthenticationConverter.java b/backend/src/main/java/de/szut/casino/security/CustomJwtAuthenticationConverter.java new file mode 100644 index 0000000..df79e08 --- /dev/null +++ b/backend/src/main/java/de/szut/casino/security/CustomJwtAuthenticationConverter.java @@ -0,0 +1,27 @@ +package de.szut.casino.security; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; +import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; + +public class CustomJwtAuthenticationConverter implements Converter { + + @Override + public AbstractAuthenticationToken convert(Jwt source) { + JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter(); + authoritiesConverter.setAuthorityPrefix("ROLE_"); // Ensure roles have the prefix + authoritiesConverter.setAuthoritiesClaimName("roles"); // Use Authentik's claim for roles + + JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); + converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter); + + return converter.convert(source); + } + + public Converter andThen(Converter after) { + return Converter.super.andThen(after); + } +} + diff --git a/backend/src/main/java/de/szut/casino/security/SecurityConfig.java b/backend/src/main/java/de/szut/casino/security/SecurityConfig.java new file mode 100644 index 0000000..408affb --- /dev/null +++ b/backend/src/main/java/de/szut/casino/security/SecurityConfig.java @@ -0,0 +1,25 @@ +package de.szut.casino.security; + +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.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(auth -> { + auth.requestMatchers("/swagger/**", "/health").permitAll() + .requestMatchers("/").authenticated(); + }) + .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(new CustomJwtAuthenticationConverter()))); + + return http.build(); + } +} + diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 356045f..6ce3e4a 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -9,18 +9,9 @@ app.frontend-host=http://localhost:4200 spring.application.name=lf12_starter #client registration configuration -spring.security.oauth2.client.registration.authentik.provider=authentik spring.security.oauth2.client.registration.authentik.client-id=MDqjm1kcWKuZfqHJXjxwAV20i44aT7m4VhhTL3Nm spring.security.oauth2.client.registration.authentik.client-secret=GY2F8te6iAVYt1TNAUVLzWZEXb6JoMNp6chbjqaXNq4gS5xTDL54HqBiAlV1jFKarN28LQ7FUsYX4SbwjfEhZhgeoKuBnZKjR9eiu7RawnGgxIK9ffvUfMkjRxnmiGI5 -spring.security.oauth2.client.registration.authentik.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} -spring.security.oauth2.client.registration.authentik.scope=openid, profile, email -spring.security.oauth2.client.registration.authentik.client-name=Authentik -spring.security.oauth2.client.registration.authentik.authorization-grant-type=authorization_code -spring.security.oauth2.client.provider.authentik.authorization-uri=https://oauth.simonis.lol/application/o/authorize/ -spring.security.oauth2.client.provider.authentik.issuer-uri=https://oauth.simonis.lol/ -spring.security.oauth2.client.provider.authentik.token-uri=https://oauth.simonis.lol/application/o/token/ -spring.security.oauth2.client.provider.authentik.user-info-uri=https://oauth.simonis.lol/application/o/userinfo/ -spring.security.oauth2.client.provider.authentik.jwk-set-uri=https://oauth.simonis.lol/application/o/jwks/ +spring.security.oauth2.resourceserver.jwt.issuer-uri=https://oauth.simonis.lol/application/o/casino-dev/ #OIDC provider configuration: logging.level.org.springframework.security=DEBUG diff --git a/frontend/src/app/feature/login-success/login-success.component.ts b/frontend/src/app/feature/login-success/login-success.component.ts index a305ad7..1becd87 100644 --- a/frontend/src/app/feature/login-success/login-success.component.ts +++ b/frontend/src/app/feature/login-success/login-success.component.ts @@ -15,6 +15,6 @@ export default class LoginSuccessComponent implements OnInit { private router: Router = inject(Router); private authService: AuthService = inject(AuthService); async ngOnInit() { - this.authService.getUserInfo() + console.log(this.authService.getAccessToken()); } } diff --git a/frontend/src/app/service/auth.service.ts b/frontend/src/app/service/auth.service.ts index fc94c3a..053add2 100644 --- a/frontend/src/app/service/auth.service.ts +++ b/frontend/src/app/service/auth.service.ts @@ -13,9 +13,6 @@ export class AuthService { private readonly authConfig: AuthConfig = { issuer: 'https://oauth.simonis.lol/application/o/casino-dev/', - loginUrl: 'https://oauth.simonis.lol/application/o/authorize/', - tokenEndpoint: 'https://oauth.simonis.lol/application/o/token/', - userinfoEndpoint: 'https://oauth.simonis.lol/application/o/userinfo/', clientId: 'MDqjm1kcWKuZfqHJXjxwAV20i44aT7m4VhhTL3Nm', dummyClientSecret: 'GY2F8te6iAVYt1TNAUVLzWZEXb6JoMNp6chbjqaXNq4gS5xTDL54HqBiAlV1jFKarN28LQ7FUsYX4SbwjfEhZhgeoKuBnZKjR9eiu7RawnGgxIK9ffvUfMkjRxnmiGI5', scope: 'openid profile email', @@ -25,6 +22,8 @@ export class AuthService { requestAccessToken: true, strictDiscoveryDocumentValidation: false, showDebugInformation: true, + skipIssuerCheck: true, + disableAtHashCheck: true, }; private isAuthenticated = new Subject(); @@ -32,9 +31,11 @@ export class AuthService { private oauthService: OAuthService = inject(OAuthService); constructor() { + this.oauthService.setStorage(localStorage); this.oauthService.configure(this.authConfig); this.oauthService.events.subscribe((event) => { if (event.type === 'token_received') { + localStorage.setItem('jwt', this.getAccessToken()); this.oauthService.loadUserProfile().then((profile) => { this.fromUserProfile(profile).subscribe((user) => { this.user = user; @@ -56,10 +57,6 @@ export class AuthService { this.isAuthenticated.next(false); } - getUserInfo() { - return this.user; - } - isLoggedIn() { return this.oauthService.hasValidAccessToken(); } diff --git a/frontend/src/app/shared/interceptor/http.interceptor.ts b/frontend/src/app/shared/interceptor/http.interceptor.ts index a62c3b1..e1b2658 100644 --- a/frontend/src/app/shared/interceptor/http.interceptor.ts +++ b/frontend/src/app/shared/interceptor/http.interceptor.ts @@ -1,9 +1,9 @@ import { HttpInterceptorFn } from '@angular/common/http'; -import { inject } from '@angular/core'; -import { AuthService } from '../../service/auth.service'; export const httpInterceptor: HttpInterceptorFn = (req, next) => { - return next(req.clone({ - setHeaders: {'Authorization': 'Bearer '+inject(AuthService).getAccessToken()}, - })); + if (localStorage.getItem('jwt')) { + return next(req.clone({ setHeaders: { 'Authorization': 'Bearer ' + localStorage.getItem('jwt') } })); + } else { + return next(req); + } };