test(auth): verify seed deletion and same-email grant isolation

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
XiaoSeS 2026-10-10 14:51:22 +08:00
parent 6842b40132
commit b4a037b0ff
2 changed files with 62 additions and 6 deletions

View file

@ -1,7 +1,11 @@
package com.iflytek.skillhub.repository;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iflytek.skillhub.bootstrap.InitialAuthSettingsInitializer;
import com.iflytek.skillhub.bootstrap.InitialAuthSettingsProperties;
import com.iflytek.skillhub.auth.repository.RoleRepository;
import com.iflytek.skillhub.auth.repository.IdentityBindingRepository;
import com.iflytek.skillhub.auth.repository.UserRoleBindingRepository;
@ -28,6 +32,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.jdbc.core.JdbcTemplate;
@ -43,8 +48,6 @@ import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import static org.mockito.Mockito.mock;
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ActiveProfiles("test")
@ -117,6 +120,57 @@ class SystemAuthSettingsPostgresTest {
assertThat(reloaded.getGrantedAt()).isNotNull();
}
@Test
@Transactional(propagation = Propagation.NOT_SUPPORTED)
void sameEmailLocalAccountStaysSeparateFromNewExternalGrant() {
String suffix = UUID.randomUUID().toString();
String email = suffix + "@example.com";
String localUserId = "local_" + suffix;
TransactionTemplate transactions = new TransactionTemplate(transactionManager);
Long ruleId = transactions.execute(status -> {
users.save(new UserAccount(localUserId, "local", email, null));
return rules.save(new ExternalRoleGrantRule(
"github", email, roles.findByCode("SUPER_ADMIN").orElseThrow(), "admin")).getId();
});
PlatformPrincipal external = bindingService().bindOrCreate(
new OAuthClaims("github", "external-" + suffix, email, true, "external", Map.of()),
UserStatus.ACTIVE);
assertThat(external.userId()).isNotEqualTo(localUserId);
assertThat(external.platformRoles()).contains("SUPER_ADMIN");
assertThat(users.findById(localUserId)).isPresent();
assertThat(userRoles.findByUserId(localUserId)).isEmpty();
assertThat(userRoles.findByUserId(external.userId())).hasSize(1);
assertThat(identities.findByProviderCodeAndSubject("github", "external-" + suffix)
.orElseThrow().getUserId()).isEqualTo(external.userId());
assertThat(rules.findById(ruleId).orElseThrow().getGrantedUserId()).isEqualTo(external.userId());
}
@Test
void deletedInitialRuleDoesNotReturnAfterInitializerRunsAgain() {
jdbc.execute("TRUNCATE TABLE user_account, external_role_grant_rule CASCADE");
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM user_account", Long.class)).isZero();
InitialAuthSettingsProperties properties = new InitialAuthSettingsProperties();
properties.setRoleGrantsJson("[{\"provider\":\"github\",\"email\":\"admin@example.com\",\"role\":\"SUPER_ADMIN\"}]");
InitialAuthSettingsInitializer initializer = new InitialAuthSettingsInitializer(
properties, settings, rules, roles, new ObjectMapper(), jdbc);
ApplicationArguments args = mock(ApplicationArguments.class);
initializer.run(args);
assertThat(rules.findAll()).hasSize(1);
Long ruleId = rules.findAll().getFirst().getId();
assertThat(settings.findBySettingKey("auth.initial-role-grants.initialized")).isPresent();
rules.deleteById(ruleId);
rules.flush();
entityManager.clear();
initializer.run(args);
assertThat(rules.findAll()).isEmpty();
assertThat(settings.findBySettingKey("auth.initial-role-grants.initialized")).isPresent();
}
@Test
@Transactional(propagation = Propagation.NOT_SUPPORTED)
void concurrentFirstLoginConsumesRuleOnceAndDoesNotRestoreManuallyRemovedRole() throws Exception {

View file

@ -92,10 +92,12 @@ class SystemAuthSettingsAppServiceTest {
@Test
void providerWithoutVerifiedEmailCannotCreateDeadGrantRule() {
assertThatThrownBy(() -> service.createRule(
new ExternalRoleGrantCreateRequest("feishu", "admin@example.com", "SUPER_ADMIN"),
"admin", new AuditRequestContext(null, null)))
.isInstanceOf(com.iflytek.skillhub.domain.shared.exception.DomainBadRequestException.class);
for (String provider : new String[] {"feishu", "dingtalk"}) {
assertThatThrownBy(() -> service.createRule(
new ExternalRoleGrantCreateRequest(provider, "admin@example.com", "SUPER_ADMIN"),
"admin", new AuditRequestContext(null, null)))
.isInstanceOf(com.iflytek.skillhub.domain.shared.exception.DomainBadRequestException.class);
}
verify(rules, never()).saveAndFlush(any());
}
}