MINIFI-238 - MiNiFi Initial Command and Control Server Implementation
This closes #75.
Signed-off-by: Aldrin Piri <aldrin@apache.org>
diff --git a/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java b/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java
index a8e7105..3ec26d0 100644
--- a/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java
+++ b/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java
@@ -27,6 +27,7 @@
import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeNotifier;
import org.apache.nifi.minifi.bootstrap.configuration.differentiators.WholeConfigDifferentiator;
import org.apache.nifi.minifi.bootstrap.configuration.differentiators.interfaces.Differentiator;
+import org.apache.nifi.minifi.commons.schema.common.StringUtil;
import org.slf4j.LoggerFactory;
import javax.net.ssl.KeyManagerFactory;
@@ -71,6 +72,7 @@
public static final String PORT_KEY = PULL_HTTP_BASE_KEY + ".port";
public static final String HOST_KEY = PULL_HTTP_BASE_KEY + ".hostname";
public static final String PATH_KEY = PULL_HTTP_BASE_KEY + ".path";
+ public static final String QUERY_KEY = PULL_HTTP_BASE_KEY + ".query";
public static final String TRUSTSTORE_LOCATION_KEY = PULL_HTTP_BASE_KEY + ".truststore.location";
public static final String TRUSTSTORE_PASSWORD_KEY = PULL_HTTP_BASE_KEY + ".truststore.password";
public static final String TRUSTSTORE_TYPE_KEY = PULL_HTTP_BASE_KEY + ".truststore.type";
@@ -86,6 +88,7 @@
private final AtomicReference<Integer> portReference = new AtomicReference<>();
private final AtomicReference<String> hostReference = new AtomicReference<>();
private final AtomicReference<String> pathReference = new AtomicReference<>();
+ private final AtomicReference<String> queryReference = new AtomicReference<>();
private volatile Differentiator<ByteBuffer> differentiator;
private volatile String connectionScheme;
private volatile String lastEtag = "";
@@ -110,6 +113,7 @@
}
final String path = properties.getProperty(PATH_KEY, "/");
+ final String query = properties.getProperty(QUERY_KEY, "");
final String portString = (String) properties.get(PORT_KEY);
final Integer port;
@@ -122,6 +126,7 @@
portReference.set(port);
hostReference.set(host);
pathReference.set(path);
+ queryReference.set(query);
final String useEtagString = (String) properties.getOrDefault(USE_ETAG_KEY, "false");
if ("true".equalsIgnoreCase(useEtagString) || "false".equalsIgnoreCase(useEtagString)){
@@ -175,10 +180,15 @@
public void run() {
try {
logger.debug("Attempting to pull new config");
- final HttpUrl url = new HttpUrl.Builder()
+ HttpUrl.Builder builder = new HttpUrl.Builder()
.host(hostReference.get())
.port(portReference.get())
- .encodedPath(pathReference.get())
+ .encodedPath(pathReference.get());
+ String query = queryReference.get();
+ if (!StringUtil.isNullOrEmpty(query)) {
+ builder = builder.encodedQuery(query);
+ }
+ final HttpUrl url = builder
.scheme(connectionScheme)
.build();
diff --git a/minifi-c2/minifi-c2-api/pom.xml b/minifi-c2/minifi-c2-api/pom.xml
new file mode 100644
index 0000000..4f1a397
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-api</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ <version>1.1.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-util</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java
new file mode 100644
index 0000000..a008f0a
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java
@@ -0,0 +1,45 @@
+/*
+ * 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.minifi.c2.api;
+
+import java.io.InputStream;
+
+/**
+ * Represents a MiNiFi configuration of a given version, format matches the format of the ConfigurationProvider
+ */
+public interface Configuration {
+ /**
+ * Gets the version
+ *
+ * @return the version
+ */
+ String getVersion();
+
+ /**
+ * Returns a boolean indicating whether this version exists
+ *
+ * @return a boolean indicating whether this version exists
+ */
+ boolean exists();
+ /**
+ * Returns an input stream to read the configuration with
+ *
+ * @return an input stream to read the configuration with
+ */
+ InputStream getInputStream() throws ConfigurationProviderException;
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProvider.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProvider.java
new file mode 100644
index 0000000..a743be3
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProvider.java
@@ -0,0 +1,43 @@
+/*
+ * 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.minifi.c2.api;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A configuration provider is capable of taking a parameter map and returning a configuration with a given content type
+ */
+public interface ConfigurationProvider {
+ /**
+ * Gets the content type that this provider returns
+ *
+ * @return the content type that this provider returns
+ */
+ String getContentType();
+
+ /**
+ * Gets the configuration that corresponds to the passed in parameters
+ *
+ * @param version the version of the configuration to get
+ * @param parameters the parameters passed in by the client (please note that these are provided by a client and should NOT be trusted to be sanitized)
+ * @return an input stream of the configuration
+ * @throws ConfigurationProviderException if there is an error in the configuration
+ */
+ Configuration getConfiguration(Integer version, Map<String, List<String>> parameters) throws ConfigurationProviderException;
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProviderException.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProviderException.java
new file mode 100644
index 0000000..16b1ed2
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProviderException.java
@@ -0,0 +1,28 @@
+/*
+ * 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.minifi.c2.api;
+
+public class ConfigurationProviderException extends Exception {
+ public ConfigurationProviderException(String message) {
+ super(message);
+ }
+
+ public ConfigurationProviderException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/InvalidParameterException.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/InvalidParameterException.java
new file mode 100644
index 0000000..33f8aa0
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/InvalidParameterException.java
@@ -0,0 +1,28 @@
+/*
+ * 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.minifi.c2.api;
+
+public class InvalidParameterException extends ConfigurationProviderException {
+ public InvalidParameterException(String message) {
+ super(message);
+ }
+
+ public InvalidParameterException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCache.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCache.java
new file mode 100644
index 0000000..00c271e
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCache.java
@@ -0,0 +1,37 @@
+/*
+ * 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.minifi.c2.api.cache;
+
+import org.apache.nifi.minifi.c2.api.InvalidParameterException;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Cache for storing configurations so they don't have to be pulled from the provider more often than necessary
+ */
+public interface ConfigurationCache {
+ /**
+ * Returns the information on a given cache entry
+ *
+ * @param parameters the parameters that identify the entry
+ * @return information on the entry
+ * @throws InvalidParameterException if there are illegal/invalid parameters
+ */
+ ConfigurationCacheFileInfo getCacheFileInfo(Map<String, List<String>> parameters) throws InvalidParameterException;
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCacheFileInfo.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCacheFileInfo.java
new file mode 100644
index 0000000..73578ba
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCacheFileInfo.java
@@ -0,0 +1,53 @@
+/*
+ * 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.minifi.c2.api.cache;
+
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+
+import java.io.IOException;
+import java.util.stream.Stream;
+
+/**
+ * Information on the different versions of a cache entry
+ */
+public interface ConfigurationCacheFileInfo {
+ /**
+ * Returns the version the file would be assigned based on its name
+ *
+ * @param filename the filename
+ * @return the version
+ */
+ Integer getVersionIfMatch(String filename);
+
+ /**
+ * Returns a stream of WritableConfigurations for this cache entry
+ *
+ * @return the stream
+ * @throws IOException if there is an error getting the configurations
+ */
+ Stream<WriteableConfiguration> getCachedConfigurations() throws IOException;
+
+ /**
+ * Returns a WritableConfiguration for the given version of this cache entry
+ *
+ * @param version the version
+ * @return the configuration
+ * @throws ConfigurationProviderException if there is a problem getting the configuration
+ */
+ WriteableConfiguration getConfiguration(Integer version) throws ConfigurationProviderException;
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/WriteableConfiguration.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/WriteableConfiguration.java
new file mode 100644
index 0000000..20d2d2e
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/WriteableConfiguration.java
@@ -0,0 +1,29 @@
+/*
+ * 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.minifi.c2.api.cache;
+
+import org.apache.nifi.minifi.c2.api.Configuration;
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+
+import java.io.OutputStream;
+
+public interface WriteableConfiguration extends Configuration {
+ OutputStream getOutputStream() throws ConfigurationProviderException;
+
+ String getName();
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/properties/C2Properties.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/properties/C2Properties.java
new file mode 100644
index 0000000..2a8df3a
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/properties/C2Properties.java
@@ -0,0 +1,89 @@
+/*
+ * 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.minifi.c2.api.properties;
+
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.Properties;
+
+public class C2Properties extends Properties {
+ public static final String MINIFI_C2_SERVER_SECURE = "minifi.c2.server.secure";
+ public static final String MINIFI_C2_SERVER_KEYSTORE_TYPE = "minifi.c2.server.keystoreType";
+ public static final String MINIFI_C2_SERVER_KEYSTORE = "minifi.c2.server.keystore";
+ public static final String MINIFI_C2_SERVER_KEYSTORE_PASSWD = "minifi.c2.server.keystorePasswd";
+ public static final String MINIFI_C2_SERVER_KEY_PASSWD = "minifi.c2.server.keyPasswd";
+ public static final String MINIFI_C2_SERVER_TRUSTSTORE = "minifi.c2.server.truststore";
+ public static final String MINIFI_C2_SERVER_TRUSTSTORE_TYPE = "minifi.c2.server.truststoreType";
+ public static final String MINIFI_C2_SERVER_TRUSTSTORE_PASSWD = "minifi.c2.server.truststorePasswd";
+
+ private static final Logger logger = LoggerFactory.getLogger(C2Properties.class);
+ private static final C2Properties properties = initProperties();
+ private static final String C2_SERVER_HOME = System.getenv("C2_SERVER_HOME");
+
+ private static C2Properties initProperties() {
+ C2Properties properties = new C2Properties();
+ try (InputStream inputStream = C2Properties.class.getClassLoader().getResourceAsStream("c2.properties")) {
+ properties.load(inputStream);
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to load c2.properties", e);
+ }
+ return properties;
+ }
+
+ public static C2Properties getInstance() {
+ return properties;
+ }
+
+ public SslContextFactory getSslContextFactory() throws GeneralSecurityException, IOException {
+ if (!Boolean.valueOf(getProperty(MINIFI_C2_SERVER_SECURE, "false"))) {
+ return null;
+ }
+
+ SslContextFactory sslContextFactory = new SslContextFactory();
+ KeyStore keyStore = KeyStore.getInstance(properties.getProperty(MINIFI_C2_SERVER_KEYSTORE_TYPE));
+ Path keyStorePath = Paths.get(C2_SERVER_HOME).resolve(properties.getProperty(MINIFI_C2_SERVER_KEYSTORE)).toAbsolutePath();
+ logger.debug("keystore path: " + keyStorePath);
+ try (InputStream inputStream = Files.newInputStream(keyStorePath)) {
+ keyStore.load(inputStream, properties.getProperty(MINIFI_C2_SERVER_KEYSTORE_PASSWD).toCharArray());
+ }
+ sslContextFactory.setKeyStore(keyStore);
+ sslContextFactory.setKeyManagerPassword(properties.getProperty(MINIFI_C2_SERVER_KEY_PASSWD));
+ sslContextFactory.setWantClientAuth(true);
+
+ String trustStorePath = Paths.get(C2_SERVER_HOME).resolve(properties.getProperty(MINIFI_C2_SERVER_TRUSTSTORE)).toAbsolutePath().toFile().getAbsolutePath();
+ logger.debug("truststore path: " + trustStorePath);
+ sslContextFactory.setTrustStorePath(trustStorePath);
+ sslContextFactory.setTrustStoreType(properties.getProperty(MINIFI_C2_SERVER_TRUSTSTORE_TYPE));
+ sslContextFactory.setTrustStorePassword(properties.getProperty(MINIFI_C2_SERVER_TRUSTSTORE_PASSWD));
+ try {
+ sslContextFactory.start();
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ return sslContextFactory;
+ }
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorityGranter.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorityGranter.java
new file mode 100644
index 0000000..2a7d913
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorityGranter.java
@@ -0,0 +1,36 @@
+/*
+ * 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.minifi.c2.api.security.authorization;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.util.Collection;
+
+/**
+ * Interface responsible for taking an authentication object and returning the GrantedAuthorities it should have
+ */
+public interface AuthorityGranter {
+ /**
+ * Returns the authorities a given Authentication object should receive
+ *
+ * @param authentication the authentication
+ * @return the authorities it should receive
+ */
+ Collection<GrantedAuthority> grantAuthorities(Authentication authentication);
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorizationException.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorizationException.java
new file mode 100644
index 0000000..2c459e0
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorizationException.java
@@ -0,0 +1,24 @@
+/*
+ * 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.minifi.c2.api.security.authorization;
+
+public class AuthorizationException extends Exception {
+ public AuthorizationException(String message) {
+ super(message);
+ }
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/Authorizer.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/Authorizer.java
new file mode 100644
index 0000000..fbdf3f5
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/Authorizer.java
@@ -0,0 +1,36 @@
+/*
+ * 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.minifi.c2.api.security.authorization;
+
+import org.springframework.security.core.Authentication;
+
+import javax.ws.rs.core.UriInfo;
+
+/**
+ * Interface responsible for authorizing a given authentication to access a given uri
+ */
+public interface Authorizer {
+ /**
+ * Throws an AuthorizationException if the authentication should not access the given uri
+ *
+ * @param authentication the authentication
+ * @param uriInfo the uri
+ * @throws AuthorizationException if the authentication should not access the uri
+ */
+ void authorize(Authentication authentication, UriInfo uriInfo) throws AuthorizationException;
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/util/DelegatingOutputStream.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/util/DelegatingOutputStream.java
new file mode 100644
index 0000000..a3f5254
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/util/DelegatingOutputStream.java
@@ -0,0 +1,54 @@
+/*
+ * 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.minifi.c2.api.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class DelegatingOutputStream extends OutputStream {
+ private final OutputStream delegate;
+
+ public DelegatingOutputStream(OutputStream delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ delegate.write(b);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ delegate.write(b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ delegate.write(b, off, len);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ delegate.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ delegate.close();
+ }
+}
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/util/Pair.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/util/Pair.java
new file mode 100644
index 0000000..edca7d0
--- /dev/null
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/util/Pair.java
@@ -0,0 +1,44 @@
+/*
+ * 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.minifi.c2.api.util;
+
+public class Pair<T, U> {
+ private final T first;
+ private final U second;
+
+ public Pair(T first, U second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ public T getFirst() {
+ return first;
+ }
+
+ public U getSecond() {
+ return second;
+ }
+
+ @Override
+ public String toString() {
+ return "Pair{" +
+ "first=" + first +
+ ", second=" + second +
+ '}';
+ }
+}
diff --git a/minifi-c2/minifi-c2-assembly/LICENSE b/minifi-c2/minifi-c2-assembly/LICENSE
new file mode 100644
index 0000000..a4b4e87
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/LICENSE
@@ -0,0 +1,330 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
+
+
+APACHE MINIFI SUBCOMPONENTS:
+
+The Apache MiNiFi project contains subcomponents with separate copyright
+notices and license terms. Your use of the source code for the these
+subcomponents is subject to the terms and conditions of the following
+licenses.
+
+The binary distribution of this product bundles 'Slf4j' which is available
+under a "3-clause BSD" license. For details see http://www.slf4j.org/
+
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+The binary distribution of this product bundles 'Antlr 3' which is available
+under a "3-clause BSD" license. For details see http://www.antlr3.org/license.html
+
+ Copyright (c) 2010 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ Neither the name of the author nor the names of its contributors may be used
+ to endorse or promote products derived from this software without specific
+ prior written permission.
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGE.
+
+This product bundles 'asm' which is available under a 3-Clause BSD style license.
+For details see http://asm.ow2.org/asmdex-license.html
+
+ Copyright (c) 2012 France Télécom
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGE.
+
+The binary distribution of this product bundles 'JLine' under a BSD
+style license.
+
+ Copyright (c) 2002-2006, Marc Prud'hommeaux <mwp1@cornell.edu>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, are permitted provided that the following
+ conditions are met:
+
+ Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with
+ the distribution.
+
+ Neither the name of JLine nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-assembly/NOTICE b/minifi-c2/minifi-c2-assembly/NOTICE
new file mode 100644
index 0000000..ebdfa69
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/NOTICE
@@ -0,0 +1,240 @@
+Apache NiFi
+Copyright 2014-2017 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+===========================================
+Apache Software License v2
+===========================================
+
+The following binary components are provided under the Apache Software License v2
+
+ (ASLv2) Apache NiFi
+ The following NOTICE information applies:
+ Apache NiFi
+ Copyright 2014-2017 The Apache Software Foundation
+
+ This product includes software developed at
+ The Apache Software Foundation (http://www.apache.org/).
+
+ This product includes the following work from the Apache Hadoop project:
+
+ BoundedByteArrayOutputStream.java adapted to SoftLimitBoundedByteArrayOutputStream.java
+
+ This includes derived works from the Apache Software License V2 library python-evtx (https://github.com/williballenthin/python-evtx)
+ Copyright 2012, 2013 Willi Ballenthin william.ballenthin@mandiant.com
+ while at Mandiant http://www.mandiant.com
+ The derived work is adapted from Evtx/Evtx.py, Evtx/BinaryParser.py, Evtx/Nodes.py, Evtx/Views.py and can be found in the org.apache.nifi.processors.evtx.parser package.
+
+
+
+ This includes derived works from the Apache Storm (ASLv2 licensed) project (https://github.com/apache/storm):
+ Copyright 2015 The Apache Software Foundation
+ The derived work is adapted from
+ org/apache/storm/hive/common/HiveWriter.java
+ org/apache/storm/hive/common/HiveOptions.java
+ and can be found in the org.apache.nifi.util.hive package
+
+ This includes derived works from the Apache Hive (ASLv2 licensed) project (https://github.com/apache/hive):
+ Copyright 2008-2017 The Apache Software Foundation
+ The derived work is adapted from
+ release-1.2.1/ql/src/java/org/apache/hadoop/hive/ql/io/orc/WriterImpl.java
+ and can be found in the org.apache.hadoop.hive.ql.io.orc package
+
+ (ASLv2) Apache Commons Lang
+ The following NOTICE information applies:
+ Apache Commons Lang
+ Copyright 2001-2015 The Apache Software Foundation
+
+ This product includes software from the Spring Framework,
+ under the Apache License 2.0 (see: StringUtils.containsWhitespace())
+
+ (ASLv2) Apache Commons Codec
+ The following NOTICE information applies:
+ Apache Commons Codec
+ Copyright 2002-2014 The Apache Software Foundation
+
+ src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java
+ contains test data from http://aspell.net/test/orig/batch0.tab.
+ Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org)
+
+ ===============================================================================
+
+ The content of package org.apache.commons.codec.language.bm has been translated
+ from the original php source code available at http://stevemorse.org/phoneticinfo.htm
+ with permission from the original authors.
+ Original source copyright:
+ Copyright (c) 2008 Alexander Beider & Stephen P. Morse.
+
+ (ASLv2) JsonPath
+ The following NOTICE information applies:
+ Copyright 2011 JsonPath authors
+
+ (ASLv2) JSON-SMART
+ The following NOTICE information applies:
+ Copyright 2011 JSON-SMART authors
+
+ (ASLv2) Jackson JSON processor
+ The following NOTICE information applies:
+ # Jackson JSON processor
+
+ Jackson is a high-performance, Free/Open Source JSON processing library.
+ It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has
+ been in development since 2007.
+ It is currently developed by a community of developers, as well as supported
+ commercially by FasterXML.com.
+
+ ## Licensing
+
+ Jackson core and extension components may licensed under different licenses.
+ To find the details that apply to this artifact see the accompanying LICENSE file.
+ For more information, including possible other licensing options, contact
+ FasterXML.com (http://fasterxml.com).
+
+ ## Credits
+
+ A list of contributors may be found from CREDITS file, which is included
+ in some artifacts (usually source distributions); but is always available
+ from the source code management (SCM) system project uses.
+
+ (ASLv2) Apache Commons Collections
+ The following NOTICE information applies:
+ Apache Commons Collections
+ Copyright 2001-2013 The Apache Software Foundation
+
+ (ASLv2) Jettison
+ The following NOTICE information applies:
+ Copyright 2006 Envoi Solutions LLC
+
+ (ASLv2) Apache HttpComponents
+ The following NOTICE information applies:
+ Apache HttpClient
+ Copyright 1999-2015 The Apache Software Foundation
+
+ Apache HttpCore
+ Copyright 2005-2015 The Apache Software Foundation
+
+ Apache HttpMime
+ Copyright 1999-2013 The Apache Software Foundation
+
+ This project contains annotations derived from JCIP-ANNOTATIONS
+ Copyright (c) 2005 Brian Goetz and Tim Peierls. See http://www.jcip.net
+
+ (ASLv2) Apache Commons Logging
+ The following NOTICE information applies:
+ Apache Commons Logging
+ Copyright 2003-2014 The Apache Software Foundation
+
+ (ASLv2) Apache Commons Net
+ The following NOTICE information applies:
+ Apache Commons Net
+ Copyright 2001-2013 The Apache Software Foundation
+
+ (ASLv2) Swagger Core
+ The following NOTICE information applies:
+ Swagger Core 1.5.3-M1
+ Copyright 2015 Reverb Technologies, Inc.
+
+ (ASLv2) Spring Security
+ The following NOTICE information applies:
+ Spring Framework 4.0.3.RELEASE
+ Copyright (c) 2002-2015 Pivotal, Inc.
+
+ (ASLv2) Spring Framework
+ The following NOTICE information applies:
+ Spring Framework 4.1.4.RELEASE
+ Copyright (c) 2002-2015 Pivotal, Inc.
+
+ (ASLv2) Quartz
+ The following NOTICE information applies:
+ Copyright Declaration:
+ Copyright © 2003-2016 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors.
+
+ Trademark and Patent declaration
+ The name Software AG and all Software AG product names are either trademarks or registered trademarks of Software AG and/or Software AG USA Inc. and/or its subsidiaries and/or its affiliates
+ and/or their licensors. Other company and product names mentioned herein may be trademarks of their respective owners.
+
+ Detailed information on trademarks and patents owned by Software AG and/or its subsidiaries is located at http://softwareag.com/licenses.
+
+ Third Party declaration
+ This software may include portions of third-party products. For third-party copyright notices, license terms, additional rights or restrictions, please refer to "License Texts, Copyright
+ Notices and Disclaimers of Third Party Products". For certain specific third-party license restrictions, please refer to section E of the Legal Notices available under "License Terms and
+ Conditions for Use of Software AG Products / Copyright and Trademark Notices of Software AG Products". These documents are part of the product documentation, located at
+ http://softwareag.com/licenses and/or in the root installation directory of the licensed product(s).
+
+ Confidentiality Disclaimer:
+ Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG.
+ Contact GitHub API Training Shop Blog About
+
+ (ASLv2) Jasypt
+ The following NOTICE information applies:
+ Copyright (c) 2007-2010, The JASYPT team (http://www.jasypt.org)
+
+ (ASLv2) Apache Commons IO
+ The following NOTICE information applies:
+ Apache Commons IO
+ Copyright 2002-2017 The Apache Software Foundation
+
+ (ASLv2) Apache ZooKeeper
+ The following NOTICE information applies:
+ Apache ZooKeeper
+ Copyright 2009-2012 The Apache Software Foundation
+
+ (ASLv2) Apache log4j
+ The following NOTICE information applies:
+ Apache log4j
+ Copyright 2007 The Apache Software Foundation
+
+ (ASLv2) The Netty Project
+ The following NOTICE information applies:
+ The Netty Project
+ Copyright 2011 The Netty Project
+
+ (ASLv2) Apache Curator
+ The following NOTICE information applies:
+ Curator Framework
+ Copyright 2011-2014 The Apache Software Foundation
+
+ Curator Client
+ Copyright 2011-2014 The Apache Software Foundation
+
+ Curator Recipes
+ Copyright 2011-2014 The Apache Software Foundation
+
+************************
+Common Development and Distribution License 1.1
+************************
+
+The following binary components are provided under the Common Development and Distribution License 1.1. See project link for details.
+
+ (CDDL 1.1) (GPL2 w/ CPE) JavaMail API (compat) (javax.mail:mail:jar:1.4.7 - http://kenai.com/projects/javamail/mail)
+ (CDDL 1.1) (GPL2 w/ CPE) jersey-json (com.sun.jersey:jersey-json:jar:1.19 - https://jersey.java.net/jersey-json/)
+ (CDDL 1.1) (GPL2 w/ CPE) Old JAXB Runtime (com.sun.xml.bind:jaxb-impl:jar:2.2.3-1 - http://jaxb.java.net/)
+ (CDDL 1.1) (GPL2 w/ CPE) Java Architecture For XML Binding (javax.xml.bind:jaxb-api:jar:2.2.2 - https://jaxb.dev.java.net/)
+ (CDDL 1.1) (GPL2 w/ CPE) aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:jar:2.4.0-b25 - https://hk2.java.net/external/aopalliance-repackaged)
+ (CDDL 1.1) (GPL2 w/ CPE) jersey-client (com.sun.jersey:jersey-client:jar:1.19 - https://jersey.java.net/jersey-client/)
+ (CDDL 1.1) (GPL2 w/ CPE) jersey-core (com.sun.jersey:jersey-core:jar:1.19 - https://jersey.java.net/jersey-core/)
+
+
+************************
+Common Development and Distribution License 1.0
+************************
+
+The following binary components are provided under the Common Development and Distribution License 1.0. See project link for details.
+
+ (CDDL 1.0) JavaBeans Activation Framework (JAF) (javax.activation:activation:jar:1.1 - http://java.sun.com/products/javabeans/jaf/index.jsp)
+ (CDDL 1.0) (GPL3) Streaming API For XML (javax.xml.stream:stax-api:jar:1.0-2 - no url provided)
+ (CDDL 1.0) JSR311 API (javax.ws.rs:jsr311-api:jar:1.1.1 - https://jsr311.dev.java.net)
+
+
+************************
+Eclipse Public License 1.0
+************************
+
+The following binary components are provided under the Eclipse Public License 1.0. See project link for details.
+
+ (EPL 1.0) AspectJ Weaver (org.aspectj:aspectjweaver:jar:1.8.5 - http://www.eclipse.org/aspectj/)
+ (EPL 1.0)(LGPL 2.1) Logback Classic (ch.qos.logback:logback-classic:jar:1.1.3 - http://logback.qos.ch/)
+ (EPL 1.0)(LGPL 2.1) Logback Core (ch.qos.logback:logback-core:jar:1.1.3 - http://logback.qos.ch/)
+ (EPL 1.0)(MPL 2.0) H2 Database (com.h2database:h2:jar:1.3.176 - http://www.h2database.com/html/license.html)
diff --git a/minifi-c2/minifi-c2-assembly/README.md b/minifi-c2/minifi-c2-assembly/README.md
new file mode 100644
index 0000000..c77e3e2
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/README.md
@@ -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
+ https://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.
+-->
+# Apache NiFi - MiNiFi - Command and Control (C2) Server
+
+MiNiFi is a child project effort of Apache NiFi. The MiNiFi C2 Server aids in transforming and distributing MiNiFi configuration files to MiNiFi instances over HTTP.
+
+## Table of Contents
+
+- [Requirements](#requirements)
+- [Getting Started](#getting-started)
+- [Getting Help](#getting-help)
+- [Documentation](#documentation)
+- [License](#license)
+- [Export Control](#export-control)
+
+## Requirements
+* JRE 1.8
+* Apache Maven 3
+
+## Getting Started
+
+The C2 server is built either as part of the top level MiNiFi build or as a build of the minifi-c2 module.
+
+```
+mvn clean install
+```
+
+It can be started with either c2.sh or c2.bat depending on platform.
+
+## Getting Help
+If you have questions, you can reach out to our mailing list: dev@nifi.apache.org
+([archive](https://mail-archives.apache.org/mod_mbox/nifi-dev)).
+We're also often available in IRC: #nifi on
+[irc.freenode.net](https://webchat.freenode.net/?channels=#nifi).
+
+## Documentation
+
+See https://nifi.apache.org/minifi and https://cwiki.apache.org/confluence/display/NIFI/MiNiFi for the latest documentation.
+
+## License
+
+Except as otherwise noted this software is licensed under the
+[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.html)
+
+Licensed 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
+
+ https://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.
+
+## Export Control
+
+This distribution includes cryptographic software. The country in which you
+currently reside may have restrictions on the import, possession, use, and/or
+re-export to another country, of encryption software. BEFORE using any
+encryption software, please check your country's laws, regulations and
+policies concerning the import, possession, or use, and re-export of encryption
+software, to see if this is permitted. See <http://www.wassenaar.org/> for more
+information.
+
+The U.S. Government Department of Commerce, Bureau of Industry and Security
+(BIS), has classified this software as Export Commodity Control Number (ECCN)
+5D002.C.1, which includes information security software using or performing
+cryptographic functions with asymmetric algorithms. The form and manner of this
+Apache Software Foundation distribution makes it eligible for export under the
+License Exception ENC Technology Software Unrestricted (TSU) exception (see the
+BIS Export Administration Regulations, Section 740.13) for both object code and
+source code.
+
+The following provides more details on the included cryptographic software:
+
+Apache NiFi - MiNiFi uses BouncyCastle, Jasypt, JCraft Inc., and the built-in
+java cryptography libraries for SSL, SSH, and the protection
+of sensitive configuration parameters. See
+https://bouncycastle.org/about.html
+http://www.jasypt.org/faq.html
+http://jcraft.com/c-info.html
+https://www.oracle.com/us/products/export/export-regulations-345813.html
+for more details on each of these libraries cryptography features.
diff --git a/minifi-c2/minifi-c2-assembly/pom.xml b/minifi-c2/minifi-c2-assembly/pom.xml
new file mode 100644
index 0000000..957f8bd
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/pom.xml
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-assembly</artifactId>
+ <packaging>pom</packaging>
+ <description>This is the assembly of Apache MiNiFi's - Command And Control Server</description>
+ <properties>
+ <minifi.c2.server.port>10080</minifi.c2.server.port>
+
+ <minifi.c2.server.secure>false</minifi.c2.server.secure>
+ <minifi.c2.server.keystore>./conf/keystore.jks</minifi.c2.server.keystore>
+ <minifi.c2.server.keystoreType>jks</minifi.c2.server.keystoreType>
+ <minifi.c2.server.keystorePasswd/>
+ <minifi.c2.server.keyPasswd/>
+ <minifi.c2.server.truststore>./conf/truststore.jks</minifi.c2.server.truststore>
+ <minifi.c2.server.truststoreType>jks</minifi.c2.server.truststoreType>
+ <minifi.c2.server.truststorePasswd/>
+
+ <minifi.c2.server.provider.nifi.rest.api.url>http://localhost:8080/nifi-api</minifi.c2.server.provider.nifi.rest.api.url>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <finalName>minifi-c2-${project.version}</finalName>
+ <attach>false</attach>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make shared resource</id>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <archiverConfig>
+ <defaultDirectoryMode>0755</defaultDirectoryMode>
+ <directoryMode>0755</directoryMode>
+ <fileMode>0644</fileMode>
+ </archiverConfig>
+ <descriptors>
+ <descriptor>src/main/assembly/dependencies.xml</descriptor>
+ </descriptors>
+ <tarLongFileMode>posix</tarLongFileMode>
+ <escapeString>\</escapeString>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-cache-filesystem</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-provider-cache</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-provider-nifi-rest</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-jetty</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-servlet</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-webapp</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-web</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-config</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-web</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.jersey.contribs</groupId>
+ <artifactId>jersey-spring</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-util</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-service</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/minifi-c2/minifi-c2-assembly/src/main/assembly/dependencies.xml b/minifi-c2/minifi-c2-assembly/src/main/assembly/dependencies.xml
new file mode 100644
index 0000000..026200c
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/assembly/dependencies.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<!--
+ 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.
+-->
+<assembly>
+ <id>bin</id>
+ <formats>
+ <format>dir</format>
+ <format>zip</format>
+ <format>tar.gz</format>
+ </formats>
+ <includeBaseDirectory>true</includeBaseDirectory>
+ <baseDirectory>minifi-c2-${project.version}</baseDirectory>
+
+ <dependencySets>
+ <!-- Write out all non-war dependency artifacts to lib directory -->
+ <dependencySet>
+ <outputDirectory>lib</outputDirectory>
+ <useProjectArtifact>false</useProjectArtifact>
+ <directoryMode>0770</directoryMode>
+ <fileMode>0660</fileMode>
+ <excludes>
+ <exclude>*:war</exclude>
+ </excludes>
+ </dependencySet>
+
+ <!-- Write out all war dependency artifacts to lib directory -->
+ <dependencySet>
+ <outputDirectory>webapps</outputDirectory>
+ <useProjectArtifact>false</useProjectArtifact>
+ <directoryMode>0770</directoryMode>
+ <fileMode>0660</fileMode>
+ <includes>
+ <include>*:war</include>
+ </includes>
+ </dependencySet>
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>${project.basedir}/src/main/resources</directory>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>0755</fileMode>
+ <filtered>true</filtered>
+ </fileSet>
+ </fileSets>
+ <files>
+ <file>
+ <source>./README.md</source>
+ <outputDirectory>./</outputDirectory>
+ <destName>README</destName>
+ <fileMode>0644</fileMode>
+ <filtered>true</filtered>
+ </file>
+ <file>
+ <source>./LICENSE</source>
+ <outputDirectory>./</outputDirectory>
+ <destName>LICENSE</destName>
+ <fileMode>0644</fileMode>
+ <filtered>true</filtered>
+ </file>
+ <file>
+ <source>./NOTICE</source>
+ <outputDirectory>./</outputDirectory>
+ <destName>NOTICE</destName>
+ <fileMode>0644</fileMode>
+ <filtered>true</filtered>
+ </file>
+ </files>
+</assembly>
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/bin/c2.bat b/minifi-c2/minifi-c2-assembly/src/main/resources/bin/c2.bat
new file mode 100644
index 0000000..6c02746
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/bin/c2.bat
@@ -0,0 +1,41 @@
+@echo off
+rem
+rem Licensed to the Apache Software Foundation (ASF) under one or more
+rem contributor license agreements. See the NOTICE file distributed with
+rem this work for additional information regarding copyright ownership.
+rem The ASF licenses this file to You under the Apache License, Version 2.0
+rem (the "License"); you may not use this file except in compliance with
+rem the License. You may obtain a copy of the License at
+rem
+rem http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem Unless required by applicable law or agreed to in writing, software
+rem distributed under the License is distributed on an "AS IS" BASIS,
+rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+rem See the License for the specific language governing permissions and
+rem limitations under the License.
+rem
+
+rem Use JAVA_HOME if it's set; otherwise, just use java
+
+if "%JAVA_HOME%" == "" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
+set JAVA_EXE=%JAVA_HOME%\bin\java.exe
+goto startConfig
+
+:noJavaHome
+echo The JAVA_HOME environment variable is not defined correctly.
+echo Instead the PATH will be used to find the java executable.
+echo.
+set JAVA_EXE=java
+goto startConfig
+
+:startConfig
+set LIB_DIR=%~dp0..\conf;%~dp0..\lib
+
+set C2_SERVER_HOME=%~sdp0..\
+
+SET JAVA_PARAMS=-cp %LIB_DIR%\* -Xms12m -Xmx24m %JAVA_ARGS% -Djava.net.preferIPv4Stack=true org.apache.nifi.minifi.c2.jetty.JettyServer
+
+cmd.exe /C "%JAVA_EXE%" %JAVA_PARAMS% %*
+
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/bin/c2.sh b/minifi-c2/minifi-c2-assembly/src/main/resources/bin/c2.sh
new file mode 100755
index 0000000..c6dc8de
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/bin/c2.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+#
+# 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.
+#
+#
+
+# Script structure inspired from Apache Karaf and other Apache projects with similar startup approaches
+
+SCRIPT_DIR=$(dirname "$0")
+SCRIPT_NAME=$(basename "$0")
+export C2_SERVER_HOME=$(cd "${SCRIPT_DIR}" && cd .. && pwd)
+PROGNAME=$(basename "$0")
+
+
+warn() {
+ echo "${PROGNAME}: $*"
+}
+
+die() {
+ warn "$*"
+ exit 1
+}
+
+detectOS() {
+ # OS specific support (must be 'true' or 'false').
+ cygwin=false;
+ aix=false;
+ os400=false;
+ darwin=false;
+ case "$(uname)" in
+ CYGWIN*)
+ cygwin=true
+ ;;
+ AIX*)
+ aix=true
+ ;;
+ OS400*)
+ os400=true
+ ;;
+ Darwin)
+ darwin=true
+ ;;
+ esac
+ # For AIX, set an environment variable
+ if ${aix}; then
+ export LDR_CNTRL=MAXDATA=0xB0000000@DSA
+ echo ${LDR_CNTRL}
+ fi
+}
+
+locateJava() {
+ # Setup the Java Virtual Machine
+ if $cygwin ; then
+ [ -n "${JAVA}" ] && JAVA=$(cygpath --unix "${JAVA}")
+ [ -n "${JAVA_HOME}" ] && JAVA_HOME=$(cygpath --unix "${JAVA_HOME}")
+ fi
+
+ if [ "x${JAVA}" = "x" ] && [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=$(java-config --jre-home)
+ fi
+ if [ "x${JAVA}" = "x" ]; then
+ if [ "x${JAVA_HOME}" != "x" ]; then
+ if [ ! -d "${JAVA_HOME}" ]; then
+ die "JAVA_HOME is not valid: ${JAVA_HOME}"
+ fi
+ JAVA="${JAVA_HOME}/bin/java"
+ else
+ warn "JAVA_HOME not set; results may vary"
+ JAVA=$(type java)
+ JAVA=$(expr "${JAVA}" : '.* \(/.*\)$')
+ if [ "x${JAVA}" = "x" ]; then
+ die "java command not found"
+ fi
+ fi
+ fi
+}
+
+init() {
+ # Determine if there is special OS handling we must perform
+ detectOS
+
+ # Locate the Java VM to execute
+ locateJava
+}
+
+run() {
+ LIBS="${C2_SERVER_HOME}/lib/*"
+
+ sudo_cmd_prefix=""
+ if $cygwin; then
+ C2_SERVER_HOME=$(cygpath --path --windows "${C2_SERVER_HOME}")
+ CLASSPATH="$C2_SERVER_HOME/conf;$(cygpath --path --windows "${LIBS}")"
+ else
+ CLASSPATH="$C2_SERVER_HOME/conf:${LIBS}"
+ fi
+
+ echo
+ echo "Java home: ${JAVA_HOME}"
+ echo "C2 Server home: ${C2_SERVER_HOME}"
+ echo
+ echo
+
+ if [ "$1" = "debug" ]; then
+ "${JAVA}" -cp "${CLASSPATH}" -Xms12m -Xmx24m -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 -Djava.net.preferIPv4Stack=true org.apache.nifi.minifi.c2.jetty.JettyServer $@
+ else
+ "${JAVA}" -cp "${CLASSPATH}" -Xms12m -Xmx24m -Djava.net.preferIPv4Stack=true org.apache.nifi.minifi.c2.jetty.JettyServer $@
+ fi
+ return $?
+}
+
+init
+run "$@"
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorities.yaml b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorities.yaml
new file mode 100644
index 0000000..a57dd4c
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorities.yaml
@@ -0,0 +1,17 @@
+# 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.
+
+CN=raspi3, OU=NIFI:
+ - CLASS_RASPI_3
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml
new file mode 100644
index 0000000..7016ff4
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml
@@ -0,0 +1,30 @@
+# 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.
+
+Default Action: deny
+Paths:
+ /c2/config:
+ Default Action: deny
+ Actions:
+ - Authorization: CLASS_RASPI_3
+ Query Parameters:
+ class: raspi3
+ Action: allow
+ - Authorization: ROLE_SUPERUSER
+ Action: allow
+
+ # Default authorization lets anonymous pull any config. Remove below to change that.
+ - Authorization: ROLE_ANONYMOUS
+ Action: allow
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/c2.properties b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/c2.properties
new file mode 100644
index 0000000..c68a3e3
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/c2.properties
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+minifi.c2.server.port=${minifi.c2.server.port}
+
+minifi.c2.server.secure=${minifi.c2.server.secure}
+minifi.c2.server.keystore=${minifi.c2.server.keystore}
+minifi.c2.server.keystoreType=${minifi.c2.server.keystoreType}
+minifi.c2.server.keystorePasswd=${minifi.c2.server.keystorePasswd}
+minifi.c2.server.keyPasswd=${minifi.c2.server.keyPasswd}
+minifi.c2.server.truststore=${minifi.c2.server.truststore}
+minifi.c2.server.truststoreType=${minifi.c2.server.truststoreType}
+minifi.c2.server.truststorePasswd=${minifi.c2.server.truststorePasswd}
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/logback.xml b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/logback.xml
new file mode 100644
index 0000000..b9a8129
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/logback.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ /*
+ ~ * 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.
+ ~ */
+ -->
+
+<configuration scan="true" scanPeriod="30 seconds">
+ <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
+ <resetJUL>true</resetJUL>
+ </contextListener>
+
+ <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <pattern>%date %level [%thread] %logger{40} %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <logger name="org.apache.nifi.minifi.c2" level="DEBUG"/>
+
+ <root level="INFO">
+ <appender-ref ref="CONSOLE"/>
+ </root>
+
+</configuration>
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-context.xml b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-context.xml
new file mode 100644
index 0000000..82a3dfc
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-context.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<beans default-lazy-init="true"
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
+
+ <bean id="configService" class="org.apache.nifi.minifi.c2.service.ConfigService" scope="singleton">
+ <constructor-arg>
+ <list>
+ <bean class="org.apache.nifi.minifi.c2.provider.cache.CacheConfigurationProvider">
+ <constructor-arg>
+ <value>text/yml</value>
+ </constructor-arg>
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.cache.filesystem.FileSystemConfigurationCache">
+ <constructor-arg>
+ <value>./files</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>\${class}/config.yml</value>
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ </bean>
+ <!--<bean class="org.apache.nifi.minifi.c2.provider.nifi.rest.NiFiRestConfigurationProvider">
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.cache.filesystem.FileSystemConfigurationCache">
+ <constructor-arg>
+ <value>./cache</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>\${class}/\${class}</value>
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ <constructor-arg>
+ <value>${minifi.c2.server.provider.nifi.rest.api.url}</value>
+ </constructor-arg>
+ </bean>-->
+ </list>
+ </constructor-arg>
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.security.authorization.GrantedAuthorityAuthorizer">
+ <constructor-arg value="classpath:authorizations.yaml"/>
+ </bean>
+ </constructor-arg>
+ </bean>
+</beans>
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-web-security-context.xml b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-web-security-context.xml
new file mode 100644
index 0000000..9b3f15c
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-web-security-context.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
+
+ <bean id="x509AuthenticationProvider" class="org.apache.nifi.minifi.c2.security.authentication.X509AuthenticationProvider">
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.security.authorization.PrincipalStringAuthorityGranter">
+ <constructor-arg value="classpath:authorities.yaml"/>
+ </bean>
+ </constructor-arg>
+ </bean>
+
+ <bean id="x509AuthenticationFilter" class="org.apache.nifi.minifi.c2.security.authentication.X509AuthenticationFilter"/>
+
+ <bean id="c2AnonymousAuthenticationFilter" class="org.apache.nifi.minifi.c2.security.authentication.C2AnonymousAuthenticationFilter"/>
+</beans>
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/webdefault.xml b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/webdefault.xml
new file mode 100644
index 0000000..8a89e1b
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/webdefault.xml
@@ -0,0 +1,556 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ 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.
+-->
+<web-app
+ xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
+ metadata-complete="false"
+ version="3.1">
+
+ <!-- ===================================================================== -->
+ <!-- This file contains the default descriptor for web applications. -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- The intent of this descriptor is to include jetty specific or common -->
+ <!-- configuration for all webapps. If a context has a webdefault.xml -->
+ <!-- descriptor, it is applied before the contexts own web.xml file -->
+ <!-- -->
+ <!-- A context may be assigned a default descriptor by: -->
+ <!-- + Calling WebApplicationContext.setDefaultsDescriptor -->
+ <!-- + Passed an arg to addWebApplications -->
+ <!-- -->
+ <!-- This file is used both as the resource within the jetty.jar (which is -->
+ <!-- used as the default if no explicit defaults descriptor is set) and it -->
+ <!-- is copied to the etc directory of the Jetty distro and explicitly -->
+ <!-- by the jetty.xml file. -->
+ <!-- -->
+ <!-- ===================================================================== -->
+
+ <description>
+ Default web.xml file.
+ This file is applied to a Web application before it's own WEB_INF/web.xml file
+ </description>
+
+ <!-- ==================================================================== -->
+ <!-- Removes static references to beans from javax.el.BeanELResolver to -->
+ <!-- ensure webapp classloader can be released on undeploy -->
+ <!-- ==================================================================== -->
+ <listener>
+ <listener-class>org.eclipse.jetty.servlet.listener.ELContextCleaner</listener-class>
+ </listener>
+
+ <!-- ==================================================================== -->
+ <!-- Removes static configurationCache of Methods from java.beans.Introspector to -->
+ <!-- ensure webapp classloader can be released on undeploy -->
+ <!-- ==================================================================== -->
+ <listener>
+ <listener-class>org.eclipse.jetty.servlet.listener.IntrospectorCleaner</listener-class>
+ </listener>
+
+
+ <!-- ==================================================================== -->
+ <!-- Context params to control Session Cookies -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!--
+ UNCOMMENT TO ACTIVATE
+ <context-param>
+ <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name>
+ <param-value>127.0.0.1</param-value>
+ </context-param>
+ <context-param>
+ <param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
+ <param-value>/</param-value>
+ </context-param>
+ <context-param>
+ <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
+ <param-value>-1</param-value>
+ </context-param>
+ -->
+
+ <!-- ==================================================================== -->
+ <!-- The default servlet. -->
+ <!-- This servlet, normally mapped to /, provides the handling for static -->
+ <!-- content, OPTIONS and TRACE methods for the context. -->
+ <!-- The following initParameters are supported: -->
+ <!--
+ * acceptRanges If true, range requests and responses are
+ * supported
+ *
+ * dirAllowed If true, directory listings are returned if no
+ * welcome file is found. Else 403 Forbidden.
+ *
+ * welcomeServlets If true, attempt to dispatch to welcome files
+ * that are servlets, but only after no matching static
+ * resources could be found. If false, then a welcome
+ * file must exist on disk. If "exact", then exact
+ * servlet matches are supported without an existing file.
+ * Default is true.
+ *
+ * This must be false if you want directory listings,
+ * but have index.jsp in your welcome file list.
+ *
+ * redirectWelcome If true, welcome files are redirected rather than
+ * forwarded to.
+ *
+ * gzip If set to true, then static content will be served as
+ * gzip content encoded if a matching resource is
+ * found ending with ".gz"
+ *
+ * resourceBase Set to replace the context resource base
+ *
+ * resourceCache If set, this is a context attribute name, which the servlet
+ * will use to look for a shared ResourceCache instance.
+ *
+ * relativeResourceBase
+ * Set with a pathname relative to the base of the
+ * servlet context root. Useful for only serving static content out
+ * of only specific subdirectories.
+ *
+ * pathInfoOnly If true, only the path info will be applied to the resourceBase
+ *
+ * stylesheet Set with the location of an optional stylesheet that will be used
+ * to decorate the directory listing html.
+ *
+ * aliases If True, aliases of resources are allowed (eg. symbolic
+ * links and caps variations). May bypass security constraints.
+ *
+ * etags If True, weak etags will be generated and handled.
+ *
+ * maxCacheSize The maximum total size of the configurationCache or 0 for no configurationCache.
+ * maxCachedFileSize The maximum size of a file to configurationCache
+ * maxCachedFiles The maximum number of files to configurationCache
+ *
+ * useFileMappedBuffer
+ * If set to true, it will use mapped file buffer to serve static content
+ * when using NIO connector. Setting this value to false means that
+ * a direct buffer will be used instead of a mapped file buffer.
+ * By default, this is set to true.
+ *
+ * cacheControl If set, all static content will have this value set as the configurationCache-control
+ * header.
+ *
+ -->
+
+
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <servlet>
+ <servlet-name>default</servlet-name>
+ <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
+ <init-param>
+ <param-name>aliases</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
+ <param-name>acceptRanges</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <init-param>
+ <param-name>dirAllowed</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
+ <param-name>welcomeServlets</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <init-param>
+ <param-name>redirectWelcome</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
+ <param-name>maxCacheSize</param-name>
+ <param-value>256000000</param-value>
+ </init-param>
+ <init-param>
+ <param-name>maxCachedFileSize</param-name>
+ <param-value>200000000</param-value>
+ </init-param>
+ <init-param>
+ <param-name>maxCachedFiles</param-name>
+ <param-value>2048</param-value>
+ </init-param>
+ <init-param>
+ <param-name>gzip</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <init-param>
+ <param-name>etags</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
+ <param-name>useFileMappedBuffer</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <!--
+ <init-param>
+ <param-name>resourceCache</param-name>
+ <param-value>resourceCache</param-value>
+ </init-param>
+ -->
+ <!--
+ <init-param>
+ <param-name>cacheControl</param-name>
+ <param-value>max-age=3600,public</param-value>
+ </init-param>
+ -->
+ <load-on-startup>0</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>default</servlet-name>
+ <url-pattern>/</url-pattern>
+ </servlet-mapping>
+
+
+ <!-- ==================================================================== -->
+ <!-- JSP Servlet -->
+ <!-- This is the jasper JSP servlet from the jakarta project -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- The JSP page compiler and execution servlet, which is the mechanism -->
+ <!-- used by Glassfish to support JSP pages. Traditionally, this servlet -->
+ <!-- is mapped to URL patterh "*.jsp". This servlet supports the -->
+ <!-- following initialization parameters (default values are in square -->
+ <!-- brackets): -->
+ <!-- -->
+ <!-- checkInterval If development is false and reloading is true, -->
+ <!-- background compiles are enabled. checkInterval -->
+ <!-- is the time in seconds between checks to see -->
+ <!-- if a JSP page needs to be recompiled. [300] -->
+ <!-- -->
+ <!-- compiler Which compiler Ant should use to compile JSP -->
+ <!-- pages. See the Ant documenation for more -->
+ <!-- information. [javac] -->
+ <!-- -->
+ <!-- classdebuginfo Should the class file be compiled with -->
+ <!-- debugging information? [true] -->
+ <!-- -->
+ <!-- classpath What class path should I use while compiling -->
+ <!-- generated servlets? [Created dynamically -->
+ <!-- based on the current web application] -->
+ <!-- Set to ? to make the container explicitly set -->
+ <!-- this parameter. -->
+ <!-- -->
+ <!-- development Is Jasper used in development mode (will check -->
+ <!-- for JSP modification on every access)? [true] -->
+ <!-- -->
+ <!-- enablePooling Determines whether tag handler pooling is -->
+ <!-- enabled [true] -->
+ <!-- -->
+ <!-- fork Tell Ant to fork compiles of JSP pages so that -->
+ <!-- a separate JVM is used for JSP page compiles -->
+ <!-- from the one Tomcat is running in. [true] -->
+ <!-- -->
+ <!-- ieClassId The class-id value to be sent to Internet -->
+ <!-- Explorer when using <jsp:plugin> tags. -->
+ <!-- [clsid:8AD9C840-044E-11D1-B3E9-00805F499D93] -->
+ <!-- -->
+ <!-- javaEncoding Java file encoding to use for generating java -->
+ <!-- source files. [UTF-8] -->
+ <!-- -->
+ <!-- keepgenerated Should we keep the generated Java source code -->
+ <!-- for each page instead of deleting it? [true] -->
+ <!-- -->
+ <!-- logVerbosityLevel The level of detailed messages to be produced -->
+ <!-- by this servlet. Increasing levels cause the -->
+ <!-- generation of more messages. Valid values are -->
+ <!-- FATAL, ERROR, WARNING, INFORMATION, and DEBUG. -->
+ <!-- [WARNING] -->
+ <!-- -->
+ <!-- mappedfile Should we generate static content with one -->
+ <!-- print statement per input line, to ease -->
+ <!-- debugging? [false] -->
+ <!-- -->
+ <!-- -->
+ <!-- reloading Should Jasper check for modified JSPs? [true] -->
+ <!-- -->
+ <!-- suppressSmap Should the generation of SMAP info for JSR45 -->
+ <!-- debugging be suppressed? [false] -->
+ <!-- -->
+ <!-- dumpSmap Should the SMAP info for JSR45 debugging be -->
+ <!-- dumped to a file? [false] -->
+ <!-- False if suppressSmap is true -->
+ <!-- -->
+ <!-- scratchdir What scratch directory should we use when -->
+ <!-- compiling JSP pages? [default work directory -->
+ <!-- for the current web application] -->
+ <!-- -->
+ <!-- tagpoolMaxSize The maximum tag handler pool size [5] -->
+ <!-- -->
+ <!-- xpoweredBy Determines whether X-Powered-By response -->
+ <!-- header is added by generated servlet [false] -->
+ <!-- -->
+ <!-- If you wish to use Jikes to compile JSP pages: -->
+ <!-- Set the init parameter "compiler" to "jikes". Define -->
+ <!-- the property "-Dbuild.compiler.emacs=true" when starting Jetty -->
+ <!-- to cause Jikes to emit error messages in a format compatible with -->
+ <!-- Jasper. -->
+ <!-- If you get an error reporting that jikes can't use UTF-8 encoding, -->
+ <!-- try setting the init parameter "javaEncoding" to "ISO-8859-1". -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <servlet id="jsp">
+ <servlet-name>jsp</servlet-name>
+ <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
+ <init-param>
+ <param-name>logVerbosityLevel</param-name>
+ <param-value>DEBUG</param-value>
+ </init-param>
+ <init-param>
+ <param-name>fork</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
+ <param-name>keepgenerated</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <init-param>
+ <param-name>development</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
+ <param-name>xpoweredBy</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
+ <param-name>compilerTargetVM</param-name>
+ <param-value>1.7</param-value>
+ </init-param>
+ <init-param>
+ <param-name>compilerSourceVM</param-name>
+ <param-value>1.7</param-value>
+ </init-param>
+ <!--
+ <init-param>
+ <param-name>classpath</param-name>
+ <param-value>?</param-value>
+ </init-param>
+ -->
+ <load-on-startup>0</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>jsp</servlet-name>
+ <url-pattern>*.jsp</url-pattern>
+ <url-pattern>*.jspf</url-pattern>
+ <url-pattern>*.jspx</url-pattern>
+ <url-pattern>*.xsp</url-pattern>
+ <url-pattern>*.JSP</url-pattern>
+ <url-pattern>*.JSPF</url-pattern>
+ <url-pattern>*.JSPX</url-pattern>
+ <url-pattern>*.XSP</url-pattern>
+ </servlet-mapping>
+
+
+ <!-- ==================================================================== -->
+ <session-config>
+ <session-timeout>30</session-timeout>
+ </session-config>
+
+ <!-- ==================================================================== -->
+ <!-- Default MIME mappings -->
+ <!-- The default MIME mappings are provided by the mime.properties -->
+ <!-- resource in the org.eclipse.jetty.server.jar file. Additional or modified -->
+ <!-- mappings may be specified here -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- UNCOMMENT TO ACTIVATE
+ <mime-mapping>
+ <extension>mysuffix</extension>
+ <mime-type>mymime/type</mime-type>
+ </mime-mapping>
+ -->
+
+ <!-- ==================================================================== -->
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ <welcome-file>index.htm</welcome-file>
+ <welcome-file>index.jsp</welcome-file>
+ </welcome-file-list>
+
+ <!-- ==================================================================== -->
+ <locale-encoding-mapping-list>
+ <locale-encoding-mapping>
+ <locale>ar</locale>
+ <encoding>ISO-8859-6</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>be</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>bg</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>ca</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>cs</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>da</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>de</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>el</locale>
+ <encoding>ISO-8859-7</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>en</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>es</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>et</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>fi</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>fr</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>hr</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>hu</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>is</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>it</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>iw</locale>
+ <encoding>ISO-8859-8</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>ja</locale>
+ <encoding>Shift_JIS</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>ko</locale>
+ <encoding>EUC-KR</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>lt</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>lv</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>mk</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>nl</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>no</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>pl</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>pt</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>ro</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>ru</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sh</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sk</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sl</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sq</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sr</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sv</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>tr</locale>
+ <encoding>ISO-8859-9</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>uk</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>zh</locale>
+ <encoding>GB2312</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>zh_TW</locale>
+ <encoding>Big5</encoding>
+ </locale-encoding-mapping>
+ </locale-encoding-mapping-list>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Disable TRACE</web-resource-name>
+ <url-pattern>/</url-pattern>
+ <http-method>TRACE</http-method>
+ </web-resource-collection>
+ <auth-constraint/>
+ </security-constraint>
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Enable everything but TRACE</web-resource-name>
+ <url-pattern>/</url-pattern>
+ <http-method-omission>TRACE</http-method-omission>
+ </web-resource-collection>
+ </security-constraint>
+
+</web-app>
+
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.yml.v1 b/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.yml.v1
new file mode 100644
index 0000000..1a7f872
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.yml.v1
@@ -0,0 +1,63 @@
+# 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.
+
+MiNiFi Config Version: 3
+Flow Controller:
+ name: MiNiFi Flow
+ comment: ''
+Core Properties:
+ flow controller graceful shutdown period: 10 sec
+ flow service write delay interval: 500 ms
+ administrative yield duration: 30 sec
+ bored yield duration: 10 millis
+ max concurrent threads: 1
+FlowFile Repository:
+ partitions: 256
+ checkpoint interval: 2 mins
+ always sync: false
+ Swap:
+ threshold: 20000
+ in period: 5 sec
+ in threads: 1
+ out period: 5 sec
+ out threads: 4
+Content Repository:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+Component Status Repository:
+ buffer size: 1440
+ snapshot frequency: 1 min
+Security Properties:
+ keystore: ''
+ keystore type: ''
+ keystore password: ''
+ key password: ''
+ truststore: ''
+ truststore type: ''
+ truststore password: ''
+ ssl protocol: ''
+ Sensitive Props:
+ key: ''
+ algorithm: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
diff --git a/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/pom.xml b/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/pom.xml
new file mode 100644
index 0000000..b11ddfa
--- /dev/null
+++ b/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2-cache</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-cache-filesystem</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemCacheFileInfoImpl.java b/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemCacheFileInfoImpl.java
new file mode 100644
index 0000000..ae2c1ae
--- /dev/null
+++ b/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemCacheFileInfoImpl.java
@@ -0,0 +1,86 @@
+/*
+ * 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.minifi.c2.cache.filesystem;
+
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.InvalidParameterException;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCacheFileInfo;
+import org.apache.nifi.minifi.c2.api.cache.WriteableConfiguration;
+import org.apache.nifi.minifi.c2.api.util.Pair;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+public class FileSystemCacheFileInfoImpl implements ConfigurationCacheFileInfo {
+ private final FileSystemConfigurationCache cache;
+ private final Path dirPath;
+ private final String expectedFilename;
+ private final int expectedFilenameLength;
+
+ public FileSystemCacheFileInfoImpl(FileSystemConfigurationCache cache, Path dirPath, String expectedFilename) {
+ this.cache = cache;
+ this.dirPath = dirPath;
+ this.expectedFilename = expectedFilename;
+ this.expectedFilenameLength = expectedFilename.length();
+ }
+
+ @Override
+ public Integer getVersionIfMatch(String filename) {
+ if (!filename.startsWith(expectedFilename) || filename.length() == expectedFilenameLength) {
+ return null;
+ }
+ try {
+ return Integer.parseInt(filename.substring(expectedFilenameLength));
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public Stream<WriteableConfiguration> getCachedConfigurations() throws IOException {
+ return Files.list(dirPath).map(p -> {
+ Integer version = getVersionIfMatch(p.getFileName().toString());
+ if (version == null) {
+ return null;
+ }
+ return new Pair<>(version, p);
+ }).filter(Objects::nonNull)
+ .sorted(Comparator.comparing(pair -> ((Pair<Integer, Path>) pair).getFirst())
+ .reversed()).map(pair -> new FileSystemWritableConfiguration(cache, pair.getSecond(), Integer.toString(pair.getFirst())));
+ }
+
+ @Override
+ public WriteableConfiguration getConfiguration(Integer version) throws ConfigurationProviderException {
+ if (version == null) {
+ try {
+ return getCachedConfigurations().findFirst().orElseThrow(() -> new ConfigurationProviderException("No configurations found for " + dirPath + "/" + expectedFilename + "[0-9]+"));
+ } catch (IOException e) {
+ throw new ConfigurationProviderException("Unable to get cached configurations.", e);
+ }
+ }
+ try {
+ return new FileSystemWritableConfiguration(cache, cache.resolveChildAndVerifyParent(dirPath, expectedFilename + version), Integer.toString(version));
+ } catch (NumberFormatException e) {
+ throw new InvalidParameterException("Expected numeric version.", e);
+ }
+ }
+}
diff --git a/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemConfigurationCache.java b/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemConfigurationCache.java
new file mode 100644
index 0000000..ced36a9
--- /dev/null
+++ b/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemConfigurationCache.java
@@ -0,0 +1,80 @@
+/*
+ * 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.minifi.c2.cache.filesystem;
+
+import org.apache.nifi.minifi.c2.api.InvalidParameterException;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCacheFileInfo;
+import org.apache.nifi.minifi.c2.api.util.Pair;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+public class FileSystemConfigurationCache implements ConfigurationCache {
+ private final Path pathRoot;
+ private final String pathPattern;
+
+ public FileSystemConfigurationCache(String pathRoot, String pathPattern) throws IOException {
+ this.pathRoot = Paths.get(System.getenv("C2_SERVER_HOME")).resolve(pathRoot).toAbsolutePath();
+ Files.createDirectories(this.pathRoot);
+ this.pathPattern = pathPattern;
+ }
+
+ protected Path resolveChildAndVerifyParent(Path parent, String s) throws InvalidParameterException {
+ Path child = parent.resolve(s).toAbsolutePath();
+ if (child.toAbsolutePath().getParent().equals(parent)) {
+ return child;
+ } else {
+ throw new InvalidParameterException("Path entry " + s + " not child of " + parent);
+ }
+ }
+
+ @Override
+ public ConfigurationCacheFileInfo getCacheFileInfo(Map<String, List<String>> parameters) throws InvalidParameterException {
+ String pathString = pathPattern;
+ for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
+ if (entry.getValue().size() != 1) {
+ throw new InvalidParameterException("Multiple values for same parameter not supported in this provider.");
+ }
+ pathString = pathString.replaceAll(Pattern.quote("${" + entry.getKey() + "}"), entry.getValue().get(0));
+ }
+ String[] split = pathString.split("/");
+ for (String s1 : split) {
+ int openBrace = s1.indexOf("${");
+ if (openBrace >= 0 && openBrace < s1.length() + 2) {
+ int closeBrace = s1.indexOf("}", openBrace + 2);
+ if (closeBrace >= 0) {
+ throw new InvalidParameterException("Found unsubstituted variable " + s1.substring(openBrace + 2, closeBrace));
+ }
+ }
+ }
+ String[] splitPath = split;
+ Path path = pathRoot.toAbsolutePath();
+ for (int i = 0; i < splitPath.length - 1; i++) {
+ String s = splitPath[i];
+ path = resolveChildAndVerifyParent(path, s);
+ }
+ Pair<Path, String> dirPathAndFilename = new Pair<>(path, splitPath[splitPath.length - 1]);
+ return new FileSystemCacheFileInfoImpl(this, dirPathAndFilename.getFirst(), dirPathAndFilename.getSecond() + ".v");
+ }
+}
diff --git a/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemWritableConfiguration.java b/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemWritableConfiguration.java
new file mode 100644
index 0000000..bb48dcc
--- /dev/null
+++ b/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemWritableConfiguration.java
@@ -0,0 +1,94 @@
+/*
+ * 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.minifi.c2.cache.filesystem;
+
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.InvalidParameterException;
+import org.apache.nifi.minifi.c2.api.cache.WriteableConfiguration;
+import org.apache.nifi.minifi.c2.api.util.DelegatingOutputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.UUID;
+
+public class FileSystemWritableConfiguration implements WriteableConfiguration {
+ private final FileSystemConfigurationCache cache;
+ private final Path path;
+ private final String version;
+
+ public FileSystemWritableConfiguration(FileSystemConfigurationCache cache, Path path, String version) {
+ this.cache = cache;
+ this.path = path;
+ this.version = version;
+ }
+
+ @Override
+ public String getVersion() {
+ return version;
+ }
+
+ @Override
+ public boolean exists() {
+ return Files.exists(path);
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws ConfigurationProviderException {
+ try {
+ Path parent = path.getParent();
+ Files.createDirectories(parent);
+ Path tmpPath = cache.resolveChildAndVerifyParent(parent, path.getFileName().toString() + "." + UUID.randomUUID().toString());
+ return new DelegatingOutputStream(Files.newOutputStream(tmpPath)) {
+ @Override
+ public void close() throws IOException {
+ super.close();
+ Files.move(tmpPath, path);
+ }
+ };
+ } catch (IOException e) {
+ throw new ConfigurationProviderException("Unable to open " + path + " for writing.", e);
+ }
+ }
+
+ @Override
+ public InputStream getInputStream() throws ConfigurationProviderException {
+ try {
+ return Files.newInputStream(path, StandardOpenOption.READ);
+ } catch (IOException e) {
+ if (Files.exists(path)) {
+ throw new ConfigurationProviderException("Unable to open " + path + " for reading.", e);
+ } else {
+ throw new InvalidParameterException("File not found: " + path, e);
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return path.getFileName().toString();
+ }
+
+ @Override
+ public String toString() {
+ return "FileSystemWritableConfiguration{path=" + path + ", version='" + version + "'}";
+ }
+}
diff --git a/minifi-c2/minifi-c2-cache/pom.xml b/minifi-c2/minifi-c2-cache/pom.xml
new file mode 100644
index 0000000..f452317
--- /dev/null
+++ b/minifi-c2/minifi-c2-cache/pom.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-cache</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>minifi-c2-cache-filesystem</module>
+ </modules>
+</project>
diff --git a/minifi-c2/minifi-c2-docker/README.md b/minifi-c2/minifi-c2-docker/README.md
new file mode 100644
index 0000000..9e0d846
--- /dev/null
+++ b/minifi-c2/minifi-c2-docker/README.md
@@ -0,0 +1,27 @@
+<!--
+ 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.
+-->
+
+Apache MiNiFi Command And Control Server
+-------------
+A subproject of Apache NiFi and a complementary data collection approach that supplements the core tenets of NiFi in dataflow management, focusing on the collection of data at the source of its creation.
+
+Specific goals for the initial thrust of the MiNiFi effort comprise:
+
+* small and lightweight footprint,
+* central management of agents,
+* generation of data provenance, and
+* integration with NiFi for follow-on dataflow management and full chain of custody of information.
+
+Perspectives of the role of MiNiFi should be from the perspective of the agent acting immediately at, or directly adjacent to, source sensors, systems, or servers.
diff --git a/minifi-c2/minifi-c2-docker/dockerhub/.dockerignore b/minifi-c2/minifi-c2-docker/dockerhub/.dockerignore
new file mode 100644
index 0000000..30a2650
--- /dev/null
+++ b/minifi-c2/minifi-c2-docker/dockerhub/.dockerignore
@@ -0,0 +1,19 @@
+# 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.
+
+# Place files you want to exclude from the docker build here similar to .gitignore https://docs.docker.com/engine/reference/builder/#dockerignore-file
+DockerBuild.sh
+DockerRun.sh
+DockerImage.txt
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-docker/dockerhub/DockerBuild.sh b/minifi-c2/minifi-c2-docker/dockerhub/DockerBuild.sh
new file mode 100755
index 0000000..0ce7783
--- /dev/null
+++ b/minifi-c2/minifi-c2-docker/dockerhub/DockerBuild.sh
@@ -0,0 +1,31 @@
+# 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.
+
+#!/bin/bash
+
+DOCKER_UID=1000
+if [ -n "$1" ]; then
+ DOCKER_UID="$1"
+fi
+
+DOCKER_GID=50
+if [ -n "$2" ]; then
+ DOCKER_GID="$2"
+fi
+
+DOCKER_IMAGE="$(egrep -v '(^#|^\s*$|^\s*\t*#)' DockerImage.txt)"
+MINIFI_C2_IMAGE_VERSION="$(echo $DOCKER_IMAGE | cut -d : -f 2)"
+echo "Building MiNiFi C2 Server Image: '$DOCKER_IMAGE' Version: $MINIFI_C2_IMAGE_VERSION"
+docker build --build-arg UID="$DOCKER_UID" --build-arg GID="$DOCKER_GID" --build-arg MINIFI_C2_VERSION="$MINIFI_C2_IMAGE_VERSION" -t $DOCKER_IMAGE .
diff --git a/minifi-c2/minifi-c2-docker/dockerhub/DockerImage.txt b/minifi-c2/minifi-c2-docker/dockerhub/DockerImage.txt
new file mode 100644
index 0000000..bc7c4a3
--- /dev/null
+++ b/minifi-c2/minifi-c2-docker/dockerhub/DockerImage.txt
@@ -0,0 +1,16 @@
+# 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.
+
+apacheminific2:0.1.0
diff --git a/minifi-c2/minifi-c2-docker/dockerhub/DockerRun.sh b/minifi-c2/minifi-c2-docker/dockerhub/DockerRun.sh
new file mode 100755
index 0000000..9436848
--- /dev/null
+++ b/minifi-c2/minifi-c2-docker/dockerhub/DockerRun.sh
@@ -0,0 +1,19 @@
+# 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.
+
+#!/bin/bash
+DOCKER_IMAGE="$(egrep -v '(^#|^\s*$|^\s*\t*#)' DockerImage.txt)"
+echo "Running Docker Image: $DOCKER_IMAGE"
+docker run -it -d $DOCKER_IMAGE
diff --git a/minifi-c2/minifi-c2-docker/dockerhub/Dockerfile b/minifi-c2/minifi-c2-docker/dockerhub/Dockerfile
new file mode 100644
index 0000000..f139052
--- /dev/null
+++ b/minifi-c2/minifi-c2-docker/dockerhub/Dockerfile
@@ -0,0 +1,49 @@
+# 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.
+#
+
+FROM openjdk:8
+MAINTAINER Apache MiNiFi <dev@nifi.apache.org>
+
+ARG UID=1000
+ARG GID=50
+ARG MINIFI_C2_VERSION=0.2.0
+
+ENV MINIFI_C2_BASE_DIR /opt/minifi-c2
+ENV MINIFI_C2_HOME $MINIFI_C2_BASE_DIR/minifi-c2-$MINIFI_C2_VERSION
+ENV MINIFI_C2_BINARY_URL https://archive.apache.org/dist/minifi/$MINIFI_C2_VERSION/minifi-c2-$MINIFI_C2_VERSION-bin.tar.gz
+
+# Setup c2 user
+RUN groupadd -g $GID c2 || groupmod -n c2 `getent group $GID | cut -d: -f1`
+RUN useradd --shell /bin/bash -u $UID -g $GID -m c2
+RUN mkdir -p $MINIFI_C2_HOME
+
+# Download, validate, and expand Apache MiNiFi C2 binary.
+RUN curl -fSL $MINIFI_C2_BINARY_URL -o $MINIFI_C2_BASE_DIR/minifi-c2-$MINIFI_C2_VERSION-bin.tar.gz \
+ && echo "$(curl $MINIFI_C2_BINARY_URL.sha256) *$MINIFI_C2_BASE_DIR/minifi-c2-$MINIFI_C2_VERSION-bin.tar.gz" | sha256sum -c - \
+ && tar -xvzf $MINIFI_C2_BASE_DIR/minifi-c2-$MINIFI_C2_VERSION-bin.tar.gz -C $MINIFI_C2_BASE_DIR \
+ && rm $MINIFI_C2_BASE_DIR/minifi-c2-$MINIFI_C2_VERSION-bin.tar.gz
+
+RUN chown -R c2:c2 $MINIFI_C2_HOME
+
+USER c2
+
+#Default http port
+EXPOSE 10080
+
+# Startup MiNiFi C2
+CMD $MINIFI_C2_HOME/bin/c2.sh
diff --git a/minifi-c2/minifi-c2-docker/dockermaven/Dockerfile b/minifi-c2/minifi-c2-docker/dockermaven/Dockerfile
new file mode 100644
index 0000000..329a110
--- /dev/null
+++ b/minifi-c2/minifi-c2-docker/dockermaven/Dockerfile
@@ -0,0 +1,44 @@
+# 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.
+#
+
+FROM openjdk:8
+MAINTAINER Apache MiNiFi <dev@nifi.apache.org>
+
+ARG UID=1000
+ARG GID=50
+ARG MINIFI_C2_VERSION
+ARG MINIFI_C2_BINARY
+
+ENV MINIFI_C2_BASE_DIR /opt/minifi-c2
+ENV MINIFI_C2_HOME $MINIFI_C2_BASE_DIR/minifi-c2-$MINIFI_C2_VERSION
+
+# Setup MiNiFi C2 user
+RUN groupadd -g $GID c2 || groupmod -n c2 `getent group $GID | cut -d: -f1`
+RUN useradd --shell /bin/bash -u $UID -g $GID -m c2
+RUN mkdir -p $MINIFI_C2_HOME
+
+ADD $MINIFI_C2_BINARY $MINIFI_C2_BASE_DIR
+RUN chown -R c2:c2 $MINIFI_C2_HOME
+
+USER c2
+
+#Default http port
+EXPOSE 10080
+
+# Startup MiNiFi c2
+CMD $MINIFI_C2_HOME/bin/c2.sh run
diff --git a/minifi-c2/minifi-c2-docker/pom.xml b/minifi-c2/minifi-c2-docker/pom.xml
new file mode 100644
index 0000000..edf91d4
--- /dev/null
+++ b/minifi-c2/minifi-c2-docker/pom.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-docker</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <properties>
+ <minifi.c2.version>${project.version}</minifi.c2.version>
+ </properties>
+
+ <profiles>
+ <!-- Profile for building official Docker images. Not bound to build phases since that would require anyone build to have the Docker engine installed on their machine -->
+ <profile>
+ <id>docker</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.spotify</groupId>
+ <artifactId>docker-maven-plugin</artifactId>
+ <version>0.4.13</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <imageName>apacheminific2</imageName>
+ <dockerDirectory>${project.basedir}/dockermaven</dockerDirectory>
+ <imageTags>
+ <imageTag>${minifi.c2.version}</imageTag>
+ </imageTags>
+ <buildArgs>
+ <UID>1000</UID>
+ <GID>1000</GID>
+ <MINIFI_C2_VERSION>${minifi.c2.version}</MINIFI_C2_VERSION>
+ <MINIFI_C2_BINARY>minifi-c2-${minifi.c2.version}-bin.tar.gz</MINIFI_C2_BINARY>
+ </buildArgs>
+ <resources>
+ <resource>
+ <targetPath>/</targetPath>
+ <directory>${project.basedir}/../minifi-c2-assembly/target</directory>
+ <include>minifi-c2-${minifi.c2.version}-bin.tar.gz</include>
+ </resource>
+ </resources>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/minifi-c2/minifi-c2-integration-tests/pom.xml b/minifi-c2/minifi-c2-integration-tests/pom.xml
new file mode 100644
index 0000000..60af910
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/pom.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-integration-tests</artifactId>
+ <packaging>jar</packaging>
+
+ <properties>
+ <minifi.c2.version>${project.version}</minifi.c2.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-commons-schema</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-api</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-toolkit-tls</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.palantir.docker.compose</groupId>
+ <artifactId>docker-compose-rule-junit4</artifactId>
+ <version>0.31.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <testResources>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <filtering>true</filtering>
+ <excludes>
+ <exclude>**/minifi-c2-context.xml</exclude>
+ </excludes>
+ </testResource>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <filtering>false</filtering>
+ <includes>
+ <include>**/minifi-c2-context.xml</include>
+ </includes>
+ </testResource>
+ </testResources>
+
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes combine.children="append">
+ <exclude>src/test/resources/mocknifi/www/nifi-api/flow/templates</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>docker</id>
+ <properties>
+ <name>docker</name>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <repositories>
+ <repository>
+ <id>palantir.bintray</id>
+ <name>Palantir Bintray</name>
+ <url>https://dl.bintray.com/palantir/releases</url>
+ </repository>
+ </repositories>
+</project>
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/AbstractTestSecure.java b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/AbstractTestSecure.java
new file mode 100644
index 0000000..222512f
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/AbstractTestSecure.java
@@ -0,0 +1,199 @@
+/*
+ * 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.minifi.c2.integration.test;
+
+import com.palantir.docker.compose.DockerComposeRule;
+import com.palantir.docker.compose.connection.DockerPort;
+import org.apache.commons.io.IOUtils;
+import org.apache.nifi.minifi.commons.schema.ConfigSchema;
+import org.apache.nifi.minifi.commons.schema.serialization.SchemaLoader;
+import org.apache.nifi.security.util.KeyStoreUtils;
+import org.apache.nifi.security.util.SslContextFactory;
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandalone;
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandaloneCommandLine;
+import org.junit.Test;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public abstract class AbstractTestSecure extends AbstractTestUnsecure {
+ public static final String C2_URL = "https://c2:10443/c2/config";
+
+ private final DockerComposeRule docker;
+ private final Path certificatesDirectory;
+ private final SSLContext trustSslContext;
+
+ protected AbstractTestSecure(DockerComposeRule docker, Path certificatesDirectory, SSLContext trustSslContext) {
+ this.docker = docker;
+ this.certificatesDirectory = certificatesDirectory;
+ this.trustSslContext = trustSslContext;
+ }
+
+ @Override
+ protected String getConfigUrl(DockerComposeRule docker) {
+ return C2_URL;
+ }
+
+ public static SSLContext initCertificates(Path certificatesDirectory, List<String> serverHostnames) throws Exception {
+ List<String> toolkitCommandLine = new ArrayList<>(Arrays.asList("-O", "-o", certificatesDirectory.toFile().getAbsolutePath(),
+ "-C", "CN=user1", "-C", "CN=user2", "-C", "CN=user3", "-C", "CN=user4", "-S", "badKeystorePass", "-K", "badKeyPass", "-P", "badTrustPass"));
+ for (String serverHostname : serverHostnames) {
+ toolkitCommandLine.add("-n");
+ toolkitCommandLine.add(serverHostname);
+ }
+ Files.createDirectories(certificatesDirectory);
+ TlsToolkitStandaloneCommandLine tlsToolkitStandaloneCommandLine = new TlsToolkitStandaloneCommandLine();
+ tlsToolkitStandaloneCommandLine.parse(toolkitCommandLine.toArray(new String[toolkitCommandLine.size()]));
+ new TlsToolkitStandalone().createNifiKeystoresAndTrustStores(tlsToolkitStandaloneCommandLine.createConfig());
+
+ tlsToolkitStandaloneCommandLine = new TlsToolkitStandaloneCommandLine();
+ tlsToolkitStandaloneCommandLine.parse(new String[]{"-O", "-o", certificatesDirectory.getParent().resolve("badCert").toFile().getAbsolutePath(), "-C", "CN=user3"});
+ new TlsToolkitStandalone().createNifiKeystoresAndTrustStores(tlsToolkitStandaloneCommandLine.createConfig());
+
+ final KeyStore trustStore = KeyStoreUtils.getTrustStore("jks");
+ try (final InputStream trustStoreStream = new FileInputStream(certificatesDirectory.resolve("c2").resolve("truststore.jks").toFile().getAbsolutePath())) {
+ trustStore.load(trustStoreStream, "badTrustPass".toCharArray());
+ }
+ final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(trustStore);
+
+ return SslContextFactory.createTrustSslContext(certificatesDirectory.resolve("c2").resolve("truststore.jks").toFile().getAbsolutePath(), "badTrustPass".toCharArray(), "jks", "TLS");
+ }
+
+ @Test
+ public void testNoClientCert() throws Exception {
+ assertReturnCode("", trustSslContext, 403);
+ assertReturnCode("?class=raspi2", trustSslContext, 403);
+ assertReturnCode("?class=raspi3", trustSslContext, 403);
+ }
+
+ @Test
+ public void testUser1() throws Exception {
+ SSLContext sslContext = loadSslContext("user1");
+
+ assertReturnCode("", sslContext, 403);
+
+ ConfigSchema configSchema = assertReturnCode("?class=raspi2", sslContext, 200);
+ assertEquals("raspi2.v1", configSchema.getFlowControllerProperties().getName());
+
+ assertReturnCode("?class=raspi3", sslContext, 403);
+ }
+
+ @Test
+ public void testUser2() throws Exception {
+ SSLContext sslContext = loadSslContext("user2");
+
+ assertReturnCode("", sslContext, 403);
+ assertReturnCode("?class=raspi2", sslContext, 403);
+
+ ConfigSchema configSchema = assertReturnCode("?class=raspi3", sslContext, 200);
+ assertEquals("raspi3.v2", configSchema.getFlowControllerProperties().getName());
+ }
+
+ @Test
+ public void testUser3() throws Exception {
+ SSLContext sslContext = loadSslContext("user3");
+
+ assertReturnCode("", sslContext, 400);
+
+ ConfigSchema configSchema = assertReturnCode("?class=raspi2", sslContext, 200);
+ assertEquals("raspi2.v1", configSchema.getFlowControllerProperties().getName());
+
+ configSchema = assertReturnCode("?class=raspi3", sslContext, 200);
+ assertEquals("raspi3.v2", configSchema.getFlowControllerProperties().getName());
+ }
+
+ @Test(expected = IOException.class)
+ public void testUser3WrongCA() throws Exception {
+ assertReturnCode("?class=raspi3", loadSslContext("user3", certificatesDirectory.getParent().resolve("badCert")), 403);
+ }
+
+ @Test
+ public void testUser4() throws Exception {
+ SSLContext sslContext = loadSslContext("user4");
+
+ assertReturnCode("", sslContext, 403);
+ assertReturnCode("?class=raspi2", sslContext, 403);
+ assertReturnCode("?class=raspi3", sslContext, 403);
+ }
+
+ protected SSLContext loadSslContext(String username) throws GeneralSecurityException, IOException {
+ return loadSslContext(username, certificatesDirectory);
+ }
+
+ protected SSLContext loadSslContext(String username, Path directory) throws GeneralSecurityException, IOException {
+ char[] keystorePasswd;
+ try (InputStream inputStream = Files.newInputStream(directory.resolve("CN=" + username + ".password"))) {
+ keystorePasswd = IOUtils.toString(inputStream, StandardCharsets.UTF_8).toCharArray();
+ }
+ return SslContextFactory.createSslContext(
+ directory.resolve("CN=" + username + ".p12").toFile().getAbsolutePath(),
+ keystorePasswd,
+ "PKCS12",
+ certificatesDirectory.resolve("c2").resolve("truststore.jks").toFile().getAbsolutePath(),
+ "badTrustPass".toCharArray(), "jks", SslContextFactory.ClientAuth.NONE, "TLS");
+ }
+
+ protected ConfigSchema assertReturnCode(String query, SSLContext sslContext, int expectedReturnCode) throws Exception {
+ HttpsURLConnection httpsURLConnection = openUrlConnection(C2_URL + query, sslContext);
+ try {
+ assertEquals(expectedReturnCode, httpsURLConnection.getResponseCode());
+ if (expectedReturnCode == 200) {
+ return SchemaLoader.loadConfigSchemaFromYaml(httpsURLConnection.getInputStream());
+ }
+ } finally {
+ httpsURLConnection.disconnect();
+ }
+ return null;
+ }
+
+ protected HttpsURLConnection openUrlConnection(String url, SSLContext sslContext) throws IOException {
+ DockerPort dockerPort = docker.containers().container("squid").port(3128);
+ HttpsURLConnection httpURLConnection = (HttpsURLConnection) new URL(url).openConnection(
+ new Proxy(Proxy.Type.HTTP, new InetSocketAddress(dockerPort.getIp(), dockerPort.getExternalPort())));
+ httpURLConnection.setSSLSocketFactory(sslContext.getSocketFactory());
+ return httpURLConnection;
+ }
+
+ @Override
+ protected HttpURLConnection openSuperUserUrlConnection(String url) throws IOException {
+ try {
+ return openUrlConnection(url, loadSslContext("user3"));
+ } catch (GeneralSecurityException e) {
+ throw new IOException(e);
+ }
+ }
+}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/AbstractTestUnsecure.java b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/AbstractTestUnsecure.java
new file mode 100644
index 0000000..27a9683
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/AbstractTestUnsecure.java
@@ -0,0 +1,107 @@
+/*
+ * 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.minifi.c2.integration.test;
+
+import com.palantir.docker.compose.DockerComposeRule;
+import com.palantir.docker.compose.connection.Container;
+import com.palantir.docker.compose.connection.DockerPort;
+import org.apache.nifi.minifi.commons.schema.ConfigSchema;
+import org.apache.nifi.minifi.commons.schema.exception.SchemaLoaderException;
+import org.apache.nifi.minifi.commons.schema.serialization.SchemaLoader;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import static org.junit.Assert.assertEquals;
+
+public abstract class AbstractTestUnsecure {
+ protected String c2Url;
+
+ public static String getUnsecureConfigUrl(Container container) {
+ DockerPort dockerPort = container.port(10080);
+ return "http://" + dockerPort.getIp() + ":" + dockerPort.getExternalPort() + "/c2/config";
+ }
+
+ protected void setup(DockerComposeRule docker) {
+ c2Url = getConfigUrl(docker);
+ }
+
+ protected String getConfigUrl(DockerComposeRule docker) {
+ return getUnsecureConfigUrl(docker.containers().container("c2"));
+ }
+
+ @Test
+ public void testCurrentVersion() throws IOException, SchemaLoaderException {
+ ConfigSchema configSchema = getConfigSchema(c2Url + "?class=raspi3");
+ assertEquals(3, configSchema.getVersion());
+ assertEquals("raspi3.v2", configSchema.getFlowControllerProperties().getName());
+ }
+
+ @Test
+ public void testVersion1() throws IOException, SchemaLoaderException {
+ ConfigSchema configSchema = getConfigSchema(c2Url + "?class=raspi3&version=1");
+ assertEquals(3, configSchema.getVersion());
+ assertEquals("raspi3.v1", configSchema.getFlowControllerProperties().getName());
+ }
+
+ @Test
+ public void testVersion2() throws IOException, SchemaLoaderException {
+ ConfigSchema configSchema = getConfigSchema(c2Url + "?class=raspi3&version=2");
+ assertEquals(3, configSchema.getVersion());
+ assertEquals("raspi3.v2", configSchema.getFlowControllerProperties().getName());
+ }
+
+ @Test
+ public void testUnacceptable() throws IOException {
+ HttpURLConnection urlConnection = openSuperUserUrlConnection(c2Url + "?class=raspi3");
+ try {
+ urlConnection.setRequestProperty("Accept", "text/xml");
+ assertEquals(406, urlConnection.getResponseCode());
+ } finally {
+ urlConnection.disconnect();
+ }
+ }
+
+ @Test
+ public void testInvalid() throws IOException {
+ HttpURLConnection urlConnection = openSuperUserUrlConnection(c2Url);
+ try {
+ assertEquals(400, urlConnection.getResponseCode());
+ } finally {
+ urlConnection.disconnect();
+ }
+ }
+
+ public ConfigSchema getConfigSchema(String urlString) throws IOException, SchemaLoaderException {
+ HttpURLConnection urlConnection = openSuperUserUrlConnection(urlString);
+ ConfigSchema configSchema;
+ try (InputStream inputStream = urlConnection.getInputStream()) {
+ configSchema = SchemaLoader.loadConfigSchemaFromYaml(inputStream);
+ } finally {
+ urlConnection.disconnect();
+ }
+ return configSchema;
+ }
+
+ protected HttpURLConnection openSuperUserUrlConnection(String url) throws IOException {
+ return (HttpURLConnection) new URL(url).openConnection();
+ }
+}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/FileSystemCacheProviderSecureTest.java b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/FileSystemCacheProviderSecureTest.java
new file mode 100644
index 0000000..14ad4ae
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/FileSystemCacheProviderSecureTest.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.minifi.c2.integration.test;
+
+import com.palantir.docker.compose.DockerComposeRule;
+import org.apache.nifi.minifi.c2.integration.test.health.HttpsStatusCodeHealthCheck;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+public class FileSystemCacheProviderSecureTest extends AbstractTestSecure {
+ private static SSLSocketFactory healthCheckSocketFactory;
+
+ // Not annotated as rule because we need to generate certificatesDirectory first
+ public static DockerComposeRule docker = DockerComposeRule.builder()
+ .file("target/test-classes/docker-compose-FileSystemCacheProviderSecureTest.yml")
+ .waitingForServices(Arrays.asList("squid", "c2"),
+ new HttpsStatusCodeHealthCheck(container -> C2_URL, containers -> containers.get(0), containers -> containers.get(1), () -> healthCheckSocketFactory, 403))
+ .build();
+ private static Path certificatesDirectory;
+ private static SSLContext trustSslContext;
+
+ public FileSystemCacheProviderSecureTest() {
+ super(docker, certificatesDirectory, trustSslContext);
+ }
+
+ /**
+ * Generates certificates with the tls-toolkit and then starts up the docker compose file
+ */
+ @BeforeClass
+ public static void initCertificates() throws Exception {
+ certificatesDirectory = Paths.get(FileSystemCacheProviderSecureTest.class.getClassLoader()
+ .getResource("docker-compose-FileSystemCacheProviderSecureTest.yml").getFile()).getParent().toAbsolutePath().resolve("certificates-FileSystemCacheProviderSecureTest");
+ trustSslContext = initCertificates(certificatesDirectory, Arrays.asList("c2"));
+ healthCheckSocketFactory = trustSslContext.getSocketFactory();
+ docker.before();
+ }
+
+ @AfterClass
+ public static void cleanup() {
+ docker.after();
+ }
+
+ @Before
+ public void setup() {
+ super.setup(docker);
+ }
+}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/FileSystemCacheProviderUnsecureTest.java b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/FileSystemCacheProviderUnsecureTest.java
new file mode 100644
index 0000000..9834d80
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/FileSystemCacheProviderUnsecureTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.minifi.c2.integration.test;
+
+import com.palantir.docker.compose.DockerComposeRule;
+import org.apache.nifi.minifi.c2.integration.test.health.HttpStatusCodeHealthCheck;
+import org.junit.Before;
+import org.junit.ClassRule;
+
+public class FileSystemCacheProviderUnsecureTest extends AbstractTestUnsecure {
+ @ClassRule
+ public static DockerComposeRule docker = DockerComposeRule.builder()
+ .file("target/test-classes/docker-compose-FileSystemProviderUnsecureTest.yml")
+ .waitingForService("c2", new HttpStatusCodeHealthCheck(FileSystemCacheProviderUnsecureTest::getUnsecureConfigUrl, 400))
+ .build();
+
+ @Before
+ public void setup() {
+ super.setup(docker);
+ }
+}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/NiFiRestConfigurationProviderSecureTest.java b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/NiFiRestConfigurationProviderSecureTest.java
new file mode 100644
index 0000000..9ce4a9f
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/NiFiRestConfigurationProviderSecureTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.minifi.c2.integration.test;
+
+import com.palantir.docker.compose.DockerComposeRule;
+import org.apache.nifi.minifi.c2.integration.test.health.HttpsStatusCodeHealthCheck;
+import org.apache.nifi.security.util.SslContextFactory;
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandalone;
+import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator;
+import org.bouncycastle.util.io.pem.PemWriter;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.util.Arrays;
+
+public class NiFiRestConfigurationProviderSecureTest extends AbstractTestSecure {
+ private static SSLSocketFactory healthCheckSocketFactory;
+ private static Path certificatesDirectory;
+ private static SSLContext trustSslContext;
+
+ // Not annotated as rule because we need to generate certificatesDirectory first
+ public static DockerComposeRule docker = DockerComposeRule.builder()
+ .file("target/test-classes/docker-compose-NiFiRestConfigurationProviderSecureTest.yml")
+ .waitingForServices(Arrays.asList("squid", "mocknifi"),
+ new HttpsStatusCodeHealthCheck(container -> "https://mocknifi:8443/", containers -> containers.get(0), containers -> containers.get(1), () -> {
+ Path c2 = certificatesDirectory.resolve("c2");
+ try {
+ return SslContextFactory.createSslContext(c2.resolve("keystore.jks").toFile().getAbsolutePath(), "badKeystorePass".toCharArray(), "badKeyPass".toCharArray(), "JKS",
+ c2.resolve("truststore.jks").toFile().getAbsolutePath(), "badTrustPass".toCharArray(), "JKS", SslContextFactory.ClientAuth.NONE, "TLS").getSocketFactory();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }, 200))
+ .waitingForServices(Arrays.asList("squid", "c2"),
+ new HttpsStatusCodeHealthCheck(container -> C2_URL, containers -> containers.get(0), containers -> containers.get(1), () -> healthCheckSocketFactory, 403))
+ .build();
+
+ public NiFiRestConfigurationProviderSecureTest() {
+ super(docker, certificatesDirectory, trustSslContext);
+ }
+
+ /**
+ * Generates certificates with the tls-toolkit and then starts up the docker compose file
+ */
+ @BeforeClass
+ public static void initCertificates() throws Exception {
+ certificatesDirectory = Paths.get(NiFiRestConfigurationProviderSecureTest.class.getClassLoader()
+ .getResource("docker-compose-NiFiRestConfigurationProviderSecureTest.yml").getFile()).getParent().toAbsolutePath().resolve("certificates-NiFiRestConfigurationProviderSecureTest");
+ trustSslContext = initCertificates(certificatesDirectory, Arrays.asList("c2", "mocknifi"));
+ healthCheckSocketFactory = trustSslContext.getSocketFactory();
+
+ KeyStore mockNiFiKeyStore = KeyStore.getInstance("JKS");
+ try (InputStream inputStream = Files.newInputStream(certificatesDirectory.resolve("mocknifi").resolve("keystore.jks"))) {
+ mockNiFiKeyStore.load(inputStream, "badKeystorePass".toCharArray());
+ }
+ try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(Files.newOutputStream(certificatesDirectory.resolve("mocknifi").resolve("cert.pem"))))) {
+ pemWriter.writeObject(new JcaMiscPEMGenerator(mockNiFiKeyStore.getKey(TlsToolkitStandalone.NIFI_KEY, "badKeyPass".toCharArray())));
+ for (Certificate certificate : mockNiFiKeyStore.getCertificateChain(TlsToolkitStandalone.NIFI_KEY)) {
+ pemWriter.writeObject(new JcaMiscPEMGenerator(certificate));
+ }
+ }
+
+ KeyStore mockNiFiTrustStore = KeyStore.getInstance("JKS");
+ try (InputStream inputStream = Files.newInputStream(certificatesDirectory.resolve("mocknifi").resolve("truststore.jks"))) {
+ mockNiFiTrustStore.load(inputStream, "badTrustPass".toCharArray());
+ }
+ try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(Files.newOutputStream(certificatesDirectory.resolve("mocknifi").resolve("ca.pem"))))) {
+ pemWriter.writeObject(new JcaMiscPEMGenerator(mockNiFiTrustStore.getCertificate(TlsToolkitStandalone.NIFI_CERT)));
+ }
+
+ docker.before();
+ }
+
+ @AfterClass
+ public static void cleanup() {
+ docker.after();
+ }
+
+ @Before
+ public void setup() {
+ super.setup(docker);
+ }
+}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/NiFiRestConfigurationProviderUnsecureTest.java b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/NiFiRestConfigurationProviderUnsecureTest.java
new file mode 100644
index 0000000..b444cc1
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/NiFiRestConfigurationProviderUnsecureTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.minifi.c2.integration.test;
+
+import com.palantir.docker.compose.DockerComposeRule;
+import com.palantir.docker.compose.connection.waiting.HealthChecks;
+import org.apache.nifi.minifi.c2.integration.test.health.HttpStatusCodeHealthCheck;
+import org.junit.Before;
+import org.junit.ClassRule;
+
+public class NiFiRestConfigurationProviderUnsecureTest extends AbstractTestUnsecure {
+ @ClassRule
+ public static DockerComposeRule docker = DockerComposeRule.builder()
+ .file("target/test-classes/docker-compose-NiFiRestConfigurationProviderUnsecureTest.yml")
+ .waitingForService("mocknifi", HealthChecks.toRespond2xxOverHttp(8080,
+ dockerPort -> "http://" + dockerPort.getIp() + ":" + dockerPort.getExternalPort() + "/"))
+ .waitingForService("c2", new HttpStatusCodeHealthCheck(FileSystemCacheProviderUnsecureTest::getUnsecureConfigUrl, 400))
+ .build();
+
+ @Before
+ public void setup() {
+ super.setup(docker);
+ }
+}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/health/HttpStatusCodeHealthCheck.java b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/health/HttpStatusCodeHealthCheck.java
new file mode 100644
index 0000000..f639d96
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/health/HttpStatusCodeHealthCheck.java
@@ -0,0 +1,55 @@
+/*
+ * 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.minifi.c2.integration.test.health;
+
+import com.palantir.docker.compose.connection.Container;
+import com.palantir.docker.compose.connection.waiting.HealthCheck;
+import com.palantir.docker.compose.connection.waiting.SuccessOrFailure;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.function.Function;
+
+public class HttpStatusCodeHealthCheck implements HealthCheck<Container> {
+ private final Function<Container, String> urlFunction;
+ private final int expected;
+
+ public HttpStatusCodeHealthCheck(Function<Container, String> urlFunction, int expected) {
+ this.urlFunction = urlFunction;
+ this.expected = expected;
+ }
+
+ @Override
+ public SuccessOrFailure isHealthy(Container target) {
+ try {
+ int responseCode = openConnection(urlFunction.apply(target)).getResponseCode();
+ if (responseCode == expected) {
+ return SuccessOrFailure.success();
+ } else {
+ return SuccessOrFailure.failure("Expected Status code " + expected + " got " + responseCode);
+ }
+ } catch (IOException e) {
+ return SuccessOrFailure.failure("Expected Status code " + expected + " got IOException " + e.getMessage());
+ }
+ }
+
+ protected HttpURLConnection openConnection(String url) throws IOException {
+ return ((HttpURLConnection) new URL(url).openConnection());
+ }
+}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/health/HttpsStatusCodeHealthCheck.java b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/health/HttpsStatusCodeHealthCheck.java
new file mode 100644
index 0000000..9842e78
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/health/HttpsStatusCodeHealthCheck.java
@@ -0,0 +1,70 @@
+/*
+ * 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.minifi.c2.integration.test.health;
+
+import com.palantir.docker.compose.connection.Container;
+import com.palantir.docker.compose.connection.DockerPort;
+import com.palantir.docker.compose.connection.waiting.HealthCheck;
+import com.palantir.docker.compose.connection.waiting.SuccessOrFailure;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URL;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public class HttpsStatusCodeHealthCheck implements HealthCheck<List<Container>> {
+ private final Function<Container, String> urlFunction;
+ private final Function<List<Container>, Container> proxyExtractor;
+ private final Function<List<Container>, Container> serverExtractor;
+ private final Supplier<SSLSocketFactory> sslSocketFactorySupplier;
+ private final int expected;
+
+ public HttpsStatusCodeHealthCheck(Function<Container, String> urlFunction, Function<List<Container>, Container> proxyExtractor,
+ Function<List<Container>, Container> serverExtractor, Supplier<SSLSocketFactory> sslSocketFactorySupplier, int expected) {
+ this.urlFunction = urlFunction;
+ this.proxyExtractor = proxyExtractor;
+ this.serverExtractor = serverExtractor;
+ this.sslSocketFactorySupplier = sslSocketFactorySupplier;
+ this.expected = expected;
+ }
+
+ @Override
+ public SuccessOrFailure isHealthy(List<Container> target) {
+
+ return new HttpStatusCodeHealthCheck(urlFunction, expected) {
+ @Override
+ protected HttpURLConnection openConnection(String url) throws IOException {
+ DockerPort dockerPort = proxyExtractor.apply(target).port(3128);
+ return getHttpURLConnection(url, sslSocketFactorySupplier.get(), dockerPort.getIp(), dockerPort.getExternalPort());
+ }
+ }.isHealthy(serverExtractor.apply(target));
+ }
+
+ public static HttpURLConnection getHttpURLConnection(String url, SSLSocketFactory sslSocketFactory, String proxyHostname, int proxyPort) throws IOException {
+ HttpsURLConnection httpURLConnection = (HttpsURLConnection) new URL(url).openConnection(
+ new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHostname, proxyPort)));
+ httpURLConnection.setSSLSocketFactory(sslSocketFactory);
+ return httpURLConnection;
+ }
+}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-rest/conf/minifi-c2-context.xml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-rest/conf/minifi-c2-context.xml
new file mode 100644
index 0000000..d648d88
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-rest/conf/minifi-c2-context.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ 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.
+ -->
+
+<beans default-lazy-init="true"
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
+
+ <bean id="configService" class="org.apache.nifi.minifi.c2.service.ConfigService" scope="singleton">
+ <constructor-arg>
+ <list>
+ <bean class="org.apache.nifi.minifi.c2.provider.nifi.rest.NiFiRestConfigurationProvider">
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.cache.filesystem.FileSystemConfigurationCache">
+ <constructor-arg>
+ <value>./cache</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>${class}/${class}</value>
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ <constructor-arg>
+ <value>https://mocknifi:8443/nifi-api</value>
+ </constructor-arg>
+ </bean>
+ </list>
+ </constructor-arg>
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.security.authorization.GrantedAuthorityAuthorizer">
+ <constructor-arg value="classpath:authorizations.yaml"/>
+ </bean>
+ </constructor-arg>
+ </bean>
+</beans>
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure/conf/authorities.yaml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure/conf/authorities.yaml
new file mode 100644
index 0000000..c137c00
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure/conf/authorities.yaml
@@ -0,0 +1,21 @@
+# 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.
+
+CN=user1:
+ - CLASS_RASPI_2
+CN=user2:
+ - CLASS_RASPI_3
+CN=user3:
+ - ROLE_SUPERUSER
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure/conf/authorizations.yaml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure/conf/authorizations.yaml
new file mode 100644
index 0000000..fec97d5
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure/conf/authorizations.yaml
@@ -0,0 +1,30 @@
+# 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.
+
+Default Action: deny
+Paths:
+ /c2/config:
+ Default Action: deny
+ Actions:
+ - Authorization: CLASS_RASPI_3
+ Query Parameters:
+ class: raspi3
+ Action: allow
+ - Authorization: CLASS_RASPI_2
+ Query Parameters:
+ class: raspi2
+ Action: allow
+ - Authorization: ROLE_SUPERUSER
+ Action: allow
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure/conf/c2.properties b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure/conf/c2.properties
new file mode 100644
index 0000000..b683350
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure/conf/c2.properties
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+minifi.c2.server.port=10443
+
+minifi.c2.server.secure=true
+minifi.c2.server.keystore=./conf/keystore.jks
+minifi.c2.server.keystoreType=JKS
+minifi.c2.server.keystorePasswd=badKeystorePass
+minifi.c2.server.keyPasswd=badKeyPass
+minifi.c2.server.truststore=./conf/truststore.jks
+minifi.c2.server.truststoreType=JKS
+minifi.c2.server.truststorePasswd=badTrustPass
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-rest/conf/minifi-c2-context.xml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-rest/conf/minifi-c2-context.xml
new file mode 100644
index 0000000..f2e4eee
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-rest/conf/minifi-c2-context.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ 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.
+ -->
+<beans default-lazy-init="true"
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
+
+ <bean id="configService" class="org.apache.nifi.minifi.c2.service.ConfigService" scope="singleton">
+ <constructor-arg>
+ <list>
+ <bean class="org.apache.nifi.minifi.c2.provider.nifi.rest.NiFiRestConfigurationProvider">
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.cache.filesystem.FileSystemConfigurationCache">
+ <constructor-arg>
+ <value>./cache</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>${class}/${class}</value>
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ <constructor-arg>
+ <value>http://mocknifi:8080/nifi-api</value>
+ </constructor-arg>
+ </bean>
+ </list>
+ </constructor-arg>
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.security.authorization.GrantedAuthorityAuthorizer">
+ <constructor-arg value="classpath:authorizations.yaml"/>
+ </bean>
+ </constructor-arg>
+ </bean>
+</beans>
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.yml.v1 b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.yml.v1
new file mode 100644
index 0000000..116426f
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.yml.v1
@@ -0,0 +1,63 @@
+# 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.
+
+MiNiFi Config Version: 3
+Flow Controller:
+ name: raspi2.v1
+ comment: ''
+Core Properties:
+ flow controller graceful shutdown period: 10 sec
+ flow service write delay interval: 500 ms
+ administrative yield duration: 30 sec
+ bored yield duration: 10 millis
+ max concurrent threads: 1
+FlowFile Repository:
+ partitions: 256
+ checkpoint interval: 2 mins
+ always sync: false
+ Swap:
+ threshold: 20000
+ in period: 5 sec
+ in threads: 1
+ out period: 5 sec
+ out threads: 4
+Content Repository:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+Component Status Repository:
+ buffer size: 1440
+ snapshot frequency: 1 min
+Security Properties:
+ keystore: ''
+ keystore type: ''
+ keystore password: ''
+ key password: ''
+ truststore: ''
+ truststore type: ''
+ truststore password: ''
+ ssl protocol: ''
+ Sensitive Props:
+ key: ''
+ algorithm: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v1 b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v1
new file mode 100644
index 0000000..690cdaa
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v1
@@ -0,0 +1,63 @@
+# 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.
+
+MiNiFi Config Version: 3
+Flow Controller:
+ name: raspi3.v1
+ comment: ''
+Core Properties:
+ flow controller graceful shutdown period: 10 sec
+ flow service write delay interval: 500 ms
+ administrative yield duration: 30 sec
+ bored yield duration: 10 millis
+ max concurrent threads: 1
+FlowFile Repository:
+ partitions: 256
+ checkpoint interval: 2 mins
+ always sync: false
+ Swap:
+ threshold: 20000
+ in period: 5 sec
+ in threads: 1
+ out period: 5 sec
+ out threads: 4
+Content Repository:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+Component Status Repository:
+ buffer size: 1440
+ snapshot frequency: 1 min
+Security Properties:
+ keystore: ''
+ keystore type: ''
+ keystore password: ''
+ key password: ''
+ truststore: ''
+ truststore type: ''
+ truststore password: ''
+ ssl protocol: ''
+ Sensitive Props:
+ key: ''
+ algorithm: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v2 b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v2
new file mode 100644
index 0000000..14750b6
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v2
@@ -0,0 +1,63 @@
+# 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.
+
+MiNiFi Config Version: 3
+Flow Controller:
+ name: raspi3.v2
+ comment: ''
+Core Properties:
+ flow controller graceful shutdown period: 10 sec
+ flow service write delay interval: 500 ms
+ administrative yield duration: 30 sec
+ bored yield duration: 10 millis
+ max concurrent threads: 1
+FlowFile Repository:
+ partitions: 256
+ checkpoint interval: 2 mins
+ always sync: false
+ Swap:
+ threshold: 20000
+ in period: 5 sec
+ in threads: 1
+ out period: 5 sec
+ out threads: 4
+Content Repository:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+Component Status Repository:
+ buffer size: 1440
+ snapshot frequency: 1 min
+Security Properties:
+ keystore: ''
+ keystore type: ''
+ keystore password: ''
+ key password: ''
+ truststore: ''
+ truststore type: ''
+ truststore password: ''
+ ssl protocol: ''
+ Sensitive Props:
+ key: ''
+ algorithm: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-FileSystemCacheProviderSecureTest.yml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-FileSystemCacheProviderSecureTest.yml
new file mode 100644
index 0000000..27768d4
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-FileSystemCacheProviderSecureTest.yml
@@ -0,0 +1,40 @@
+# 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.
+
+version: "2"
+
+services:
+ c2:
+ image: apacheminific2:${minifi.c2.version}
+ ports:
+ - "10443"
+ hostname: c2
+ volumes:
+ - ./c2/files:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/files
+
+ - ./c2-secure/conf/c2.properties:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/c2.properties
+ - ./c2-secure/conf/authorities.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorities.yaml
+ - ./c2-secure/conf/authorizations.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorizations.yaml
+
+ - ./certificates-FileSystemCacheProviderSecureTest/c2/keystore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/keystore.jks
+ - ./certificates-FileSystemCacheProviderSecureTest/c2/truststore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/truststore.jks
+
+ squid:
+ image: chrisdaish/squid
+ ports:
+ - "3128"
+ hostname: squid
+ volumes:
+ - ./squid/squid.conf:/etc/squid/squid.conf
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-FileSystemProviderUnsecureTest.yml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-FileSystemProviderUnsecureTest.yml
new file mode 100644
index 0000000..fe4f8ec
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-FileSystemProviderUnsecureTest.yml
@@ -0,0 +1,25 @@
+# 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.
+
+version: "2"
+
+services:
+ c2:
+ image: apacheminific2:${minifi.c2.version}
+ ports:
+ - "10080"
+ hostname: c2
+ volumes:
+ - ./c2/files:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/files
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-NiFiRestConfigurationProviderSecureTest.yml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-NiFiRestConfigurationProviderSecureTest.yml
new file mode 100644
index 0000000..8665b7f
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-NiFiRestConfigurationProviderSecureTest.yml
@@ -0,0 +1,55 @@
+# 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.
+
+version: "2"
+
+services:
+ c2:
+ image: apacheminific2:${minifi.c2.version}
+ ports:
+ - "10443"
+ hostname: c2
+ volumes:
+ - ./c2-secure/conf/c2.properties:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/c2.properties
+ - ./c2-secure/conf/authorities.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorities.yaml
+ - ./c2-secure/conf/authorizations.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorizations.yaml
+ - ./c2-secure-rest/conf/minifi-c2-context.xml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/minifi-c2-context.xml
+
+ - ./certificates-NiFiRestConfigurationProviderSecureTest/c2/keystore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/keystore.jks
+ - ./certificates-NiFiRestConfigurationProviderSecureTest/c2/truststore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/truststore.jks
+
+ squid:
+ image: chrisdaish/squid
+ ports:
+ - "3128"
+ hostname: squid
+ volumes:
+ - ./squid/squid.conf:/etc/squid/squid.conf
+
+ mocknifi:
+ image: python:2
+ ports:
+ - "8443"
+ hostname: mocknifi
+ volumes:
+ - ./mocknifi-secure/server.py:/root/server.py
+ - ./mocknifi/www:/var/www
+
+ - ./certificates-NiFiRestConfigurationProviderSecureTest/mocknifi/cert.pem:/root/cert.pem
+ - ./certificates-NiFiRestConfigurationProviderSecureTest/mocknifi/ca.pem:/root/ca.pem
+ working_dir: /var/www
+ entrypoint:
+ - python
+ - /root/server.py
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-NiFiRestConfigurationProviderUnsecureTest.yml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-NiFiRestConfigurationProviderUnsecureTest.yml
new file mode 100644
index 0000000..a80428c
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-NiFiRestConfigurationProviderUnsecureTest.yml
@@ -0,0 +1,37 @@
+# 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.
+
+version: "2"
+
+services:
+ c2:
+ image: apacheminific2:${minifi.c2.version}
+ ports:
+ - "10080"
+ hostname: c2
+ volumes:
+ - ./c2-unsecure-rest/conf/minifi-c2-context.xml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/minifi-c2-context.xml
+ mocknifi:
+ image: python:2
+ ports:
+ - "8080"
+ hostname: mocknifi
+ volumes:
+ - ./mocknifi-unsecure/server.py:/root/server.py
+ - ./mocknifi/www:/var/www
+ working_dir: /var/www
+ entrypoint:
+ - python
+ - /root/server.py
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi-secure/server.py b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi-secure/server.py
new file mode 100644
index 0000000..fe869a8
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi-secure/server.py
@@ -0,0 +1,48 @@
+# 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.
+
+#!/usr/bin/env python
+
+import logging
+
+from argparse import ArgumentParser
+from BaseHTTPServer import HTTPServer
+from os import chdir
+from SimpleHTTPServer import SimpleHTTPRequestHandler
+from SocketServer import ThreadingMixIn
+from ssl import CERT_REQUIRED, wrap_socket
+
+# Needs to be threaded or health check hangs the server
+class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
+ pass
+
+if __name__ == '__main__':
+ logging.basicConfig(level=logging.DEBUG)
+ parser = ArgumentParser(description='Serve up directory with ssl')
+ parser.add_argument('--dir', default='/var/www')
+ parser.add_argument('--port', type=int, default=8443)
+ parser.add_argument('--cert', default='/root/cert.pem')
+ parser.add_argument('--ca', default='/root/ca.pem')
+
+ logging.debug('About to parse arguments')
+ args = parser.parse_args()
+
+ logging.debug('Serving directory ' + args.dir + ' via HTTPS at port ' + str(args.port))
+
+ chdir(args.dir)
+
+ server = ThreadedHTTPServer(('', args.port), SimpleHTTPRequestHandler)
+ server.socket = wrap_socket(server.socket, certfile=args.cert, ca_certs=args.ca, server_side=True, cert_reqs=CERT_REQUIRED)
+ server.serve_forever()
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi-unsecure/server.py b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi-unsecure/server.py
new file mode 100644
index 0000000..82d5f6a
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi-unsecure/server.py
@@ -0,0 +1,44 @@
+# 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.
+
+#!/usr/bin/env python
+
+import logging
+
+from argparse import ArgumentParser
+from BaseHTTPServer import HTTPServer
+from os import chdir
+from SimpleHTTPServer import SimpleHTTPRequestHandler
+from SocketServer import ThreadingMixIn
+
+# Needs to be threaded or health check hangs the server
+class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
+ pass
+
+if __name__ == '__main__':
+ logging.basicConfig(level=logging.DEBUG)
+ parser = ArgumentParser(description='Serve up directory over http')
+ parser.add_argument('--dir', default='/var/www')
+ parser.add_argument('--port', type=int, default=8080)
+
+ logging.debug('About to parse arguments')
+ args = parser.parse_args()
+
+ logging.debug('Serving directory ' + args.dir + ' via HTTP at port ' + str(args.port))
+
+ chdir(args.dir)
+
+ server = ThreadedHTTPServer(('', args.port), SimpleHTTPRequestHandler)
+ server.serve_forever()
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/flow/templates b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/flow/templates
new file mode 100644
index 0000000..496665b
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/flow/templates
@@ -0,0 +1,53 @@
+{
+ "generated": "15:41:45 EDT",
+ "templates": [
+ {
+ "id": "f080ec50-ca32-4b36-8453-5a7145bec4c5",
+ "permissions": {
+ "canRead": true,
+ "canWrite": true
+ },
+ "template": {
+ "description": "",
+ "encoding-version": "1.0",
+ "groupId": "8f8eda5e-015a-1000-a9c1-b7e4fe10ae83",
+ "id": "f080ec50-ca32-4b36-8453-5a7145bec4c5",
+ "name": "raspi3.v1",
+ "timestamp": "03/07/2017 11:13:03 EST",
+ "uri": "http://localhost:8080/nifi-api/templates/f080ec50-ca32-4b36-8453-5a7145bec4c5"
+ }
+ },
+ {
+ "id": "87048385-a6ca-42fe-b2d8-6a563cedd036",
+ "permissions": {
+ "canRead": true,
+ "canWrite": true
+ },
+ "template": {
+ "description": "",
+ "encoding-version": "1.0",
+ "groupId": "8f8eda5e-015a-1000-a9c1-b7e4fe10ae83",
+ "id": "87048385-a6ca-42fe-b2d8-6a563cedd036",
+ "name": "raspi2.v1",
+ "timestamp": "03/17/2017 15:41:33 EDT",
+ "uri": "http://localhost:8080/nifi-api/templates/87048385-a6ca-42fe-b2d8-6a563cedd036"
+ }
+ },
+ {
+ "id": "dd737a3e-333e-40df-a0bc-d7e28c8e6843",
+ "permissions": {
+ "canRead": true,
+ "canWrite": true
+ },
+ "template": {
+ "description": "",
+ "encoding-version": "1.0",
+ "groupId": "8f8eda5e-015a-1000-a9c1-b7e4fe10ae83",
+ "id": "dd737a3e-333e-40df-a0bc-d7e28c8e6843",
+ "name": "raspi3.v2",
+ "timestamp": "03/17/2017 13:22:58 EDT",
+ "uri": "http://localhost:8080/nifi-api/templates/dd737a3e-333e-40df-a0bc-d7e28c8e6843"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/templates/87048385-a6ca-42fe-b2d8-6a563cedd036/download b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/templates/87048385-a6ca-42fe-b2d8-6a563cedd036/download
new file mode 100644
index 0000000..5d36113
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/templates/87048385-a6ca-42fe-b2d8-6a563cedd036/download
@@ -0,0 +1,203 @@
+<?xml version="1.0" ?>
+<!--
+ 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.
+-->
+<template encoding-version="1.0">
+ <description></description>
+ <groupId>8f8eda5e-015a-1000-a9c1-b7e4fe10ae83</groupId>
+ <name>raspi2.v1</name>
+ <snippet>
+ <connections>
+ <id>8f96f2a9-015a-1000-0000-000000000000</id>
+ <parentGroupId>8f8eda5e-015a-1000-0000-000000000000</parentGroupId>
+ <backPressureDataSizeThreshold>1 GB</backPressureDataSizeThreshold>
+ <backPressureObjectThreshold>10000</backPressureObjectThreshold>
+ <destination>
+ <groupId>8f8eda5e-015a-1000-0000-000000000000</groupId>
+ <id>8f96bf68-015a-1000-0000-000000000000</id>
+ <type>PROCESSOR</type>
+ </destination>
+ <flowFileExpiration>0 sec</flowFileExpiration>
+ <labelIndex>1</labelIndex>
+ <name></name>
+ <selectedRelationships>success</selectedRelationships>
+ <source>
+ <groupId>8f8eda5e-015a-1000-0000-000000000000</groupId>
+ <id>8f96e313-015a-1000-0000-000000000000</id>
+ <type>PROCESSOR</type>
+ </source>
+ <zIndex>0</zIndex>
+ </connections>
+ <processors>
+ <id>8f96bf68-015a-1000-0000-000000000000</id>
+ <parentGroupId>8f8eda5e-015a-1000-0000-000000000000</parentGroupId>
+ <position>
+ <x>14.0</x>
+ <y>253.0</y>
+ </position>
+ <config>
+ <bulletinLevel>WARN</bulletinLevel>
+ <comments></comments>
+ <concurrentlySchedulableTaskCount>1</concurrentlySchedulableTaskCount>
+ <descriptors>
+ <entry>
+ <key>Log Level</key>
+ <value>
+ <name>Log Level</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Log Payload</key>
+ <value>
+ <name>Log Payload</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Attributes to Log</key>
+ <value>
+ <name>Attributes to Log</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Attributes to Ignore</key>
+ <value>
+ <name>Attributes to Ignore</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Log prefix</key>
+ <value>
+ <name>Log prefix</name>
+ </value>
+ </entry>
+ </descriptors>
+ <executionNode>ALL</executionNode>
+ <lossTolerant>false</lossTolerant>
+ <penaltyDuration>30 sec</penaltyDuration>
+ <properties>
+ <entry>
+ <key>Log Level</key>
+ <value>info</value>
+ </entry>
+ <entry>
+ <key>Log Payload</key>
+ <value>true</value>
+ </entry>
+ <entry>
+ <key>Attributes to Log</key>
+ </entry>
+ <entry>
+ <key>Attributes to Ignore</key>
+ </entry>
+ <entry>
+ <key>Log prefix</key>
+ </entry>
+ </properties>
+ <runDurationMillis>0</runDurationMillis>
+ <schedulingPeriod>0 sec</schedulingPeriod>
+ <schedulingStrategy>TIMER_DRIVEN</schedulingStrategy>
+ <yieldDuration>1 sec</yieldDuration>
+ </config>
+ <name>LogAttribute</name>
+ <relationships>
+ <autoTerminate>true</autoTerminate>
+ <name>success</name>
+ </relationships>
+ <style></style>
+ <type>org.apache.nifi.processors.standard.LogAttribute</type>
+ </processors>
+ <processors>
+ <id>8f96e313-015a-1000-0000-000000000000</id>
+ <parentGroupId>8f8eda5e-015a-1000-0000-000000000000</parentGroupId>
+ <position>
+ <x>0.0</x>
+ <y>0.0</y>
+ </position>
+ <config>
+ <bulletinLevel>WARN</bulletinLevel>
+ <comments></comments>
+ <concurrentlySchedulableTaskCount>1</concurrentlySchedulableTaskCount>
+ <descriptors>
+ <entry>
+ <key>File Size</key>
+ <value>
+ <name>File Size</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Batch Size</key>
+ <value>
+ <name>Batch Size</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Data Format</key>
+ <value>
+ <name>Data Format</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Unique FlowFiles</key>
+ <value>
+ <name>Unique FlowFiles</name>
+ </value>
+ </entry>
+ <entry>
+ <key>generate-ff-custom-text</key>
+ <value>
+ <name>generate-ff-custom-text</name>
+ </value>
+ </entry>
+ </descriptors>
+ <executionNode>ALL</executionNode>
+ <lossTolerant>false</lossTolerant>
+ <penaltyDuration>30 sec</penaltyDuration>
+ <properties>
+ <entry>
+ <key>File Size</key>
+ <value>0B</value>
+ </entry>
+ <entry>
+ <key>Batch Size</key>
+ <value>1</value>
+ </entry>
+ <entry>
+ <key>Data Format</key>
+ <value>Text</value>
+ </entry>
+ <entry>
+ <key>Unique FlowFiles</key>
+ <value>false</value>
+ </entry>
+ <entry>
+ <key>generate-ff-custom-text</key>
+ <value>abcdefg</value>
+ </entry>
+ </properties>
+ <runDurationMillis>0</runDurationMillis>
+ <schedulingPeriod>0 sec</schedulingPeriod>
+ <schedulingStrategy>TIMER_DRIVEN</schedulingStrategy>
+ <yieldDuration>1 sec</yieldDuration>
+ </config>
+ <name>GenerateFlowFile</name>
+ <relationships>
+ <autoTerminate>false</autoTerminate>
+ <name>success</name>
+ </relationships>
+ <style></style>
+ <type>org.apache.nifi.processors.standard.GenerateFlowFile</type>
+ </processors>
+ </snippet>
+ <timestamp>03/17/2017 15:41:33 EDT</timestamp>
+</template>
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/templates/dd737a3e-333e-40df-a0bc-d7e28c8e6843/download b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/templates/dd737a3e-333e-40df-a0bc-d7e28c8e6843/download
new file mode 100644
index 0000000..6b364d0
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/templates/dd737a3e-333e-40df-a0bc-d7e28c8e6843/download
@@ -0,0 +1,203 @@
+<?xml version="1.0" ?>
+<!--
+ 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.
+-->
+<template encoding-version="1.0">
+ <description></description>
+ <groupId>8f8eda5e-015a-1000-a9c1-b7e4fe10ae83</groupId>
+ <name>raspi3.v2</name>
+ <snippet>
+ <connections>
+ <id>8f96f2a9-015a-1000-0000-000000000000</id>
+ <parentGroupId>8f8eda5e-015a-1000-0000-000000000000</parentGroupId>
+ <backPressureDataSizeThreshold>1 GB</backPressureDataSizeThreshold>
+ <backPressureObjectThreshold>10000</backPressureObjectThreshold>
+ <destination>
+ <groupId>8f8eda5e-015a-1000-0000-000000000000</groupId>
+ <id>8f96bf68-015a-1000-0000-000000000000</id>
+ <type>PROCESSOR</type>
+ </destination>
+ <flowFileExpiration>0 sec</flowFileExpiration>
+ <labelIndex>1</labelIndex>
+ <name></name>
+ <selectedRelationships>success</selectedRelationships>
+ <source>
+ <groupId>8f8eda5e-015a-1000-0000-000000000000</groupId>
+ <id>8f96e313-015a-1000-0000-000000000000</id>
+ <type>PROCESSOR</type>
+ </source>
+ <zIndex>0</zIndex>
+ </connections>
+ <processors>
+ <id>8f96bf68-015a-1000-0000-000000000000</id>
+ <parentGroupId>8f8eda5e-015a-1000-0000-000000000000</parentGroupId>
+ <position>
+ <x>14.0</x>
+ <y>253.0</y>
+ </position>
+ <config>
+ <bulletinLevel>WARN</bulletinLevel>
+ <comments></comments>
+ <concurrentlySchedulableTaskCount>1</concurrentlySchedulableTaskCount>
+ <descriptors>
+ <entry>
+ <key>Log Level</key>
+ <value>
+ <name>Log Level</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Log Payload</key>
+ <value>
+ <name>Log Payload</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Attributes to Log</key>
+ <value>
+ <name>Attributes to Log</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Attributes to Ignore</key>
+ <value>
+ <name>Attributes to Ignore</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Log prefix</key>
+ <value>
+ <name>Log prefix</name>
+ </value>
+ </entry>
+ </descriptors>
+ <executionNode>ALL</executionNode>
+ <lossTolerant>false</lossTolerant>
+ <penaltyDuration>30 sec</penaltyDuration>
+ <properties>
+ <entry>
+ <key>Log Level</key>
+ <value>info</value>
+ </entry>
+ <entry>
+ <key>Log Payload</key>
+ <value>true</value>
+ </entry>
+ <entry>
+ <key>Attributes to Log</key>
+ </entry>
+ <entry>
+ <key>Attributes to Ignore</key>
+ </entry>
+ <entry>
+ <key>Log prefix</key>
+ </entry>
+ </properties>
+ <runDurationMillis>0</runDurationMillis>
+ <schedulingPeriod>0 sec</schedulingPeriod>
+ <schedulingStrategy>TIMER_DRIVEN</schedulingStrategy>
+ <yieldDuration>1 sec</yieldDuration>
+ </config>
+ <name>LogAttribute</name>
+ <relationships>
+ <autoTerminate>true</autoTerminate>
+ <name>success</name>
+ </relationships>
+ <style></style>
+ <type>org.apache.nifi.processors.standard.LogAttribute</type>
+ </processors>
+ <processors>
+ <id>8f96e313-015a-1000-0000-000000000000</id>
+ <parentGroupId>8f8eda5e-015a-1000-0000-000000000000</parentGroupId>
+ <position>
+ <x>0.0</x>
+ <y>0.0</y>
+ </position>
+ <config>
+ <bulletinLevel>WARN</bulletinLevel>
+ <comments></comments>
+ <concurrentlySchedulableTaskCount>1</concurrentlySchedulableTaskCount>
+ <descriptors>
+ <entry>
+ <key>File Size</key>
+ <value>
+ <name>File Size</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Batch Size</key>
+ <value>
+ <name>Batch Size</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Data Format</key>
+ <value>
+ <name>Data Format</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Unique FlowFiles</key>
+ <value>
+ <name>Unique FlowFiles</name>
+ </value>
+ </entry>
+ <entry>
+ <key>generate-ff-custom-text</key>
+ <value>
+ <name>generate-ff-custom-text</name>
+ </value>
+ </entry>
+ </descriptors>
+ <executionNode>ALL</executionNode>
+ <lossTolerant>false</lossTolerant>
+ <penaltyDuration>30 sec</penaltyDuration>
+ <properties>
+ <entry>
+ <key>File Size</key>
+ <value>0B</value>
+ </entry>
+ <entry>
+ <key>Batch Size</key>
+ <value>1</value>
+ </entry>
+ <entry>
+ <key>Data Format</key>
+ <value>Text</value>
+ </entry>
+ <entry>
+ <key>Unique FlowFiles</key>
+ <value>false</value>
+ </entry>
+ <entry>
+ <key>generate-ff-custom-text</key>
+ <value>abcdefg</value>
+ </entry>
+ </properties>
+ <runDurationMillis>0</runDurationMillis>
+ <schedulingPeriod>0 sec</schedulingPeriod>
+ <schedulingStrategy>TIMER_DRIVEN</schedulingStrategy>
+ <yieldDuration>1 sec</yieldDuration>
+ </config>
+ <name>GenerateFlowFile</name>
+ <relationships>
+ <autoTerminate>false</autoTerminate>
+ <name>success</name>
+ </relationships>
+ <style></style>
+ <type>org.apache.nifi.processors.standard.GenerateFlowFile</type>
+ </processors>
+ </snippet>
+ <timestamp>03/17/2017 13:22:58 EDT</timestamp>
+</template>
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/templates/f080ec50-ca32-4b36-8453-5a7145bec4c5/download b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/templates/f080ec50-ca32-4b36-8453-5a7145bec4c5/download
new file mode 100644
index 0000000..ad65498
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/mocknifi/www/nifi-api/templates/f080ec50-ca32-4b36-8453-5a7145bec4c5/download
@@ -0,0 +1,202 @@
+<?xml version="1.0" ?>
+<!--
+ 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.
+-->
+<template encoding-version="1.0">
+ <description></description>
+ <groupId>8f8eda5e-015a-1000-a9c1-b7e4fe10ae83</groupId>
+ <name>raspi3.v1</name>
+ <snippet>
+ <connections>
+ <id>8f96f2a9-015a-1000-0000-000000000000</id>
+ <parentGroupId>8f8eda5e-015a-1000-0000-000000000000</parentGroupId>
+ <backPressureDataSizeThreshold>1 GB</backPressureDataSizeThreshold>
+ <backPressureObjectThreshold>10000</backPressureObjectThreshold>
+ <destination>
+ <groupId>8f8eda5e-015a-1000-0000-000000000000</groupId>
+ <id>8f96bf68-015a-1000-0000-000000000000</id>
+ <type>PROCESSOR</type>
+ </destination>
+ <flowFileExpiration>0 sec</flowFileExpiration>
+ <labelIndex>1</labelIndex>
+ <name></name>
+ <selectedRelationships>success</selectedRelationships>
+ <source>
+ <groupId>8f8eda5e-015a-1000-0000-000000000000</groupId>
+ <id>8f96e313-015a-1000-0000-000000000000</id>
+ <type>PROCESSOR</type>
+ </source>
+ <zIndex>0</zIndex>
+ </connections>
+ <processors>
+ <id>8f96bf68-015a-1000-0000-000000000000</id>
+ <parentGroupId>8f8eda5e-015a-1000-0000-000000000000</parentGroupId>
+ <position>
+ <x>14.0</x>
+ <y>253.0</y>
+ </position>
+ <config>
+ <bulletinLevel>WARN</bulletinLevel>
+ <comments></comments>
+ <concurrentlySchedulableTaskCount>1</concurrentlySchedulableTaskCount>
+ <descriptors>
+ <entry>
+ <key>Log prefix</key>
+ <value>
+ <name>Log prefix</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Log Level</key>
+ <value>
+ <name>Log Level</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Attributes to Ignore</key>
+ <value>
+ <name>Attributes to Ignore</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Attributes to Log</key>
+ <value>
+ <name>Attributes to Log</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Log Payload</key>
+ <value>
+ <name>Log Payload</name>
+ </value>
+ </entry>
+ </descriptors>
+ <executionNode>ALL</executionNode>
+ <lossTolerant>false</lossTolerant>
+ <penaltyDuration>30 sec</penaltyDuration>
+ <properties>
+ <entry>
+ <key>Log prefix</key>
+ </entry>
+ <entry>
+ <key>Log Level</key>
+ <value>info</value>
+ </entry>
+ <entry>
+ <key>Attributes to Ignore</key>
+ </entry>
+ <entry>
+ <key>Attributes to Log</key>
+ </entry>
+ <entry>
+ <key>Log Payload</key>
+ <value>true</value>
+ </entry>
+ </properties>
+ <runDurationMillis>0</runDurationMillis>
+ <schedulingPeriod>0 sec</schedulingPeriod>
+ <schedulingStrategy>TIMER_DRIVEN</schedulingStrategy>
+ <yieldDuration>1 sec</yieldDuration>
+ </config>
+ <name>LogAttribute</name>
+ <relationships>
+ <autoTerminate>true</autoTerminate>
+ <name>success</name>
+ </relationships>
+ <style></style>
+ <type>org.apache.nifi.processors.standard.LogAttribute</type>
+ </processors>
+ <processors>
+ <id>8f96e313-015a-1000-0000-000000000000</id>
+ <parentGroupId>8f8eda5e-015a-1000-0000-000000000000</parentGroupId>
+ <position>
+ <x>0.0</x>
+ <y>0.0</y>
+ </position>
+ <config>
+ <bulletinLevel>WARN</bulletinLevel>
+ <comments></comments>
+ <concurrentlySchedulableTaskCount>1</concurrentlySchedulableTaskCount>
+ <descriptors>
+ <entry>
+ <key>File Size</key>
+ <value>
+ <name>File Size</name>
+ </value>
+ </entry>
+ <entry>
+ <key>generate-ff-custom-text</key>
+ <value>
+ <name>generate-ff-custom-text</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Batch Size</key>
+ <value>
+ <name>Batch Size</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Unique FlowFiles</key>
+ <value>
+ <name>Unique FlowFiles</name>
+ </value>
+ </entry>
+ <entry>
+ <key>Data Format</key>
+ <value>
+ <name>Data Format</name>
+ </value>
+ </entry>
+ </descriptors>
+ <executionNode>ALL</executionNode>
+ <lossTolerant>false</lossTolerant>
+ <penaltyDuration>30 sec</penaltyDuration>
+ <properties>
+ <entry>
+ <key>File Size</key>
+ <value>0B</value>
+ </entry>
+ <entry>
+ <key>generate-ff-custom-text</key>
+ </entry>
+ <entry>
+ <key>Batch Size</key>
+ <value>1</value>
+ </entry>
+ <entry>
+ <key>Unique FlowFiles</key>
+ <value>false</value>
+ </entry>
+ <entry>
+ <key>Data Format</key>
+ <value>Text</value>
+ </entry>
+ </properties>
+ <runDurationMillis>0</runDurationMillis>
+ <schedulingPeriod>0 sec</schedulingPeriod>
+ <schedulingStrategy>TIMER_DRIVEN</schedulingStrategy>
+ <yieldDuration>1 sec</yieldDuration>
+ </config>
+ <name>GenerateFlowFile</name>
+ <relationships>
+ <autoTerminate>false</autoTerminate>
+ <name>success</name>
+ </relationships>
+ <style></style>
+ <type>org.apache.nifi.processors.standard.GenerateFlowFile</type>
+ </processors>
+ </snippet>
+ <timestamp>03/07/2017 11:13:03 EST</timestamp>
+</template>
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/overlay.properties b/minifi-c2/minifi-c2-integration-tests/src/test/resources/overlay.properties
new file mode 100644
index 0000000..b1312a0
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/overlay.properties
@@ -0,0 +1,16 @@
+#
+# 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.
+#
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/squid/squid.conf b/minifi-c2/minifi-c2-integration-tests/src/test/resources/squid/squid.conf
new file mode 100644
index 0000000..90a5248
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/squid/squid.conf
@@ -0,0 +1,19 @@
+# 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.
+
+http_access allow all
+
+# Choose the port you want. Below we set it to default 3128.
+http_port 3128
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-jetty/pom.xml b/minifi-c2/minifi-c2-jetty/pom.xml
new file mode 100644
index 0000000..df24c62
--- /dev/null
+++ b/minifi-c2/minifi-c2-jetty/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-jetty</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-webapp</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/minifi-c2/minifi-c2-jetty/src/main/java/org/apache/nifi/minifi/c2/jetty/JettyServer.java b/minifi-c2/minifi-c2-jetty/src/main/java/org/apache/nifi/minifi/c2/jetty/JettyServer.java
new file mode 100644
index 0000000..5c8b1f8
--- /dev/null
+++ b/minifi-c2/minifi-c2-jetty/src/main/java/org/apache/nifi/minifi/c2/jetty/JettyServer.java
@@ -0,0 +1,142 @@
+/*
+ * 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.minifi.c2.jetty;
+
+import org.apache.nifi.minifi.c2.api.properties.C2Properties;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.webapp.WebAppClassLoader;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class JettyServer {
+ private static final Logger logger = LoggerFactory.getLogger(JettyServer.class);
+ private static String C2_SERVER_HOME = System.getenv("C2_SERVER_HOME");
+ private static final String WEB_DEFAULTS_XML = "webdefault.xml";
+
+ public static void main(String[] args) throws Exception {
+ C2Properties properties = C2Properties.getInstance();
+
+ final HandlerCollection handlers = new HandlerCollection();
+ for (Path path : Files.list(Paths.get(C2_SERVER_HOME, "webapps")).collect(Collectors.toList())) {
+ handlers.addHandler(loadWar(path.toFile(), "/c2", JettyServer.class.getClassLoader()));
+ }
+
+ Server server;
+ int port = Integer.parseInt(properties.getProperty("minifi.c2.server.port", "10080"));
+ SslContextFactory sslContextFactory = properties.getSslContextFactory();
+ if (sslContextFactory == null) {
+ server = new Server(port);
+ } else {
+ HttpConfiguration config = new HttpConfiguration();
+ config.setSecureScheme("https");
+ config.setSecurePort(port);
+ config.addCustomizer(new SecureRequestCustomizer());
+
+ server = new Server();
+
+ ServerConnector serverConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"), new HttpConnectionFactory(config));
+ serverConnector.setPort(port);
+
+ server.addConnector(serverConnector);
+ }
+
+ server.setHandler(handlers);
+ server.start();
+
+ // ensure everything started successfully
+ for (Handler handler : server.getChildHandlers()) {
+ // see if the handler is a web app
+ if (handler instanceof WebAppContext) {
+ WebAppContext context = (WebAppContext) handler;
+
+ // see if this webapp had any exceptions that would
+ // cause it to be unavailable
+ if (context.getUnavailableException() != null) {
+
+ System.err.println("Failed to start web server: " + context.getUnavailableException().getMessage());
+ System.err.println("Shutting down...");
+ logger.warn("Failed to start web server... shutting down.", context.getUnavailableException());
+ server.stop();
+ System.exit(1);
+ }
+ }
+ }
+
+ server.dumpStdErr();
+ server.join();
+ }
+
+ private static WebAppContext loadWar(final File warFile, final String contextPath, final ClassLoader parentClassLoader) throws IOException {
+ final WebAppContext webappContext = new WebAppContext(warFile.getPath(), contextPath);
+ webappContext.setContextPath(contextPath);
+ webappContext.setDisplayName(contextPath);
+
+ // instruction jetty to examine these jars for tlds, web-fragments, etc
+ webappContext.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\\\.jar$|.*/[^/]*taglibs.*\\.jar$" );
+
+ // remove slf4j server class to allow WAR files to have slf4j dependencies in WEB-INF/lib
+ List<String> serverClasses = new ArrayList<>(Arrays.asList(webappContext.getServerClasses()));
+ serverClasses.remove("org.slf4j.");
+ webappContext.setServerClasses(serverClasses.toArray(new String[0]));
+ webappContext.setDefaultsDescriptor(WEB_DEFAULTS_XML);
+
+ // get the temp directory for this webapp
+ File tempDir = Paths.get(C2_SERVER_HOME, "tmp", warFile.getName()).toFile();
+ if (tempDir.exists() && !tempDir.isDirectory()) {
+ throw new RuntimeException(tempDir.getAbsolutePath() + " is not a directory");
+ } else if (!tempDir.exists()) {
+ final boolean made = tempDir.mkdirs();
+ if (!made) {
+ throw new RuntimeException(tempDir.getAbsolutePath() + " could not be created");
+ }
+ }
+ if (!(tempDir.canRead() && tempDir.canWrite())) {
+ throw new RuntimeException(tempDir.getAbsolutePath() + " directory does not have read/write privilege");
+ }
+
+ // configure the temp dir
+ webappContext.setTempDirectory(tempDir);
+
+ // configure the max form size (3x the default)
+ webappContext.setMaxFormContentSize(600000);
+
+ webappContext.setClassLoader(new WebAppClassLoader(parentClassLoader, webappContext));
+
+ logger.info("Loading WAR: " + warFile.getAbsolutePath() + " with context path set to " + contextPath);
+ return webappContext;
+ }
+}
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/pom.xml b/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/pom.xml
new file mode 100644
index 0000000..76e082e
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2-provider</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-provider-cache</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/main/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProvider.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/main/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProvider.java
new file mode 100644
index 0000000..b0864ac
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/main/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProvider.java
@@ -0,0 +1,46 @@
+/*
+ * 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.minifi.c2.provider.cache;
+
+import org.apache.nifi.minifi.c2.api.Configuration;
+import org.apache.nifi.minifi.c2.api.ConfigurationProvider;
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
+
+import java.util.List;
+import java.util.Map;
+
+public class CacheConfigurationProvider implements ConfigurationProvider {
+ private final String contentType;
+ private final ConfigurationCache configurationCache;
+
+ public CacheConfigurationProvider(String contentType, ConfigurationCache configurationCache) {
+ this.contentType = contentType;
+ this.configurationCache = configurationCache;
+ }
+
+ @Override
+ public String getContentType() {
+ return contentType;
+ }
+
+ @Override
+ public Configuration getConfiguration(Integer version, Map<String, List<String>> parameters) throws ConfigurationProviderException {
+ return configurationCache.getCacheFileInfo(parameters).getConfiguration(version);
+ }
+}
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/test/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProviderTest.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/test/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProviderTest.java
new file mode 100644
index 0000000..d038194
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/test/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProviderTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.minifi.c2.provider.cache;
+
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCacheFileInfo;
+import org.apache.nifi.minifi.c2.api.cache.WriteableConfiguration;
+import org.apache.nifi.minifi.c2.provider.cache.CacheConfigurationProvider;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class CacheConfigurationProviderTest {
+ public static final String TEST_CONTENT_TYPE = "test/contenttype";
+
+ private CacheConfigurationProvider cacheConfigurationProvider;
+ private ConfigurationCache configConfigurationCache;
+
+ @Before
+ public void setup() {
+ configConfigurationCache = mock(ConfigurationCache.class);
+ cacheConfigurationProvider = new CacheConfigurationProvider(TEST_CONTENT_TYPE, configConfigurationCache);
+ }
+
+ @Test
+ public void testContentType() {
+ assertEquals(TEST_CONTENT_TYPE, cacheConfigurationProvider.getContentType());
+ }
+
+ @Test
+ public void testGetConfiguration() throws ConfigurationProviderException {
+ int version = 99;
+
+ Map<String, List<String>> parameters = mock(Map.class);
+ ConfigurationCacheFileInfo configurationCacheFileInfo = mock(ConfigurationCacheFileInfo.class);
+ WriteableConfiguration configuration = mock(WriteableConfiguration.class);
+
+ when(configConfigurationCache.getCacheFileInfo(parameters)).thenReturn(configurationCacheFileInfo);
+ when(configurationCacheFileInfo.getConfiguration(version)).thenReturn(configuration);
+
+ assertEquals(configuration, cacheConfigurationProvider.getConfiguration(version, parameters));
+ }
+}
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml
new file mode 100644
index 0000000..8595246
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2-provider</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-provider-nifi-rest</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>2.8.7</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-toolkit-configuration</artifactId>
+ <version>${project.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes combine.children="append">
+ <exclude>src/test/resources/noTemplates.json</exclude>
+ <exclude>src/test/resources/oneTemplate.json</exclude>
+ <exclude>src/test/resources/twoTemplates.json</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProvider.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProvider.java
new file mode 100644
index 0000000..77175d7
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProvider.java
@@ -0,0 +1,149 @@
+/*
+ * 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.minifi.c2.provider.nifi.rest;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import org.apache.nifi.minifi.c2.api.Configuration;
+import org.apache.nifi.minifi.c2.api.ConfigurationProvider;
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.InvalidParameterException;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCacheFileInfo;
+import org.apache.nifi.minifi.c2.api.cache.WriteableConfiguration;
+import org.apache.nifi.minifi.c2.api.util.Pair;
+import org.apache.nifi.minifi.commons.schema.ConfigSchema;
+import org.apache.nifi.minifi.commons.schema.serialization.SchemaSaver;
+import org.apache.nifi.minifi.toolkit.configuration.ConfigMain;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.JAXBException;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.security.GeneralSecurityException;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+public class NiFiRestConfigurationProvider implements ConfigurationProvider {
+ public static final String CONTENT_TYPE = "text/yml";
+ private static final Logger logger = LoggerFactory.getLogger(NiFiRestConfigurationProvider.class);
+ private final JsonFactory jsonFactory = new JsonFactory();
+ private final ConfigurationCache configurationCache;
+ private final NiFiRestConnector niFiRestConnector;
+
+ public NiFiRestConfigurationProvider(ConfigurationCache configurationCache, String nifiUrl) throws InvalidParameterException, GeneralSecurityException, IOException {
+ this(configurationCache, new NiFiRestConnector(nifiUrl));
+ }
+
+ public NiFiRestConfigurationProvider(ConfigurationCache configurationCache, NiFiRestConnector niFiRestConnector) {
+ this.configurationCache = configurationCache;
+ this.niFiRestConnector = niFiRestConnector;
+ }
+
+ @Override
+ public String getContentType() {
+ return CONTENT_TYPE;
+ }
+
+ @Override
+ public Configuration getConfiguration(Integer version, Map<String, List<String>> parameters) throws ConfigurationProviderException {
+ ConfigurationCacheFileInfo configurationCacheFileInfo = configurationCache.getCacheFileInfo(parameters);
+ String id = null;
+ if (version == null) {
+ Pair<String, Integer> maxIdAndVersion = getMaxIdAndVersion(configurationCacheFileInfo);
+ id = maxIdAndVersion.getFirst();
+ version = maxIdAndVersion.getSecond();
+ }
+ WriteableConfiguration configuration = configurationCacheFileInfo.getConfiguration(version);
+ if (configuration.exists()) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Configuration " + configuration + " exists and can be served from configurationCache.");
+ }
+ } else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Configuration " + configuration + " doesn't exist, will need to download and convert template.");
+ }
+ if (id == null) {
+ try {
+ String filename = configuration.getName();
+ Pair<Stream<Pair<String, String>>, Closeable> streamCloseablePair = getIdAndFilenameStream();
+ try {
+ id = streamCloseablePair.getFirst().filter(p -> filename.equals(p.getSecond())).map(Pair::getFirst).findFirst()
+ .orElseThrow(() -> new InvalidParameterException("Unable to find template named " + filename));
+ } finally {
+ streamCloseablePair.getSecond().close();
+ }
+ } catch (IOException|TemplatesIteratorException e) {
+ throw new ConfigurationProviderException("Unable to retrieve template list", e);
+ }
+ }
+
+ HttpURLConnection urlConnection = niFiRestConnector.get("/templates/" + id + "/download");
+
+ try (InputStream inputStream = urlConnection.getInputStream()){
+ ConfigSchema configSchema = ConfigMain.transformTemplateToSchema(inputStream);
+ SchemaSaver.saveConfigSchema(configSchema, configuration.getOutputStream());
+ } catch (IOException e) {
+ throw new ConfigurationProviderException("Unable to download template from url " + urlConnection.getURL(), e);
+ } catch (JAXBException e) {
+ throw new ConfigurationProviderException("Unable to convert template to yaml", e);
+ } finally {
+ urlConnection.disconnect();
+ }
+ }
+ return configuration;
+ }
+
+ private Pair<Stream<Pair<String, String>>, Closeable> getIdAndFilenameStream() throws ConfigurationProviderException, IOException {
+ TemplatesIterator templatesIterator = new TemplatesIterator(niFiRestConnector, jsonFactory);
+ return new Pair<>(StreamSupport.stream(Spliterators.spliteratorUnknownSize(templatesIterator, Spliterator.ORDERED), false), templatesIterator);
+ }
+
+ private Pair<Stream<Pair<String, Integer>>, Closeable> getIdAndVersionStream(ConfigurationCacheFileInfo configurationCacheFileInfo) throws ConfigurationProviderException, IOException {
+ Pair<Stream<Pair<String, String>>, Closeable> streamCloseablePair = getIdAndFilenameStream();
+ return new Pair<>(streamCloseablePair.getFirst().map(p -> {
+ Integer version = configurationCacheFileInfo.getVersionIfMatch(p.getSecond());
+ if (version == null) {
+ return null;
+ }
+ return new Pair<>(p.getFirst(), version);
+ }).filter(Objects::nonNull), streamCloseablePair.getSecond());
+ }
+
+ private Pair<String, Integer> getMaxIdAndVersion(ConfigurationCacheFileInfo configurationCacheFileInfo) throws ConfigurationProviderException {
+ try {
+ Pair<Stream<Pair<String, Integer>>, Closeable> streamCloseablePair = getIdAndVersionStream(configurationCacheFileInfo);
+ try {
+ return streamCloseablePair.getFirst().sorted(Comparator.comparing(p -> ((Pair<String, Integer>) p).getSecond()).reversed()).findFirst()
+ .orElseThrow(() -> new ConfigurationProviderException("Didn't find any templates that matched " + configurationCacheFileInfo + ".v[0-9]+"));
+ } finally {
+ streamCloseablePair.getSecond().close();
+ }
+ } catch (IOException|TemplatesIteratorException e) {
+ throw new ConfigurationProviderException("Unable to retrieve template list", e);
+ }
+ }
+}
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConnector.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConnector.java
new file mode 100644
index 0000000..9a0befc
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConnector.java
@@ -0,0 +1,80 @@
+/*
+ * 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.minifi.c2.provider.nifi.rest;
+
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.InvalidParameterException;
+import org.apache.nifi.minifi.c2.api.properties.C2Properties;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+
+public class NiFiRestConnector {
+ private static final Logger logger = LoggerFactory.getLogger(NiFiRestConnector.class);
+
+ private final String nifiApiUrl;
+ private final SslContextFactory sslContextFactory;
+
+ public NiFiRestConnector(String nifiApiUrl) throws InvalidParameterException, GeneralSecurityException, IOException {
+ if (nifiApiUrl.startsWith("https:")) {
+ sslContextFactory = C2Properties.getInstance().getSslContextFactory();
+ if (sslContextFactory == null) {
+ throw new InvalidParameterException("Need sslContextFactory to connect to https NiFi endpoint (" + nifiApiUrl + ")");
+ }
+ } else {
+ sslContextFactory = null;
+ }
+ this.nifiApiUrl = nifiApiUrl;
+ }
+
+ protected HttpURLConnection get(String endpointPath) throws ConfigurationProviderException {
+ String endpointUrl = nifiApiUrl + endpointPath;
+ if (logger.isDebugEnabled()) {
+ logger.debug("Connecting to NiFi endpoint: " + endpointUrl);
+ }
+ URL url;
+ try {
+ url = new URL(endpointUrl);
+ } catch (MalformedURLException e) {
+ throw new ConfigurationProviderException("Malformed url " + endpointUrl, e);
+ }
+
+ try {
+ if (sslContextFactory == null) {
+ return (HttpURLConnection) url.openConnection();
+ } else {
+ HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
+ SSLContext sslContext = sslContextFactory.getSslContext();
+ SSLSocketFactory socketFactory = sslContext.getSocketFactory();
+ httpsURLConnection.setSSLSocketFactory(socketFactory);
+ return httpsURLConnection;
+ }
+ } catch (IOException e) {
+ throw new ConfigurationProviderException("Unable to connect to " + url, e);
+ }
+ }
+}
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIterator.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIterator.java
new file mode 100644
index 0000000..afe6c6e
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIterator.java
@@ -0,0 +1,115 @@
+/*
+ * 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.minifi.c2.provider.nifi.rest;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.util.Pair;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class TemplatesIterator implements Iterator<Pair<String, String>>, Closeable {
+ public static final String FLOW_TEMPLATES = "/flow/templates";
+
+ private final HttpURLConnection urlConnection;
+ private final InputStream inputStream;
+ private final JsonParser parser;
+ private Pair<String, String> next;
+
+ public TemplatesIterator(NiFiRestConnector niFiRestConnector, JsonFactory jsonFactory) throws ConfigurationProviderException, IOException {
+ urlConnection = niFiRestConnector.get(FLOW_TEMPLATES);
+ inputStream = urlConnection.getInputStream();
+ parser = jsonFactory.createParser(inputStream);
+ while (parser.nextToken() != JsonToken.END_OBJECT) {
+ if ("templates".equals(parser.getCurrentName())) {
+ break;
+ }
+ }
+ next = getNext();
+ }
+
+ private Pair<String, String> getNext() throws IOException {
+ while (parser.nextToken() != JsonToken.END_ARRAY) {
+ if ("template".equals(parser.getCurrentName())) {
+ String id = null;
+ String name = null;
+ while (parser.nextToken() != JsonToken.END_OBJECT) {
+ String currentName = parser.getCurrentName();
+ if ("id".equals(currentName)) {
+ parser.nextToken();
+ id = parser.getText();
+ } else if ("name".equals(currentName)) {
+ parser.nextToken();
+ name = parser.getText();
+ }
+ }
+ return new Pair<>(id, name);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public Pair<String, String> next() {
+ if (next == null) {
+ throw new NoSuchElementException();
+ }
+ try {
+ return next;
+ } finally {
+ try {
+ next = getNext();
+ } catch (IOException e) {
+ throw new TemplatesIteratorException(e);
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (parser != null) {
+ try {
+ parser.close();
+ } catch (IOException e) {
+ //Ignore
+ }
+ }
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ //Ignore
+ }
+ }
+ if (urlConnection != null) {
+ urlConnection.disconnect();
+ }
+ }
+}
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorException.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorException.java
new file mode 100644
index 0000000..af22474
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.minifi.c2.provider.nifi.rest;
+
+import java.io.IOException;
+
+public class TemplatesIteratorException extends RuntimeException {
+ public TemplatesIteratorException(IOException cause) {
+ super(cause);
+ }
+
+ @Override
+ public synchronized IOException getCause() {
+ return (IOException) super.getCause();
+ }
+}
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProviderTest.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProviderTest.java
new file mode 100644
index 0000000..2cb3a8d
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProviderTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.minifi.c2.provider.nifi.rest;
+
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Comparator;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+public class NiFiRestConfigurationProviderTest {
+ private ConfigurationCache configConfigurationCache;
+ private NiFiRestConnector niFiRestConnector;
+ private NiFiRestConfigurationProvider niFiRestConfigurationProvider;
+ private Path cachePath;
+
+ @Before
+ public void setup() throws IOException {
+ configConfigurationCache = mock(ConfigurationCache.class);
+ niFiRestConnector = mock(NiFiRestConnector.class);
+ niFiRestConfigurationProvider = new NiFiRestConfigurationProvider(configConfigurationCache, niFiRestConnector);
+ cachePath = Files.createTempDirectory(NiFiRestConfigurationProviderTest.class.getCanonicalName());
+ }
+
+ @After
+ public void teardown() throws IOException {
+ Files.walk(cachePath)
+ .sorted(Comparator.reverseOrder())
+ .forEach(p -> {
+ try {
+ Files.deleteIfExists(p);
+ } catch (IOException e) {
+ p.toFile().deleteOnExit();
+ }
+ });
+ }
+
+ @Test
+ public void testContentType() {
+ assertEquals(NiFiRestConfigurationProvider.CONTENT_TYPE, niFiRestConfigurationProvider.getContentType());
+ }
+
+
+}
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorExceptionTest.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorExceptionTest.java
new file mode 100644
index 0000000..3be3445
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorExceptionTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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.minifi.c2.provider.nifi.rest;
+
+import org.apache.nifi.minifi.c2.provider.nifi.rest.TemplatesIteratorException;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+public class TemplatesIteratorExceptionTest {
+ @Test
+ public void testCauseConstructor() {
+ IOException ioException = mock(IOException.class);
+ assertEquals(ioException, new TemplatesIteratorException(ioException).getCause());
+ }
+}
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorTest.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorTest.java
new file mode 100644
index 0000000..ca20e4a
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.minifi.c2.provider.nifi.rest;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.google.common.collect.Lists;
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.util.Pair;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class TemplatesIteratorTest {
+ private JsonFactory jsonFactory;
+ private HttpURLConnection httpURLConnection;
+ private NiFiRestConnector niFiRestConnector;
+
+ @Before
+ public void setup() throws ConfigurationProviderException {
+ jsonFactory = new JsonFactory();
+ httpURLConnection = mock(HttpURLConnection.class);
+ niFiRestConnector = mock(NiFiRestConnector.class);
+ when(niFiRestConnector.get(TemplatesIterator.FLOW_TEMPLATES)).thenReturn(httpURLConnection);
+ }
+
+ @Test(expected = NoSuchElementException.class)
+ public void testIteratorNoSuchElementException() throws ConfigurationProviderException, IOException {
+ when(httpURLConnection.getInputStream()).thenReturn(TemplatesIteratorTest.class.getClassLoader().getResourceAsStream("noTemplates.json"));
+
+ try (TemplatesIterator templatesIterator = new TemplatesIterator(niFiRestConnector, jsonFactory)) {
+ assertFalse(templatesIterator.hasNext());
+ templatesIterator.next();
+ } finally {
+ verify(httpURLConnection).disconnect();
+ }
+ }
+
+ @Test
+ public void testIteratorNoTemplates() throws ConfigurationProviderException, IOException {
+ when(httpURLConnection.getInputStream()).thenReturn(TemplatesIteratorTest.class.getClassLoader().getResourceAsStream("noTemplates.json"));
+ List<Pair<String, String>> idToNameList;
+ try (TemplatesIterator templatesIterator = new TemplatesIterator(niFiRestConnector, jsonFactory)) {
+ idToNameList = Lists.newArrayList(templatesIterator);
+ }
+ assertEquals(0, idToNameList.size());
+
+ verify(httpURLConnection).disconnect();
+ }
+
+ @Test
+ public void testIteratorSingleTemplate() throws ConfigurationProviderException, IOException {
+ when(httpURLConnection.getInputStream()).thenReturn(TemplatesIteratorTest.class.getClassLoader().getResourceAsStream("oneTemplate.json"));
+ List<Pair<String, String>> idToNameList;
+ try (TemplatesIterator templatesIterator = new TemplatesIterator(niFiRestConnector, jsonFactory)) {
+ idToNameList = Lists.newArrayList(templatesIterator);
+ }
+ assertEquals(1, idToNameList.size());
+ Pair<String, String> idNamePair = idToNameList.get(0);
+ assertEquals("d05845ae-ceda-4c50-b7c2-037e42ddf1d3", idNamePair.getFirst());
+ assertEquals("raspi3.v1", idNamePair.getSecond());
+
+ verify(httpURLConnection).disconnect();
+ }
+
+ @Test
+ public void testIteratorTwoTemplates() throws ConfigurationProviderException, IOException {
+ when(httpURLConnection.getInputStream()).thenReturn(TemplatesIteratorTest.class.getClassLoader().getResourceAsStream("twoTemplates.json"));
+ List<Pair<String, String>> idToNameList;
+ try (TemplatesIterator templatesIterator = new TemplatesIterator(niFiRestConnector, jsonFactory)) {
+ idToNameList = Lists.newArrayList(templatesIterator);
+ }
+ assertEquals(2, idToNameList.size());
+ Pair<String, String> idNamePair = idToNameList.get(0);
+ assertEquals("d05845ae-ceda-4c50-b7c2-037e42ddf1d3", idNamePair.getFirst());
+ assertEquals("raspi3.v1", idNamePair.getSecond());
+
+ idNamePair = idToNameList.get(1);
+ assertEquals("9384b48d-85b4-478a-bf3e-64d113f8fbc5", idNamePair.getFirst());
+ assertEquals("raspi3.v2", idNamePair.getSecond());
+
+ verify(httpURLConnection).disconnect();
+ }
+}
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/resources/noTemplates.json b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/resources/noTemplates.json
new file mode 100644
index 0000000..ff41507
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/resources/noTemplates.json
@@ -0,0 +1 @@
+{"templates":[],"generated":"14:55:13 EST"}
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/resources/oneTemplate.json b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/resources/oneTemplate.json
new file mode 100644
index 0000000..0d981f1
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/resources/oneTemplate.json
@@ -0,0 +1,21 @@
+{
+ "generated": "10:26:04 EST",
+ "templates": [
+ {
+ "id": "d05845ae-ceda-4c50-b7c2-037e42ddf1d3",
+ "permissions": {
+ "canRead": true,
+ "canWrite": true
+ },
+ "template": {
+ "description": "",
+ "encoding-version": "1.0",
+ "groupId": "8f8eda5e-015a-1000-a9c1-b7e4fe10ae83",
+ "id": "d05845ae-ceda-4c50-b7c2-037e42ddf1d3",
+ "name": "raspi3.v1",
+ "timestamp": "03/02/2017 10:26:01 EST",
+ "uri": "http://localhost:8081/nifi-api/templates/d05845ae-ceda-4c50-b7c2-037e42ddf1d3"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/resources/twoTemplates.json b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/resources/twoTemplates.json
new file mode 100644
index 0000000..9b4245a
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/resources/twoTemplates.json
@@ -0,0 +1,37 @@
+{
+ "generated": "14:53:15 EST",
+ "templates": [
+ {
+ "id": "d05845ae-ceda-4c50-b7c2-037e42ddf1d3",
+ "permissions": {
+ "canRead": true,
+ "canWrite": true
+ },
+ "template": {
+ "description": "",
+ "encoding-version": "1.0",
+ "groupId": "8f8eda5e-015a-1000-a9c1-b7e4fe10ae83",
+ "id": "d05845ae-ceda-4c50-b7c2-037e42ddf1d3",
+ "name": "raspi3.v1",
+ "timestamp": "03/02/2017 10:26:01 EST",
+ "uri": "http://localhost:8081/nifi-api/templates/d05845ae-ceda-4c50-b7c2-037e42ddf1d3"
+ }
+ },
+ {
+ "id": "9384b48d-85b4-478a-bf3e-64d113f8fbc5",
+ "permissions": {
+ "canRead": true,
+ "canWrite": true
+ },
+ "template": {
+ "description": "",
+ "encoding-version": "1.0",
+ "groupId": "8f8eda5e-015a-1000-a9c1-b7e4fe10ae83",
+ "id": "9384b48d-85b4-478a-bf3e-64d113f8fbc5",
+ "name": "raspi3.v2",
+ "timestamp": "03/02/2017 13:08:14 EST",
+ "uri": "http://localhost:8081/nifi-api/templates/9384b48d-85b4-478a-bf3e-64d113f8fbc5"
+ }
+ }
+ ]
+}
diff --git a/minifi-c2/minifi-c2-provider/pom.xml b/minifi-c2/minifi-c2-provider/pom.xml
new file mode 100644
index 0000000..fc0fbae
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-provider</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>minifi-c2-provider-cache</module>
+ <module>minifi-c2-provider-nifi-rest</module>
+ </modules>
+</project>
diff --git a/minifi-c2/minifi-c2-service/pom.xml b/minifi-c2/minifi-c2-service/pom.xml
new file mode 100644
index 0000000..eb52d7d
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-service</artifactId>
+ <packaging>war</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-api</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-web</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-web</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-config</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.yaml</groupId>
+ <artifactId>snakeyaml</artifactId>
+ <version>1.17</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ <version>1.1.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.wordnik</groupId>
+ <artifactId>swagger-annotations</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/configuration/Configuration.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/configuration/Configuration.java
new file mode 100644
index 0000000..19b647f
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/configuration/Configuration.java
@@ -0,0 +1,28 @@
+/*
+ * 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.minifi.c2.configuration;
+
+import org.apache.nifi.minifi.c2.security.SecurityConfiguration;
+import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.ImportResource;
+
+@org.springframework.context.annotation.Configuration
+@Import({SecurityConfiguration.class})
+@ImportResource({"classpath:minifi-c2-context.xml"})
+public class Configuration {
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/SecurityConfiguration.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/SecurityConfiguration.java
new file mode 100644
index 0000000..2c4630c
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/SecurityConfiguration.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.minifi.c2.security;
+
+import org.apache.nifi.minifi.c2.security.authentication.C2AnonymousAuthenticationFilter;
+import org.apache.nifi.minifi.c2.security.authentication.X509AuthenticationFilter;
+import org.apache.nifi.minifi.c2.security.authentication.X509AuthenticationProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.ImportResource;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
+
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+@ImportResource({"classpath:minifi-c2-web-security-context.xml"})
+public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+ private AuthenticationProvider authenticationProvider;
+ private X509AuthenticationFilter x509AuthenticationFilter;
+ private C2AnonymousAuthenticationFilter c2AnonymousAuthenticationFilter;
+
+ public SecurityConfiguration() {
+ super(true);
+ }
+
+ @Bean
+ @Override
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ // override xxxBean method so the authentication manager is available in app context (necessary for the method level security)
+ return super.authenticationManagerBean();
+ }
+
+ @Override
+ public void configure(WebSecurity web) throws Exception {
+ web.ignoring().antMatchers("/access", "/access/config", "/access/token", "/access/kerberos");
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .rememberMe().disable().authorizeRequests().anyRequest().fullyAuthenticated().and()
+ .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+ http.addFilterBefore(x509AuthenticationFilter, AnonymousAuthenticationFilter.class);
+ http.anonymous().authenticationFilter(c2AnonymousAuthenticationFilter);
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.authenticationProvider(authenticationProvider);
+ }
+
+ @Autowired
+ public void setX509AuthenticationProvider(X509AuthenticationProvider x509AuthenticationProvider) {
+ this.authenticationProvider = x509AuthenticationProvider;
+ }
+
+ @Autowired
+ public void setX509AuthenticationFilter(X509AuthenticationFilter x509AuthenticationFilter) {
+ this.x509AuthenticationFilter = x509AuthenticationFilter;
+ }
+
+ @Autowired
+ public void setC2AnonymousAuthenticationFilter(C2AnonymousAuthenticationFilter c2AnonymousAuthenticationFilter) {
+ this.c2AnonymousAuthenticationFilter = c2AnonymousAuthenticationFilter;
+ }
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/C2AnonymousAuthenticationFilter.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/C2AnonymousAuthenticationFilter.java
new file mode 100644
index 0000000..e73d2ee
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/C2AnonymousAuthenticationFilter.java
@@ -0,0 +1,38 @@
+/*
+ * 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.minifi.c2.security.authentication;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+
+public class C2AnonymousAuthenticationFilter extends AnonymousAuthenticationFilter {
+ public static final String ANONYMOUS = "anonymous";
+
+ public C2AnonymousAuthenticationFilter() {
+ super(ANONYMOUS);
+ }
+
+ @Override
+ protected Authentication createAuthentication(HttpServletRequest request) {
+ return new C2AuthenticationToken(ANONYMOUS, null, Arrays.asList(new SimpleGrantedAuthority("ROLE_ANONYMOUS")));
+ }
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/C2AuthenticationToken.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/C2AuthenticationToken.java
new file mode 100644
index 0000000..d6f85ec
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/C2AuthenticationToken.java
@@ -0,0 +1,51 @@
+/*
+ * 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.minifi.c2.security.authentication;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.util.Collection;
+
+public class C2AuthenticationToken extends AbstractAuthenticationToken {
+ private final String principal;
+ private Object credentials;
+
+ public C2AuthenticationToken(String principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
+ super(authorities);
+ setAuthenticated(true);
+ this.principal = principal;
+ this.credentials = credentials;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return credentials;
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return principal;
+ }
+
+ @Override
+ public void eraseCredentials() {
+ super.eraseCredentials();
+ credentials = null;
+ }
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/X509AuthenticationFilter.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/X509AuthenticationFilter.java
new file mode 100644
index 0000000..63c743b
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/X509AuthenticationFilter.java
@@ -0,0 +1,70 @@
+/*
+ * 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.minifi.c2.security.authentication;
+
+import org.apache.nifi.minifi.c2.util.HttpRequestUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.filter.GenericFilterBean;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+
+public class X509AuthenticationFilter extends GenericFilterBean {
+ private static final Logger logger = LoggerFactory.getLogger(X509AuthenticationFilter.class);
+ private AuthenticationManager authenticationManager;
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ authenticateIfPossible(request);
+ chain.doFilter(request, response);
+ }
+
+ private void authenticateIfPossible(ServletRequest request) {
+ if (!request.isSecure()) {
+ return;
+ }
+
+ X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
+
+ if (certs == null || certs.length == 0) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Unable to get certificates in request from " + HttpRequestUtil.getClientString(request));
+ }
+ return;
+ }
+
+ Authentication authentication = authenticationManager.authenticate(new X509AuthenticationToken(certs));
+ if (authentication.isAuthenticated()) {
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
+ }
+
+ @Autowired
+ public void setAuthenticationManager(AuthenticationManager authenticationManager) {
+ this.authenticationManager = authenticationManager;
+ }
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/X509AuthenticationProvider.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/X509AuthenticationProvider.java
new file mode 100644
index 0000000..c297947
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/X509AuthenticationProvider.java
@@ -0,0 +1,49 @@
+/*
+ * 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.minifi.c2.security.authentication;
+
+import org.apache.nifi.minifi.c2.api.security.authorization.AuthorityGranter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+
+public class X509AuthenticationProvider implements AuthenticationProvider {
+ private static final Logger logger = LoggerFactory.getLogger(X509AuthenticationProvider.class);
+ private final AuthorityGranter authorityGranter;
+
+ public X509AuthenticationProvider(AuthorityGranter authorityGranter) {
+ this.authorityGranter = authorityGranter;
+ }
+
+ @Override
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+ X509AuthenticationToken x509AuthenticationToken = (X509AuthenticationToken) authentication;
+ if (logger.isDebugEnabled()) {
+ logger.debug("Authenticating " + X509AuthenticationToken.class.getSimpleName() + " with principal " + x509AuthenticationToken.getPrincipal());
+ }
+ return new C2AuthenticationToken(x509AuthenticationToken.getPrincipal(), x509AuthenticationToken.getCredentials(),
+ authorityGranter.grantAuthorities(authentication));
+ }
+
+ @Override
+ public boolean supports(Class<?> authentication) {
+ return X509AuthenticationToken.class.isAssignableFrom(authentication);
+ }
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/X509AuthenticationToken.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/X509AuthenticationToken.java
new file mode 100644
index 0000000..1faa0b3
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authentication/X509AuthenticationToken.java
@@ -0,0 +1,52 @@
+/*
+ * 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.minifi.c2.security.authentication;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+
+public class X509AuthenticationToken extends AbstractAuthenticationToken {
+ private final X509Certificate[] x509Certificates;
+ private final String subjectDn;
+
+ public X509AuthenticationToken(X509Certificate[] x509Certificates) {
+ this(x509Certificates, null);
+ setAuthenticated(false);
+ }
+
+ protected X509AuthenticationToken(X509Certificate[] x509Certificates, Collection<GrantedAuthority> grantedAuthorities) {
+ super(grantedAuthorities);
+ this.x509Certificates = Arrays.copyOf(x509Certificates, x509Certificates.length, X509Certificate[].class);
+ X509Certificate x509Certificate = x509Certificates[0];
+ this.subjectDn = x509Certificate.getSubjectDN().getName().trim();
+ }
+
+ @Override
+ public X509Certificate[] getCredentials() {
+ return x509Certificates;
+ }
+
+ @Override
+ public String getPrincipal() {
+ return subjectDn;
+ }
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authorization/GrantedAuthorityAuthorizer.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authorization/GrantedAuthorityAuthorizer.java
new file mode 100644
index 0000000..71f3fa4
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authorization/GrantedAuthorityAuthorizer.java
@@ -0,0 +1,138 @@
+/*
+ * 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.minifi.c2.security.authorization;
+
+import org.apache.nifi.minifi.c2.api.security.authorization.AuthorizationException;
+import org.apache.nifi.minifi.c2.api.security.authorization.Authorizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.Resource;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.yaml.snakeyaml.Yaml;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class GrantedAuthorityAuthorizer implements Authorizer {
+ private static final Logger logger = LoggerFactory.getLogger(GrantedAuthorityAuthorizer.class);
+
+ public static final String DENY = "deny";
+ public static final String ALLOW = "allow";
+ public static final String DEFAULT_ACTION = "Default Action";
+ private final Map<String, Object> grantedAuthorityMap;
+
+ public GrantedAuthorityAuthorizer(Resource configYaml) throws IOException {
+ try (InputStream inputStream = configYaml.getInputStream()) {
+ grantedAuthorityMap = as(Map.class, new Yaml().load(inputStream), o -> new IllegalArgumentException("Expected yaml map for root of configuration but was " + o));
+ }
+ }
+
+ @Override
+ public void authorize(Authentication authentication, UriInfo uriInfo) throws AuthorizationException {
+ if (authentication == null) {
+ throw new AuthorizationException("null authentication object provided.");
+ }
+
+ if (!authentication.isAuthenticated()) {
+ throw new AuthorizationException(authentication + " not authenticated.");
+ }
+
+ Set<String> authorities = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
+
+ String defaultAction = as(String.class, grantedAuthorityMap.getOrDefault(DEFAULT_ACTION, DENY));
+ String path = uriInfo.getAbsolutePath().getPath();
+ Map<String, Object> pathAuthorizations = as(Map.class, grantedAuthorityMap.get("Paths"));
+ if (pathAuthorizations == null && !ALLOW.equalsIgnoreCase(defaultAction)) {
+ throw new AuthorizationException("Didn't find authorizations for " + path + " and default policy is " + defaultAction + " instead of allow");
+ }
+
+ Map<String, Object> pathAuthorization = as(Map.class, pathAuthorizations.get(path));
+ if (pathAuthorization == null && !ALLOW.equalsIgnoreCase(defaultAction)) {
+ throw new AuthorizationException("Didn't find authorizations for " + path + " and default policy is " + defaultAction + " instead of allow");
+ }
+ defaultAction = as(String.class, pathAuthorization.getOrDefault(DEFAULT_ACTION, defaultAction));
+ List<Map<String, Object>> actions = as(List.class, pathAuthorization.get("Actions"));
+ MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters();
+ for (Map<String, Object> action : actions) {
+ String ruleAction = as(String.class, action.get("Action"));
+ if (ruleAction == null || !(ALLOW.equalsIgnoreCase(ruleAction) || DENY.equalsIgnoreCase(ruleAction))) {
+ throw new AuthorizationException("Expected Action key of allow or deny for " + action);
+ }
+ String authorization = as(String.class, action.get("Authorization"));
+ if (authorization != null && !authorities.contains(authorization)) {
+ continue;
+ }
+ Map<String, Object> parameters = as(Map.class, action.get("Query Parameters"));
+ if (parameters != null) {
+ boolean foundParameterMismatch = false;
+ for (Map.Entry<String, Object> parameter : parameters.entrySet()) {
+ Object value = parameter.getValue();
+ if (value instanceof String) {
+ value = Arrays.asList((String)value);
+ }
+ if (!Objects.equals(queryParameters.get(parameter.getKey()), value)) {
+ foundParameterMismatch = true;
+ break;
+ }
+ }
+ if (foundParameterMismatch) {
+ continue;
+ }
+ }
+ if (ALLOW.equalsIgnoreCase(ruleAction)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Action " + action + "matched which resulted in " + ruleAction);
+ }
+ return;
+ } else {
+ throw new AuthorizationException("Action " + action + " matched which resulted in " + ruleAction);
+ }
+ }
+ if (ALLOW.equalsIgnoreCase(defaultAction)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found no matching actions so falling back to default action " + defaultAction);
+ }
+ } else {
+ throw new AuthorizationException("Didn't find authorizations for " + path + " and default policy is " + defaultAction + " instead of allow");
+ }
+ }
+
+ private static <T> T as(Class<T> clazz, Object object) throws AuthorizationException {
+ return as(clazz, object, o -> new AuthorizationException("Expected " + clazz + " but was " + o));
+ }
+
+ private static <T, E extends Throwable> T as(Class<T> clazz, Object object, Function<Object, E> exceptionSupplier) throws E {
+ if (object == null) {
+ return null;
+ }
+ if (!clazz.isInstance(object)) {
+ throw exceptionSupplier.apply(object);
+ }
+ return clazz.cast(object);
+ }
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authorization/PrincipalStringAuthorityGranter.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authorization/PrincipalStringAuthorityGranter.java
new file mode 100644
index 0000000..24e1ffa
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/security/authorization/PrincipalStringAuthorityGranter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.minifi.c2.security.authorization;
+
+import org.apache.nifi.minifi.c2.api.security.authorization.AuthorityGranter;
+import org.springframework.core.io.Resource;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class PrincipalStringAuthorityGranter implements AuthorityGranter {
+ private final Map<String, List<String>> grantedAuthorityMap;
+
+ public PrincipalStringAuthorityGranter(Resource configYaml) throws IOException {
+ try (InputStream inputStream = configYaml.getInputStream()) {
+ Object yaml = new Yaml().load(inputStream);
+ if (!(yaml instanceof Map)) {
+ throw new IllegalArgumentException("Expected authority map of Principal -> Authority list");
+ }
+ grantedAuthorityMap = (Map<String, List<String>>) yaml;
+ }
+ }
+ @Override
+ public Collection<GrantedAuthority> grantAuthorities(Authentication authentication) {
+ List<String> authorities = grantedAuthorityMap.get(authentication.getPrincipal().toString());
+ if (authorities == null) {
+ return null;
+ }
+ return authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
+ }
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
new file mode 100644
index 0000000..e57089e
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
@@ -0,0 +1,167 @@
+/*
+ * 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.minifi.c2.service;
+
+import com.wordnik.swagger.annotations.Api;
+import org.apache.nifi.minifi.c2.api.Configuration;
+import org.apache.nifi.minifi.c2.api.ConfigurationProvider;
+import org.apache.nifi.minifi.c2.api.InvalidParameterException;
+import org.apache.nifi.minifi.c2.api.security.authorization.AuthorizationException;
+import org.apache.nifi.minifi.c2.api.security.authorization.Authorizer;
+import org.apache.nifi.minifi.c2.api.util.Pair;
+import org.apache.nifi.minifi.c2.util.HttpRequestUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Path("/config")
+@Api(
+ value = "/config",
+ description = "Provides configuration for MiNiFi instances"
+)
+public class ConfigService {
+ private static final Logger logger = LoggerFactory.getLogger(ConfigService.class);
+ private final List<Pair<MediaType, ConfigurationProvider>> configurationProviders;
+ private final Authorizer authorizer;
+
+ public ConfigService(List<ConfigurationProvider> configurationProviders, Authorizer authorizer) {
+ this.authorizer = authorizer;
+ if (configurationProviders == null || configurationProviders.size() == 0) {
+ throw new IllegalArgumentException("Expected at least one configuration provider");
+ }
+ this.configurationProviders = configurationProviders.stream().map(c -> new Pair<>(MediaType.valueOf(c.getContentType()), c)).collect(Collectors.toList());
+ }
+
+ @GET
+ public Response getConfig(@Context HttpServletRequest request, @Context HttpHeaders httpHeaders, @Context UriInfo uriInfo) {
+ try {
+ authorizer.authorize(SecurityContextHolder.getContext().getAuthentication(), uriInfo);
+ } catch (AuthorizationException e) {
+ logger.warn(HttpRequestUtil.getClientString(request) + " not authorized to access " + uriInfo, e);
+ return Response.status(403).build();
+ }
+ Map<String, List<String>> parameters = new HashMap<>();
+ for (Map.Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+ parameters.put(entry.getKey(), entry.getValue());
+ }
+ List<MediaType> acceptValues = httpHeaders.getAcceptableMediaTypes();
+ boolean defaultAccept = false;
+ if (acceptValues.size() == 0) {
+ acceptValues = Arrays.asList(MediaType.WILDCARD_TYPE);
+ defaultAccept = true;
+ }
+ if (logger.isDebugEnabled()) {
+ StringBuilder builder = new StringBuilder("Handling request from ")
+ .append(HttpRequestUtil.getClientString(request))
+ .append(" with parameters ")
+ .append(parameters)
+ .append(" and Accept");
+ if (defaultAccept) {
+ builder = builder.append(" default value");
+ }
+ builder = builder.append(": ")
+ .append(acceptValues.stream().map(Object::toString).collect(Collectors.joining(", ")));
+ logger.debug(builder.toString());
+ }
+ Pair<MediaType, ConfigurationProvider> providerPair = getProvider(acceptValues);
+
+ try {
+ Integer version = null;
+ List<String> versionList = parameters.get("version");
+ if (versionList != null && versionList.size() > 0) {
+ try {
+ version = Integer.parseInt(versionList.get(0));
+ } catch (NumberFormatException e) {
+ throw new InvalidParameterException("Unable to parse " + version + " as integer.", e);
+ }
+ }
+ Response.ResponseBuilder ok = Response.ok();
+ Configuration configuration = providerPair.getSecond().getConfiguration(version, parameters);
+ ok = ok.header("X-Content-Version", configuration.getVersion());
+ ok = ok.type(providerPair.getFirst());
+ byte[] buffer = new byte[1024];
+ int read;
+ try (InputStream inputStream = configuration.getInputStream();
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
+ while((read = inputStream.read(buffer)) >= 0) {
+ outputStream.write(buffer, 0, read);
+ md5.update(buffer, 0, read);
+ sha256.update(buffer, 0, read);
+ }
+ ok = ok.header("Content-MD5", bytesToHex(md5.digest()));
+ ok = ok.header("X-Content-SHA-256", bytesToHex(sha256.digest()));
+ ok = ok.entity(outputStream.toByteArray());
+ } catch (IOException|NoSuchAlgorithmException e) {
+ logger.error("Error reading or checksumming configuration file", e);
+ throw new WebApplicationException(500);
+ }
+ return ok.build();
+ } catch (InvalidParameterException e) {
+ logger.info(HttpRequestUtil.getClientString(request) + " made invalid request with " + HttpRequestUtil.getQueryString(request), e);
+ return Response.status(400).entity("Invalid request.").build();
+ } catch (Throwable t) {
+ logger.error(HttpRequestUtil.getClientString(request) + " made request with " + HttpRequestUtil.getQueryString(request) + " that caused error in " + providerPair.getSecond(), t);
+ return Response.status(500).entity("Internal error").build();
+ }
+ }
+
+ // see: http://stackoverflow.com/questions/15429257/how-to-convert-byte-array-to-hexstring-in-java#answer-15429408
+ protected static String bytesToHex(byte[] in) {
+ final StringBuilder builder = new StringBuilder();
+ for(byte b : in) {
+ builder.append(String.format("%02x", b));
+ }
+ return builder.toString();
+ }
+
+ private Pair<MediaType, ConfigurationProvider> getProvider(List<MediaType> acceptValues) {
+ for (MediaType accept : acceptValues) {
+ for (Pair<MediaType, ConfigurationProvider> configurationProviderPair : configurationProviders) {
+ if (accept.isCompatible(configurationProviderPair.getFirst())) {
+ return configurationProviderPair;
+ }
+ }
+ }
+
+ throw new WebApplicationException(Response.status(406).entity("Unable to find configuration provider for " +
+ "\"Accept: " + acceptValues.stream().map(Object::toString).collect(Collectors.joining(", ")) + "\" supported media types are " +
+ configurationProviders.stream().map(Pair::getFirst).map(Object::toString).collect(Collectors.joining(", "))).build());
+ }
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/util/HttpRequestUtil.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/util/HttpRequestUtil.java
new file mode 100644
index 0000000..395eb73
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/util/HttpRequestUtil.java
@@ -0,0 +1,41 @@
+/*
+ * 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.minifi.c2.util;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+public class HttpRequestUtil {
+ public static String getQueryString(HttpServletRequest request) {
+ String queryString = request.getQueryString();
+ if (queryString == null) {
+ return "no query string";
+ }
+ return "query string \"" + queryString + "\"";
+ }
+
+ public static String getClientString(ServletRequest request) {
+ String remoteHost = request.getRemoteHost();
+ String remoteAddr = request.getRemoteAddr();
+ String result = "Client " + remoteHost;
+ if (!remoteAddr.equals(remoteHost)) {
+ result = result + " (" + remoteAddr + ")";
+ }
+ return result;
+ }
+}
diff --git a/minifi-c2/minifi-c2-service/src/main/webapp/WEB-INF/web.xml b/minifi-c2/minifi-c2-service/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..7be7364
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
+ <display-name>minifi-c2</display-name>
+ <context-param>
+ <param-name>contextClass</param-name>
+ <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
+ </context-param>
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>org.apache.nifi.minifi.c2.configuration</param-value>
+ </context-param>
+ <listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+ </listener>
+ <servlet>
+ <servlet-name>jerseySpring</servlet-name>
+ <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
+ <init-param>
+ <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>jerseySpring</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+ <filter>
+ <filter-name>springSecurityFilterChain</filter-name>
+ <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+ </filter>
+ <filter-mapping>
+ <filter-name>springSecurityFilterChain</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+</web-app>
diff --git a/minifi-c2/pom.xml b/minifi-c2/pom.xml
new file mode 100644
index 0000000..f4d5add
--- /dev/null
+++ b/minifi-c2/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>minifi-c2-api</module>
+ <module>minifi-c2-cache</module>
+ <module>minifi-c2-provider</module>
+ <module>minifi-c2-service</module>
+ <module>minifi-c2-jetty</module>
+ <module>minifi-c2-assembly</module>
+ <module>minifi-c2-docker</module>
+ <module>minifi-c2-integration-tests</module>
+ </modules>
+</project>
diff --git a/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-resources/src/main/resources/conf/bootstrap.conf b/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-resources/src/main/resources/conf/bootstrap.conf
index 537536e..85204cc 100644
--- a/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-resources/src/main/resources/conf/bootstrap.conf
+++ b/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-resources/src/main/resources/conf/bootstrap.conf
@@ -54,6 +54,10 @@
#nifi.minifi.notifier.ingestors.pull.http.hostname=localhost
# Port on which to pull configurations from
#nifi.minifi.notifier.ingestors.pull.http.port=4567
+# Path to pull configurations from
+#nifi.minifi.notifier.ingestors.pull.http.path=/c2/config
+# Query string to pull configurations with
+#nifi.minifi.notifier.ingestors.pull.http.query=class=raspi3
# Period on which to pull configurations from, defaults to 5 minutes if commented out
#nifi.minifi.notifier.ingestors.pull.http.period.ms=300000
diff --git a/pom.xml b/pom.xml
index 3727ce4..3fa1f2a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,6 +39,7 @@
<module>minifi-assembly</module>
<module>minifi-toolkit</module>
<module>minifi-docker</module>
+ <module>minifi-c2</module>
</modules>
<url>http://nifi.apache.org/minifi</url>
@@ -402,6 +403,11 @@
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-toolkit-tls</artifactId>
+ <version>${org.apache.nifi.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
<artifactId>nifi-resources</artifactId>
<version>${org.apache.nifi.version}</version>
<classifier>resources</classifier>