diff --git a/minifi/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java b/minifi/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java
index 90fbdba346..3f78b52269 100644
--- a/minifi/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java
+++ b/minifi/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java
@@ -18,6 +18,7 @@
package org.apache.nifi.minifi.c2.api;
import java.io.InputStream;
+import java.net.URL;
/**
* Represents a MiNiFi configuration of a given version, format matches the format of the ConfigurationProvider
@@ -44,4 +45,11 @@ public interface Configuration {
* @return an input stream to read the configuration with
*/
InputStream getInputStream() throws ConfigurationProviderException;
+
+ /**
+ * Gets the URL of the resource
+ *
+ * @return the URL of the resource
+ */
+ URL getURL() throws ConfigurationProviderException;
}
diff --git a/minifi/minifi-c2/minifi-c2-assembly/pom.xml b/minifi/minifi-c2/minifi-c2-assembly/pom.xml
index ba2553e395..148a6efe7b 100644
--- a/minifi/minifi-c2/minifi-c2-assembly/pom.xml
+++ b/minifi/minifi-c2/minifi-c2-assembly/pom.xml
@@ -26,7 +26,7 @@ limitations under the License.
pomThis is the assembly of Apache MiNiFi's - Command And Control Server
- 10080
+ 10090false./conf/keystore.jks
diff --git a/minifi/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml b/minifi/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml
index 5669451940..14386e5c17 100644
--- a/minifi/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml
+++ b/minifi/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml
@@ -37,3 +37,31 @@ Paths:
# Default authorization lets anonymous pull any config. Remove below to change that.
- Authorization: ROLE_ANONYMOUS
Action: allow
+
+ /c2/config/heartbeat:
+ 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
+
+ /c2/config/acknowledge:
+ 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
diff --git a/minifi/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemWritableConfiguration.java b/minifi/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemWritableConfiguration.java
index bb48dcc3df..65afe5c1fd 100644
--- a/minifi/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemWritableConfiguration.java
+++ b/minifi/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemWritableConfiguration.java
@@ -25,6 +25,8 @@ import org.apache.nifi.minifi.c2.api.util.DelegatingOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
@@ -82,6 +84,15 @@ public class FileSystemWritableConfiguration implements WriteableConfiguration {
}
}
+ @Override
+ public URL getURL() throws ConfigurationProviderException {
+ try {
+ return path.toUri().toURL();
+ } catch (MalformedURLException murle) {
+ throw new ConfigurationProviderException("Could not determine URL of " + path, murle);
+ }
+ }
+
@Override
public String getName() {
return path.getFileName().toString();
diff --git a/minifi/minifi-c2/minifi-c2-cache/minifi-c2-cache-s3/src/main/java/org/apache/nifi/minifi/c2/cache/s3/S3WritableConfiguration.java b/minifi/minifi-c2/minifi-c2-cache/minifi-c2-cache-s3/src/main/java/org/apache/nifi/minifi/c2/cache/s3/S3WritableConfiguration.java
index 4ab62c9885..7bcf0a668b 100644
--- a/minifi/minifi-c2/minifi-c2-cache/minifi-c2-cache-s3/src/main/java/org/apache/nifi/minifi/c2/cache/s3/S3WritableConfiguration.java
+++ b/minifi/minifi-c2/minifi-c2-cache/minifi-c2-cache-s3/src/main/java/org/apache/nifi/minifi/c2/cache/s3/S3WritableConfiguration.java
@@ -23,13 +23,14 @@ import com.amazonaws.services.s3.model.S3ObjectSummary;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.URL;
import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
import org.apache.nifi.minifi.c2.api.cache.WriteableConfiguration;
public class S3WritableConfiguration implements WriteableConfiguration {
- private AmazonS3 s3;
+ private final AmazonS3 s3;
private final S3Object s3Object;
private final String version;
@@ -81,6 +82,11 @@ public class S3WritableConfiguration implements WriteableConfiguration {
return s3Object.getObjectContent();
}
+ @Override
+ public URL getURL() throws ConfigurationProviderException {
+ return s3.getUrl(s3Object.getBucketName(), s3Object.getKey());
+ }
+
@Override
public String getName() {
return s3Object.getKey();
diff --git a/minifi/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml b/minifi/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml
index cec43376aa..bd5517fc71 100644
--- a/minifi/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml
+++ b/minifi/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml
@@ -15,7 +15,8 @@ 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.
-->
-
+4.0.0minifi-c2-provider
@@ -53,6 +54,10 @@ limitations under the License.
org.slf4jslf4j-log4j12
+
+ org.glassfish.jersey.media
+ jersey-media-json-jackson
+
diff --git a/minifi/minifi-c2/minifi-c2-service/pom.xml b/minifi/minifi-c2/minifi-c2-service/pom.xml
index 6fcd217313..97de3fb79e 100644
--- a/minifi/minifi-c2/minifi-c2-service/pom.xml
+++ b/minifi/minifi-c2/minifi-c2-service/pom.xml
@@ -29,9 +29,29 @@ limitations under the License.
org.apache.nifi.minifiminifi-c2-api
- ${project.version}
+ 1.17.0-SNAPSHOTprovided
+
+ org.apache.nifi
+ c2-protocol-api
+ 1.17.0-SNAPSHOT
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jaxb-annotations
+ provided
+
+
+ com.fasterxml.jackson.jaxrs
+ jackson-jaxrs-json-provider
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+ org.springframeworkspring-context
diff --git a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/configuration/C2ResourceConfig.java b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/configuration/C2ResourceConfig.java
index 5ed07b23be..95dc5f620c 100644
--- a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/configuration/C2ResourceConfig.java
+++ b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/configuration/C2ResourceConfig.java
@@ -17,6 +17,7 @@
package org.apache.nifi.minifi.c2.configuration;
+import org.apache.nifi.minifi.c2.service.C2JsonProviderFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
@@ -29,6 +30,8 @@ public class C2ResourceConfig extends ResourceConfig {
public C2ResourceConfig(@Context ServletContext servletContext) {
final ApplicationContext appCtx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
+ // register Jackson Object Mapper Resolver
+ register(C2JsonProviderFeature.class);
register(appCtx.getBean("configService"));
}
}
diff --git a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2JsonProvider.java b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2JsonProvider.java
new file mode 100644
index 0000000000..c12cfc9e74
--- /dev/null
+++ b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2JsonProvider.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.service;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+@Produces(MediaType.APPLICATION_JSON)
+public class C2JsonProvider extends JacksonJaxbJsonProvider {
+
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+
+ static {
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ }
+
+ public C2JsonProvider() {
+ super();
+ setMapper(objectMapper);
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2JsonProviderFeature.java b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2JsonProviderFeature.java
new file mode 100644
index 0000000000..e40e8201ad
--- /dev/null
+++ b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2JsonProviderFeature.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.service;
+
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.FeatureContext;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+public class C2JsonProviderFeature implements Feature {
+
+ @Override
+ public boolean configure(FeatureContext context) {
+ context.register(C2JsonProvider.class, MessageBodyReader.class, MessageBodyWriter.class);
+ return true;
+ }
+}
diff --git a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2ProtocolContext.java b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2ProtocolContext.java
new file mode 100644
index 0000000000..e09af8e7b2
--- /dev/null
+++ b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2ProtocolContext.java
@@ -0,0 +1,96 @@
+/*
+ * 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+
+public class C2ProtocolContext {
+ private static final Logger logger = LoggerFactory.getLogger(C2ProtocolContext.class);
+
+ private static final C2ProtocolContext EMPTY = builder().build();
+
+ private final URI baseUri;
+ private final Long contentLength;
+ private final String sha256;
+
+ C2ProtocolContext(final Builder builder) {
+ this.baseUri = builder.baseUri;
+ this.contentLength = builder.contentLength;
+ this.sha256 = builder.sha256;
+ }
+
+ public URI getBaseUri() {
+ return baseUri;
+ }
+
+ public Long getContentLength() {
+ return contentLength;
+ }
+
+ public String getSha256() {
+ return sha256;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static C2ProtocolContext empty() {
+ return EMPTY;
+ }
+
+ public static class Builder {
+
+ private URI baseUri;
+ private Long contentLength;
+ private String sha256;
+
+ private Builder() {
+ }
+
+ public Builder baseUri(final URI baseUri) {
+ this.baseUri = baseUri;
+ return this;
+ }
+
+ public Builder contentLength(final Long contentLength) {
+ this.contentLength = contentLength;
+ return this;
+ }
+
+ public Builder contentLength(final String contentLength) {
+ try {
+ this.contentLength = Long.valueOf(contentLength);
+ } catch (final NumberFormatException e) {
+ logger.debug("Could not parse content length string: " + contentLength, e);
+ }
+ return this;
+ }
+
+ public Builder sha256(final String sha256) {
+ this.sha256 = sha256;
+ return this;
+ }
+
+ public C2ProtocolContext build() {
+ return new C2ProtocolContext(this);
+ }
+ }
+}
diff --git a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2ProtocolService.java b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2ProtocolService.java
new file mode 100644
index 0000000000..756c92065a
--- /dev/null
+++ b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/C2ProtocolService.java
@@ -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.
+ */
+package org.apache.nifi.minifi.c2.service;
+
+import org.apache.nifi.c2.protocol.api.C2Heartbeat;
+import org.apache.nifi.c2.protocol.api.C2HeartbeatResponse;
+import org.apache.nifi.c2.protocol.api.C2OperationAck;
+
+public interface C2ProtocolService {
+ C2HeartbeatResponse processHeartbeat(C2Heartbeat heartbeat, C2ProtocolContext context);
+
+ void processOperationAck(C2OperationAck operationAck, C2ProtocolContext context);
+}
diff --git a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
index 0732befcd7..9b70fba527 100644
--- a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
+++ b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
@@ -18,14 +18,19 @@
package org.apache.nifi.minifi.c2.service;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import io.swagger.annotations.ApiModel;
-import org.apache.nifi.minifi.c2.api.Configuration;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.apache.nifi.c2.protocol.api.C2Heartbeat;
+import org.apache.nifi.c2.protocol.api.C2HeartbeatResponse;
+import org.apache.nifi.c2.protocol.api.C2OperationAck;
import org.apache.nifi.minifi.c2.api.ConfigurationProvider;
import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
import org.apache.nifi.minifi.c2.api.InvalidParameterException;
@@ -35,10 +40,13 @@ 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.context.annotation.Configuration;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
+import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
@@ -50,10 +58,11 @@ import javax.ws.rs.core.UriInfo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.net.URI;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -61,36 +70,53 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
+import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH;
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+@Configuration
@Path("/config")
@ApiModel(
value = "/config",
- description = "Provides configuration for MiNiFi instances"
+ description = "Provides configuration and heartbeat/acknowledge capabilities for MiNiFi instances"
)
public class ConfigService {
+
+ public static final String MESSAGE_400 = "MiNiFi C2 server was unable to complete the request because it was invalid. The request should not be retried without modification.";
+
private static final Logger logger = LoggerFactory.getLogger(ConfigService.class);
private final Authorizer authorizer;
private final ObjectMapper objectMapper;
private final Supplier configurationProviderInfo;
private final LoadingCache configurationCache;
+ private final C2ProtocolService c2ProtocolService;
+
+ @Context
+ protected HttpServletRequest httpServletRequest;
+
+ @Context
+ protected UriInfo uriInfo;
public ConfigService(List configurationProviders, Authorizer authorizer) {
this(configurationProviders, authorizer, 1000, 300_000);
}
+
public ConfigService(List configurationProviders, Authorizer authorizer, long maximumCacheSize, long cacheTtlMillis) {
- this.authorizer = authorizer;
this.objectMapper = new ObjectMapper();
+
+ this.authorizer = authorizer;
if (configurationProviders == null || configurationProviders.size() == 0) {
throw new IllegalArgumentException("Expected at least one configuration provider");
}
this.configurationProviderInfo = Suppliers.memoizeWithExpiration(() -> initContentTypeInfo(configurationProviders), cacheTtlMillis, TimeUnit.MILLISECONDS);
CacheBuilder