This is an automated email from the ASF dual-hosted git repository. bbende pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nifi.git
commit d99983bdc70c8a91ea9b389fc576e6b84c76a27e Author: Bence Simon <[email protected]> AuthorDate: Fri Jun 5 17:47:09 2020 +0200 NIFI-7442 Add CLI commands to the registry in order to support automatic registry setup --- nifi-docs/src/main/asciidoc/toolkit-guide.adoc | 6 + .../impl/client/ExtendedNiFiRegistryClient.java | 61 +++++ .../client/JerseyExtendedNiFiRegistryClient.java | 300 +++++++++++++++++++++ .../cli/impl/client/NiFiRegistryClientFactory.java | 37 ++- .../cli/impl/client/registry/PoliciesClient.java | 64 +++++ .../cli/impl/client/registry/TenantsClient.java | 122 +++++++++ .../client/registry/impl/JerseyPoliciesClient.java | 82 ++++++ .../client/registry/impl/JerseyTenantsClient.java | 146 ++++++++++ .../toolkit/cli/impl/command/CommandOption.java | 2 + .../command/registry/NiFiRegistryCommandGroup.java | 12 + .../impl/command/registry/tenant/CreatePolicy.java | 97 +++++++ .../impl/command/registry/tenant/CreateUser.java | 69 +++++ .../command/registry/tenant/CreateUserGroup.java | 83 ++++++ .../impl/command/registry/tenant/TenantHelper.java | 93 +++++++ .../impl/command/registry/tenant/UpdatePolicy.java | 112 ++++++++ .../impl/command/registry/tenant/UpdateUser.java | 79 ++++++ .../command/registry/tenant/UpdateUserGroup.java | 91 +++++++ 17 files changed, 1449 insertions(+), 7 deletions(-) diff --git a/nifi-docs/src/main/asciidoc/toolkit-guide.adoc b/nifi-docs/src/main/asciidoc/toolkit-guide.adoc index 76b7333..44df219 100644 --- a/nifi-docs/src/main/asciidoc/toolkit-guide.adoc +++ b/nifi-docs/src/main/asciidoc/toolkit-guide.adoc @@ -106,6 +106,12 @@ The following are available commands: registry import-flow-version registry sync-flow-versions registry transfer-flow-version + registry create-user + registry update-user + registry create-user-group + registry update-user-group + registry create-policy + registry update-policy session keys session show session get diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/ExtendedNiFiRegistryClient.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/ExtendedNiFiRegistryClient.java new file mode 100644 index 0000000..cecce2e --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/ExtendedNiFiRegistryClient.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.client; + +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.PoliciesClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; + +/** + * Extends NiFiRegistry client with additional exposed service. + * + * Note: in longer term the functionality of this should be merged into the NiFiRegistryClient. + */ +public interface ExtendedNiFiRegistryClient extends NiFiRegistryClient { + + /** + * Returns client for interacting with tenants. + * + * @return the client for interacting with tenants + */ + TenantsClient getTenantsClient(); + + /** + * Returns client for interacting with tenants. + * + * @param proxiedEntity The given proxied entities. + * + * @return the client for interacting with tenants on behalf of the given proxied entities. + */ + TenantsClient getTenantsClient(String ... proxiedEntity); + + /** + * Returns client for interacting with access policies. + * + * @return the client for interacting with access policies + */ + PoliciesClient getPoliciesClient(); + + /** + * Returns client for interacting with access policies. + * + * @param proxiedEntity The given proxied entities. + * + * @return the client for interacting with access policies on behalf of the given proxied entities. + */ + PoliciesClient getPoliciesClient(String ... proxiedEntity); +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/JerseyExtendedNiFiRegistryClient.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/JerseyExtendedNiFiRegistryClient.java new file mode 100644 index 0000000..edf0300 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/JerseyExtendedNiFiRegistryClient.java @@ -0,0 +1,300 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.client; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.bucket.BucketItem; +import org.apache.nifi.registry.client.BucketClient; +import org.apache.nifi.registry.client.BundleClient; +import org.apache.nifi.registry.client.BundleVersionClient; +import org.apache.nifi.registry.client.ExtensionClient; +import org.apache.nifi.registry.client.ExtensionRepoClient; +import org.apache.nifi.registry.client.FlowClient; +import org.apache.nifi.registry.client.FlowSnapshotClient; +import org.apache.nifi.registry.client.ItemsClient; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryClientConfig; +import org.apache.nifi.registry.client.UserClient; +import org.apache.nifi.registry.client.impl.BucketItemDeserializer; +import org.apache.nifi.registry.security.util.ProxiedEntitiesUtils; +import org.apache.nifi.toolkit.cli.impl.client.registry.PoliciesClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.impl.JerseyPoliciesClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.impl.JerseyTenantsClient; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.RequestEntityProcessing; +import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider; +import org.glassfish.jersey.media.multipart.MultiPartFeature; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Decorator around (Jersey based) NiFiRegistryClient in order to extend it's capabilities without + * actually changing it. + */ +public class JerseyExtendedNiFiRegistryClient implements ExtendedNiFiRegistryClient { + // Copied from JerseyNiFiRegistryClient! + static final String NIFI_REGISTRY_CONTEXT = "nifi-registry-api"; + static final int DEFAULT_CONNECT_TIMEOUT = 10000; + static final int DEFAULT_READ_TIMEOUT = 10000; + + private final NiFiRegistryClient payload; + private final Client client; + private final WebTarget baseTarget; + private final TenantsClient tenantsClient; + private final PoliciesClient policiesClient; + + public JerseyExtendedNiFiRegistryClient(final NiFiRegistryClient payload, final NiFiRegistryClient.Builder builder) { + this.payload = payload; + + // Copied from JerseyNiFiRegistryClient! + final NiFiRegistryClientConfig registryClientConfig = builder.getConfig(); + if (registryClientConfig == null) { + throw new IllegalArgumentException("NiFiRegistryClientConfig cannot be null"); + } + + String baseUrl = registryClientConfig.getBaseUrl(); + if (StringUtils.isBlank(baseUrl)) { + throw new IllegalArgumentException("Base URL cannot be blank"); + } + + if (baseUrl.endsWith("/")) { + baseUrl = baseUrl.substring(0, baseUrl.length() - 1); + } + + if (!baseUrl.endsWith(NIFI_REGISTRY_CONTEXT)) { + baseUrl = baseUrl + "/" + NIFI_REGISTRY_CONTEXT; + } + + try { + new URI(baseUrl); + } catch (final Exception e) { + throw new IllegalArgumentException("Invalid base URL: " + e.getMessage(), e); + } + + final SSLContext sslContext = registryClientConfig.getSslContext(); + final HostnameVerifier hostnameVerifier = registryClientConfig.getHostnameVerifier(); + + final ClientBuilder clientBuilder = ClientBuilder.newBuilder(); + if (sslContext != null) { + clientBuilder.sslContext(sslContext); + } + if (hostnameVerifier != null) { + clientBuilder.hostnameVerifier(hostnameVerifier); + } + + final int connectTimeout = registryClientConfig.getConnectTimeout() == null ? DEFAULT_CONNECT_TIMEOUT : registryClientConfig.getConnectTimeout(); + final int readTimeout = registryClientConfig.getReadTimeout() == null ? DEFAULT_READ_TIMEOUT : registryClientConfig.getReadTimeout(); + + final ClientConfig clientConfig = new ClientConfig(); + clientConfig.property(ClientProperties.CONNECT_TIMEOUT, connectTimeout); + clientConfig.property(ClientProperties.READ_TIMEOUT, readTimeout); + clientConfig.property(ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.CHUNKED); + clientConfig.register(jacksonJaxbJsonProvider()); + clientBuilder.withConfig(clientConfig); + + this.client = clientBuilder + .register(MultiPartFeature.class) + .build(); + + this.baseTarget = client.target(baseUrl); + + this.tenantsClient = new JerseyTenantsClient(baseTarget); + this.policiesClient = new JerseyPoliciesClient(baseTarget); + } + + @Override + public TenantsClient getTenantsClient() { + return tenantsClient; + } + + @Override + public TenantsClient getTenantsClient(final String... proxiedEntity) { + final Map<String,String> headers = getHeaders(proxiedEntity); + return new JerseyTenantsClient(baseTarget, headers); + } + + @Override + public PoliciesClient getPoliciesClient() { + return policiesClient; + } + + @Override + public PoliciesClient getPoliciesClient(final String... proxiedEntity) { + final Map<String,String> headers = getHeaders(proxiedEntity); + return new JerseyPoliciesClient(baseTarget, headers); + } + + @Override + public BucketClient getBucketClient() { + return payload.getBucketClient(); + } + + @Override + public BucketClient getBucketClient(final String... proxiedEntity) { + return payload.getBucketClient(proxiedEntity); + } + + @Override + public FlowClient getFlowClient() { + return payload.getFlowClient(); + } + + @Override + public FlowClient getFlowClient(final String... proxiedEntity) { + return payload.getFlowClient(proxiedEntity); + } + + @Override + public FlowSnapshotClient getFlowSnapshotClient() { + return payload.getFlowSnapshotClient(); + } + + @Override + public FlowSnapshotClient getFlowSnapshotClient(final String... proxiedEntity) { + return payload.getFlowSnapshotClient(proxiedEntity); + } + + @Override + public ItemsClient getItemsClient() { + return payload.getItemsClient(); + } + + @Override + public ItemsClient getItemsClient(final String... proxiedEntity) { + return payload.getItemsClient(proxiedEntity); + } + + @Override + public UserClient getUserClient() { + return payload.getUserClient(); + } + + @Override + public UserClient getUserClient(final String... proxiedEntity) { + return payload.getUserClient(proxiedEntity); + } + + @Override + public BundleClient getBundleClient() { + return payload.getBundleClient(); + } + + @Override + public BundleClient getBundleClient(final String... proxiedEntity) { + return payload.getBundleClient(proxiedEntity); + } + + @Override + public BundleVersionClient getBundleVersionClient() { + return payload.getBundleVersionClient(); + } + + @Override + public BundleVersionClient getBundleVersionClient(final String... proxiedEntity) { + return payload.getBundleVersionClient(proxiedEntity); + } + + @Override + public ExtensionRepoClient getExtensionRepoClient() { + return payload.getExtensionRepoClient(); + } + + @Override + public ExtensionRepoClient getExtensionRepoClient(final String... proxiedEntity) { + return payload.getExtensionRepoClient(proxiedEntity); + } + + @Override + public ExtensionClient getExtensionClient() { + return payload.getExtensionClient(); + } + + @Override + public ExtensionClient getExtensionClient(final String... proxiedEntity) { + return payload.getExtensionClient(proxiedEntity); + } + + @Override + public void close() throws IOException { + payload.close(); + + if (this.client != null) { + try { + this.client.close(); + } catch (Exception e) { + + } + } + } + + // Copied from JerseyNiFiRegistryClient! + private Map<String,String> getHeaders(String[] proxiedEntities) { + final String proxiedEntitiesValue = getProxiedEntitesValue(proxiedEntities); + + final Map<String,String> headers = new HashMap<>(); + if (proxiedEntitiesValue != null) { + headers.put(ProxiedEntitiesUtils.PROXY_ENTITIES_CHAIN, proxiedEntitiesValue); + } + return headers; + } + + // Copied from JerseyNiFiRegistryClient! + private String getProxiedEntitesValue(String[] proxiedEntities) { + if (proxiedEntities == null) { + return null; + } + + final List<String> proxiedEntityChain = Arrays.stream(proxiedEntities).map(ProxiedEntitiesUtils::formatProxyDn).collect(Collectors.toList()); + return StringUtils.join(proxiedEntityChain, ""); + } + + // Copied from JerseyNiFiRegistryClient! + private static JacksonJaxbJsonProvider jacksonJaxbJsonProvider() { + JacksonJaxbJsonProvider jacksonJaxbJsonProvider = new JacksonJaxbJsonProvider(); + + ObjectMapper mapper = new ObjectMapper(); + mapper.setPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL)); + mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(mapper.getTypeFactory())); + // Ignore unknown properties so that deployed client remain compatible with future versions of NiFi Registry that add new fields + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + SimpleModule module = new SimpleModule(); + module.addDeserializer(BucketItem[].class, new BucketItemDeserializer()); + mapper.registerModule(module); + + jacksonJaxbJsonProvider.setMapper(mapper); + return jacksonJaxbJsonProvider; + } +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/NiFiRegistryClientFactory.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/NiFiRegistryClientFactory.java index bdc2535..cbdfd36 100644 --- a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/NiFiRegistryClientFactory.java +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/NiFiRegistryClientFactory.java @@ -32,6 +32,8 @@ import org.apache.nifi.registry.client.UserClient; import org.apache.nifi.registry.client.impl.JerseyNiFiRegistryClient; import org.apache.nifi.registry.security.util.KeystoreType; import org.apache.nifi.toolkit.cli.api.ClientFactory; +import org.apache.nifi.toolkit.cli.impl.client.registry.PoliciesClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; import org.apache.nifi.toolkit.cli.impl.command.CommandOption; import java.io.IOException; @@ -97,13 +99,15 @@ public class NiFiRegistryClientFactory implements ClientFactory<NiFiRegistryClie } } - final NiFiRegistryClient client = new JerseyNiFiRegistryClient.Builder().config(clientConfigBuilder.build()).build(); + final NiFiRegistryClientConfig builder = clientConfigBuilder.build(); + final NiFiRegistryClient client = new JerseyNiFiRegistryClient.Builder().config(builder).build(); + final ExtendedNiFiRegistryClient extendedClient = new JerseyExtendedNiFiRegistryClient(client, new JerseyNiFiRegistryClient.Builder().config(builder)); // if a proxied entity was specified then return a wrapped client, otherwise return the regular client if (!StringUtils.isBlank(proxiedEntity)) { - return new ProxiedNiFiRegistryClient(client, proxiedEntity); + return new ProxiedNiFiRegistryClient(extendedClient, proxiedEntity); } else { - return client; + return extendedClient; } } @@ -111,12 +115,12 @@ public class NiFiRegistryClientFactory implements ClientFactory<NiFiRegistryClie * Wraps a NiFiRegistryClient and ensures that all methods to obtain a more specific client will * call the proxied-entity variation so that callers don't have to care if proxying is taking place. */ - private static class ProxiedNiFiRegistryClient implements NiFiRegistryClient { + private static class ProxiedNiFiRegistryClient implements ExtendedNiFiRegistryClient { - private final NiFiRegistryClient client; + private final ExtendedNiFiRegistryClient client; private final String proxiedEntity; - public ProxiedNiFiRegistryClient(final NiFiRegistryClient client, final String proxiedEntity) { + public ProxiedNiFiRegistryClient(final ExtendedNiFiRegistryClient client, final String proxiedEntity) { this.client = client; this.proxiedEntity = proxiedEntity; } @@ -212,9 +216,28 @@ public class NiFiRegistryClientFactory implements ClientFactory<NiFiRegistryClie } @Override + public TenantsClient getTenantsClient() { + return getTenantsClient(proxiedEntity); + } + + @Override + public TenantsClient getTenantsClient(String... proxiedEntity) { + return client.getTenantsClient(proxiedEntity); + } + + @Override + public PoliciesClient getPoliciesClient() { + return getPoliciesClient(proxiedEntity); + } + + @Override + public PoliciesClient getPoliciesClient(String... proxiedEntity) { + return client.getPoliciesClient(proxiedEntity); + } + + @Override public void close() throws IOException { client.close(); } } - } diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/PoliciesClient.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/PoliciesClient.java new file mode 100644 index 0000000..be481a8 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/PoliciesClient.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.client.registry; + +import org.apache.nifi.registry.authorization.AccessPolicy; +import org.apache.nifi.registry.client.NiFiRegistryException; + +import java.io.IOException; + +/** + * Provides API for the services might be called from registry related to access policies. + */ +public interface PoliciesClient { + + /** + * Returns with a given access policy. + * + * @param id The identifier of the access policy. + * + * @return The access policy. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry. + */ + AccessPolicy getPolicy(String id) throws NiFiRegistryException, IOException; + + /** + * Creates a new access policy within the registry. + * + * @param policy The attributes of the access policy. Note: identifier will be ignored and generated. + * + * @return The access policy after store, containing it's identifier. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry. + */ + AccessPolicy createPolicy(AccessPolicy policy) throws NiFiRegistryException, IOException; + + /** + * Updates an existing access policy. + * + * @param policy The updated attributes of the access policy. + * + * @return The stored access policy. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry. + */ + AccessPolicy updatePolicy(AccessPolicy policy) throws NiFiRegistryException, IOException; +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/TenantsClient.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/TenantsClient.java new file mode 100644 index 0000000..5ad56f8 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/TenantsClient.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.client.registry; + +import org.apache.nifi.registry.authorization.User; +import org.apache.nifi.registry.authorization.UserGroup; +import org.apache.nifi.registry.client.NiFiRegistryException; + +import java.io.IOException; +import java.util.List; + +/** + * Provides API for the services might be called from registry related to tenants. + */ +public interface TenantsClient { + + /** + * Returns all the users. + * + * @return The list of users in the registry. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry. + */ + List<User> getUsers() throws NiFiRegistryException, IOException; + + /** + * Returns a given user based on id. + * + * @param id Identifier of the user. + * + * @return The user. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry. + */ + User getUser(String id) throws NiFiRegistryException, IOException; + + /** + * Creates a new user in the registry. + * + * @param user The new user. Note: identifier will be ignored and generated. + * + * @return The user after store, containing it's identifier. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry. + */ + User createUser(User user) throws NiFiRegistryException, IOException; + + /** + * Updates an existing user. + * + * @param user The user with the new attributes. + * + * @return The user after store. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry. + */ + User updateUser(User user) throws NiFiRegistryException, IOException; + + /** + * Returns all the user groups. + * + * @return The list of user groups. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry. + */ + List<UserGroup> getUserGroups() throws NiFiRegistryException, IOException; + + /** + * Returns the given user group based on identifier. + * + * @param id The user group's identifier. + * + * @return The user group. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry. + */ + UserGroup getUserGroup(String id) throws NiFiRegistryException, IOException; + + /** + * Creates a new user group in the registry. + * + * @param group The user group to store. Note: identifier will be ignored and generated. + * + * @return The stored user group, containing id. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry.@throws IOException + */ + UserGroup createUserGroup(UserGroup group) throws NiFiRegistryException, IOException; + + /** + * Updates an existing user group. + * + * @param group The user group with the new attributes. + * + * @return The user group after store. + * + * @throws NiFiRegistryException Thrown in case os unsuccessful execution. + * @throws IOException Thrown when there is an issue with communicating the registry. + */ + UserGroup updateUserGroup(UserGroup group) throws NiFiRegistryException, IOException; +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/impl/JerseyPoliciesClient.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/impl/JerseyPoliciesClient.java new file mode 100644 index 0000000..ee7a806 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/impl/JerseyPoliciesClient.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.client.registry.impl; + +import org.apache.nifi.registry.authorization.AccessPolicy; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.registry.client.impl.AbstractJerseyClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.PoliciesClient; +import org.apache.nifi.util.StringUtils; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +public class JerseyPoliciesClient extends AbstractJerseyClient implements PoliciesClient { + private final WebTarget policiesTarget; + + public JerseyPoliciesClient(final WebTarget baseTarget, final Map<String, String> headers) { + super(headers); + this.policiesTarget = baseTarget.path("/policies"); + } + + public JerseyPoliciesClient(final WebTarget baseTarget) { + this(baseTarget, Collections.emptyMap()); + } + + @Override + public AccessPolicy getPolicy(final String id) throws NiFiRegistryException, IOException { + if (StringUtils.isBlank(id)) { + throw new IllegalArgumentException("Access policy id cannot be null"); + } + + return executeAction("Error retrieving access policy", () -> { + final WebTarget target = policiesTarget.path("{id}").resolveTemplate("id", id); + return getRequestBuilder(target).get(AccessPolicy.class); + }); + } + + @Override + public AccessPolicy createPolicy(final AccessPolicy policy) throws NiFiRegistryException, IOException { + if (policy == null) { + throw new IllegalArgumentException("Access policy cannot be null"); + } + + return executeAction("Error creating access policy", () -> { + return getRequestBuilder(policiesTarget).post( + Entity.entity(policy, MediaType.APPLICATION_JSON_TYPE), AccessPolicy.class + ); + }); + } + + @Override + public AccessPolicy updatePolicy(final AccessPolicy policy) throws NiFiRegistryException, IOException { + if (policy == null) { + throw new IllegalArgumentException("Access policy cannot be null"); + } + + return executeAction("Error creating access policy", () -> { + final WebTarget target = policiesTarget.path("{id}").resolveTemplate("id", policy.getIdentifier()); + return getRequestBuilder(target).put( + Entity.entity(policy, MediaType.APPLICATION_JSON_TYPE), AccessPolicy.class + ); + }); + } +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/impl/JerseyTenantsClient.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/impl/JerseyTenantsClient.java new file mode 100644 index 0000000..a135702 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/registry/impl/JerseyTenantsClient.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.client.registry.impl; + +import org.apache.nifi.registry.authorization.User; +import org.apache.nifi.registry.authorization.UserGroup; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.registry.client.impl.AbstractJerseyClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; +import org.apache.nifi.util.StringUtils; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class JerseyTenantsClient extends AbstractJerseyClient implements TenantsClient { + private final WebTarget tenantsTarget; + + public JerseyTenantsClient(final WebTarget baseTarget, final Map<String, String> headers) { + super(headers); + this.tenantsTarget = baseTarget.path("/tenants"); + } + + public JerseyTenantsClient(final WebTarget baseTarget) { + this(baseTarget, Collections.emptyMap()); + } + + @Override + public List<User> getUsers() throws NiFiRegistryException, IOException { + return executeAction("Error retrieving users", () -> { + final WebTarget target = tenantsTarget.path("users"); + return Arrays.asList(getRequestBuilder(target).get(User[].class)); + }); + } + + @Override + public User getUser(final String id) throws NiFiRegistryException, IOException { + if (StringUtils.isBlank(id)) { + throw new IllegalArgumentException("User id cannot be null"); + } + + return executeAction("Error retrieving user", () -> { + final WebTarget target = tenantsTarget.path("users/{id}").resolveTemplate("id", id); + return getRequestBuilder(target).get(User.class); + }); + } + + @Override + public User createUser(final User user) throws NiFiRegistryException, IOException { + if (user == null) { + throw new IllegalArgumentException("User cannot be null"); + } + + return executeAction("Error creating user", () -> { + final WebTarget target = tenantsTarget.path("users"); + + return getRequestBuilder(target).post( + Entity.entity(user, MediaType.APPLICATION_JSON_TYPE), User.class + ); + }); + } + + @Override + public User updateUser(final User user) throws NiFiRegistryException, IOException { + if (user == null) { + throw new IllegalArgumentException("User cannot be null"); + } + + return executeAction("Error updating user", () -> { + final WebTarget target = tenantsTarget.path("users/{id}").resolveTemplate("id", user.getIdentifier()); + + return getRequestBuilder(target).put( + Entity.entity(user, MediaType.APPLICATION_JSON_TYPE), User.class + ); + }); + } + + @Override + public List<UserGroup> getUserGroups() throws NiFiRegistryException, IOException { + return executeAction("Error retrieving users", () -> { + final WebTarget target = tenantsTarget.path("user-groups"); + return Arrays.asList(getRequestBuilder(target).get(UserGroup[].class)); + }); + } + + @Override + public UserGroup getUserGroup(final String id) throws NiFiRegistryException, IOException { + if (StringUtils.isBlank(id)) { + throw new IllegalArgumentException("User group id cannot be null"); + } + + return executeAction("Error retrieving user group", () -> { + final WebTarget target = tenantsTarget.path("user-groups/{id}").resolveTemplate("id", id); + return getRequestBuilder(target).get(UserGroup.class); + }); + } + + @Override + public UserGroup createUserGroup(final UserGroup group) throws NiFiRegistryException, IOException { + if (group == null) { + throw new IllegalArgumentException("User group cannot be null"); + } + + return executeAction("Error creating group", () -> { + final WebTarget target = tenantsTarget.path("user-groups"); + + return getRequestBuilder(target).post( + Entity.entity(group, MediaType.APPLICATION_JSON_TYPE), UserGroup.class + ); + }); + } + + @Override + public UserGroup updateUserGroup(final UserGroup group) throws NiFiRegistryException, IOException { + if (group == null) { + throw new IllegalArgumentException("User group cannot be null"); + } + + return executeAction("Error creating group", () -> { + final WebTarget target = tenantsTarget.path("user-groups/{id}").resolveTemplate("id", group.getIdentifier()); + + return getRequestBuilder(target).put( + Entity.entity(group, MediaType.APPLICATION_JSON_TYPE), UserGroup.class + ); + }); + } +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/CommandOption.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/CommandOption.java index 623d555..eb5b28d 100644 --- a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/CommandOption.java +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/CommandOption.java @@ -93,6 +93,7 @@ public enum CommandOption { // NiFi - User/Group USER_NAME("un", "userName", "The name of a user", true), + USER_ID("ui", "userIdentifier", "The identifier of a user", true), UG_ID("ugid", "userGroupId", "The id of a user group", true), UG_NAME("ugn", "userGroupName", "The name of a user group", true), USER_NAME_LIST("unl", "userNameList", "The comma-separated user name list", true), @@ -101,6 +102,7 @@ public enum CommandOption { GROUP_ID_LIST("gil", "groupIdList", "The comma-separated user group id list", true), // NiFi - Access Policies + POLICY_ID("pi", "accessPolicyIdentifier", "The identifier of an access policy", true), POLICY_RESOURCE("por", "accessPolicyResource", "The resource of an access policy", true), POLICY_ACTION("poa", "accessPolicyAction", "The action of an access policy (read or write)", true), OVERWRITE_POLICY("owp", "overwritePolicy", "Overwrite the user list and group list for the access policy", false), diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/NiFiRegistryCommandGroup.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/NiFiRegistryCommandGroup.java index 3e14906..8b9c93f 100644 --- a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/NiFiRegistryCommandGroup.java +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/NiFiRegistryCommandGroup.java @@ -39,6 +39,12 @@ import org.apache.nifi.toolkit.cli.impl.command.registry.flow.ListFlowVersions; import org.apache.nifi.toolkit.cli.impl.command.registry.flow.ListFlows; import org.apache.nifi.toolkit.cli.impl.command.registry.flow.SyncFlowVersions; import org.apache.nifi.toolkit.cli.impl.command.registry.flow.TransferFlowVersion; +import org.apache.nifi.toolkit.cli.impl.command.registry.tenant.CreatePolicy; +import org.apache.nifi.toolkit.cli.impl.command.registry.tenant.CreateUser; +import org.apache.nifi.toolkit.cli.impl.command.registry.tenant.CreateUserGroup; +import org.apache.nifi.toolkit.cli.impl.command.registry.tenant.UpdatePolicy; +import org.apache.nifi.toolkit.cli.impl.command.registry.tenant.UpdateUser; +import org.apache.nifi.toolkit.cli.impl.command.registry.tenant.UpdateUserGroup; import org.apache.nifi.toolkit.cli.impl.command.registry.user.CurrentUser; import java.util.ArrayList; @@ -80,6 +86,12 @@ public class NiFiRegistryCommandGroup extends AbstractCommandGroup { commandList.add(new GetBundleChecksum()); commandList.add(new ListExtensionTags()); commandList.add(new ListExtensions()); + commandList.add(new CreateUser()); + commandList.add(new UpdateUser()); + commandList.add(new CreateUserGroup()); + commandList.add(new UpdateUserGroup()); + commandList.add(new CreatePolicy()); + commandList.add(new UpdatePolicy()); return new ArrayList<>(commandList); } } diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/CreatePolicy.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/CreatePolicy.java new file mode 100644 index 0000000..5ab45aa --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/CreatePolicy.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.command.registry.tenant; + +import org.apache.commons.cli.ParseException; +import org.apache.nifi.registry.authorization.AccessPolicy; +import org.apache.nifi.registry.authorization.Tenant; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.toolkit.cli.api.Context; +import org.apache.nifi.toolkit.cli.impl.client.ExtendedNiFiRegistryClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.PoliciesClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; +import org.apache.nifi.toolkit.cli.impl.command.CommandOption; +import org.apache.nifi.toolkit.cli.impl.command.registry.AbstractNiFiRegistryCommand; +import org.apache.nifi.toolkit.cli.impl.result.StringResult; + +import java.io.IOException; +import java.util.Properties; +import java.util.Set; + +/** + * Command for creating an access policy. + */ +public class CreatePolicy extends AbstractNiFiRegistryCommand<StringResult> { + + public CreatePolicy() { + super("create-policy", StringResult.class); + } + + @Override + public String getDescription() { + return "Creates new access policy"; + } + + @Override + protected void doInitialize(final Context context) { + // Required + addOption(CommandOption.POLICY_RESOURCE.createOption()); + addOption(CommandOption.POLICY_ACTION.createOption()); + + // Optional + addOption(CommandOption.USER_NAME_LIST.createOption()); + addOption(CommandOption.USER_ID_LIST.createOption()); + addOption(CommandOption.GROUP_NAME_LIST.createOption()); + addOption(CommandOption.GROUP_ID_LIST.createOption()); + } + + @Override + public StringResult doExecute(final NiFiRegistryClient client, final Properties properties) + throws IOException, NiFiRegistryException, ParseException { + + if (!(client instanceof ExtendedNiFiRegistryClient)) { + throw new IllegalArgumentException("This command needs extended registry client!"); + } + + final ExtendedNiFiRegistryClient extendedClient = (ExtendedNiFiRegistryClient) client; + final PoliciesClient policiesClient = extendedClient.getPoliciesClient(); + final TenantsClient tenantsClient = extendedClient.getTenantsClient(); + + final String resource = getRequiredArg(properties, CommandOption.POLICY_RESOURCE); + final String action = getRequiredArg(properties, CommandOption.POLICY_ACTION); + + final Set<Tenant> users = TenantHelper.getExistingUsers( + tenantsClient, + getArg(properties, CommandOption.USER_NAME_LIST), + getArg(properties, CommandOption.USER_ID_LIST)); + + final Set<Tenant> userGroups = TenantHelper.getExistingGroups( + tenantsClient, + getArg(properties, CommandOption.GROUP_NAME_LIST), + getArg(properties, CommandOption.GROUP_ID_LIST)); + + final AccessPolicy policy = new AccessPolicy(); + policy.setAction(action); + policy.setResource(resource); + policy.setUsers(users); + policy.setUserGroups(userGroups); + + final AccessPolicy createdPolicy = policiesClient.createPolicy(policy); + return new StringResult(createdPolicy.getIdentifier(), getContext().isInteractive()); + } +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/CreateUser.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/CreateUser.java new file mode 100644 index 0000000..baf61f0 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/CreateUser.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.command.registry.tenant; + +import org.apache.commons.cli.ParseException; +import org.apache.nifi.registry.authorization.User; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.toolkit.cli.api.Context; +import org.apache.nifi.toolkit.cli.impl.client.ExtendedNiFiRegistryClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; +import org.apache.nifi.toolkit.cli.impl.command.CommandOption; +import org.apache.nifi.toolkit.cli.impl.command.registry.AbstractNiFiRegistryCommand; +import org.apache.nifi.toolkit.cli.impl.result.StringResult; + +import java.io.IOException; +import java.util.Properties; + +/** + * Command for creating a user. + */ +public class CreateUser extends AbstractNiFiRegistryCommand<StringResult> { + + public CreateUser() { + super("create-user", StringResult.class); + } + + @Override + public String getDescription() { + return "Creates new user."; + } + + @Override + protected void doInitialize(final Context context) { + addOption(CommandOption.USER_NAME.createOption()); + } + + @Override + public StringResult doExecute(final NiFiRegistryClient client, final Properties properties) + throws IOException, NiFiRegistryException, ParseException { + + if (!(client instanceof ExtendedNiFiRegistryClient)) { + throw new IllegalArgumentException("This command needs extended registry client!"); + } + + final ExtendedNiFiRegistryClient extendedClient = (ExtendedNiFiRegistryClient) client; + final TenantsClient tenantsClient = extendedClient.getTenantsClient(); + + final String userName = getRequiredArg(properties, CommandOption.USER_NAME); + final User user = new User(null, userName); + final User createdUser = tenantsClient.createUser(user); + + return new StringResult(createdUser.getIdentifier(), getContext().isInteractive()); + } +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/CreateUserGroup.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/CreateUserGroup.java new file mode 100644 index 0000000..fced142 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/CreateUserGroup.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.command.registry.tenant; + +import org.apache.commons.cli.ParseException; +import org.apache.nifi.registry.authorization.Tenant; +import org.apache.nifi.registry.authorization.UserGroup; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.toolkit.cli.api.Context; +import org.apache.nifi.toolkit.cli.impl.client.ExtendedNiFiRegistryClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; +import org.apache.nifi.toolkit.cli.impl.command.CommandOption; +import org.apache.nifi.toolkit.cli.impl.command.registry.AbstractNiFiRegistryCommand; +import org.apache.nifi.toolkit.cli.impl.result.StringResult; + +import java.io.IOException; +import java.util.Properties; +import java.util.Set; + +/** + * Command for creating a user group. + */ +public class CreateUserGroup extends AbstractNiFiRegistryCommand<StringResult> { + + public CreateUserGroup() { + super("create-user-group", StringResult.class); + } + + @Override + public String getDescription() { + return "Creates user group"; + } + + @Override + protected void doInitialize(final Context context) { + // Required + addOption(CommandOption.UG_NAME.createOption()); + + // Optional + addOption(CommandOption.USER_NAME_LIST.createOption()); + addOption(CommandOption.USER_ID_LIST.createOption()); + } + + @Override + public StringResult doExecute(final NiFiRegistryClient client, final Properties properties) + throws IOException, NiFiRegistryException, ParseException { + + if (!(client instanceof ExtendedNiFiRegistryClient)) { + throw new IllegalArgumentException("This command needs extended registry client!"); + } + + final ExtendedNiFiRegistryClient extendedClient = (ExtendedNiFiRegistryClient) client; + final TenantsClient tenantsClient = extendedClient.getTenantsClient(); + + final String groupName = getRequiredArg(properties, CommandOption.UG_NAME); + + final Set<Tenant> tenants = TenantHelper.getExistingUsers( + tenantsClient, + getArg(properties, CommandOption.USER_NAME_LIST), + getArg(properties, CommandOption.USER_ID_LIST)); + + final UserGroup group = new UserGroup(null, groupName); + group.setUsers(tenants); + + final UserGroup createdGroup = tenantsClient.createUserGroup(group); + return new StringResult(createdGroup.getIdentifier(), getContext().isInteractive()); + } +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/TenantHelper.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/TenantHelper.java new file mode 100644 index 0000000..64415f9 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/TenantHelper.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.command.registry.tenant; + +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.authorization.Tenant; +import org.apache.nifi.registry.authorization.User; +import org.apache.nifi.registry.authorization.UserGroup; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +final class TenantHelper { + private static final String SEPARATOR = ","; + + private TenantHelper() { + // no op + } + + public static Set<Tenant> getExistingUsers(final TenantsClient client, final String userNamesArgument, final String userIdsArgument) + throws IOException, NiFiRegistryException { + final Set<Tenant> result = new HashSet<>(); + + final Set<String> userNames = StringUtils.isNotBlank(userNamesArgument) + ? new HashSet<>(Arrays.asList(userNamesArgument.split(SEPARATOR))) + : Collections.emptySet(); + + final Set<String> userIds = StringUtils.isNotBlank(userIdsArgument) + ? new HashSet<>(Arrays.asList(userIdsArgument.split(SEPARATOR))) + : Collections.emptySet(); + + if (userNames.isEmpty() && userIds.isEmpty()) { + return result; + } + + final List<User> users = client.getUsers(); + + for (final User user : users) { + if (userNames.contains(user.getIdentity()) || userIds.contains(user.getIdentifier())) { + result.add(user); + } + } + + return result; + } + + public static Set<Tenant> getExistingGroups(final TenantsClient client, final String userGroupNamesArgument, final String userGroupIdsArgument) + throws IOException, NiFiRegistryException { + final Set<Tenant> result = new HashSet<>(); + + final Set<String> userGroupNames = StringUtils.isNotBlank(userGroupNamesArgument) + ? new HashSet<>(Arrays.asList(userGroupNamesArgument.split(SEPARATOR))) + : Collections.emptySet(); + + final Set<String> userGroupIds = StringUtils.isNotBlank(userGroupIdsArgument) + ? new HashSet<>(Arrays.asList(userGroupIdsArgument.split(SEPARATOR))) + : Collections.emptySet(); + + if (userGroupNames.isEmpty() && userGroupIds.isEmpty()) { + return result; + } + + final List<UserGroup> usersGroups = client.getUserGroups(); + + for (final UserGroup userGroup : usersGroups) { + if (userGroupNames.contains(userGroup.getIdentity()) || userGroupIds.contains(userGroup.getIdentifier())) { + result.add(userGroup); + } + } + + return result; + } +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/UpdatePolicy.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/UpdatePolicy.java new file mode 100644 index 0000000..f30f3cf --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/UpdatePolicy.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.command.registry.tenant; + +import org.apache.commons.cli.ParseException; +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.authorization.AccessPolicy; +import org.apache.nifi.registry.authorization.Tenant; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.toolkit.cli.api.Context; +import org.apache.nifi.toolkit.cli.impl.client.ExtendedNiFiRegistryClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.PoliciesClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; +import org.apache.nifi.toolkit.cli.impl.command.CommandOption; +import org.apache.nifi.toolkit.cli.impl.command.registry.AbstractNiFiRegistryCommand; +import org.apache.nifi.toolkit.cli.impl.result.StringResult; + +import java.io.IOException; +import java.util.Properties; +import java.util.Set; + +/** + * Command for update an existing policy. + */ +public class UpdatePolicy extends AbstractNiFiRegistryCommand<StringResult> { + + public UpdatePolicy() { + super("update-policy", StringResult.class); + } + + @Override + public String getDescription() { + return "Updates an existing access policy."; + } + + @Override + protected void doInitialize(final Context context) { + // Required + addOption(CommandOption.POLICY_ID.createOption()); + + // Optional + addOption(CommandOption.POLICY_RESOURCE.createOption()); + addOption(CommandOption.POLICY_ACTION.createOption()); + addOption(CommandOption.USER_NAME_LIST.createOption()); + addOption(CommandOption.USER_ID_LIST.createOption()); + addOption(CommandOption.GROUP_NAME_LIST.createOption()); + addOption(CommandOption.GROUP_ID_LIST.createOption()); + } + + @Override + public StringResult doExecute(final NiFiRegistryClient client, final Properties properties) + throws IOException, NiFiRegistryException, ParseException { + + if (!(client instanceof ExtendedNiFiRegistryClient)) { + throw new IllegalArgumentException("This command needs extended registry client!"); + } + + final ExtendedNiFiRegistryClient extendedClient = (ExtendedNiFiRegistryClient) client; + final PoliciesClient policiesClient = extendedClient.getPoliciesClient(); + final TenantsClient tenantsClient = extendedClient.getTenantsClient(); + + final String policyId = getRequiredArg(properties, CommandOption.POLICY_ID); + final String resource = getArg(properties, CommandOption.POLICY_RESOURCE); + final String action = getArg(properties, CommandOption.POLICY_ACTION); + + final AccessPolicy existingPolicy = policiesClient.getPolicy(policyId); + + if (StringUtils.isNotBlank(resource)) { + existingPolicy.setResource(resource); + } + + if (StringUtils.isNotBlank(action)) { + existingPolicy.setAction(action); + } + + final Set<Tenant> users = TenantHelper.getExistingUsers( + tenantsClient, + getArg(properties, CommandOption.USER_NAME_LIST), + getArg(properties, CommandOption.USER_ID_LIST)); + + if (StringUtils.isNotBlank(getArg(properties, CommandOption.USER_NAME_LIST)) || StringUtils.isNotBlank(getArg(properties, CommandOption.USER_ID_LIST))) { + existingPolicy.setUsers(users); + } + + final Set<Tenant> userGroups = TenantHelper.getExistingGroups( + tenantsClient, + getArg(properties, CommandOption.GROUP_NAME_LIST), + getArg(properties, CommandOption.GROUP_ID_LIST)); + + if (StringUtils.isNotBlank(getArg(properties, CommandOption.GROUP_NAME_LIST)) || StringUtils.isNotBlank(getArg(properties, CommandOption.GROUP_ID_LIST))) { + existingPolicy.setUserGroups(userGroups); + } + + final AccessPolicy updatedPolicy = policiesClient.updatePolicy(existingPolicy); + return new StringResult(updatedPolicy.getIdentifier(), getContext().isInteractive()); + } +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/UpdateUser.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/UpdateUser.java new file mode 100644 index 0000000..c41f1ba --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/UpdateUser.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.command.registry.tenant; + +import org.apache.commons.cli.ParseException; +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.authorization.User; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.toolkit.cli.api.Context; +import org.apache.nifi.toolkit.cli.impl.client.ExtendedNiFiRegistryClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; +import org.apache.nifi.toolkit.cli.impl.command.CommandOption; +import org.apache.nifi.toolkit.cli.impl.command.registry.AbstractNiFiRegistryCommand; +import org.apache.nifi.toolkit.cli.impl.result.StringResult; + +import java.io.IOException; +import java.util.Properties; + +/** + * Command for update an existing user. + */ +public class UpdateUser extends AbstractNiFiRegistryCommand<StringResult> { + + public UpdateUser() { + super("update-user", StringResult.class); + } + + @Override + public String getDescription() { + return "Updates an existing user."; + } + + @Override + protected void doInitialize(final Context context) { + // Required + addOption(CommandOption.USER_ID.createOption()); + + // Optional + addOption(CommandOption.USER_NAME.createOption()); + } + + @Override + public StringResult doExecute(final NiFiRegistryClient client, final Properties properties) + throws IOException, NiFiRegistryException, ParseException { + + if (!(client instanceof ExtendedNiFiRegistryClient)) { + throw new IllegalArgumentException("This command needs extended registry client!"); + } + + final ExtendedNiFiRegistryClient extendedClient = (ExtendedNiFiRegistryClient) client; + final TenantsClient tenantsClient = extendedClient.getTenantsClient(); + final String userId = getRequiredArg(properties, CommandOption.USER_ID); + final User existingUser = tenantsClient.getUser(userId); + + final String userName = getArg(properties, CommandOption.USER_NAME); + + if (StringUtils.isNotBlank(userName)) { + existingUser.setIdentity(userName); + } + + final User updatedUser = tenantsClient.updateUser(existingUser); + return new StringResult(updatedUser.getIdentifier(), getContext().isInteractive()); + } +} diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/UpdateUserGroup.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/UpdateUserGroup.java new file mode 100644 index 0000000..d29a843 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/tenant/UpdateUserGroup.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.toolkit.cli.impl.command.registry.tenant; + +import org.apache.commons.cli.ParseException; +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.authorization.Tenant; +import org.apache.nifi.registry.authorization.UserGroup; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.toolkit.cli.api.Context; +import org.apache.nifi.toolkit.cli.impl.client.ExtendedNiFiRegistryClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.TenantsClient; +import org.apache.nifi.toolkit.cli.impl.command.CommandOption; +import org.apache.nifi.toolkit.cli.impl.command.registry.AbstractNiFiRegistryCommand; +import org.apache.nifi.toolkit.cli.impl.result.StringResult; + +import java.io.IOException; +import java.util.Properties; +import java.util.Set; + +/** + * Command for update an existing user group. + */ +public class UpdateUserGroup extends AbstractNiFiRegistryCommand<StringResult> { + + public UpdateUserGroup() { + super("update-user-group", StringResult.class); + } + + @Override + public String getDescription() { + return "Updates existing user group."; + } + + @Override + protected void doInitialize(final Context context) { + // Required + addOption(CommandOption.UG_ID.createOption()); + + // Optional + addOption(CommandOption.UG_NAME.createOption()); + addOption(CommandOption.USER_NAME_LIST.createOption()); + addOption(CommandOption.USER_ID_LIST.createOption()); + } + + @Override + public StringResult doExecute(final NiFiRegistryClient client, final Properties properties) + throws IOException, NiFiRegistryException, ParseException { + if (!(client instanceof ExtendedNiFiRegistryClient)) { + throw new IllegalArgumentException("This command needs extended registry client!"); + } + + final ExtendedNiFiRegistryClient extendedClient = (ExtendedNiFiRegistryClient) client; + final TenantsClient tenantsClient = extendedClient.getTenantsClient(); + final String groupId = getRequiredArg(properties, CommandOption.UG_ID); + final UserGroup existingGroup = tenantsClient.getUserGroup(groupId); + + // Update group name + final String groupName = getArg(properties, CommandOption.UG_NAME); + + if (StringUtils.isNotBlank(groupName)) { + existingGroup.setIdentity(groupName); + } + + // Update group members + final Set<Tenant> tenants = TenantHelper.getExistingUsers( + tenantsClient, + getArg(properties, CommandOption.USER_NAME_LIST), + getArg(properties, CommandOption.USER_ID_LIST)); + + existingGroup.setUsers(tenants); + + final UserGroup updatedGroup = tenantsClient.updateUserGroup(existingGroup); + return new StringResult(updatedGroup.getIdentifier(), getContext().isInteractive()); + } +}
