diff --git a/backend/src/main/java/de/szut/casino/security/GoogleController.java b/backend/src/main/java/de/szut/casino/security/GoogleController.java deleted file mode 100644 index 2219d5d..0000000 --- a/backend/src/main/java/de/szut/casino/security/GoogleController.java +++ /dev/null @@ -1,49 +0,0 @@ -package de.szut.casino.security; - -import de.szut.casino.security.dto.AuthResponseDto; -import de.szut.casino.security.dto.GithubCallbackDto; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.view.RedirectView; - -@RestController -@RequestMapping("/oauth2/google") -public class GoogleController { - private static final Logger logger = LoggerFactory.getLogger(GoogleController.class); - - @Value("${spring.security.oauth2.client.registration.google.client-id}") - private String clientId; - - @Value("${spring.security.oauth2.client.provider.google.authorization-uri}") - private String authorizationUri; - - @Value("${spring.security.oauth2.client.registration.google.redirect-uri}") - private String redirectUri; - - @Autowired - private GoogleService googleService; - - @GetMapping("/authorize") - public RedirectView authorizeGoogle() { - logger.info("Redirecting to Google for authorization"); - - String authUrl = authorizationUri + - "?client_id=" + clientId + - "&redirect_uri=" + redirectUri + - "&response_type=code" + - "&scope=email profile"; - - return new RedirectView(authUrl); - } - - @PostMapping("/callback") - public ResponseEntity googleCallback(@RequestBody GithubCallbackDto callbackDto) { - String code = callbackDto.getCode(); - AuthResponseDto response = googleService.processGoogleCode(code); - return ResponseEntity.ok(response); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/GoogleService.java b/backend/src/main/java/de/szut/casino/security/GoogleService.java deleted file mode 100644 index 703b85a..0000000 --- a/backend/src/main/java/de/szut/casino/security/GoogleService.java +++ /dev/null @@ -1,164 +0,0 @@ -package de.szut.casino.security; - -import de.szut.casino.security.dto.AuthResponseDto; -import de.szut.casino.security.jwt.JwtUtils; -import de.szut.casino.user.AuthProvider; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; - -import java.math.BigDecimal; -import java.util.*; - -@Service -public class GoogleService { - private static final Logger logger = LoggerFactory.getLogger(GoogleService.class); - - @Value("${spring.security.oauth2.client.registration.google.client-id}") - private String clientId; - - @Value("${spring.security.oauth2.client.registration.google.client-secret}") - private String clientSecret; - - @Value("${spring.security.oauth2.client.registration.google.redirect-uri}") - private String redirectUri; - - @Value("${spring.security.oauth2.client.provider.google.token-uri}") - private String tokenUri; - - @Value("${spring.security.oauth2.client.provider.google.user-info-uri}") - private String userInfoUri; - - @Autowired - private AuthenticationManager authenticationManager; - - @Autowired - private UserRepository userRepository; - - @Autowired - private JwtUtils jwtUtils; - - @Autowired - private PasswordEncoder oauth2PasswordEncoder; - - public AuthResponseDto processGoogleCode(String code) { - try { - RestTemplate restTemplate = new RestTemplate(); - - HttpHeaders tokenHeaders = new HttpHeaders(); - tokenHeaders.set("Content-Type", "application/x-www-form-urlencoded"); - - MultiValueMap tokenRequestBody = new LinkedMultiValueMap<>(); - tokenRequestBody.add("client_id", clientId); - tokenRequestBody.add("client_secret", clientSecret); - tokenRequestBody.add("code", code); - tokenRequestBody.add("redirect_uri", redirectUri); - tokenRequestBody.add("grant_type", "authorization_code"); - - HttpEntity> tokenRequestEntity = new HttpEntity<>(tokenRequestBody, tokenHeaders); - - ResponseEntity tokenResponse = restTemplate.exchange( - tokenUri, - HttpMethod.POST, - tokenRequestEntity, - Map.class - ); - - Map tokenResponseBody = tokenResponse.getBody(); - - if (tokenResponseBody == null || tokenResponseBody.containsKey("error")) { - String error = tokenResponseBody != null ? (String) tokenResponseBody.get("error") : "Unknown error"; - throw new RuntimeException("Google OAuth error: " + error); - } - - String accessToken = (String) tokenResponseBody.get("access_token"); - if (accessToken == null || accessToken.isEmpty()) { - throw new RuntimeException("Failed to receive access token from Google"); - } - - HttpHeaders userInfoHeaders = new HttpHeaders(); - userInfoHeaders.set("Authorization", "Bearer " + accessToken); - - HttpEntity userInfoRequestEntity = new HttpEntity<>(null, userInfoHeaders); - - ResponseEntity userResponse = restTemplate.exchange( - userInfoUri, - HttpMethod.GET, - userInfoRequestEntity, - Map.class - ); - - Map userAttributes = userResponse.getBody(); - if (userAttributes == null) { - throw new RuntimeException("Failed to fetch user data from Google"); - } - - String googleId = (String) userAttributes.get("sub"); - String email = (String) userAttributes.get("email"); - String name = (String) userAttributes.get("name"); - Boolean emailVerified = (Boolean) userAttributes.getOrDefault("email_verified", false); - - if (email == null) { - throw new RuntimeException("Google account does not have an email"); - } - - String username = name != null ? name.replaceAll("\\s+", "") : email.split("@")[0]; - - Optional userOptional = userRepository.findByProviderId(googleId); - UserEntity user; - - if (userOptional.isPresent()) { - user = userOptional.get(); - } else { - userOptional = userRepository.findByEmail(email); - - if (userOptional.isPresent()) { - user = userOptional.get(); - user.setProvider(AuthProvider.GOOGLE); - user.setProviderId(googleId); - } else { - user = new UserEntity(); - user.setEmail(email); - user.setUsername(username); - user.setProvider(AuthProvider.GOOGLE); - user.setProviderId(googleId); - user.setEmailVerified(emailVerified); - - user.setBalance(new BigDecimal("100.00")); - } - } - - String randomPassword = UUID.randomUUID().toString(); - user.setPassword(oauth2PasswordEncoder.encode(randomPassword)); - - userRepository.save(user); - - Authentication authentication = authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken(user.getEmail(), randomPassword) - ); - - String token = jwtUtils.generateToken(authentication); - - return new AuthResponseDto(token); - - } catch (Exception e) { - logger.error("Failed to process Google authentication", e); - throw new RuntimeException("Failed to process Google authentication", e); - } - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/GoogleOAuth2UserInfo.java b/backend/src/main/java/de/szut/casino/security/oauth2/GoogleOAuth2UserInfo.java deleted file mode 100644 index 66fc99c..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/GoogleOAuth2UserInfo.java +++ /dev/null @@ -1,25 +0,0 @@ -package de.szut.casino.security.oauth2; - -import java.util.Map; - -public class GoogleOAuth2UserInfo extends OAuth2UserInfo { - - public GoogleOAuth2UserInfo(Map attributes) { - super(attributes); - } - - @Override - public String getId() { - return (String) attributes.get("sub"); - } - - @Override - public String getName() { - return (String) attributes.get("name"); - } - - @Override - public String getEmail() { - return (String) attributes.get("email"); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2UserInfoFactory.java b/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2UserInfoFactory.java index 8e0e936..b7d4365 100644 --- a/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2UserInfoFactory.java +++ b/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2UserInfoFactory.java @@ -10,8 +10,6 @@ public class OAuth2UserInfoFactory { public static OAuth2UserInfo getOAuth2UserInfo(String registrationId, Map attributes) { if (registrationId.equalsIgnoreCase(AuthProvider.GITHUB.toString())) { return new GitHubOAuth2UserInfo(attributes); - } else if (registrationId.equalsIgnoreCase(AuthProvider.GOOGLE.toString())) { - return new GoogleOAuth2UserInfo(attributes); } else { throw new OAuth2AuthenticationProcessingException("Sorry! Login with " + registrationId + " is not supported yet."); } diff --git a/backend/src/main/java/de/szut/casino/user/AuthProvider.java b/backend/src/main/java/de/szut/casino/user/AuthProvider.java index c26b45c..2216da7 100644 --- a/backend/src/main/java/de/szut/casino/user/AuthProvider.java +++ b/backend/src/main/java/de/szut/casino/user/AuthProvider.java @@ -2,6 +2,5 @@ package de.szut.casino.user; public enum AuthProvider { LOCAL, - GITHUB, - GOOGLE + GITHUB } diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 0fa2407..e583c50 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -41,13 +41,3 @@ spring.security.oauth2.client.provider.github.user-name-attribute=login # OAuth Success and Failure URLs app.oauth2.authorizedRedirectUris=${app.frontend-host}/auth/oauth2/callback -# Google OAuth2 Configuration -spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID:350791038883-c1r7v4o793itq8a0rh7dut7itm7uneam.apps.googleusercontent.com} -spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET: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} -spring.security.oauth2.client.registration.google.redirect-uri=${app.frontend-host}/oauth2/callback/google -spring.security.oauth2.client.registration.google.scope=email,profile -spring.security.oauth2.client.provider.google.authorization-uri=https://accounts.google.com/o/oauth2/v2/auth -spring.security.oauth2.client.provider.google.token-uri=https://oauth2.googleapis.com/token -spring.security.oauth2.client.provider.google.user-info-uri=https://www.googleapis.com/oauth2/v3/userinfo -spring.security.oauth2.client.provider.google.user-name-attribute=sub - diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts index 44c342a..6e9f9b7 100644 --- a/frontend/src/app/app.routes.ts +++ b/frontend/src/app/app.routes.ts @@ -34,25 +34,11 @@ export const routes: Routes = [ ), }, { - path: 'oauth2/callback', - children: [ - { - path: 'github', - loadComponent: () => - import('./feature/auth/oauth2/oauth2-callback.component').then( - (m) => m.OAuth2CallbackComponent - ), - data: { provider: 'github' }, - }, - { - path: 'google', - loadComponent: () => - import('./feature/auth/oauth2/oauth2-callback.component').then( - (m) => m.OAuth2CallbackComponent - ), - data: { provider: 'google' }, - }, - ], + path: 'oauth2/callback/github', + loadComponent: () => + import('./feature/auth/oauth2/oauth2-callback.component').then( + (m) => m.OAuth2CallbackComponent + ), }, { path: 'game/blackjack', diff --git a/frontend/src/app/feature/auth/login/login.component.html b/frontend/src/app/feature/auth/login/login.component.html index 044742c..14a7d1e 100644 --- a/frontend/src/app/feature/auth/login/login.component.html +++ b/frontend/src/app/feature/auth/login/login.component.html @@ -89,7 +89,7 @@
-
+
- -
diff --git a/frontend/src/app/feature/auth/login/login.component.ts b/frontend/src/app/feature/auth/login/login.component.ts index 09c1cdf..2b78f29 100644 --- a/frontend/src/app/feature/auth/login/login.component.ts +++ b/frontend/src/app/feature/auth/login/login.component.ts @@ -71,11 +71,6 @@ export class LoginComponent { window.location.href = `${environment.apiUrl}/oauth2/github/authorize`; } - loginWithGoogle(): void { - this.isLoading.set(true); - window.location.href = `${environment.apiUrl}/oauth2/google/authorize`; - } - switchToForgotPassword() { this.forgotPassword.emit(); } diff --git a/frontend/src/app/feature/auth/oauth2/oauth2-callback.component.ts b/frontend/src/app/feature/auth/oauth2/oauth2-callback.component.ts index ebd2688..f905f75 100644 --- a/frontend/src/app/feature/auth/oauth2/oauth2-callback.component.ts +++ b/frontend/src/app/feature/auth/oauth2/oauth2-callback.component.ts @@ -1,7 +1,7 @@ -import { Component, computed, inject, OnInit, Signal } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ActivatedRoute, Router } from '@angular/router'; -import { Oauth2Service } from './oauth2.service'; +import { AuthService } from '@service/auth.service'; @Component({ selector: 'app-oauth2-callback', @@ -10,34 +10,51 @@ import { Oauth2Service } from './oauth2.service'; template: `
-

Authentifizierung...

+

Finishing authentication...

-

{{ error() }}

+

{{ error }}

`, }) export class OAuth2CallbackComponent implements OnInit { - error: Signal = computed(() => this.oauthService.error()); + error: string | null = null; - private route: ActivatedRoute = inject(ActivatedRoute); - private router: Router = inject(Router); - private oauthService: Oauth2Service = inject(Oauth2Service); + constructor( + private route: ActivatedRoute, + private router: Router, + private authService: AuthService + ) {} ngOnInit(): void { + // Check for code in URL params this.route.queryParams.subscribe((params) => { const code = params['code']; - const provider = this.route.snapshot.data['provider'] || 'github'; if (code) { - this.oauthService.oauth(provider, code); - } else { - this.oauthService.error.set( - 'Authentifizierung fehlgeschlagen. Bitte versuchen Sie es erneut.' - ); + // Exchange GitHub code for a JWT token + this.authService.githubAuth(code).subscribe({ + next: () => { + // Redirect to home after successful authentication + this.router.navigate(['/home']); + }, + error: (err) => { + console.error('GitHub authentication error:', err); + this.error = err.error?.message || 'Authentication failed. Please try again.'; + console.log('Error details:', err); + // Redirect back to landing page after showing error + setTimeout(() => { + this.router.navigate(['/']); + }, 3000); + }, + }); + } else { + this.error = 'Authentication failed. No authorization code received.'; + + // Redirect back to landing page after showing error setTimeout(() => { this.router.navigate(['/']); }, 3000); diff --git a/frontend/src/app/feature/auth/oauth2/oauth2.service.ts b/frontend/src/app/feature/auth/oauth2/oauth2.service.ts deleted file mode 100644 index 79ad6d9..0000000 --- a/frontend/src/app/feature/auth/oauth2/oauth2.service.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { inject, Injectable, signal } from '@angular/core'; -import { Router } from '@angular/router'; -import { AuthService } from '@service/auth.service'; - -@Injectable({ - providedIn: 'root', -}) -export class Oauth2Service { - private router: Router = inject(Router); - private authService: AuthService = inject(AuthService); - private _error = signal(''); - - oauth(provider: string, code: string) { - const oauth$ = - provider === 'github' ? this.authService.githubAuth(code) : this.authService.googleAuth(code); - - oauth$.subscribe({ - next: () => { - this.router.navigate(['/home']); - }, - error: (err) => { - this._error.set( - err.error?.message || 'Authentifizierung fehlgeschlagen. Bitte versuchen Sie es erneut.' - ); - - setTimeout(() => { - this.router.navigate(['/']); - }, 3000); - }, - }); - } - - public get error() { - return this._error; - } -} diff --git a/frontend/src/app/service/auth.service.ts b/frontend/src/app/service/auth.service.ts index 61b3e7d..081ad72 100644 --- a/frontend/src/app/service/auth.service.ts +++ b/frontend/src/app/service/auth.service.ts @@ -79,15 +79,6 @@ export class AuthService { ); } - googleAuth(code: string): Observable { - return this.http.post(`${this.oauthUrl}/google/callback`, { code }).pipe( - tap((response) => { - this.setToken(response.token); - this.loadCurrentUser(); - }) - ); - } - logout(): void { localStorage.removeItem(TOKEN_KEY); localStorage.removeItem(USER_KEY);