From e35e99ae598ca331317a52b2ef3fae2d46cdea65 Mon Sep 17 00:00:00 2001 From: dongmucat <1127093059@qq.com> Date: Tue, 14 Apr 2026 14:44:08 +0800 Subject: [PATCH] fix(auth): backfill bootstrap admin role binding --- .../bootstrap/BootstrapAdminInitializer.java | 25 +++++++++----- .../BootstrapAdminInitializerTest.java | 33 +++++++++++++++++-- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/server/skillhub-app/src/main/java/com/iflytek/skillhub/bootstrap/BootstrapAdminInitializer.java b/server/skillhub-app/src/main/java/com/iflytek/skillhub/bootstrap/BootstrapAdminInitializer.java index f8e7fab5..b440ab8c 100644 --- a/server/skillhub-app/src/main/java/com/iflytek/skillhub/bootstrap/BootstrapAdminInitializer.java +++ b/server/skillhub-app/src/main/java/com/iflytek/skillhub/bootstrap/BootstrapAdminInitializer.java @@ -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") diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/bootstrap/BootstrapAdminInitializerTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/bootstrap/BootstrapAdminInitializerTest.java index a151d2a8..276e9925 100644 --- a/server/skillhub-app/src/test/java/com/iflytek/skillhub/bootstrap/BootstrapAdminInitializerTest.java +++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/bootstrap/BootstrapAdminInitializerTest.java @@ -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)); }