diff --git a/application/src/main/java/run/halo/app/core/extension/reconciler/AuthProviderReconciler.java b/application/src/main/java/run/halo/app/core/extension/reconciler/AuthProviderReconciler.java new file mode 100644 index 000000000..615bb5f0a --- /dev/null +++ b/application/src/main/java/run/halo/app/core/extension/reconciler/AuthProviderReconciler.java @@ -0,0 +1,90 @@ +package run.halo.app.core.extension.reconciler; + +import java.util.HashSet; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.stereotype.Component; +import run.halo.app.core.extension.AuthProvider; +import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.MetadataUtil; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; +import run.halo.app.extension.controller.Reconciler; +import run.halo.app.security.AuthProviderService; + +/** + * Reconciler for {@link AuthProvider}. + * + * @author guqing + * @since 2.4.0 + */ +@Component +@RequiredArgsConstructor +public class AuthProviderReconciler implements Reconciler { + private static final String FINALIZER_NAME = "auth-provider-protection"; + private final ExtensionClient client; + private final AuthProviderService authProviderService; + + @Override + public Result reconcile(Request request) { + client.fetch(AuthProvider.class, request.name()) + .ifPresent(authProvider -> { + if (authProvider.getMetadata().getDeletionTimestamp() != null) { + removeFinalizer(request.name()); + return; + } + addFinalizerIfNecessary(authProvider); + handlePrivileged(authProvider); + }); + return Result.doNotRetry(); + } + + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new AuthProvider()) + .build(); + } + + private void handlePrivileged(AuthProvider authProvider) { + if (privileged(authProvider)) { + authProviderService.enable(authProvider.getMetadata().getName()).block(); + } + } + + private void addFinalizerIfNecessary(AuthProvider oldAuthProvider) { + Set finalizers = oldAuthProvider.getMetadata().getFinalizers(); + if (finalizers != null && finalizers.contains(FINALIZER_NAME)) { + return; + } + client.fetch(AuthProvider.class, oldAuthProvider.getMetadata().getName()) + .ifPresent(authProvider -> { + Set newFinalizers = authProvider.getMetadata().getFinalizers(); + if (newFinalizers == null) { + newFinalizers = new HashSet<>(); + authProvider.getMetadata().setFinalizers(newFinalizers); + } + newFinalizers.add(FINALIZER_NAME); + client.update(authProvider); + }); + } + + private void removeFinalizer(String authProviderName) { + client.fetch(AuthProvider.class, authProviderName) + .ifPresent(authProvider -> { + // Disable auth provider + authProviderService.disable(authProviderName).block(); + + if (authProvider.getMetadata().getFinalizers() != null) { + authProvider.getMetadata().getFinalizers().remove(FINALIZER_NAME); + } + client.update(authProvider); + }); + } + + private boolean privileged(AuthProvider authProvider) { + return BooleanUtils.TRUE.equals(MetadataUtil.nullSafeLabels(authProvider) + .get(AuthProvider.PRIVILEGED_LABEL)); + } +} diff --git a/application/src/main/java/run/halo/app/security/AuthProviderServiceImpl.java b/application/src/main/java/run/halo/app/security/AuthProviderServiceImpl.java index 42cd14f48..257dbedec 100644 --- a/application/src/main/java/run/halo/app/security/AuthProviderServiceImpl.java +++ b/application/src/main/java/run/halo/app/security/AuthProviderServiceImpl.java @@ -19,6 +19,7 @@ import reactor.core.publisher.Mono; import run.halo.app.core.extension.AuthProvider; import run.halo.app.core.extension.UserConnection; import run.halo.app.extension.ConfigMap; +import run.halo.app.extension.Metadata; import run.halo.app.extension.MetadataUtil; import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.infra.SystemSetting; @@ -45,7 +46,9 @@ public class AuthProviderServiceImpl implements AuthProviderService { @Override public Mono disable(String name) { + // privileged auth provider cannot be disabled return client.get(AuthProvider.class, name) + .filter(authProvider -> !privileged(authProvider)) .flatMap(authProvider -> updateAuthProviderEnabled(enabled -> enabled.remove(name)) .thenReturn(authProvider) ); @@ -104,28 +107,22 @@ public class AuthProviderServiceImpl implements AuthProviderService { private Mono updateAuthProviderEnabled(Consumer> consumer) { return client.fetch(ConfigMap.class, SystemSetting.SYSTEM_CONFIG) + .switchIfEmpty(Mono.defer(() -> { + ConfigMap configMap = new ConfigMap(); + configMap.setMetadata(new Metadata()); + configMap.getMetadata().setName(SystemSetting.SYSTEM_CONFIG); + configMap.setData(new HashMap<>()); + return client.create(configMap); + })) .flatMap(configMap -> { SystemSetting.AuthProvider authProvider = getAuthProvider(configMap); consumer.accept(authProvider.getEnabled()); - return fetchPrivilegedProviders() - .doOnNext(privileged -> { - authProvider.getEnabled().addAll(privileged); - }) - .then(Mono.defer(() -> { - final Map data = configMap.getData(); - data.put(SystemSetting.AuthProvider.GROUP, - JsonUtils.objectToJson(authProvider)); - return client.update(configMap); - })); - }); - } - private Mono> fetchPrivilegedProviders() { - return client.list(AuthProvider.class, - provider -> privileged(provider), - null) - .map(provider -> provider.getMetadata().getName()) - .collectList(); + final Map data = configMap.getData(); + data.put(SystemSetting.AuthProvider.GROUP, + JsonUtils.objectToJson(authProvider)); + return client.update(configMap); + }); } private ListedAuthProvider convertTo(AuthProvider authProvider) { @@ -150,7 +147,7 @@ public class AuthProviderServiceImpl implements AuthProviderService { return BooleanUtils.TRUE.equals(MetadataUtil.nullSafeLabels(authProvider) .get(AuthProvider.AUTH_BINDING_LABEL)); } - + private boolean privileged(AuthProvider authProvider) { return BooleanUtils.TRUE.equals(MetadataUtil.nullSafeLabels(authProvider) .get(AuthProvider.PRIVILEGED_LABEL)); diff --git a/application/src/test/java/run/halo/app/security/AuthProviderServiceImplTest.java b/application/src/test/java/run/halo/app/security/AuthProviderServiceImplTest.java index fe16bc663..6487ee375 100644 --- a/application/src/test/java/run/halo/app/security/AuthProviderServiceImplTest.java +++ b/application/src/test/java/run/halo/app/security/AuthProviderServiceImplTest.java @@ -70,7 +70,7 @@ class AuthProviderServiceImplTest { Set enabled = JsonUtils.jsonToObject(providerSettingStr, SystemSetting.AuthProvider.class) .getEnabled(); - assertThat(enabled).containsExactly("github", "local"); + assertThat(enabled).containsExactly("github"); // Verify the result verify(client).get(AuthProvider.class, "github"); verify(client).fetch(eq(ConfigMap.class), eq(SystemSetting.SYSTEM_CONFIG)); @@ -104,7 +104,7 @@ class AuthProviderServiceImplTest { Set enabled = JsonUtils.jsonToObject(providerSettingStr, SystemSetting.AuthProvider.class) .getEnabled(); - assertThat(enabled).containsExactly("local"); + assertThat(enabled).isEmpty(); // Verify the result verify(client).get(AuthProvider.class, "github"); verify(client).fetch(eq(ConfigMap.class), eq(SystemSetting.SYSTEM_CONFIG));