diff --git a/application/src/main/java/run/halo/app/security/HaloServerRequestCache.java b/application/src/main/java/run/halo/app/security/HaloServerRequestCache.java index 67cb3eedc..b2b588fbd 100644 --- a/application/src/main/java/run/halo/app/security/HaloServerRequestCache.java +++ b/application/src/main/java/run/halo/app/security/HaloServerRequestCache.java @@ -106,7 +106,8 @@ public class HaloServerRequestCache extends WebSessionServerRequestCache { var get = pathMatchers(HttpMethod.GET, "/**"); var notFavicon = new NegatedServerWebExchangeMatcher( pathMatchers( - "/favicon.*", "/login/**", "/signup/**", "/password-reset/**", "/challenges/**" + "/favicon.*", "/login/**", "/signup/**", "/password-reset/**", "/challenges/**", + "/oauth2/**", "/social/**" )); var html = new MediaTypeServerWebExchangeMatcher(MediaType.TEXT_HTML); html.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL)); diff --git a/application/src/main/java/run/halo/app/security/authentication/oauth2/MapOAuth2AuthenticationFilter.java b/application/src/main/java/run/halo/app/security/authentication/oauth2/MapOAuth2AuthenticationFilter.java index e4e5ba64c..43989bb37 100644 --- a/application/src/main/java/run/halo/app/security/authentication/oauth2/MapOAuth2AuthenticationFilter.java +++ b/application/src/main/java/run/halo/app/security/authentication/oauth2/MapOAuth2AuthenticationFilter.java @@ -23,6 +23,7 @@ import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; import run.halo.app.core.user.service.UserConnectionService; +import run.halo.app.security.LoginHandlerEnhancer; /** * A filter to map OAuth2 authentication to authenticated user. @@ -47,6 +48,8 @@ class MapOAuth2AuthenticationFilter implements WebFilter { private final ServerLogoutHandler logoutHandler; + private final LoginHandlerEnhancer loginHandlerEnhancer; + private final ServerRedirectStrategy redirectStrategy = new DefaultServerRedirectStrategy(); @Setter @@ -56,10 +59,12 @@ class MapOAuth2AuthenticationFilter implements WebFilter { public MapOAuth2AuthenticationFilter( ServerSecurityContextRepository securityContextRepository, UserConnectionService connectionService, - ReactiveUserDetailsService userDetailsService) { + ReactiveUserDetailsService userDetailsService, + LoginHandlerEnhancer loginHandlerEnhancer) { this.connectionService = connectionService; this.securityContextRepository = securityContextRepository; this.userDetailsService = userDetailsService; + this.loginHandlerEnhancer = loginHandlerEnhancer; var logoutHandler = new SecurityContextServerLogoutHandler(); logoutHandler.setSecurityContextRepository(securityContextRepository); this.logoutHandler = logoutHandler; @@ -116,7 +121,10 @@ class MapOAuth2AuthenticationFilter implements WebFilter { .map(userDetails -> authenticated(userDetails, oauth2Token)) .flatMap(haloOAuth2Token -> { var securityContext = new SecurityContextImpl(haloOAuth2Token); - return securityContextRepository.save(exchange, securityContext); + return securityContextRepository.save(exchange, securityContext) + .then( + loginHandlerEnhancer.onLoginSuccess(exchange, haloOAuth2Token) + ); // because this happens after the filter, there is no need to // write SecurityContext to the context }); diff --git a/application/src/main/java/run/halo/app/security/authentication/oauth2/OAuth2SecurityConfigurer.java b/application/src/main/java/run/halo/app/security/authentication/oauth2/OAuth2SecurityConfigurer.java index 0f25d6883..0d930b150 100644 --- a/application/src/main/java/run/halo/app/security/authentication/oauth2/OAuth2SecurityConfigurer.java +++ b/application/src/main/java/run/halo/app/security/authentication/oauth2/OAuth2SecurityConfigurer.java @@ -7,6 +7,7 @@ import org.springframework.security.core.userdetails.ReactiveUserDetailsService; import org.springframework.security.web.server.context.ServerSecurityContextRepository; import org.springframework.stereotype.Component; import run.halo.app.core.user.service.UserConnectionService; +import run.halo.app.security.LoginHandlerEnhancer; import run.halo.app.security.authentication.SecurityConfigurer; /** @@ -25,17 +26,21 @@ class OAuth2SecurityConfigurer implements SecurityConfigurer { private final ReactiveUserDetailsService userDetailsService; + private final LoginHandlerEnhancer loginHandlerEnhancer; + public OAuth2SecurityConfigurer(ServerSecurityContextRepository securityContextRepository, - UserConnectionService connectionService, ReactiveUserDetailsService userDetailsService) { + UserConnectionService connectionService, ReactiveUserDetailsService userDetailsService, + LoginHandlerEnhancer loginHandlerEnhancer) { this.securityContextRepository = securityContextRepository; this.connectionService = connectionService; this.userDetailsService = userDetailsService; + this.loginHandlerEnhancer = loginHandlerEnhancer; } @Override public void configure(ServerHttpSecurity http) { var mapOAuth2Filter = new MapOAuth2AuthenticationFilter( - securityContextRepository, connectionService, userDetailsService + securityContextRepository, connectionService, userDetailsService, loginHandlerEnhancer ); http.addFilterBefore(mapOAuth2Filter, SecurityWebFiltersOrder.AUTHENTICATION); } diff --git a/application/src/main/java/run/halo/app/security/preauth/PreAuthLoginEndpoint.java b/application/src/main/java/run/halo/app/security/preauth/PreAuthLoginEndpoint.java index 4e7fc1954..8dd34bf8e 100644 --- a/application/src/main/java/run/halo/app/security/preauth/PreAuthLoginEndpoint.java +++ b/application/src/main/java/run/halo/app/security/preauth/PreAuthLoginEndpoint.java @@ -2,6 +2,7 @@ package run.halo.app.security.preauth; import static org.springframework.web.reactive.function.server.RequestPredicates.path; +import java.net.URI; import java.util.Base64; import java.util.Map; import java.util.Objects; @@ -10,6 +11,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Bean; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; +import org.springframework.http.HttpStatus; import org.springframework.security.web.server.savedrequest.ServerRequestCache; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RouterFunction; @@ -115,6 +117,24 @@ class PreAuthLoginEndpoint { )) )); }) + .POST("/social/{authProviderName}", request -> { + var authProviderName = request.pathVariable("authProviderName"); + return authProviderService.getEnabledProviders() + .filter(ap -> Objects.equals(authProviderName, ap.getMetadata().getName())) + .filter(ap -> !AuthProvider.AuthType.FORM.equals(ap.getSpec().getAuthType())) + .next() + .switchIfEmpty(Mono.error(() -> new ServerWebInputException( + "Auth provider " + authProviderName + " not found or not enabled." + ))) + .flatMap(ap -> { + var authenticationUrl = ap.getSpec().getAuthenticationUrl(); + return rememberMeRequestCache.saveRememberMe(request.exchange()) + .then(Mono.defer(() -> ServerResponse.status(HttpStatus.FOUND) + .location(URI.create(authenticationUrl)) + .build() + )); + }); + }) .before(HaloUtils.noCache()) .build()); } diff --git a/application/src/main/resources/static/styles/main.css b/application/src/main/resources/static/styles/main.css index 0a4be9fcd..04e810d66 100644 --- a/application/src/main/resources/static/styles/main.css +++ b/application/src/main/resources/static/styles/main.css @@ -293,7 +293,15 @@ overflow: hidden; } -.pill-items li a { +.pill-items li button { + all: unset; + cursor: pointer; + width: 100%; + height: 100%; +} + +.pill-items li a, +.pill-items li button { gap: var(--spacing-sm); font-size: var(--text-sm); color: #1f2937; @@ -313,7 +321,7 @@ background: #f3f4f6; } -.pill-items li:hover a { +.pill-items li:hover { color: #111827; } diff --git a/application/src/main/resources/templates/gateway_fragments/common.html b/application/src/main/resources/templates/gateway_fragments/common.html index 296af122c..e05004591 100644 --- a/application/src/main/resources/templates/gateway_fragments/common.html +++ b/application/src/main/resources/templates/gateway_fragments/common.html @@ -113,13 +113,35 @@