Merge pull request #480 from yaffir/main

fix(auth): hide placeholder OAuth providers
This commit is contained in:
XiaoSeS 2026-07-29 09:00:19 +08:00 committed by GitHub
commit 9f602f8184
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 52 additions and 10 deletions

View file

@ -12,6 +12,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties;
import org.springframework.stereotype.Service;
@ -43,6 +44,7 @@ public class AuthMethodCatalog {
public List<AuthProviderResponse> listOAuthProviders(String returnTo) {
String sanitizedReturnTo = OAuthLoginRedirectSupport.sanitizeReturnTo(returnTo);
return new ArrayList<>(oAuth2ClientProperties.getRegistration().entrySet().stream()
.filter(entry -> isValidOAuthProvider(entry.getValue()))
.sorted(Comparator.comparing(entry -> entry.getKey()))
.map(entry -> new AuthProviderResponse(
entry.getKey(),
@ -54,6 +56,17 @@ public class AuthMethodCatalog {
.toList());
}
/**
* Checks whether an OAuth provider has a non-empty, non-placeholder client ID.
*/
private boolean isValidOAuthProvider(OAuth2ClientProperties.Registration registration) {
String clientId = registration.getClientId();
if (clientId == null || clientId.isBlank()) {
return false;
}
return !clientId.toLowerCase(Locale.ROOT).contains("placeholder");
}
public List<AuthMethodResponse> listMethods(String returnTo) {
String sanitizedReturnTo = OAuthLoginRedirectSupport.sanitizeReturnTo(returnTo);
List<AuthMethodResponse> methods = new ArrayList<>();
@ -67,6 +80,7 @@ public class AuthMethodCatalog {
));
oAuth2ClientProperties.getRegistration().entrySet().stream()
.filter(entry -> isValidOAuthProvider(entry.getValue()))
.sorted(Comparator.comparing(entry -> entry.getKey()))
.forEach(entry -> methods.add(new AuthMethodResponse(
"oauth-" + entry.getKey(),

View file

@ -150,13 +150,9 @@ class AuthControllerTest {
mockMvc.perform(get("/api/v1/auth/providers"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data.length()").value(3))
.andExpect(jsonPath("$.data[*].id", hasItems("github", "gitee", "gitlab")))
.andExpect(jsonPath("$.data[*].authorizationUrl", hasItems(
"/oauth2/authorization/github",
"/oauth2/authorization/gitee",
"/oauth2/authorization/gitlab"
)))
.andExpect(jsonPath("$.data.length()").value(1))
.andExpect(jsonPath("$.data[*].id", hasItems("github")))
.andExpect(jsonPath("$.data[*].authorizationUrl", hasItems("/oauth2/authorization/github")))
.andExpect(jsonPath("$.timestamp").isNotEmpty())
.andExpect(jsonPath("$.requestId").isNotEmpty());
}
@ -167,8 +163,7 @@ class AuthControllerTest {
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data[*].authorizationUrl", hasItems(
"/oauth2/authorization/github?returnTo=%2Fdashboard%2Fpublish",
"/oauth2/authorization/gitee?returnTo=%2Fdashboard%2Fpublish"
"/oauth2/authorization/github?returnTo=%2Fdashboard%2Fpublish"
)));
}
@ -177,7 +172,8 @@ class AuthControllerTest {
mockMvc.perform(get("/api/v1/auth/methods").param("returnTo", "/dashboard/publish"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data[*].id", hasItems("local-password", "oauth-github", "oauth-gitee")))
.andExpect(jsonPath("$.data.length()").value(2))
.andExpect(jsonPath("$.data[*].id", hasItems("local-password", "oauth-github")))
.andExpect(jsonPath("$.data[?(@.id=='local-password')].methodType").value(hasItems("PASSWORD")))
.andExpect(jsonPath("$.data[?(@.id=='oauth-github')].actionUrl")
.value(hasItems("/oauth2/authorization/github?returnTo=%2Fdashboard%2Fpublish")));

View file

@ -16,6 +16,31 @@ import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2Clien
class AuthMethodCatalogTest {
@Test
void catalogsShouldHideEmptyAndPlaceholderOAuthProviders() {
OAuth2ClientProperties oauthProperties = new OAuth2ClientProperties();
oauthProperties.getRegistration().put("valid", registration("production-client", "Valid"));
oauthProperties.getRegistration().put("missing", registration(null, "Missing"));
oauthProperties.getRegistration().put("blank", registration(" ", "Blank"));
oauthProperties.getRegistration().put("placeholder", registration("PLACEHOLDER", "Placeholder"));
oauthProperties.getRegistration().put("local", registration("local-placeholder", "Local"));
AuthMethodCatalog catalog = new AuthMethodCatalog(
oauthProperties,
new DirectAuthProperties(),
new AuthSessionBootstrapProperties(),
List.of(),
List.of()
);
assertThat(catalog.listOAuthProviders(null))
.extracting(provider -> provider.id())
.containsExactly("valid");
assertThat(catalog.listMethods(null))
.extracting(method -> method.id())
.containsExactly("local-password", "oauth-valid");
}
@Test
void listMethodsShouldUseProviderDisplayNamesForCompatibleAuthMethods() {
OAuth2ClientProperties oauthProperties = new OAuth2ClientProperties();
@ -122,4 +147,11 @@ class AuthMethodCatalogTest {
"bootstrap-private-sso:private-sso"
);
}
private static OAuth2ClientProperties.Registration registration(String clientId, String clientName) {
OAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();
registration.setClientId(clientId);
registration.setClientName(clientName);
return registration;
}
}