io.streamthoughts.jikkou.kafka.change.user.UserChangeComputer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jikkou-provider-kafka Show documentation
Show all versions of jikkou-provider-kafka Show documentation
Integration between Apache Kafka and Jikkou
The newest version!
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) The original authors
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.streamthoughts.jikkou.kafka.change.user;
import io.streamthoughts.jikkou.common.utils.Classes;
import io.streamthoughts.jikkou.common.utils.SecurePasswordGenerator;
import io.streamthoughts.jikkou.common.utils.Strings;
import io.streamthoughts.jikkou.core.data.TypeConverter;
import io.streamthoughts.jikkou.core.models.change.GenericResourceChange;
import io.streamthoughts.jikkou.core.models.change.ResourceChange;
import io.streamthoughts.jikkou.core.models.change.ResourceChangeSpec;
import io.streamthoughts.jikkou.core.models.change.SpecificStateChange;
import io.streamthoughts.jikkou.core.models.change.StateChange;
import io.streamthoughts.jikkou.core.reconciler.Change;
import io.streamthoughts.jikkou.core.reconciler.Operation;
import io.streamthoughts.jikkou.core.reconciler.change.ChangeComputer;
import io.streamthoughts.jikkou.core.reconciler.change.ChangeComputerBuilder;
import io.streamthoughts.jikkou.core.reconciler.change.ResourceChangeComputer;
import io.streamthoughts.jikkou.core.reconciler.change.ResourceChangeFactory;
import io.streamthoughts.jikkou.kafka.KafkaLabelAndAnnotations;
import io.streamthoughts.jikkou.kafka.model.user.V1KafkaUser;
import io.streamthoughts.jikkou.kafka.model.user.V1KafkaUserAuthentication;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
/**
* ResourceChangeComputer for {@link V1KafkaUser}.
*/
public final class UserChangeComputer extends ResourceChangeComputer {
public static final String AUTHENTICATIONS_CHANGE_PREFIX = "authentications.";
public UserChangeComputer() {
super(ChangeComputerBuilder.KeyMapper.byName(), new UserChangeFactory(), false);
}
public static final class UserChangeFactory extends ResourceChangeFactory {
/**
* {@inheritDoc}
*/
@Override
public ResourceChange createChangeForCreate(final String key, final V1KafkaUser after) {
List authentications = after.getSpec().authentications();
// Compute change for 'authentications'
List> changes = authentications
.stream()
.map(it ->
StateChange.create(
getUserAuthenticationChangeName(it),
getUserAuthenticationWithDefaults(it)
)
)
.toList();
return GenericResourceChange
.builder(V1KafkaUser.class)
.withMetadata(after.getMetadata())
.withSpec(ResourceChangeSpec
.builder()
.withOperation(Operation.CREATE)
.withChanges(changes)
.build()
)
.build();
}
private static @NotNull String getUserAuthenticationChangeName(V1KafkaUserAuthentication it) {
return AUTHENTICATIONS_CHANGE_PREFIX + Classes.toKebabCase(it.getClass());
}
/**
* {@inheritDoc}
*/
@Override
public ResourceChange createChangeForUpdate(final String key, final V1KafkaUser before, final V1KafkaUser after) {
boolean forcePasswordRenewal = after.getMetadata()
.findAnnotationByKey(KafkaLabelAndAnnotations.JIKKOU_IO_KAFKA_FORCE_PASSWORD_RENEWAL)
.map(TypeConverter.Boolean()::convertValue)
.orElse(false);
final Map beforeAuthenticationsByKey = before.getSpec().authentications()
.stream()
.collect(Collectors.toMap(UserChangeFactory::getUserAuthenticationChangeName, Function.identity()));
final Map afterAuthenticationsByKey = after.getSpec().authentications()
.stream()
.collect(Collectors.toMap(UserChangeFactory::getUserAuthenticationChangeName, Function.identity()));
List stateChanges = ChangeComputer.computeChanges(
beforeAuthenticationsByKey,
afterAuthenticationsByKey,
true,
(o1, o2) -> !forcePasswordRenewal
);
stateChanges = stateChanges.stream()
.map(change -> {
Operation op = change.getOp();
if (op.equals(Operation.DELETE) || op.equals(Operation.NONE)) {
return change;
}
V1KafkaUserAuthentication authentication = (V1KafkaUserAuthentication) change.getAfter();
authentication = getUserAuthenticationWithDefaults(authentication);
return new SpecificStateChange<>(
change.getName(),
change.getOp(),
change.getBefore(),
authentication,
change.getDescription()
);
})
.toList();
return GenericResourceChange
.builder(V1KafkaUser.class)
.withMetadata(after.getMetadata())
.withSpec(ResourceChangeSpec
.builder()
.withOperation(Change.computeOperation(stateChanges))
.withChanges(stateChanges)
.build()
)
.build();
}
/**
* {@inheritDoc}
*/
@Override
public ResourceChange createChangeForDelete(final String key, final V1KafkaUser before) {
List authentications = before.getSpec().authentications();
List> changes = authentications
.stream()
.map(it -> StateChange.delete(getUserAuthenticationChangeName(it), it))
.toList();
return GenericResourceChange
.builder(V1KafkaUser.class)
.withMetadata(before.getMetadata())
.withSpec(ResourceChangeSpec
.builder()
.withOperation(Operation.DELETE)
.withChanges(changes)
.build()
)
.build();
}
private @NotNull V1KafkaUserAuthentication getUserAuthenticationWithDefaults(final V1KafkaUserAuthentication authentication) {
return switch (authentication) {
case V1KafkaUserAuthentication.ScramSha256 scramSha256 -> {
yield new V1KafkaUserAuthentication.ScramSha256(
Strings.isBlank(scramSha256.password()) ? SecurePasswordGenerator.getDefault().generate(32) : scramSha256.password(),
Optional.ofNullable(scramSha256.iterations()).orElse(V1KafkaUserAuthentication.DEFAULT_ITERATIONS),
scramSha256.salt()
);
}
case V1KafkaUserAuthentication.ScramSha512 scramSha512 -> {
yield new V1KafkaUserAuthentication.ScramSha512(
Strings.isBlank(scramSha512.password()) ? SecurePasswordGenerator.getDefault().generate(32) : scramSha512.password(),
Optional.ofNullable(scramSha512.iterations()).orElse(V1KafkaUserAuthentication.DEFAULT_ITERATIONS),
scramSha512.salt()
);
}
};
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy