http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java new file mode 100644 index 0000000..543ea87 --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java @@ -0,0 +1,651 @@ +/* + * 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.registry.web.api; + +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.SecureLdapTestApiApplication; +import org.apache.nifi.registry.authorization.AccessPolicy; +import org.apache.nifi.registry.authorization.AccessPolicySummary; +import org.apache.nifi.registry.authorization.CurrentUser; +import org.apache.nifi.registry.authorization.Permissions; +import org.apache.nifi.registry.authorization.Tenant; +import org.apache.nifi.registry.bucket.Bucket; +import org.apache.nifi.registry.extension.ExtensionManager; +import org.apache.nifi.registry.properties.AESSensitivePropertyProvider; +import org.apache.nifi.registry.properties.NiFiRegistryProperties; +import org.apache.nifi.registry.properties.SensitivePropertyProvider; +import org.apache.nifi.registry.security.authorization.Authorizer; +import org.apache.nifi.registry.security.authorization.AuthorizerFactory; +import org.apache.nifi.registry.security.crypto.BootstrapFileCryptoKeyProvider; +import org.apache.nifi.registry.security.crypto.CryptoKeyProvider; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.DependsOn; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Form; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Deploy the Web API Application using an embedded Jetty Server for local integration testing, with the follow characteristics: + * + * - A NiFiRegistryProperties has to be explicitly provided to the ApplicationContext using a profile unique to this test suite. + * - A NiFiRegistryClientConfig has been configured to create a client capable of completing one-way TLS + * - The database is embed H2 using volatile (in-memory) persistence + * - Custom SQL is clearing the DB before each test method by default, unless method overrides this behavior + */ +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = SecureLdapTestApiApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = "spring.profiles.include=ITSecureLdap") +@Import(SecureITClientConfiguration.class) +@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:db/clearDB.sql") +public class SecureLdapIT extends IntegrationTestBase { + + private static final String tokenLoginPath = "access/token/login"; + private static final String tokenIdentityProviderPath = "access/token/identity-provider"; + + @TestConfiguration + @Profile("ITSecureLdap") + public static class LdapTestConfiguration { + + static AuthorizerFactory authorizerFactory; + + @Primary + @Bean + @DependsOn({"directoryServer"}) // Can't load LdapUserGroupProvider until the embedded LDAP server, which creates the "directoryServer" bean, is running + public static Authorizer getAuthorizer(@Autowired NiFiRegistryProperties properties, ExtensionManager extensionManager) throws Exception { + if (authorizerFactory == null) { + authorizerFactory = new AuthorizerFactory(properties, extensionManager, sensitivePropertyProvider()); + } + return authorizerFactory.getAuthorizer(); + } + + @Primary + @Bean + public static SensitivePropertyProvider sensitivePropertyProvider() throws Exception { + return new AESSensitivePropertyProvider(getNiFiRegistryMasterKeyProvider().getKey()); + } + + private static CryptoKeyProvider getNiFiRegistryMasterKeyProvider() { + return new BootstrapFileCryptoKeyProvider("src/test/resources/conf/secure-ldap/bootstrap.conf"); + } + + } + + private String adminAuthToken; + private List<AccessPolicy> beforeTestAccessPoliciesSnapshot; + + @Before + public void setup() { + final String basicAuthCredentials = encodeCredentialsForBasicAuth("nifiadmin", "password"); + final String token = client + .target(createURL(tokenIdentityProviderPath)) + .request() + .header("Authorization", "Basic " + basicAuthCredentials) + .post(null, String.class); + adminAuthToken = token; + + beforeTestAccessPoliciesSnapshot = createAccessPoliciesSnapshot(); + } + + @After + public void cleanup() { + restoreAccessPoliciesSnapshot(beforeTestAccessPoliciesSnapshot); + } + + @Test + public void testTokenGenerationAndAccessStatus() throws Exception { + + // Note: this test intentionally does not use the token generated + // for nifiadmin by the @Before method + + // Given: the client and server have been configured correctly for LDAP authentication + String expectedJwtPayloadJson = "{" + + "\"sub\":\"nobel\"," + + "\"preferred_username\":\"nobel\"," + + "\"iss\":\"LdapIdentityProvider\"" + + "}"; + String expectedAccessStatusJson = "{" + + "\"identity\":\"nobel\"," + + "\"anonymous\":false" + + "}"; + + // When: the /access/token/login endpoint is queried + final String basicAuthCredentials = encodeCredentialsForBasicAuth("nobel", "password"); + final Response tokenResponse = client + .target(createURL(tokenIdentityProviderPath)) + .request() + .header("Authorization", "Basic " + basicAuthCredentials) + .post(null, Response.class); + + // Then: the server returns 200 OK with an access token + assertEquals(201, tokenResponse.getStatus()); + String token = tokenResponse.readEntity(String.class); + assertTrue(StringUtils.isNotEmpty(token)); + String[] jwtParts = token.split("\\."); + assertEquals(3, jwtParts.length); + String jwtPayload = new String(Base64.getDecoder().decode(jwtParts[1]), "UTF-8"); + JSONAssert.assertEquals(expectedJwtPayloadJson, jwtPayload, false); + + // When: the token is returned in the Authorization header + final Response accessResponse = client + .target(createURL("access")) + .request() + .header("Authorization", "Bearer " + token) + .get(Response.class); + + // Then: the server acknowledges the client has access + assertEquals(200, accessResponse.getStatus()); + String accessStatus = accessResponse.readEntity(String.class); + JSONAssert.assertEquals(expectedAccessStatusJson, accessStatus, false); + + } + + @Test + public void testTokenGenerationWithIdentityProvider() throws Exception { + + // Given: the client and server have been configured correctly for LDAP authentication + String expectedJwtPayloadJson = "{" + + "\"sub\":\"nobel\"," + + "\"preferred_username\":\"nobel\"," + + "\"iss\":\"LdapIdentityProvider\"," + + "\"aud\":\"LdapIdentityProvider\"" + + "}"; + String expectedAccessStatusJson = "{" + + "\"identity\":\"nobel\"," + + "\"anonymous\":false" + + "}"; + + // When: the /access/token/identity-provider endpoint is queried + final String basicAuthCredentials = encodeCredentialsForBasicAuth("nobel", "password"); + final Response tokenResponse = client + .target(createURL(tokenIdentityProviderPath)) + .request() + .header("Authorization", "Basic " + basicAuthCredentials) + .post(null, Response.class); + + // Then: the server returns 200 OK with an access token + assertEquals(201, tokenResponse.getStatus()); + String token = tokenResponse.readEntity(String.class); + assertTrue(StringUtils.isNotEmpty(token)); + String[] jwtParts = token.split("\\."); + assertEquals(3, jwtParts.length); + String jwtPayload = new String(Base64.getDecoder().decode(jwtParts[1]), "UTF-8"); + JSONAssert.assertEquals(expectedJwtPayloadJson, jwtPayload, false); + + // When: the token is returned in the Authorization header + final Response accessResponse = client + .target(createURL("access")) + .request() + .header("Authorization", "Bearer " + token) + .get(Response.class); + + // Then: the server acknowledges the client has access + assertEquals(200, accessResponse.getStatus()); + String accessStatus = accessResponse.readEntity(String.class); + JSONAssert.assertEquals(expectedAccessStatusJson, accessStatus, false); + + } + + @Test + public void testGetCurrentUserFailsForAnonymous() throws Exception { + + // Given: the client is connected to an unsecured NiFi Registry + + // When: the /access endpoint is queried with no credentials + final Response response = client + .target(createURL("/access")) + .request() + .get(Response.class); + + // Then: the server returns a 200 OK with the expected current user + assertEquals(401, response.getStatus()); + + } + + @Test + public void testGetCurrentUser() throws Exception { + + // Given: the client is connected to an unsecured NiFi Registry + String expectedJson = "{" + + "\"identity\":\"nifiadmin\"," + + "\"anonymous\":false," + + "\"resourcePermissions\":{" + + "\"anyTopLevelResource\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"buckets\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"tenants\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"policies\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"proxy\":{\"canRead\":false,\"canWrite\":true,\"canDelete\":false}}" + + "}"; + + // When: the /access endpoint is queried using a JWT for the nifiadmin LDAP user + final Response response = client + .target(createURL("/access")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(Response.class); + + // Then: the server returns a 200 OK with the expected current user + assertEquals(200, response.getStatus()); + String actualJson = response.readEntity(String.class); + JSONAssert.assertEquals(expectedJson, actualJson, false); + + } + + @Test + public void testUsers() throws Exception { + + // Given: the client and server have been configured correctly for LDAP authentication + String expectedJson = "[" + + "{\"identity\":\"nifiadmin\",\"userGroups\":[],\"configurable\":false," + + "\"resourcePermissions\":{" + + "\"anyTopLevelResource\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"buckets\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"tenants\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"policies\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"proxy\":{\"canRead\":false,\"canWrite\":true,\"canDelete\":false}}}," + + "{\"identity\":\"euler\",\"userGroups\":[{\"identity\":\"mathematicians\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"euclid\",\"userGroups\":[{\"identity\":\"mathematicians\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"boyle\",\"userGroups\":[{\"identity\":\"chemists\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"newton\",\"userGroups\":[{\"identity\":\"scientists\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"riemann\",\"userGroups\":[{\"identity\":\"mathematicians\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"gauss\",\"userGroups\":[{\"identity\":\"mathematicians\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"galileo\",\"userGroups\":[{\"identity\":\"scientists\"},{\"identity\":\"italians\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"nobel\",\"userGroups\":[{\"identity\":\"chemists\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"pasteur\",\"userGroups\":[{\"identity\":\"chemists\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"tesla\",\"userGroups\":[{\"identity\":\"scientists\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"nogroup\",\"userGroups\":[],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"einstein\",\"userGroups\":[{\"identity\":\"scientists\"}],\"accessPolicies\":[],\"configurable\":false}," + + "{\"identity\":\"curie\",\"userGroups\":[{\"identity\":\"chemists\"}],\"accessPolicies\":[],\"configurable\":false}]"; + + // When: the /tenants/users endpoint is queried + final String usersJson = client + .target(createURL("tenants/users")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(String.class); + + // Then: the server returns a list of all users (see test-ldap-data.ldif) + JSONAssert.assertEquals(expectedJson, usersJson, false); + } + + @Test + public void testUserGroups() throws Exception { + + // Given: the client and server have been configured correctly for LDAP authentication + String expectedJson = "[" + + "{" + + "\"identity\":\"chemists\"," + + "\"users\":[{\"identity\":\"pasteur\"},{\"identity\":\"boyle\"},{\"identity\":\"curie\"},{\"identity\":\"nobel\"}]," + + "\"accessPolicies\":[]," + + "\"configurable\":false" + + "}," + + "{" + + "\"identity\":\"mathematicians\"," + + "\"users\":[{\"identity\":\"gauss\"},{\"identity\":\"euclid\"},{\"identity\":\"riemann\"},{\"identity\":\"euler\"}]," + + "\"accessPolicies\":[]," + + "\"configurable\":false" + + "}," + + "{" + + "\"identity\":\"scientists\"," + + "\"users\":[{\"identity\":\"einstein\"},{\"identity\":\"tesla\"},{\"identity\":\"newton\"},{\"identity\":\"galileo\"}]," + + "\"accessPolicies\":[]," + + "\"configurable\":false" + + "}," + + "{" + + "\"identity\":\"italians\"," + + "\"users\":[{\"identity\":\"galileo\"}]," + + "\"accessPolicies\":[]," + + "\"configurable\":false" + + "}]"; + + // When: the /tenants/users endpoint is queried + final String groupsJson = client + .target(createURL("tenants/user-groups")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(String.class); + + // Then: the server returns a list of all users (see test-ldap-data.ldif) + JSONAssert.assertEquals(expectedJson, groupsJson, false); + } + + @Test + public void testCreateTenantFails() throws Exception { + + // Given: the server has been configured with the LdapUserGroupProvider, which is non-configurable, + // and: the client wants to create a tenant + Tenant tenant = new Tenant(); + tenant.setIdentity("new_tenant"); + + // When: the POST /tenants/users endpoint is accessed + final Response createUserResponse = client + .target(createURL("tenants/users")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .post(Entity.entity(tenant, MediaType.APPLICATION_JSON_TYPE), Response.class); + + // Then: an error is returned + assertEquals(409, createUserResponse.getStatus()); + + // When: the POST /tenants/users endpoint is accessed + final Response createUserGroupResponse = client + .target(createURL("tenants/user-groups")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .post(Entity.entity(tenant, MediaType.APPLICATION_JSON_TYPE), Response.class); + + // Then: an error is returned because the UserGroupProvider is non-configurable + assertEquals(409, createUserGroupResponse.getStatus()); + } + + @Test + public void testAccessPolicyCreation() throws Exception { + + // Given: the server has been configured with an initial admin "nifiadmin" and a user with no accessPolicies "nobel" + String nobelId = getTenantIdentifierByIdentity("nobel"); + String chemistsId = getTenantIdentifierByIdentity("chemists"); // a group containing user "nobel" + + final String basicAuthCredentials = encodeCredentialsForBasicAuth("nobel", "password"); + final String nobelAuthToken = client + .target(createURL(tokenIdentityProviderPath)) + .request() + .header("Authorization", "Basic " + basicAuthCredentials) + .post(null, String.class); + + // When: user nobel re-checks top-level permissions + final CurrentUser currentUser = client + .target(createURL("/access")) + .request() + .header("Authorization", "Bearer " + nobelAuthToken) + .get(CurrentUser.class); + + // Then: 200 OK is returned indicating user has access to no top-level resources + assertEquals(new Permissions(), currentUser.getResourcePermissions().getBuckets()); + assertEquals(new Permissions(), currentUser.getResourcePermissions().getTenants()); + assertEquals(new Permissions(), currentUser.getResourcePermissions().getPolicies()); + assertEquals(new Permissions(), currentUser.getResourcePermissions().getProxy()); + + // When: nifiadmin creates a bucket + final Bucket bucket = new Bucket(); + bucket.setName("Integration Test Bucket"); + bucket.setDescription("A bucket created by an integration test."); + Response adminCreatesBucketResponse = client + .target(createURL("buckets")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .post(Entity.entity(bucket, MediaType.APPLICATION_JSON), Response.class); + + // Then: the server returns a 200 OK + assertEquals(200, adminCreatesBucketResponse.getStatus()); + Bucket createdBucket = adminCreatesBucketResponse.readEntity(Bucket.class); + + + // When: user nobel initial queries /buckets + final Bucket[] buckets1 = client + .target(createURL("buckets")) + .request() + .header("Authorization", "Bearer " + nobelAuthToken) + .get(Bucket[].class); + + // Then: an empty list is returned (nobel has no read access yet) + assertNotNull(buckets1); + assertEquals(0, buckets1.length); + + + // When: nifiadmin grants read access on createdBucket to 'chemists' a group containing nobel + AccessPolicy readPolicy = new AccessPolicy(); + readPolicy.setResource("/buckets/" + createdBucket.getIdentifier()); + readPolicy.setAction("read"); + readPolicy.addUserGroups(Arrays.asList(new Tenant(chemistsId, "chemists"))); + Response adminGrantsReadAccessResponse = client + .target(createURL("policies")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .post(Entity.entity(readPolicy, MediaType.APPLICATION_JSON), Response.class); + + // Then: the server returns a 201 Created + assertEquals(201, adminGrantsReadAccessResponse.getStatus()); + + + // When: nifiadmin tries to list all buckets + final Bucket[] adminBuckets = client + .target(createURL("buckets")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(Bucket[].class); + + // Then: the full list is returned (verifies that per-bucket access policies are additive to base /buckets policy) + assertNotNull(adminBuckets); + assertEquals(1, adminBuckets.length); + assertEquals(createdBucket.getIdentifier(), adminBuckets[0].getIdentifier()); + assertEquals(new Permissions().withCanRead(true).withCanWrite(true).withCanDelete(true), adminBuckets[0].getPermissions()); + + + // When: user nobel re-queries /buckets + final Bucket[] buckets2 = client + .target(createURL("buckets")) + .request() + .header("Authorization", "Bearer " + nobelAuthToken) + .get(Bucket[].class); + + // Then: the created bucket is now present + assertNotNull(buckets2); + assertEquals(1, buckets2.length); + assertEquals(createdBucket.getIdentifier(), buckets2[0].getIdentifier()); + assertEquals(new Permissions().withCanRead(true), buckets2[0].getPermissions()); + + + // When: nifiadmin grants write access on createdBucket to user 'nobel' + AccessPolicy writePolicy = new AccessPolicy(); + writePolicy.setResource("/buckets/" + createdBucket.getIdentifier()); + writePolicy.setAction("write"); + writePolicy.addUsers(Arrays.asList(new Tenant(nobelId, "nobel"))); + Response adminGrantsWriteAccessResponse = client + .target(createURL("policies")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .post(Entity.entity(writePolicy, MediaType.APPLICATION_JSON), Response.class); + + // Then: the server returns a 201 Created + assertEquals(201, adminGrantsWriteAccessResponse.getStatus()); + + + // When: user nobel re-queries /buckets + final Bucket[] buckets3 = client + .target(createURL("buckets")) + .request() + .header("Authorization", "Bearer " + nobelAuthToken) + .get(Bucket[].class); + + // Then: the authorizedActions are updated + assertNotNull(buckets3); + assertEquals(1, buckets3.length); + assertEquals(createdBucket.getIdentifier(), buckets3[0].getIdentifier()); + assertEquals(new Permissions().withCanRead(true).withCanWrite(true), buckets3[0].getPermissions()); + + } + + /** A helper method to lookup identifiers for tenant identities using the REST API + * + * @param tenantIdentity - the identity to lookup + * @return A string containing the identifier of the tenant, or null if the tenant identity is not found. + */ + private String getTenantIdentifierByIdentity(String tenantIdentity) { + + final Tenant[] users = client + .target(createURL("tenants/users")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(Tenant[].class); + + final Tenant[] groups = client + .target(createURL("tenants/user-groups")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(Tenant[].class); + + final Tenant matchedTenant = Stream.concat(Arrays.stream(users), Arrays.stream(groups)) + .filter(tenant -> tenant.getIdentity().equalsIgnoreCase(tenantIdentity)) + .findFirst() + .orElse(null); + + return matchedTenant != null ? matchedTenant.getIdentifier() : null; + } + + /** A helper method to lookup access policies + * + * @return A string containing the identifier of the policy, or null if the policy identity is not found. + */ + private AccessPolicy getPolicyByResourceAction(String action, String resource) { + + final AccessPolicySummary[] policies = client + .target(createURL("policies")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(AccessPolicySummary[].class); + + final AccessPolicySummary matchedPolicy = Arrays.stream(policies) + .filter(p -> p.getAction().equalsIgnoreCase(action) && p.getResource().equalsIgnoreCase(resource)) + .findFirst() + .orElse(null); + + if (matchedPolicy == null) { + return null; + } + + String policyId = matchedPolicy.getIdentifier(); + + final AccessPolicy policy = client + .target(createURL("policies/" + policyId)) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(AccessPolicy.class); + + return policy; + } + + private List<AccessPolicy> createAccessPoliciesSnapshot() { + + final AccessPolicySummary[] policySummaries = client + .target(createURL("policies")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(AccessPolicySummary[].class); + + final List<AccessPolicy> policies = new ArrayList<>(policySummaries.length); + for (AccessPolicySummary s : policySummaries) { + AccessPolicy policy = client + .target(createURL("policies/" + s.getIdentifier())) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(AccessPolicy.class); + policies.add(policy); + } + + return policies; + } + + private void restoreAccessPoliciesSnapshot(List<AccessPolicy> accessPoliciesSnapshot) { + + List<AccessPolicy> currentAccessPolicies = createAccessPoliciesSnapshot(); + + Set<String> policiesToRestore = accessPoliciesSnapshot.stream() + .map(AccessPolicy::getIdentifier) + .collect(Collectors.toSet()); + + Set<String> policiesToDelete = currentAccessPolicies.stream() + .filter(p -> !policiesToRestore.contains(p.getIdentifier())) + .map(AccessPolicy::getIdentifier) + .collect(Collectors.toSet()); + + for (AccessPolicy originalPolicy : accessPoliciesSnapshot) { + + Response getCurrentPolicy = client + .target(createURL("policies/" + originalPolicy.getIdentifier())) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .get(Response.class); + + if (getCurrentPolicy.getStatus() == 200) { + // update policy to match original + client.target(createURL("policies/" + originalPolicy.getIdentifier())) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .put(Entity.entity(originalPolicy, MediaType.APPLICATION_JSON)); + } else { + // post the original policy + client.target(createURL("policies")) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .post(Entity.entity(originalPolicy, MediaType.APPLICATION_JSON)); + } + + } + + for (String id : policiesToDelete) { + try { + client.target(createURL("policies/" + id)) + .request() + .header("Authorization", "Bearer " + adminAuthToken) + .delete(); + } catch (Exception e) { + // do nothing + } + } + + } + + private static Form encodeCredentialsForURLFormParams(String username, String password) { + return new Form() + .param("username", username) + .param("password", password); + } + + private static String encodeCredentialsForBasicAuth(String username, String password) { + final String credentials = username + ":" + password; + final String base64credentials = new String(Base64.getEncoder().encode(credentials.getBytes(Charset.forName("UTF-8")))); + return base64credentials; + } +}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureNiFiRegistryClientIT.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureNiFiRegistryClientIT.java b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureNiFiRegistryClientIT.java new file mode 100644 index 0000000..cb14b90 --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureNiFiRegistryClientIT.java @@ -0,0 +1,217 @@ +/* + * 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.registry.web.api; + +import org.apache.nifi.registry.NiFiRegistryTestApiApplication; +import org.apache.nifi.registry.authorization.Permissions; +import org.apache.nifi.registry.bucket.Bucket; +import org.apache.nifi.registry.client.BucketClient; +import org.apache.nifi.registry.client.FlowClient; +import org.apache.nifi.registry.client.FlowSnapshotClient; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryClientConfig; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.registry.client.UserClient; +import org.apache.nifi.registry.client.impl.JerseyNiFiRegistryClient; +import org.apache.nifi.registry.flow.VersionedFlow; +import org.apache.nifi.registry.flow.VersionedFlowSnapshot; +import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; +import org.apache.nifi.registry.flow.VersionedProcessGroup; +import org.apache.nifi.registry.authorization.CurrentUser; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.ws.rs.ForbiddenException; +import java.io.IOException; +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = NiFiRegistryTestApiApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = "spring.profiles.include=ITSecureFile") +@Import(SecureITClientConfiguration.class) +@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {"classpath:db/clearDB.sql", "classpath:db/FlowsIT.sql"}) +public class SecureNiFiRegistryClientIT extends IntegrationTestBase { + + static final Logger LOGGER = LoggerFactory.getLogger(SecureNiFiRegistryClientIT.class); + + private NiFiRegistryClient client; + + @Before + public void setup() { + final String baseUrl = createBaseURL(); + LOGGER.info("Using base url = " + baseUrl); + + final NiFiRegistryClientConfig clientConfig = createClientConfig(baseUrl); + Assert.assertNotNull(clientConfig); + + final NiFiRegistryClient client = new JerseyNiFiRegistryClient.Builder() + .config(clientConfig) + .build(); + Assert.assertNotNull(client); + this.client = client; + } + + @After + public void teardown() { + try { + client.close(); + } catch (Exception e) { + + } + } + + @Test + public void testGetAccessStatus() throws IOException, NiFiRegistryException { + final UserClient userClient = client.getUserClient(); + final CurrentUser currentUser = userClient.getAccessStatus(); + Assert.assertEquals("CN=user1, OU=nifi", currentUser.getIdentity()); + Assert.assertFalse(currentUser.isAnonymous()); + Assert.assertNotNull(currentUser.getResourcePermissions()); + Permissions fullAccess = new Permissions().withCanRead(true).withCanWrite(true).withCanDelete(true); + Assert.assertEquals(fullAccess, currentUser.getResourcePermissions().getAnyTopLevelResource()); + Assert.assertEquals(fullAccess, currentUser.getResourcePermissions().getBuckets()); + Assert.assertEquals(fullAccess, currentUser.getResourcePermissions().getTenants()); + Assert.assertEquals(fullAccess, currentUser.getResourcePermissions().getPolicies()); + Assert.assertEquals(new Permissions().withCanWrite(true), currentUser.getResourcePermissions().getProxy()); + } + + @Test + public void testCrudOperations() throws IOException, NiFiRegistryException { + final Bucket bucket = new Bucket(); + bucket.setName("Bucket 1 " + System.currentTimeMillis()); + bucket.setDescription("This is bucket 1"); + + final BucketClient bucketClient = client.getBucketClient(); + final Bucket createdBucket = bucketClient.create(bucket); + Assert.assertNotNull(createdBucket); + Assert.assertNotNull(createdBucket.getIdentifier()); + + final List<Bucket> buckets = bucketClient.getAll(); + Assert.assertEquals(4, buckets.size()); + + final VersionedFlow flow = new VersionedFlow(); + flow.setBucketIdentifier(createdBucket.getIdentifier()); + flow.setName("Flow 1 - " + System.currentTimeMillis()); + + final FlowClient flowClient = client.getFlowClient(); + final VersionedFlow createdFlow = flowClient.create(flow); + Assert.assertNotNull(createdFlow); + Assert.assertNotNull(createdFlow.getIdentifier()); + + final VersionedFlowSnapshotMetadata snapshotMetadata = new VersionedFlowSnapshotMetadata(); + snapshotMetadata.setBucketIdentifier(createdFlow.getBucketIdentifier()); + snapshotMetadata.setFlowIdentifier(createdFlow.getIdentifier()); + snapshotMetadata.setVersion(1); + snapshotMetadata.setComments("This is snapshot #1"); + + final VersionedProcessGroup rootProcessGroup = new VersionedProcessGroup(); + rootProcessGroup.setIdentifier("root-pg"); + rootProcessGroup.setName("Root Process Group"); + + final VersionedFlowSnapshot snapshot = new VersionedFlowSnapshot(); + snapshot.setSnapshotMetadata(snapshotMetadata); + snapshot.setFlowContents(rootProcessGroup); + + final FlowSnapshotClient snapshotClient = client.getFlowSnapshotClient(); + final VersionedFlowSnapshot createdSnapshot = snapshotClient.create(snapshot); + Assert.assertNotNull(createdSnapshot); + Assert.assertEquals("CN=user1, OU=nifi", createdSnapshot.getSnapshotMetadata().getAuthor()); + } + + @Test + public void testGetAccessStatusWithProxiedEntity() throws IOException, NiFiRegistryException { + final String proxiedEntity = "user2"; + final UserClient userClient = client.getUserClient(proxiedEntity); + final CurrentUser status = userClient.getAccessStatus(); + Assert.assertEquals("user2", status.getIdentity()); + Assert.assertFalse(status.isAnonymous()); + } + + @Test + public void testCreatedBucketWithProxiedEntity() throws IOException, NiFiRegistryException { + final String proxiedEntity = "user2"; + final BucketClient bucketClient = client.getBucketClient(proxiedEntity); + + final Bucket bucket = new Bucket(); + bucket.setName("Bucket 1"); + bucket.setDescription("This is bucket 1"); + + try { + bucketClient.create(bucket); + Assert.fail("Shouldn't have been able to create a bucket"); + } catch (Exception e) { + + } + } + + @Test + public void testDirectFlowAccess() throws IOException { + // this user shouldn't have access to anything + final String proxiedEntity = "CN=no-access, OU=nifi"; + + final FlowClient proxiedFlowClient = client.getFlowClient(proxiedEntity); + final FlowSnapshotClient proxiedFlowSnapshotClient = client.getFlowSnapshotClient(proxiedEntity); + + try { + proxiedFlowClient.get("1"); + Assert.fail("Shouldn't have been able to retrieve flow"); + } catch (NiFiRegistryException e) { + Assert.assertTrue(e.getCause() instanceof ForbiddenException); + } + + try { + proxiedFlowSnapshotClient.getLatest("1"); + Assert.fail("Shouldn't have been able to retrieve flow"); + } catch (NiFiRegistryException e) { + Assert.assertTrue(e.getCause() instanceof ForbiddenException); + } + + try { + proxiedFlowSnapshotClient.getLatestMetadata("1"); + Assert.fail("Shouldn't have been able to retrieve flow"); + } catch (NiFiRegistryException e) { + Assert.assertTrue(e.getCause() instanceof ForbiddenException); + } + + try { + proxiedFlowSnapshotClient.get("1", 1); + Assert.fail("Shouldn't have been able to retrieve flow"); + } catch (NiFiRegistryException e) { + Assert.assertTrue(e.getCause() instanceof ForbiddenException); + } + + try { + proxiedFlowSnapshotClient.getSnapshotMetadata("1"); + Assert.fail("Shouldn't have been able to retrieve flow"); + } catch (NiFiRegistryException e) { + Assert.assertTrue(e.getCause() instanceof ForbiddenException); + } + + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredITBase.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredITBase.java b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredITBase.java new file mode 100644 index 0000000..a0c981b --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredITBase.java @@ -0,0 +1,42 @@ +/* + * 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.registry.web.api; + +import org.apache.nifi.registry.NiFiRegistryTestApiApplication; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Deploy the Web API Application using an embedded Jetty Server for local integration testing, with the follow characteristics: + * + * - A NiFiRegistryProperties has to be explicitly provided to the ApplicationContext using a profile unique to this test suite. + * - The database is embed H2 using volatile (in-memory) persistence + * - Custom SQL is clearing the DB before each test method by default, unless method overrides this behavior + */ +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = NiFiRegistryTestApiApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = "spring.profiles.include=ITUnsecured") +@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:db/clearDB.sql") +public class UnsecuredITBase extends IntegrationTestBase { + + // Tests cases defined in subclasses + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java new file mode 100644 index 0000000..2410234 --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java @@ -0,0 +1,403 @@ +/* + * 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.registry.web.api; + +import org.apache.nifi.registry.authorization.CurrentUser; +import org.apache.nifi.registry.authorization.Permissions; +import org.apache.nifi.registry.bucket.Bucket; +import org.apache.nifi.registry.bucket.BucketItem; +import org.apache.nifi.registry.client.BucketClient; +import org.apache.nifi.registry.client.FlowClient; +import org.apache.nifi.registry.client.FlowSnapshotClient; +import org.apache.nifi.registry.client.ItemsClient; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryClientConfig; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.registry.client.UserClient; +import org.apache.nifi.registry.client.impl.JerseyNiFiRegistryClient; +import org.apache.nifi.registry.diff.VersionedFlowDifference; +import org.apache.nifi.registry.field.Fields; +import org.apache.nifi.registry.flow.VersionedFlow; +import org.apache.nifi.registry.flow.VersionedFlowSnapshot; +import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; +import org.apache.nifi.registry.flow.VersionedProcessGroup; +import org.apache.nifi.registry.flow.VersionedProcessor; +import org.apache.nifi.registry.flow.VersionedPropertyDescriptor; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Test all basic functionality of JerseyNiFiRegistryClient. + */ +public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase { + + static final Logger LOGGER = LoggerFactory.getLogger(UnsecuredNiFiRegistryClientIT.class); + + private NiFiRegistryClient client; + + @Before + public void setup() { + final String baseUrl = createBaseURL(); + LOGGER.info("Using base url = " + baseUrl); + + final NiFiRegistryClientConfig clientConfig = new NiFiRegistryClientConfig.Builder() + .baseUrl(baseUrl) + .build(); + + Assert.assertNotNull(clientConfig); + + final NiFiRegistryClient client = new JerseyNiFiRegistryClient.Builder() + .config(clientConfig) + .build(); + + Assert.assertNotNull(client); + this.client = client; + } + + @After + public void teardown() { + try { + client.close(); + } catch (Exception e) { + + } + } + + @Test + public void testGetAccessStatus() throws IOException, NiFiRegistryException { + final UserClient userClient = client.getUserClient(); + final CurrentUser currentUser = userClient.getAccessStatus(); + Assert.assertEquals("anonymous", currentUser.getIdentity()); + Assert.assertTrue(currentUser.isAnonymous()); + Assert.assertNotNull(currentUser.getResourcePermissions()); + Permissions fullAccess = new Permissions().withCanRead(true).withCanWrite(true).withCanDelete(true); + Assert.assertEquals(fullAccess, currentUser.getResourcePermissions().getAnyTopLevelResource()); + Assert.assertEquals(fullAccess, currentUser.getResourcePermissions().getBuckets()); + Assert.assertEquals(fullAccess, currentUser.getResourcePermissions().getTenants()); + Assert.assertEquals(fullAccess, currentUser.getResourcePermissions().getPolicies()); + Assert.assertEquals(fullAccess, currentUser.getResourcePermissions().getProxy()); + } + + @Test + public void testNiFiRegistryClient() throws IOException, NiFiRegistryException { + // ---------------------- TEST BUCKETS --------------------------// + + final BucketClient bucketClient = client.getBucketClient(); + + // create buckets + final int numBuckets = 10; + final List<Bucket> createdBuckets = new ArrayList<>(); + + for (int i=0; i < numBuckets; i++) { + final Bucket createdBucket = createBucket(bucketClient, i); + LOGGER.info("Created bucket # " + i + " with id " + createdBucket.getIdentifier()); + createdBuckets.add(createdBucket); + } + + // get each bucket + for (final Bucket bucket : createdBuckets) { + final Bucket retrievedBucket = bucketClient.get(bucket.getIdentifier()); + Assert.assertNotNull(retrievedBucket); + LOGGER.info("Retrieved bucket " + retrievedBucket.getIdentifier()); + } + + //final Bucket nonExistentBucket = bucketClient.get("does-not-exist"); + //Assert.assertNull(nonExistentBucket); + + // get bucket fields + final Fields bucketFields = bucketClient.getFields(); + Assert.assertNotNull(bucketFields); + LOGGER.info("Retrieved bucket fields, size = " + bucketFields.getFields().size()); + Assert.assertTrue(bucketFields.getFields().size() > 0); + + // get all buckets + final List<Bucket> allBuckets = bucketClient.getAll(); + LOGGER.info("Retrieved buckets, size = " + allBuckets.size()); + Assert.assertEquals(numBuckets, allBuckets.size()); + allBuckets.stream().forEach(b -> System.out.println("Retrieve bucket " + b.getIdentifier())); + + // update each bucket + for (final Bucket bucket : createdBuckets) { + final Bucket bucketUpdate = new Bucket(); + bucketUpdate.setIdentifier(bucket.getIdentifier()); + bucketUpdate.setDescription(bucket.getDescription() + " UPDATE"); + + final Bucket updatedBucket = bucketClient.update(bucketUpdate); + Assert.assertNotNull(updatedBucket); + LOGGER.info("Updated bucket " + updatedBucket.getIdentifier()); + } + + // ---------------------- TEST FLOWS --------------------------// + + final FlowClient flowClient = client.getFlowClient(); + + // create flows + final Bucket flowsBucket = createdBuckets.get(0); + + final VersionedFlow flow1 = createFlow(flowClient, flowsBucket, 1); + LOGGER.info("Created flow # 1 with id " + flow1.getIdentifier()); + + final VersionedFlow flow2 = createFlow(flowClient, flowsBucket, 2); + LOGGER.info("Created flow # 2 with id " + flow2.getIdentifier()); + + // get flow + final VersionedFlow retrievedFlow1 = flowClient.get(flowsBucket.getIdentifier(), flow1.getIdentifier()); + Assert.assertNotNull(retrievedFlow1); + LOGGER.info("Retrieved flow # 1 with id " + retrievedFlow1.getIdentifier()); + + final VersionedFlow retrievedFlow2 = flowClient.get(flowsBucket.getIdentifier(), flow2.getIdentifier()); + Assert.assertNotNull(retrievedFlow2); + LOGGER.info("Retrieved flow # 2 with id " + retrievedFlow2.getIdentifier()); + + // get flow without bucket + final VersionedFlow retrievedFlow1WithoutBucket = flowClient.get(flow1.getIdentifier()); + Assert.assertNotNull(retrievedFlow1WithoutBucket); + Assert.assertEquals(flow1.getIdentifier(), retrievedFlow1WithoutBucket.getIdentifier()); + LOGGER.info("Retrieved flow # 1 without bucket id, with id " + retrievedFlow1WithoutBucket.getIdentifier()); + + // update flows + final VersionedFlow flow1Update = new VersionedFlow(); + flow1Update.setIdentifier(flow1.getIdentifier()); + flow1Update.setName(flow1.getName() + " UPDATED"); + + final VersionedFlow updatedFlow1 = flowClient.update(flowsBucket.getIdentifier(), flow1Update); + Assert.assertNotNull(updatedFlow1); + LOGGER.info("Updated flow # 1 with id " + updatedFlow1.getIdentifier()); + + // get flow fields + final Fields flowFields = flowClient.getFields(); + Assert.assertNotNull(flowFields); + LOGGER.info("Retrieved flow fields, size = " + flowFields.getFields().size()); + Assert.assertTrue(flowFields.getFields().size() > 0); + + // get flows in bucket + final List<VersionedFlow> flowsInBucket = flowClient.getByBucket(flowsBucket.getIdentifier()); + Assert.assertNotNull(flowsInBucket); + Assert.assertEquals(2, flowsInBucket.size()); + flowsInBucket.stream().forEach(f -> LOGGER.info("Flow in bucket, flow id " + f.getIdentifier())); + + // ---------------------- TEST SNAPSHOTS --------------------------// + + final FlowSnapshotClient snapshotClient = client.getFlowSnapshotClient(); + + // create snapshots + final VersionedFlow snapshotFlow = flow1; + + final VersionedFlowSnapshot snapshot1 = createSnapshot(snapshotClient, snapshotFlow, 1); + LOGGER.info("Created snapshot # 1 with version " + snapshot1.getSnapshotMetadata().getVersion()); + + final VersionedFlowSnapshot snapshot2 = createSnapshot(snapshotClient, snapshotFlow, 2); + LOGGER.info("Created snapshot # 2 with version " + snapshot2.getSnapshotMetadata().getVersion()); + + // get snapshot + final VersionedFlowSnapshot retrievedSnapshot1 = snapshotClient.get(snapshotFlow.getBucketIdentifier(), snapshotFlow.getIdentifier(), 1); + Assert.assertNotNull(retrievedSnapshot1); + Assert.assertFalse(retrievedSnapshot1.isLatest()); + LOGGER.info("Retrieved snapshot # 1 with version " + retrievedSnapshot1.getSnapshotMetadata().getVersion()); + + final VersionedFlowSnapshot retrievedSnapshot2 = snapshotClient.get(snapshotFlow.getBucketIdentifier(), snapshotFlow.getIdentifier(), 2); + Assert.assertNotNull(retrievedSnapshot2); + Assert.assertTrue(retrievedSnapshot2.isLatest()); + LOGGER.info("Retrieved snapshot # 2 with version " + retrievedSnapshot2.getSnapshotMetadata().getVersion()); + + // get snapshot without bucket + final VersionedFlowSnapshot retrievedSnapshot1WithoutBucket = snapshotClient.get(snapshotFlow.getIdentifier(), 1); + Assert.assertNotNull(retrievedSnapshot1WithoutBucket); + Assert.assertFalse(retrievedSnapshot1WithoutBucket.isLatest()); + Assert.assertEquals(snapshotFlow.getIdentifier(), retrievedSnapshot1WithoutBucket.getSnapshotMetadata().getFlowIdentifier()); + Assert.assertEquals(1, retrievedSnapshot1WithoutBucket.getSnapshotMetadata().getVersion()); + LOGGER.info("Retrieved snapshot # 1 without using bucket id, with version " + retrievedSnapshot1WithoutBucket.getSnapshotMetadata().getVersion()); + + // get latest + final VersionedFlowSnapshot retrievedSnapshotLatest = snapshotClient.getLatest(snapshotFlow.getBucketIdentifier(), snapshotFlow.getIdentifier()); + Assert.assertNotNull(retrievedSnapshotLatest); + Assert.assertEquals(snapshot2.getSnapshotMetadata().getVersion(), retrievedSnapshotLatest.getSnapshotMetadata().getVersion()); + Assert.assertTrue(retrievedSnapshotLatest.isLatest()); + LOGGER.info("Retrieved latest snapshot with version " + retrievedSnapshotLatest.getSnapshotMetadata().getVersion()); + + // get latest without bucket + final VersionedFlowSnapshot retrievedSnapshotLatestWithoutBucket = snapshotClient.getLatest(snapshotFlow.getIdentifier()); + Assert.assertNotNull(retrievedSnapshotLatestWithoutBucket); + Assert.assertEquals(snapshot2.getSnapshotMetadata().getVersion(), retrievedSnapshotLatestWithoutBucket.getSnapshotMetadata().getVersion()); + Assert.assertTrue(retrievedSnapshotLatestWithoutBucket.isLatest()); + LOGGER.info("Retrieved latest snapshot without bucket, with version " + retrievedSnapshotLatestWithoutBucket.getSnapshotMetadata().getVersion()); + + // get metadata + final List<VersionedFlowSnapshotMetadata> retrievedMetadata = snapshotClient.getSnapshotMetadata(snapshotFlow.getBucketIdentifier(), snapshotFlow.getIdentifier()); + Assert.assertNotNull(retrievedMetadata); + Assert.assertEquals(2, retrievedMetadata.size()); + Assert.assertEquals(2, retrievedMetadata.get(0).getVersion()); + Assert.assertEquals(1, retrievedMetadata.get(1).getVersion()); + retrievedMetadata.stream().forEach(s -> LOGGER.info("Retrieved snapshot metadata " + s.getVersion())); + + // get metadata without bucket + final List<VersionedFlowSnapshotMetadata> retrievedMetadataWithoutBucket = snapshotClient.getSnapshotMetadata(snapshotFlow.getIdentifier()); + Assert.assertNotNull(retrievedMetadataWithoutBucket); + Assert.assertEquals(2, retrievedMetadataWithoutBucket.size()); + Assert.assertEquals(2, retrievedMetadataWithoutBucket.get(0).getVersion()); + Assert.assertEquals(1, retrievedMetadataWithoutBucket.get(1).getVersion()); + retrievedMetadataWithoutBucket.stream().forEach(s -> LOGGER.info("Retrieved snapshot metadata " + s.getVersion())); + + // get latest metadata + final VersionedFlowSnapshotMetadata latestMetadata = snapshotClient.getLatestMetadata(snapshotFlow.getBucketIdentifier(), snapshotFlow.getIdentifier()); + Assert.assertNotNull(latestMetadata); + Assert.assertEquals(2, latestMetadata.getVersion()); + + // get latest metadata that doesn't exist + try { + snapshotClient.getLatestMetadata(snapshotFlow.getBucketIdentifier(), "DOES-NOT-EXIST"); + Assert.fail("Should have thrown exception"); + } catch (NiFiRegistryException nfe) { + Assert.assertEquals("Error retrieving latest snapshot metadata: The specified flow ID does not exist in this bucket.", nfe.getMessage()); + } + + // get latest metadata without bucket + final VersionedFlowSnapshotMetadata latestMetadataWithoutBucket = snapshotClient.getLatestMetadata(snapshotFlow.getIdentifier()); + Assert.assertNotNull(latestMetadataWithoutBucket); + Assert.assertEquals(snapshotFlow.getIdentifier(), latestMetadataWithoutBucket.getFlowIdentifier()); + Assert.assertEquals(2, latestMetadataWithoutBucket.getVersion()); + + // ---------------------- TEST ITEMS --------------------------// + + final ItemsClient itemsClient = client.getItemsClient(); + + // get fields + final Fields itemFields = itemsClient.getFields(); + Assert.assertNotNull(itemFields.getFields()); + Assert.assertTrue(itemFields.getFields().size() > 0); + + // get all items + final List<BucketItem> allItems = itemsClient.getAll(); + Assert.assertEquals(2, allItems.size()); + allItems.stream().forEach(i -> Assert.assertNotNull(i.getBucketName())); + allItems.stream().forEach(i -> LOGGER.info("All items, item " + i.getIdentifier())); + + // get items for bucket + final List<BucketItem> bucketItems = itemsClient.getByBucket(flowsBucket.getIdentifier()); + Assert.assertEquals(2, bucketItems.size()); + allItems.stream().forEach(i -> Assert.assertNotNull(i.getBucketName())); + bucketItems.stream().forEach(i -> LOGGER.info("Items in bucket, item " + i.getIdentifier())); + + // ----------------------- TEST DIFF ---------------------------// + + final VersionedFlowSnapshot snapshot3 = buildSnapshot(snapshotFlow, 3); + final VersionedProcessGroup newlyAddedPG = new VersionedProcessGroup(); + newlyAddedPG.setIdentifier("new-pg"); + newlyAddedPG.setName("NEW Process Group"); + snapshot3.getFlowContents().getProcessGroups().add(newlyAddedPG); + snapshotClient.create(snapshot3); + + VersionedFlowDifference diff = flowClient.diff(snapshotFlow.getBucketIdentifier(), snapshotFlow.getIdentifier(), 3, 2); + Assert.assertNotNull(diff); + Assert.assertEquals(1, diff.getComponentDifferenceGroups().size()); + + // ---------------------- DELETE DATA --------------------------// + + final VersionedFlow deletedFlow1 = flowClient.delete(flowsBucket.getIdentifier(), flow1.getIdentifier()); + Assert.assertNotNull(deletedFlow1); + LOGGER.info("Deleted flow " + deletedFlow1.getIdentifier()); + + final VersionedFlow deletedFlow2 = flowClient.delete(flowsBucket.getIdentifier(), flow2.getIdentifier()); + Assert.assertNotNull(deletedFlow2); + LOGGER.info("Deleted flow " + deletedFlow2.getIdentifier()); + + // delete each bucket + for (final Bucket bucket : createdBuckets) { + final Bucket deletedBucket = bucketClient.delete(bucket.getIdentifier()); + Assert.assertNotNull(deletedBucket); + LOGGER.info("Deleted bucket " + deletedBucket.getIdentifier()); + } + Assert.assertEquals(0, bucketClient.getAll().size()); + + LOGGER.info("!!! SUCCESS !!!"); + + } + + private static Bucket createBucket(BucketClient bucketClient, int num) throws IOException, NiFiRegistryException { + final Bucket bucket = new Bucket(); + bucket.setName("Bucket #" + num); + bucket.setDescription("This is bucket #" + num); + return bucketClient.create(bucket); + } + + private static VersionedFlow createFlow(FlowClient client, Bucket bucket, int num) throws IOException, NiFiRegistryException { + final VersionedFlow versionedFlow = new VersionedFlow(); + versionedFlow.setName(bucket.getName() + " Flow #" + num); + versionedFlow.setDescription("This is " + bucket.getName() + " flow #" + num); + versionedFlow.setBucketIdentifier(bucket.getIdentifier()); + return client.create(versionedFlow); + } + + private static VersionedFlowSnapshot buildSnapshot(VersionedFlow flow, int num) { + final VersionedFlowSnapshotMetadata snapshotMetadata = new VersionedFlowSnapshotMetadata(); + snapshotMetadata.setBucketIdentifier(flow.getBucketIdentifier()); + snapshotMetadata.setFlowIdentifier(flow.getIdentifier()); + snapshotMetadata.setVersion(num); + snapshotMetadata.setComments("This is snapshot #" + num); + + final VersionedProcessGroup rootProcessGroup = new VersionedProcessGroup(); + rootProcessGroup.setIdentifier("root-pg"); + rootProcessGroup.setName("Root Process Group"); + + final VersionedProcessGroup subProcessGroup = new VersionedProcessGroup(); + subProcessGroup.setIdentifier("sub-pg"); + subProcessGroup.setName("Sub Process Group"); + rootProcessGroup.getProcessGroups().add(subProcessGroup); + + final Map<String,String> processorProperties = new HashMap<>(); + processorProperties.put("Prop 1", "Val 1"); + processorProperties.put("Prop 2", "Val 2"); + + final Map<String, VersionedPropertyDescriptor> propertyDescriptors = new HashMap<>(); + + final VersionedProcessor processor1 = new VersionedProcessor(); + processor1.setIdentifier("p1"); + processor1.setName("Processor 1"); + processor1.setProperties(processorProperties); + processor1.setPropertyDescriptors(propertyDescriptors); + + final VersionedProcessor processor2 = new VersionedProcessor(); + processor2.setIdentifier("p2"); + processor2.setName("Processor 2"); + processor2.setProperties(processorProperties); + processor2.setPropertyDescriptors(propertyDescriptors); + + subProcessGroup.getProcessors().add(processor1); + subProcessGroup.getProcessors().add(processor2); + + final VersionedFlowSnapshot snapshot = new VersionedFlowSnapshot(); + snapshot.setSnapshotMetadata(snapshotMetadata); + snapshot.setFlowContents(rootProcessGroup); + return snapshot; + } + + private static VersionedFlowSnapshot createSnapshot(FlowSnapshotClient client, VersionedFlow flow, int num) throws IOException, NiFiRegistryException { + final VersionedFlowSnapshot snapshot = buildSnapshot(flow, num); + + return client.create(snapshot); + } +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/link/TestLinkService.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/link/TestLinkService.java b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/link/TestLinkService.java new file mode 100644 index 0000000..bfc9a46 --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/link/TestLinkService.java @@ -0,0 +1,124 @@ +/* + * 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.registry.web.link; + +import org.apache.nifi.registry.bucket.Bucket; +import org.apache.nifi.registry.bucket.BucketItem; +import org.apache.nifi.registry.flow.VersionedFlow; +import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +public class TestLinkService { + + private LinkService linkService; + + private List<Bucket> buckets; + private List<VersionedFlow> flows; + private List<VersionedFlowSnapshotMetadata> snapshots; + private List<BucketItem> items; + + @Before + public void setup() { + linkService = new LinkService(); + + // setup buckets + final Bucket bucket1 = new Bucket(); + bucket1.setIdentifier("b1"); + bucket1.setName("Bucket 1"); + + final Bucket bucket2 = new Bucket(); + bucket2.setIdentifier("b2"); + bucket2.setName("Bucket 2"); + + buckets = new ArrayList<>(); + buckets.add(bucket1); + buckets.add(bucket2); + + // setup flows + final VersionedFlow flow1 = new VersionedFlow(); + flow1.setIdentifier("f1"); + flow1.setName("Flow 1"); + flow1.setBucketIdentifier(bucket1.getIdentifier()); + + final VersionedFlow flow2 = new VersionedFlow(); + flow2.setIdentifier("f2"); + flow2.setName("Flow 2"); + flow2.setBucketIdentifier(bucket1.getIdentifier()); + + flows = new ArrayList<>(); + flows.add(flow1); + flows.add(flow2); + + //setup snapshots + final VersionedFlowSnapshotMetadata snapshotMetadata1 = new VersionedFlowSnapshotMetadata(); + snapshotMetadata1.setFlowIdentifier(flow1.getIdentifier()); + snapshotMetadata1.setVersion(1); + snapshotMetadata1.setBucketIdentifier(bucket1.getIdentifier()); + + final VersionedFlowSnapshotMetadata snapshotMetadata2 = new VersionedFlowSnapshotMetadata(); + snapshotMetadata2.setFlowIdentifier(flow1.getIdentifier()); + snapshotMetadata2.setVersion(2); + snapshotMetadata2.setBucketIdentifier(bucket1.getIdentifier()); + + snapshots = new ArrayList<>(); + snapshots.add(snapshotMetadata1); + snapshots.add(snapshotMetadata2); + + // setup items + items = new ArrayList<>(); + items.add(flow1); + items.add(flow2); + } + + @Test + public void testPopulateBucketLinks() { + buckets.stream().forEach(b -> Assert.assertNull(b.getLink())); + linkService.populateBucketLinks(buckets); + buckets.stream().forEach(b -> Assert.assertEquals( + "buckets/" + b.getIdentifier(), b.getLink().getUri().toString())); + } + + @Test + public void testPopulateFlowLinks() { + flows.stream().forEach(f -> Assert.assertNull(f.getLink())); + linkService.populateFlowLinks(flows); + flows.stream().forEach(f -> Assert.assertEquals( + "buckets/" + f.getBucketIdentifier() + "/flows/" + f.getIdentifier(), f.getLink().getUri().toString())); + } + + @Test + public void testPopulateSnapshotLinks() { + snapshots.stream().forEach(s -> Assert.assertNull(s.getLink())); + linkService.populateSnapshotLinks(snapshots); + snapshots.stream().forEach(s -> Assert.assertEquals( + "buckets/" + s.getBucketIdentifier() + "/flows/" + s.getFlowIdentifier() + "/versions/" + s.getVersion(), s.getLink().getUri().toString())); + } + + @Test + public void testPopulateItemLinks() { + items.stream().forEach(i -> Assert.assertNull(i.getLink())); + linkService.populateItemLinks(items); + items.stream().forEach(i -> Assert.assertEquals( + "buckets/" + i.getBucketIdentifier() + "/flows/" + i.getIdentifier(), i.getLink().getUri().toString())); + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureFile.properties ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureFile.properties b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureFile.properties new file mode 100644 index 0000000..3ea5398 --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureFile.properties @@ -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. +# + + +# Properties for Spring Boot integration tests +# Documentation for common Spring Boot application properties can be found at: +# https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html + + +# Custom (non-standard to Spring Boot) properties +nifi.registry.properties.file: src/test/resources/conf/secure-file/nifi-registry.properties +nifi.registry.client.properties.file: src/test/resources/conf/secure-file/nifi-registry-client.properties + + +# Embedded Server SSL Context Config +server.ssl.client-auth: need +server.ssl.key-store: ./target/test-classes/keys/localhost-ks.jks +server.ssl.key-store-password: localhostKeystorePassword +server.ssl.key-password: localhostKeystorePassword +server.ssl.protocol: TLS +server.ssl.trust-store: ./target/test-classes/keys/localhost-ts.jks +server.ssl.trust-store-password: localhostTruststorePassword http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureKerberos.properties ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureKerberos.properties b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureKerberos.properties new file mode 100644 index 0000000..6ce3665 --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureKerberos.properties @@ -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. +# + + +# Properties for Spring Boot integration tests +# Documentation for common Spring Boot application properties can be found at: +# https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html + + +# Custom (non-standard to Spring Boot) properties +nifi.registry.properties.file: src/test/resources/conf/secure-kerberos/nifi-registry.properties +nifi.registry.client.properties.file: src/test/resources/conf/secure-kerberos/nifi-registry-client.properties + + +# Embedded Server SSL Context Config +#server.ssl.client-auth: need # LDAP-configured server does not require two-way TLS +server.ssl.key-store: ./target/test-classes/keys/localhost-ks.jks +server.ssl.key-store-password: localhostKeystorePassword +server.ssl.key-password: localhostKeystorePassword +server.ssl.protocol: TLS +server.ssl.trust-store: ./target/test-classes/keys/localhost-ts.jks +server.ssl.trust-store-password: localhostTruststorePassword http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureLdap.properties ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureLdap.properties b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureLdap.properties new file mode 100644 index 0000000..ffcc43e --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITSecureLdap.properties @@ -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. +# + + +# Properties for Spring Boot integration tests +# Documentation for common Spring Boot application properties can be found at: +# https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html + + +# Custom (non-standard to Spring Boot) properties +nifi.registry.properties.file: src/test/resources/conf/secure-ldap/nifi-registry.properties +nifi.registry.client.properties.file: src/test/resources/conf/secure-ldap/nifi-registry-client.properties + + +# Embedded Server SSL Context Config +#server.ssl.client-auth: need # LDAP-configured server does not require two-way TLS +server.ssl.key-store: ./target/test-classes/keys/localhost-ks.jks +server.ssl.key-store-password: localhostKeystorePassword +server.ssl.key-password: localhostKeystorePassword +server.ssl.protocol: TLS +server.ssl.trust-store: ./target/test-classes/keys/localhost-ts.jks +server.ssl.trust-store-password: localhostTruststorePassword + +# Embedded LDAP Config +spring.ldap.embedded.base-dn: dc=example,dc=com +spring.ldap.embedded.credential.username: cn=read-only-admin,dc=example,dc=com +spring.ldap.embedded.credential.password: password +spring.ldap.embedded.ldif: classpath:conf/secure-ldap/test-ldap-data.ldif +spring.ldap.embedded.port: 8389 +spring.ldap.embedded.validation.enabled: false + +# Additional Logging Config +logging.level.org.springframework.security.ldap: DEBUG +logging.level.org.springframework.ldap: DEBUG \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITUnsecured.properties ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITUnsecured.properties b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITUnsecured.properties new file mode 100644 index 0000000..bcd338c --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application-ITUnsecured.properties @@ -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. +# + +# Integration Test Profile for running an unsecured NiFi Registry instance + +# Custom (non-standard to Spring Boot) properties +nifi.registry.properties.file = src/test/resources/conf/unsecured/nifi-registry.properties http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/resources/application.properties ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/application.properties b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application.properties new file mode 100644 index 0000000..efa0290 --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application.properties @@ -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. +# + +# Properties for Spring Boot integration tests +# Documentation for commoon Spring Boot application properties can be found at: +# https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html + +# These verbose log levels can be enabled locally for dev testing, but disable them in the repo to minimize travis logs. +#logging.level.org.springframework.core.io.support: DEBUG +#logging.level.org.springframework.context.annotation: DEBUG +#logging.level.org.springframework.web: DEBUG http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/resources/banner.txt ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/banner.txt b/nifi-registry-core/nifi-registry-web-api/src/test/resources/banner.txt new file mode 100644 index 0000000..2f54644 --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/resources/banner.txt @@ -0,0 +1,8 @@ + + Apache NiFi _ _ + _ __ ___ __ _(_)___| |_ _ __ _ _ +| '__/ _ \/ _` | / __| __| '__| | | | +| | | __/ (_| | \__ \ |_| | | |_| | +|_| \___|\__, |_|___/\__|_| \__, | +==========|___/================|___/= + Integration Test http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/providers.xml ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/providers.xml b/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/providers.xml new file mode 100644 index 0000000..fd002be --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/providers.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!-- + ~ 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. + --> +<providers> + + <flowPersistenceProvider> + <class>org.apache.nifi.registry.provider.flow.FileSystemFlowPersistenceProvider</class> + <property name="Flow Storage Directory">./target/test-classes/flow_storage</property> + </flowPersistenceProvider> + +</providers> \ No newline at end of file