diff --git a/pom.xml b/pom.xml
index 838e28a..37ccd51 100644
--- a/pom.xml
+++ b/pom.xml
@@ -153,6 +153,10 @@
org.springframework.security
spring-security-oauth2-jose
+
+ org.springframework.boot
+ spring-boot-starter-oauth2-client
+
diff --git a/src/main/java/com/security/config/auth/AuthorizationServerConfig.java b/src/main/java/com/security/config/auth/AuthorizationServerConfig.java
new file mode 100644
index 0000000..66eb48d
--- /dev/null
+++ b/src/main/java/com/security/config/auth/AuthorizationServerConfig.java
@@ -0,0 +1,77 @@
+package com.security.config.auth;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
+import org.springframework.security.oauth2.core.oidc.OidcScopes;
+import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
+import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
+import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
+import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
+import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
+import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
+import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
+
+import java.time.Duration;
+import java.util.UUID;
+
+@Configuration
+@RequiredArgsConstructor
+public class AuthorizationServerConfig {
+
+ private final AuthProperties authProperties;
+ private final PasswordEncoder passwordEncoder;
+
+ @Bean
+ public RegisteredClientRepository registeredClientRepository() {
+ RegisteredClient.Builder clientBuilder = RegisteredClient.withId(UUID.randomUUID().toString())
+ .clientId("gateway-client")
+ .clientSecret(passwordEncoder.encode("gateway-secret"))
+ .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
+ .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
+ .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
+ .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
+ .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
+ .redirectUri("http://localhost:9090/login/oauth2/code/gateway-client")
+ .redirectUri("http://localhost:9090/authorized")
+ .postLogoutRedirectUri("http://localhost:9090/logout")
+ .scope(OidcScopes.OPENID)
+ .scope(OidcScopes.PROFILE)
+ .scope(OidcScopes.EMAIL)
+ .scope("read")
+ .scope("write")
+ .clientSettings(ClientSettings.builder()
+ .requireAuthorizationConsent(false)
+ .requireProofKey(false)
+ .build())
+ .tokenSettings(TokenSettings.builder()
+ .accessTokenTimeToLive(Duration.ofMinutes(15))
+ .refreshTokenTimeToLive(Duration.ofDays(7))
+ .reuseRefreshTokens(false)
+ .accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED)
+ .build());
+
+ authProperties.getClient().getRedirectUris().forEach(clientBuilder::redirectUri);
+ RegisteredClient client = clientBuilder.build();
+ return new InMemoryRegisteredClientRepository(client);
+ }
+
+
+ @Bean
+ public AuthorizationServerSettings authorizationServerSettings() {
+ return AuthorizationServerSettings.builder()
+ .issuer(authProperties.getServer().getIssuer())
+ .authorizationEndpoint("/oauth2/authorize")
+ .tokenEndpoint("/oauth2/token")
+ .tokenIntrospectionEndpoint("/oauth2/introspect")
+ .tokenRevocationEndpoint("/oauth2/revoke")
+ .jwkSetEndpoint("/.well-known/jwks.json")
+ .oidcLogoutEndpoint("/connect/logout")
+ .oidcUserInfoEndpoint("/userinfo")
+ .oidcClientRegistrationEndpoint("/connect/register")
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/security/config/auth/JwtConfig.java b/src/main/java/com/security/config/auth/JwtConfig.java
new file mode 100644
index 0000000..5ef5219
--- /dev/null
+++ b/src/main/java/com/security/config/auth/JwtConfig.java
@@ -0,0 +1,60 @@
+package com.security.config.auth;
+
+import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.jose.jwk.RSAKey;
+import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
+import com.nimbusds.jose.jwk.source.JWKSource;
+import com.nimbusds.jose.proc.SecurityContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.jwt.JwtDecoder;
+import org.springframework.security.oauth2.jwt.JwtEncoder;
+import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
+import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.UUID;
+
+@Configuration
+public class JwtConfig {
+
+ @Bean
+ public JWKSource jwkSource() {
+ KeyPair keyPair = generateRsaKey();
+ RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+ RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
+ RSAKey rsaKey = new RSAKey.Builder(publicKey)
+ .privateKey(privateKey)
+ .keyID(UUID.randomUUID().toString())
+ .build();
+ JWKSet jwkSet = new JWKSet(rsaKey);
+ return new ImmutableJWKSet<>(jwkSet);
+ }
+
+ private static KeyPair generateRsaKey() {
+ KeyPair keyPair;
+ try {
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(2048);
+ keyPair = keyPairGenerator.generateKeyPair();
+ } catch (
+ Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ return keyPair;
+ }
+
+ @Bean
+ public JwtDecoder jwtDecoder(JWKSource jwkSource) {
+ return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
+ }
+
+ @Bean
+ public JwtEncoder jwtEncoder(JWKSource jwkSource) {
+ return new NimbusJwtEncoder(jwkSource);
+ }
+
+}
diff --git a/src/main/java/com/security/config/auth/SecurityConfig.java b/src/main/java/com/security/config/auth/SecurityConfig.java
index feb31da..10b62e0 100644
--- a/src/main/java/com/security/config/auth/SecurityConfig.java
+++ b/src/main/java/com/security/config/auth/SecurityConfig.java
@@ -1,10 +1,7 @@
package com.security.config.auth;
-import com.nimbusds.jose.jwk.JWKSet;
-import com.nimbusds.jose.jwk.RSAKey;
-import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
-import com.nimbusds.jose.jwk.source.JWKSource;
-import com.nimbusds.jose.proc.SecurityContext;
+import com.security.config.auth.oauth2.OAuth2AuthenticationSuccessHandler;
+import com.security.services.oauth2.CustomOAuth2UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -18,42 +15,29 @@
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.security.oauth2.core.AuthorizationGrantType;
-import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
-import org.springframework.security.oauth2.core.oidc.OidcScopes;
-import org.springframework.security.oauth2.jwt.JwtDecoder;
-import org.springframework.security.oauth2.jwt.JwtEncoder;
-import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
-import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
-import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
-import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
-import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
+import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
+import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
+import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
-import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
-import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
-import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
-import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
-import java.util.UUID;
-
-import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
-@EnableMethodSecurity(prePostEnabled = true)
+@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {
+
+ private final CustomOAuth2UserService customOAuth2UserService;
+
@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
@@ -75,7 +59,13 @@ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity h
@Bean
@Order(2)
- public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, CookieAuthenticationFilter cookieAuthenticationFilter) throws Exception {
+ public SecurityFilterChain defaultSecurityFilterChain(
+ HttpSecurity http,
+ CookieAuthenticationFilter cookieAuthenticationFilter,
+ OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler,
+ OAuth2UserService customOidcUserService,
+ AuthorizationRequestRepository authorizationRequestRepository) throws Exception {
+
return http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(
@@ -87,12 +77,25 @@ public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, CookieA
"/auth/login",
"/auth/refresh",
"/auth/register",
+ "/oauth2/**",
+ "/login/oauth2/**",
"/test/saludo",
"/test/notification",
"/"
).permitAll()
.anyRequest().authenticated()
)
+ .oauth2Login(oauth2 ->
+ oauth2.authorizationEndpoint(authorization ->
+ authorization.authorizationRequestRepository(authorizationRequestRepository)
+ )
+ .userInfoEndpoint(userInfo -> userInfo
+ .userService(customOAuth2UserService)
+ .oidcUserService(customOidcUserService)
+ )
+ .successHandler(oAuth2AuthenticationSuccessHandler)
+ )
+ .oauth2Client(Customizer.withDefaults())
.addFilterBefore(cookieAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.oauth2ResourceServer(oauth2ResourceServer ->
oauth2ResourceServer.jwt(Customizer.withDefaults())
@@ -105,33 +108,36 @@ public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, CookieA
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter scopeConverter = new JwtGrantedAuthoritiesConverter();
scopeConverter.setAuthorityPrefix("SCOPE_");
+
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(jwt -> {
Collection authorities = new ArrayList<>();
- Collection scopeAuth = (Collection) scopeConverter.convert(jwt);
- if (scopeAuth != null)
+ Collection scopeAuth = scopeConverter.convert(jwt);
+ if (scopeAuth != null) {
authorities.addAll(scopeAuth);
+ }
Object claim = jwt.getClaims().get("authorities");
- if (claim != null) {
- if (claim instanceof String) {
- String[] parts = ((String) claim).trim().split("\\s+");
- for (String p : parts) {
- if (!p.isBlank())
- authorities.add(new SimpleGrantedAuthority(p));
+ if (claim instanceof String authString) {
+ String[] parts = authString.trim().split("\\s+");
+ for (String part : parts) {
+ if (!part.isBlank()) {
+ authorities.add(new SimpleGrantedAuthority(part));
}
- } else if (claim instanceof Collection>) {
- ((Collection>) claim).forEach(o -> {
- if (o != null)
- authorities.add(new SimpleGrantedAuthority(o.toString()));
- });
- } else if (claim instanceof Map, ?>) {
- ((Map, ?>) claim).values().forEach(v -> {
- if (v != null)
- authorities.add(new SimpleGrantedAuthority(v.toString()));
- });
}
+ } else if (claim instanceof Collection> authCollection) {
+ authCollection.forEach(o -> {
+ if (o != null) {
+ authorities.add(new SimpleGrantedAuthority(o.toString()));
+ }
+ });
+ } else if (claim instanceof Map, ?> authMap) {
+ authMap.values().forEach(v -> {
+ if (v != null) {
+ authorities.add(new SimpleGrantedAuthority(v.toString()));
+ }
+ });
}
return authorities;
@@ -140,93 +146,8 @@ public JwtAuthenticationConverter jwtAuthenticationConverter() {
return converter;
}
- @Bean
- public RegisteredClientRepository registeredClientRepository() {
- RegisteredClient gatewayClient = RegisteredClient.withId(UUID.randomUUID().toString())
- .clientId("gateway-client")
- .clientSecret(passwordEncoder().encode("gateway-secret"))
- .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
- .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
- .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
- .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
- .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
- .redirectUri("http://localhost:9090/login/oauth2/code/gateway-client")
- .redirectUri("http://localhost:9090/authorized")
- .postLogoutRedirectUri("http://localhost:9090/logout")
- .scope(OidcScopes.OPENID)
- .scope(OidcScopes.PROFILE)
- .scope(OidcScopes.EMAIL)
- .scope("read")
- .scope("write")
- .clientSettings(ClientSettings.builder()
- .requireAuthorizationConsent(false)
- .requireProofKey(false)
- .build())
-
- .tokenSettings(TokenSettings.builder()
- .accessTokenTimeToLive(Duration.ofMinutes(15))
- .refreshTokenTimeToLive(Duration.ofDays(7))
- .reuseRefreshTokens(false)
- .accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED)
- .build())
- .build();
-
- return new InMemoryRegisteredClientRepository(gatewayClient);
- }
-
- @Bean
- public JWKSource jwkSource() {
- KeyPair keyPair = generateRsaKey();
- RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
- RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
- RSAKey rsaKey = new RSAKey.Builder(publicKey)
- .privateKey(privateKey)
- .keyID(UUID.randomUUID().toString())
- .build();
- JWKSet jwkSet = new JWKSet(rsaKey);
- return new ImmutableJWKSet<>(jwkSet);
- }
-
- private static KeyPair generateRsaKey() {
- KeyPair keyPair;
- try {
- KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- keyPairGenerator.initialize(2048);
- keyPair = keyPairGenerator.generateKeyPair();
- } catch (
- Exception ex) {
- throw new IllegalStateException(ex);
- }
- return keyPair;
- }
-
- @Bean
- public JwtDecoder jwtDecoder(JWKSource jwkSource) {
- return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
- }
-
- @Bean
- public JwtEncoder jwtEncoder(JWKSource jwkSource) {
- return new NimbusJwtEncoder(jwkSource);
- }
-
- @Bean
- public AuthorizationServerSettings authorizationServerSettings() {
- return AuthorizationServerSettings.builder()
- .issuer("http://localhost:9091")
- .authorizationEndpoint("/oauth2/authorize")
- .tokenEndpoint("/oauth2/token")
- .tokenIntrospectionEndpoint("/oauth2/introspect")
- .tokenRevocationEndpoint("/oauth2/revoke")
- .jwkSetEndpoint("/.well-known/jwks.json")
- .oidcLogoutEndpoint("/connect/logout")
- .oidcUserInfoEndpoint("/userinfo")
- .oidcClientRegistrationEndpoint("/connect/register")
- .build();
- }
-
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/security/config/auth/oauth2/OAuth2AuthenticationSuccessHandler.java b/src/main/java/com/security/config/auth/oauth2/OAuth2AuthenticationSuccessHandler.java
new file mode 100644
index 0000000..f8db052
--- /dev/null
+++ b/src/main/java/com/security/config/auth/oauth2/OAuth2AuthenticationSuccessHandler.java
@@ -0,0 +1,89 @@
+package com.security.config.auth.oauth2;
+
+import com.security.entity.UserEntity;
+import com.security.services.AuthService;
+import com.security.services.CookieService;
+import com.security.services.oauth2.CustomOAuth2User;
+import com.security.services.oauth2.CustomOidcUser;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.oauth2.core.user.OAuth2User;
+import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
+import org.springframework.stereotype.Component;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.io.IOException;
+
+@Component
+@RequiredArgsConstructor
+@Slf4j
+public class OAuth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
+
+ private final AuthService authService;
+ private final CookieService cookieService;
+
+ @Override
+ public void onAuthenticationSuccess(
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Authentication authentication) throws IOException {
+
+ Object principal = authentication.getPrincipal();
+ UserEntity user = null;
+
+ if (principal instanceof CustomOidcUser customOidcUser) {
+ user = customOidcUser.getUser();
+ log.info("✅ Usuario obtenido desde CustomOidcUser: {}", user.getEmail());
+ } else if (principal instanceof CustomOAuth2User customOAuth2User) {
+ user = customOAuth2User.getUser();
+ log.info("✅ Usuario obtenido desde CustomOAuth2User: {}", user.getEmail());
+ } else {
+ log.error("❌ Principal NO es CustomOAuth2User ni CustomOidcUser. Tipo: {}", principal.getClass().getName());
+ if (principal instanceof OAuth2User oauth2User) {
+ log.error("❌ Atributos: {}", oauth2User.getAttributes());
+ }
+
+ getRedirectStrategy().sendRedirect(request, response,
+ "http://localhost:5173/auth?error=oauth_user_service_failed");
+ return;
+ }
+
+ if (user == null) {
+ log.error("❌ Usuario es NULL después de obtenerlo del principal");
+ getRedirectStrategy().sendRedirect(request, response,
+ "http://localhost:5173/auth?error=oauth_user_null");
+ return;
+ }
+
+ try {
+ var loginResponse = authService.createTokensForOAuth2User(user);
+ cookieService.setSecureTokenCookies(response, loginResponse);
+
+ log.info("✅ Cookies establecidas para usuario OAuth2: {}", user.getEmail());
+
+ // ✅ Redirigir al frontend
+ String targetUrl = UriComponentsBuilder
+ .fromUriString("http://localhost:5173/auth/callback")
+ .queryParam("success", "true")
+ .build()
+ .toUriString();
+
+ if (response.isCommitted()) {
+ log.debug("⚠️ La respuesta ya fue enviada. No se puede redirigir a {}", targetUrl);
+ return;
+ }
+
+ clearAuthenticationAttributes(request);
+ getRedirectStrategy().sendRedirect(request, response, targetUrl);
+
+ } catch (
+ Exception e) {
+ log.error("❌ Error generando tokens para OAuth2", e);
+ getRedirectStrategy().sendRedirect(request, response,
+ "http://localhost:5173/auth?error=token_generation_failed");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/security/config/auth/oauth2/OAuth2Config.java b/src/main/java/com/security/config/auth/oauth2/OAuth2Config.java
new file mode 100644
index 0000000..0a8e079
--- /dev/null
+++ b/src/main/java/com/security/config/auth/oauth2/OAuth2Config.java
@@ -0,0 +1,54 @@
+package com.security.config.auth.oauth2;
+
+import com.security.services.AuthService;
+import com.security.services.CookieService;
+import com.security.services.oauth2.CustomOAuth2UserService;
+import com.security.services.oauth2.CustomOidcUser;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
+import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
+import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
+import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
+import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
+import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
+import org.springframework.security.oauth2.core.user.OAuth2User;
+
+
+@Configuration
+public class OAuth2Config {
+
+ @Bean
+ public OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler(
+ AuthService authService,
+ CookieService cookieService) {
+ return new OAuth2AuthenticationSuccessHandler(authService, cookieService);
+ }
+
+ @Bean
+ public OAuth2UserService customOidcUserService(
+ CustomOAuth2UserService customOAuth2UserService) {
+ return new OidcUserService() {
+ @Override
+ public OidcUser loadUser(OidcUserRequest userRequest) {
+ OAuth2UserRequest oauth2UserRequest = new OAuth2UserRequest(
+ userRequest.getClientRegistration(),
+ userRequest.getAccessToken(),
+ userRequest.getAdditionalParameters()
+ );
+ OAuth2User oauth2User = customOAuth2UserService.loadUser(oauth2UserRequest);
+ if (oauth2User instanceof com.security.services.oauth2.CustomOAuth2User customUser) {
+ return new CustomOidcUser(customUser, userRequest.getIdToken());
+ }
+ return super.loadUser(userRequest);
+ }
+ };
+ }
+
+ @Bean
+ public AuthorizationRequestRepository authorizationRequestRepository() {
+ return new HttpSessionOAuth2AuthorizationRequestRepository();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/security/entity/UserEntity.java b/src/main/java/com/security/entity/UserEntity.java
index b6141f3..bdda4cc 100644
--- a/src/main/java/com/security/entity/UserEntity.java
+++ b/src/main/java/com/security/entity/UserEntity.java
@@ -2,6 +2,7 @@
import com.security.config.audit.Audit;
import com.security.config.audit.AuditListener;
+import com.security.enums.AuthProvider;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -28,13 +29,14 @@ public class UserEntity implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
-// private String username;
+ @Column(unique = true)
private String email;
private String password;
-// private String firstName;
-// private String lastName;
-// private String dni;
-// private String phone;
+ @Column(unique = true)
+ private String googleId;
+ @Enumerated(EnumType.STRING)
+ @Builder.Default
+ private AuthProvider provider = AuthProvider.LOCAL;
@Embedded
private Audit audit;
@@ -54,7 +56,11 @@ public class UserEntity implements UserDetails {
private Boolean credentialsNonExpired = true;
@ManyToMany(fetch = FetchType.EAGER)
- @JoinTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
+ @JoinTable(
+ name = "user_roles",
+ joinColumns = @JoinColumn(name = "user_id"),
+ inverseJoinColumns = @JoinColumn(name = "role_id")
+ )
private Set roles;
@Override
diff --git a/src/main/java/com/security/enums/AuthProvider.java b/src/main/java/com/security/enums/AuthProvider.java
new file mode 100644
index 0000000..7d4d603
--- /dev/null
+++ b/src/main/java/com/security/enums/AuthProvider.java
@@ -0,0 +1,5 @@
+package com.security.enums;
+
+public enum AuthProvider {
+ LOCAL, GOOGLE
+}
diff --git a/src/main/java/com/security/events/notification/CreatedUserEvent.java b/src/main/java/com/security/events/notification/CreatedUserEvent.java
index c1521ab..606f407 100644
--- a/src/main/java/com/security/events/notification/CreatedUserEvent.java
+++ b/src/main/java/com/security/events/notification/CreatedUserEvent.java
@@ -5,6 +5,7 @@ public record CreatedUserEvent(
String firstName,
String lastName,
String dni,
- String phone
+ String phone,
+ String profileImageUrl
) {
}
diff --git a/src/main/java/com/security/exceptions/AuthenticationException.java b/src/main/java/com/security/exceptions/AuthenticationException.java
new file mode 100644
index 0000000..a6b18be
--- /dev/null
+++ b/src/main/java/com/security/exceptions/AuthenticationException.java
@@ -0,0 +1,7 @@
+package com.security.exceptions;
+
+public class AuthenticationException extends RuntimeException {
+ public AuthenticationException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/security/exceptions/GlobalExceptionController.java b/src/main/java/com/security/exceptions/GlobalExceptionController.java
index 59b3b87..08c1291 100644
--- a/src/main/java/com/security/exceptions/GlobalExceptionController.java
+++ b/src/main/java/com/security/exceptions/GlobalExceptionController.java
@@ -15,6 +15,7 @@
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.NoHandlerFoundException;
import java.util.Collections;
@@ -174,4 +175,42 @@ public ResponseEntity