fix(auth): backfill bootstrap admin role binding

This commit is contained in:
dongmucat 2026-04-14 14:44:08 +08:00
parent 9644d50fbb
commit e35e99ae59
2 changed files with 46 additions and 12 deletions

View file

@ -63,8 +63,13 @@ public class BootstrapAdminInitializer implements ApplicationRunner {
log.info("Bootstrap admin is disabled");
return;
}
if (localCredentialRepository.existsByUsernameIgnoreCase(bootstrapAdminProperties.getUsername())) {
log.info("Bootstrap admin already exists, skipping");
LocalCredential existingCredential = localCredentialRepository
.findByUsernameIgnoreCase(bootstrapAdminProperties.getUsername())
.orElse(null);
if (existingCredential != null
&& !bootstrapAdminProperties.getUserId().equals(existingCredential.getUserId())) {
log.info("Bootstrap admin username '{}' is already bound to another user, skipping",
bootstrapAdminProperties.getUsername());
return;
}
@ -83,13 +88,15 @@ public class BootstrapAdminInitializer implements ApplicationRunner {
admin = userAccountRepository.save(admin);
// 2. Create local credential (username/password)
localCredentialRepository.save(
new LocalCredential(
admin.getId(),
bootstrapAdminProperties.getUsername(),
passwordEncoder.encode(bootstrapAdminProperties.getPassword())
)
);
if (existingCredential == null) {
localCredentialRepository.save(
new LocalCredential(
admin.getId(),
bootstrapAdminProperties.getUsername(),
passwordEncoder.encode(bootstrapAdminProperties.getPassword())
)
);
}
// 3. Assign SUPER_ADMIN role
Role superAdmin = roleRepository.findByCode("SUPER_ADMIN")

View file

@ -73,7 +73,6 @@ class BootstrapAdminInitializerTest {
setField(superAdminRole, "id", 1L);
setField(superAdminRole, "code", "SUPER_ADMIN");
when(localCredentialRepository.existsByUsernameIgnoreCase("admin")).thenReturn(false);
when(userAccountRepository.findById("docker-admin")).thenReturn(Optional.empty());
when(userAccountRepository.save(any(UserAccount.class))).thenAnswer(invocation -> invocation.getArgument(0));
when(passwordEncoder.encode("ChangeMe!2026")).thenReturn("encoded-password");
@ -111,7 +110,8 @@ class BootstrapAdminInitializerTest {
@Test
void shouldSkipWhenBootstrapAdminCredentialAlreadyExists() {
bootstrapAdminProperties.setEnabled(true);
when(localCredentialRepository.existsByUsernameIgnoreCase("admin")).thenReturn(true);
LocalCredential conflictingCredential = new LocalCredential("someone-else", "admin", "encoded-password");
when(localCredentialRepository.findByUsernameIgnoreCase("admin")).thenReturn(Optional.of(conflictingCredential));
initializer.run(new DefaultApplicationArguments(new String[0]));
@ -121,13 +121,40 @@ class BootstrapAdminInitializerTest {
verify(namespaceMemberRepository, never()).save(any(NamespaceMember.class));
}
@Test
void shouldStillEnsureRoleAndMembershipWhenBootstrapCredentialExistsForConfiguredUser() throws Exception {
bootstrapAdminProperties.setEnabled(true);
Namespace global = new Namespace("global", "Global", "system");
setField(global, "id", 1L);
Role superAdminRole = new Role();
setField(superAdminRole, "id", 1L);
setField(superAdminRole, "code", "SUPER_ADMIN");
LocalCredential existingCredential = new LocalCredential("docker-admin", "admin", "encoded-password");
when(localCredentialRepository.findByUsernameIgnoreCase("admin")).thenReturn(Optional.of(existingCredential));
when(userAccountRepository.findById("docker-admin")).thenReturn(Optional.empty());
when(userAccountRepository.save(any(UserAccount.class))).thenAnswer(invocation -> invocation.getArgument(0));
when(roleRepository.findByCode("SUPER_ADMIN")).thenReturn(Optional.of(superAdminRole));
when(userRoleBindingRepository.findByUserId("docker-admin")).thenReturn(List.of());
when(namespaceRepository.findBySlug("global")).thenReturn(Optional.of(global));
when(namespaceMemberRepository.findByNamespaceIdAndUserId(1L, "docker-admin")).thenReturn(Optional.empty());
initializer.run(new DefaultApplicationArguments(new String[0]));
verify(localCredentialRepository, never()).save(any(LocalCredential.class));
verify(userRoleBindingRepository).save(any(UserRoleBinding.class));
verify(namespaceMemberRepository).save(any(NamespaceMember.class));
}
@Test
void shouldSkipWhenBootstrapAdminIsDisabled() {
bootstrapAdminProperties.setEnabled(false);
initializer.run(new DefaultApplicationArguments(new String[0]));
verify(localCredentialRepository, never()).existsByUsernameIgnoreCase(any());
verify(localCredentialRepository, never()).findByUsernameIgnoreCase(any());
verify(userAccountRepository, never()).save(any(UserAccount.class));
}