mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-27 11:14:59 +00:00
fix(auth): report unconfigured legacy identity providers
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
parent
c9a3933677
commit
bbffb3281c
5 changed files with 125 additions and 2 deletions
|
|
@ -0,0 +1,32 @@
|
|||
package com.iflytek.skillhub.auth.identity;
|
||||
|
||||
import com.iflytek.skillhub.auth.repository.IdentityBindingRepository;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
class IdentityBindingPreflightService {
|
||||
|
||||
private final IdentityBindingRepository bindingRepository;
|
||||
|
||||
IdentityBindingPreflightService(
|
||||
IdentityBindingRepository bindingRepository) {
|
||||
this.bindingRepository = bindingRepository;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<String> findProvidersWithoutTrustedDescriptor(
|
||||
List<ProviderDescriptor> descriptors) {
|
||||
Set<String> trustedProviderCodes = descriptors.stream()
|
||||
.map(ProviderDescriptor::providerCode)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
return bindingRepository.findDistinctProviderCodes().stream()
|
||||
.filter(providerCode ->
|
||||
!trustedProviderCodes.contains(providerCode))
|
||||
.sorted()
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
|
@ -25,14 +25,17 @@ class ReconciledIdentityProviderCatalog
|
|||
|
||||
private final TrustedProviderDescriptorSource descriptorSource;
|
||||
private final ProviderAuthorityLockService authorityLockService;
|
||||
private final IdentityBindingPreflightService bindingPreflightService;
|
||||
private final AtomicReference<List<ProviderDescriptor>>
|
||||
configuredProviders = new AtomicReference<>(List.of());
|
||||
|
||||
ReconciledIdentityProviderCatalog(
|
||||
TrustedProviderDescriptorSource descriptorSource,
|
||||
ProviderAuthorityLockService authorityLockService) {
|
||||
ProviderAuthorityLockService authorityLockService,
|
||||
IdentityBindingPreflightService bindingPreflightService) {
|
||||
this.descriptorSource = descriptorSource;
|
||||
this.authorityLockService = authorityLockService;
|
||||
this.bindingPreflightService = bindingPreflightService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -53,6 +56,7 @@ class ReconciledIdentityProviderCatalog
|
|||
return;
|
||||
}
|
||||
configuredProviders.set(descriptors);
|
||||
reportUnconfiguredBindingProviders(descriptors);
|
||||
for (ProviderDescriptor descriptor : descriptors) {
|
||||
try {
|
||||
authorityLockService.requirePinnedAuthority(descriptor);
|
||||
|
|
@ -70,6 +74,23 @@ class ReconciledIdentityProviderCatalog
|
|||
}
|
||||
}
|
||||
|
||||
private void reportUnconfiguredBindingProviders(
|
||||
List<ProviderDescriptor> descriptors) {
|
||||
try {
|
||||
List<String> unconfiguredProviders = bindingPreflightService
|
||||
.findProvidersWithoutTrustedDescriptor(descriptors);
|
||||
if (!unconfiguredProviders.isEmpty()) {
|
||||
log.error(
|
||||
"Identity binding preflight found provider codes without a trusted descriptor: {}",
|
||||
unconfiguredProviders);
|
||||
}
|
||||
} catch (RuntimeException exception) {
|
||||
log.error(
|
||||
"Identity binding provider preflight failed",
|
||||
exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IdentityProviderLoginMethod> listReadyProviders() {
|
||||
return configuredProviders.get().stream()
|
||||
|
|
|
|||
|
|
@ -18,6 +18,13 @@ import org.springframework.stereotype.Repository;
|
|||
public interface IdentityBindingRepository extends JpaRepository<IdentityBinding, Long> {
|
||||
Optional<IdentityBinding> findByProviderCodeAndSubject(String providerCode, String subject);
|
||||
|
||||
@Query("""
|
||||
select distinct binding.providerCode
|
||||
from IdentityBinding binding
|
||||
order by binding.providerCode
|
||||
""")
|
||||
List<String> findDistinctProviderCodes();
|
||||
|
||||
@Lock(LockModeType.PESSIMISTIC_WRITE)
|
||||
@Query("""
|
||||
select binding
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
package com.iflytek.skillhub.auth.identity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.iflytek.skillhub.auth.repository.IdentityBindingRepository;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class IdentityBindingPreflightServiceTest {
|
||||
|
||||
@Test
|
||||
void reportsHistoricalProviderCodesWithoutTrustedDescriptors() {
|
||||
IdentityBindingRepository bindingRepository =
|
||||
mock(IdentityBindingRepository.class);
|
||||
when(bindingRepository.findDistinctProviderCodes())
|
||||
.thenReturn(List.of(
|
||||
"removed-provider",
|
||||
"github",
|
||||
"ambiguous-provider"));
|
||||
IdentityBindingPreflightService service =
|
||||
new IdentityBindingPreflightService(
|
||||
bindingRepository);
|
||||
|
||||
assertThat(service.findProvidersWithoutTrustedDescriptor(
|
||||
List.of(descriptor("github"))))
|
||||
.containsExactly(
|
||||
"ambiguous-provider",
|
||||
"removed-provider");
|
||||
}
|
||||
|
||||
private static ProviderDescriptor descriptor(String providerCode) {
|
||||
return new ProviderDescriptor(
|
||||
providerCode,
|
||||
"oidc",
|
||||
"https://" + providerCode + ".example",
|
||||
providerCode,
|
||||
"oidc_sub",
|
||||
"oidc_sub",
|
||||
Map.of(
|
||||
"oidc_sub",
|
||||
SubjectCanonicalizer.EXACT),
|
||||
List.of("name"),
|
||||
List.of("email"),
|
||||
List.of("picture"),
|
||||
EmailAssurance.VERIFIED);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
package com.iflytek.skillhub.auth.identity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -17,15 +19,22 @@ class ReconciledIdentityProviderCatalogTest {
|
|||
|
||||
private TrustedProviderDescriptorSource descriptorSource;
|
||||
private ProviderAuthorityLockService authorityLockService;
|
||||
private IdentityBindingPreflightService bindingPreflightService;
|
||||
private ReconciledIdentityProviderCatalog catalog;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
descriptorSource = mock(TrustedProviderDescriptorSource.class);
|
||||
authorityLockService = mock(ProviderAuthorityLockService.class);
|
||||
bindingPreflightService = mock(
|
||||
IdentityBindingPreflightService.class);
|
||||
when(bindingPreflightService
|
||||
.findProvidersWithoutTrustedDescriptor(anyList()))
|
||||
.thenReturn(List.of());
|
||||
catalog = new ReconciledIdentityProviderCatalog(
|
||||
descriptorSource,
|
||||
authorityLockService);
|
||||
authorityLockService,
|
||||
bindingPreflightService);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -37,6 +46,10 @@ class ReconciledIdentityProviderCatalogTest {
|
|||
|
||||
catalog.reconcile();
|
||||
|
||||
verify(bindingPreflightService)
|
||||
.findProvidersWithoutTrustedDescriptor(
|
||||
List.of(github));
|
||||
|
||||
assertThat(catalog.listReadyProviders())
|
||||
.containsExactly(new IdentityProviderLoginMethod(
|
||||
"github",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue