use of io.strimzi.operator.user.model.acl.SimpleAclRule in project strimzi by strimzi.
the class KafkaUserOperatorTest method testReconcileNewTlsUser.
@Test
public void testReconcileNewTlsUser(VertxTestContext context) {
CrdOperator mockCrdOps = mock(CrdOperator.class);
SecretOperator mockSecretOps = mock(SecretOperator.class);
SimpleAclOperator aclOps = mock(SimpleAclOperator.class);
ScramCredentialsOperator scramOps = mock(ScramCredentialsOperator.class);
QuotasOperator quotasOps = mock(QuotasOperator.class);
KafkaUserOperator op = new KafkaUserOperator(vertx, mockCertManager, mockCrdOps, mockSecretOps, scramOps, quotasOps, aclOps, ResourceUtils.createUserOperatorConfig());
KafkaUser user = ResourceUtils.createKafkaUserTls();
Secret clientsCa = ResourceUtils.createClientsCaCertSecret();
Secret clientsCaKey = ResourceUtils.createClientsCaKeySecret();
ArgumentCaptor<String> secretNamespaceCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> secretNameCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Secret> secretCaptor = ArgumentCaptor.forClass(Secret.class);
when(mockSecretOps.reconcile(any(), secretNamespaceCaptor.capture(), secretNameCaptor.capture(), secretCaptor.capture())).thenReturn(Future.succeededFuture());
ArgumentCaptor<String> aclNameCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Set<SimpleAclRule>> aclRulesCaptor = ArgumentCaptor.forClass(Set.class);
when(aclOps.reconcile(any(), aclNameCaptor.capture(), aclRulesCaptor.capture())).thenReturn(Future.succeededFuture());
when(scramOps.reconcile(any(), any(), any())).thenReturn(Future.succeededFuture());
when(mockSecretOps.getAsync(anyString(), eq(clientsCa.getMetadata().getName()))).thenReturn(Future.succeededFuture(clientsCa));
when(mockSecretOps.getAsync(anyString(), eq(clientsCaKey.getMetadata().getName()))).thenReturn(Future.succeededFuture(clientsCaKey));
when(mockSecretOps.getAsync(anyString(), eq(user.getMetadata().getName()))).thenReturn(Future.succeededFuture(null));
when(mockCrdOps.get(eq(user.getMetadata().getNamespace()), eq(user.getMetadata().getName()))).thenReturn(user);
when(mockCrdOps.getAsync(anyString(), anyString())).thenReturn(Future.succeededFuture(user));
when(mockCrdOps.updateStatusAsync(any(), any(KafkaUser.class))).thenReturn(Future.succeededFuture());
when(quotasOps.reconcile(any(), any(), any())).thenReturn(Future.succeededFuture());
Checkpoint async = context.checkpoint();
op.reconcile(new Reconciliation("test-trigger", KafkaUser.RESOURCE_KIND, ResourceUtils.NAMESPACE, ResourceUtils.NAME)).onComplete(context.succeeding(v -> context.verify(() -> {
List<String> capturedNames = secretNameCaptor.getAllValues();
assertThat(capturedNames, hasSize(1));
assertThat(capturedNames.get(0), is(ResourceUtils.NAME));
List<String> capturedNamespaces = secretNamespaceCaptor.getAllValues();
assertThat(capturedNamespaces, hasSize(1));
assertThat(capturedNamespaces.get(0), is(ResourceUtils.NAMESPACE));
List<Secret> capturedSecrets = secretCaptor.getAllValues();
assertThat(capturedSecrets, hasSize(1));
Secret captured = capturedSecrets.get(0);
assertThat(captured.getMetadata().getName(), is(user.getMetadata().getName()));
assertThat(captured.getMetadata().getNamespace(), is(user.getMetadata().getNamespace()));
assertThat(captured.getMetadata().getLabels(), is(Labels.fromMap(user.getMetadata().getLabels()).withStrimziKind(KafkaUser.RESOURCE_KIND).withKubernetesName(KafkaUserModel.KAFKA_USER_OPERATOR_NAME).withKubernetesInstance(ResourceUtils.NAME).withKubernetesPartOf(ResourceUtils.NAME).withKubernetesManagedBy(KafkaUserModel.KAFKA_USER_OPERATOR_NAME).toMap()));
assertThat(new String(Base64.getDecoder().decode(captured.getData().get("ca.crt"))), is("clients-ca-crt"));
assertThat(new String(Base64.getDecoder().decode(captured.getData().get("user.crt"))), is("crt file"));
assertThat(new String(Base64.getDecoder().decode(captured.getData().get("user.key"))), is("key file"));
List<String> capturedAclNames = aclNameCaptor.getAllValues();
assertThat(capturedAclNames, hasSize(2));
assertThat(capturedAclNames.get(0), is(KafkaUserModel.getTlsUserName(ResourceUtils.NAME)));
assertThat(capturedAclNames.get(1), is(KafkaUserModel.getScramUserName(ResourceUtils.NAME)));
List<Set<SimpleAclRule>> capturedAcls = aclRulesCaptor.getAllValues();
assertThat(capturedAcls, hasSize(2));
Set<SimpleAclRule> aclRules = capturedAcls.get(0);
assertThat(aclRules, hasSize(ResourceUtils.createExpectedSimpleAclRules(user).size()));
assertThat(aclRules, is(ResourceUtils.createExpectedSimpleAclRules(user)));
assertThat(capturedAcls.get(1), is(nullValue()));
async.flag();
})));
}
use of io.strimzi.operator.user.model.acl.SimpleAclRule in project strimzi by strimzi.
the class KafkaUserOperatorTest method testUpdateUserNoAuthenticationAndNoAuthorization.
/**
* Tests what happens when the TlsClientAuthentication and SimpleAuthorization are disabled for the user
* (delete entries from the spec of the KafkaUser resource)
*/
@Test
public void testUpdateUserNoAuthenticationAndNoAuthorization(VertxTestContext context) {
CrdOperator mockCrdOps = mock(CrdOperator.class);
SecretOperator mockSecretOps = mock(SecretOperator.class);
SimpleAclOperator aclOps = mock(SimpleAclOperator.class);
ScramCredentialsOperator scramOps = mock(ScramCredentialsOperator.class);
QuotasOperator quotasOps = mock(QuotasOperator.class);
ArgumentCaptor<String> secretNamespaceCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> secretNameCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Secret> secretCaptor = ArgumentCaptor.forClass(Secret.class);
when(mockSecretOps.reconcile(any(), secretNamespaceCaptor.capture(), secretNameCaptor.capture(), secretCaptor.capture())).thenReturn(Future.succeededFuture());
when(mockSecretOps.getAsync(anyString(), eq(ResourceUtils.NAME))).thenReturn(Future.succeededFuture(null));
when(scramOps.reconcile(any(), any(), any())).thenReturn(Future.succeededFuture());
ArgumentCaptor<String> aclNameCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Set<SimpleAclRule>> aclRulesCaptor = ArgumentCaptor.forClass(Set.class);
when(aclOps.reconcile(any(), aclNameCaptor.capture(), aclRulesCaptor.capture())).thenReturn(Future.succeededFuture());
KafkaUser user = ResourceUtils.createKafkaUserTls();
user.getSpec().setAuthorization(null);
user.getSpec().setAuthentication(null);
when(mockCrdOps.getAsync(anyString(), anyString())).thenReturn(Future.succeededFuture(user));
when(mockCrdOps.updateStatusAsync(any(), any(KafkaUser.class))).thenReturn(Future.succeededFuture());
KafkaUserOperator op = new KafkaUserOperator(vertx, mockCertManager, mockCrdOps, mockSecretOps, scramOps, quotasOps, aclOps, ResourceUtils.createUserOperatorConfig());
when(quotasOps.reconcile(any(), any(), any())).thenReturn(Future.succeededFuture());
Checkpoint async = context.checkpoint();
op.createOrUpdate(new Reconciliation("test-trigger", KafkaUser.RESOURCE_KIND, ResourceUtils.NAMESPACE, ResourceUtils.NAME), user).onComplete(context.succeeding(v -> context.verify(() -> {
List<String> capturedNames = secretNameCaptor.getAllValues();
assertThat(capturedNames, hasSize(1));
assertThat(capturedNames.get(0), is(ResourceUtils.NAME));
List<String> capturedNamespaces = secretNamespaceCaptor.getAllValues();
assertThat(capturedNamespaces, hasSize(1));
assertThat(capturedNamespaces.get(0), is(ResourceUtils.NAMESPACE));
List<Secret> capturedSecrets = secretCaptor.getAllValues();
assertThat(capturedSecrets, hasSize(1));
Secret captured = capturedSecrets.get(0);
assertThat(captured, is(nullValue()));
List<String> capturedAclNames = aclNameCaptor.getAllValues();
assertThat(capturedAclNames, hasSize(2));
assertThat(capturedAclNames.get(0), is(KafkaUserModel.getTlsUserName(ResourceUtils.NAME)));
assertThat(capturedAclNames.get(1), is(KafkaUserModel.getScramUserName(ResourceUtils.NAME)));
List<Set<SimpleAclRule>> capturedAcls = aclRulesCaptor.getAllValues();
assertThat(capturedAcls, hasSize(2));
assertThat(capturedAcls.get(0), is(nullValue()));
assertThat(capturedAcls.get(1), is(nullValue()));
async.flag();
})));
}
use of io.strimzi.operator.user.model.acl.SimpleAclRule in project strimzi by strimzi.
the class KafkaUserOperator method reconcileCredentialsQuotasAndAcls.
/**
* Reconciles the credentials, quotas and ACLs
*
* @param reconciliation Unique identification for the reconciliation
* @param user Model describing the KafkaUser
* @param userStatus Status subresource of the KafkaUser custom resource
*
* @return Future describing the result
*/
private CompositeFuture reconcileCredentialsQuotasAndAcls(Reconciliation reconciliation, KafkaUserModel user, KafkaUserStatus userStatus) {
Set<SimpleAclRule> tlsAcls = null;
Set<SimpleAclRule> scramOrNoneAcls = null;
KafkaUserQuotas tlsQuotas = null;
KafkaUserQuotas scramOrNoneQuotas = null;
if (user.isTlsUser() || user.isTlsExternalUser()) {
tlsAcls = user.getSimpleAclRules();
tlsQuotas = user.getQuotas();
} else if (user.isScramUser() || user.isNoneUser()) {
scramOrNoneAcls = user.getSimpleAclRules();
scramOrNoneQuotas = user.getQuotas();
}
// Reconcile the user SCRAM-SHA-512 credentials
Future<ReconcileResult<String>> scramCredentialsFuture = scramCredentialsOperator.reconcile(reconciliation, user.getName(), user.getScramSha512Password());
// Quotas need to reconciled for both regular and TLS username. It will be (possibly) set for one user and deleted for the other
Future<ReconcileResult<KafkaUserQuotas>> tlsQuotasFuture = quotasOperator.reconcile(reconciliation, KafkaUserModel.getTlsUserName(reconciliation.name()), tlsQuotas);
Future<ReconcileResult<KafkaUserQuotas>> quotasFuture = quotasOperator.reconcile(reconciliation, KafkaUserModel.getScramUserName(reconciliation.name()), scramOrNoneQuotas);
// Reconcile the user secret generated by the user operator with the credentials
Future<ReconcileResult<Secret>> userSecretFuture = reconcileUserSecret(reconciliation, user, userStatus);
// ACLs need to reconciled for both regular and TLS username. It will be (possibly) set for one user and deleted for the other
Future<ReconcileResult<Set<SimpleAclRule>>> aclsTlsUserFuture;
Future<ReconcileResult<Set<SimpleAclRule>>> aclsScramUserFuture;
if (config.isAclsAdminApiSupported()) {
aclsTlsUserFuture = aclOperations.reconcile(reconciliation, KafkaUserModel.getTlsUserName(reconciliation.name()), tlsAcls);
aclsScramUserFuture = aclOperations.reconcile(reconciliation, KafkaUserModel.getScramUserName(reconciliation.name()), scramOrNoneAcls);
} else {
aclsTlsUserFuture = Future.succeededFuture(ReconcileResult.noop(null));
aclsScramUserFuture = Future.succeededFuture(ReconcileResult.noop(null));
}
return CompositeFuture.join(scramCredentialsFuture, tlsQuotasFuture, quotasFuture, aclsTlsUserFuture, aclsScramUserFuture, userSecretFuture);
}
use of io.strimzi.operator.user.model.acl.SimpleAclRule in project strimzi by strimzi.
the class KafkaUserModel method setSimpleAclRules.
/**
* Sets the list of ACL rules for Simple authorization.
*
* @param rules List of ACL rules which should be applied to this user.
*/
public void setSimpleAclRules(List<AclRule> rules) {
Set<SimpleAclRule> simpleAclRules = new HashSet<>();
for (AclRule rule : rules) {
simpleAclRules.add(SimpleAclRule.fromCrd(rule));
}
this.simpleAclRules = simpleAclRules;
}
use of io.strimzi.operator.user.model.acl.SimpleAclRule in project strimzi by strimzi.
the class SimpleAclOperatorTest method testReconcileInternalUpdateCreatesNewAclsAndDeletesOldAcls.
@Test
public void testReconcileInternalUpdateCreatesNewAclsAndDeletesOldAcls(VertxTestContext context) {
Admin mockAdminClient = mock(AdminClient.class);
SimpleAclOperator aclOp = new SimpleAclOperator(vertx, mockAdminClient);
ResourcePattern resource1 = new ResourcePattern(ResourceType.TOPIC, "my-topic", PatternType.LITERAL);
ResourcePattern resource2 = new ResourcePattern(ResourceType.TOPIC, "my-topic2", PatternType.LITERAL);
KafkaPrincipal foo = new KafkaPrincipal(KafkaPrincipal.USER_TYPE, "CN=foo");
AclBinding readAclBinding = new AclBinding(resource1, new AccessControlEntry(foo.toString(), "*", org.apache.kafka.common.acl.AclOperation.READ, AclPermissionType.ALLOW));
AclBinding writeAclBinding = new AclBinding(resource2, new AccessControlEntry(foo.toString(), "*", org.apache.kafka.common.acl.AclOperation.WRITE, AclPermissionType.ALLOW));
SimpleAclRuleResource resource = new SimpleAclRuleResource("my-topic2", SimpleAclRuleResourceType.TOPIC, AclResourcePatternType.LITERAL);
SimpleAclRule rule1 = new SimpleAclRule(AclRuleType.ALLOW, resource, "*", AclOperation.WRITE);
ArgumentCaptor<Collection<AclBinding>> aclBindingsCaptor = ArgumentCaptor.forClass(Collection.class);
ArgumentCaptor<Collection<AclBindingFilter>> aclBindingFiltersCaptor = ArgumentCaptor.forClass(Collection.class);
assertDoesNotThrow(() -> {
mockDescribeAcls(mockAdminClient, null, Collections.singleton(readAclBinding));
mockCreateAcls(mockAdminClient, aclBindingsCaptor);
mockDeleteAcls(mockAdminClient, Collections.singleton(readAclBinding), aclBindingFiltersCaptor);
});
Checkpoint async = context.checkpoint();
aclOp.reconcile(Reconciliation.DUMMY_RECONCILIATION, "CN=foo", new LinkedHashSet(asList(rule1))).onComplete(context.succeeding(rr -> context.verify(() -> {
// Create Write rule for resource 2
Collection<AclBinding> capturedAclBindings = aclBindingsCaptor.getValue();
assertThat(capturedAclBindings, hasSize(1));
assertThat(capturedAclBindings, hasItem(writeAclBinding));
Set<ResourcePattern> capturedResourcePatterns = capturedAclBindings.stream().map(AclBinding::pattern).collect(Collectors.toSet());
assertThat(capturedResourcePatterns, hasSize(1));
assertThat(capturedResourcePatterns, hasItem(resource2));
// Delete read rule for resource 1
Collection<AclBindingFilter> capturedAclBindingFilters = aclBindingFiltersCaptor.getValue();
assertThat(capturedAclBindingFilters, hasSize(1));
assertThat(capturedAclBindingFilters, hasItem(readAclBinding.toFilter()));
Set<ResourcePatternFilter> capturedResourcePatternFilters = capturedAclBindingFilters.stream().map(AclBindingFilter::patternFilter).collect(Collectors.toSet());
assertThat(capturedResourcePatternFilters, hasSize(1));
assertThat(capturedResourcePatternFilters, hasItem(resource1.toFilter()));
async.flag();
})));
}
Aggregations