Repository: nifi-registry Updated Branches: refs/heads/master a931858f1 -> 04cf23220
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestUtils.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestUtils.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestUtils.java new file mode 100644 index 0000000..8cfcb38 --- /dev/null +++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestUtils.java @@ -0,0 +1,120 @@ +/* + * 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.bucket.Bucket; +import org.apache.nifi.registry.flow.VersionedComponent; +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 java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +class IntegrationTestUtils { + + public static void assertBucketsEqual(Bucket expected, Bucket actual, boolean checkServerSetFields) { + assertNotNull(actual); + assertEquals(expected.getName(), actual.getName()); + assertEquals(expected.getDescription(), actual.getDescription()); + if (checkServerSetFields) { + assertEquals(expected.getIdentifier(), actual.getIdentifier()); + assertEquals(expected.getCreatedTimestamp(), actual.getCreatedTimestamp()); + assertEquals(expected.getPermissions(), actual.getPermissions()); + assertEquals(expected.getLink(), actual.getLink()); + } + } + + public static void assertFlowsEqual(VersionedFlow expected, VersionedFlow actual, boolean checkServerSetFields) { + assertNotNull(actual); + assertEquals(expected.getName(), actual.getName()); + assertEquals(expected.getDescription(), actual.getDescription()); + assertEquals(expected.getBucketIdentifier(), actual.getBucketIdentifier()); + if (checkServerSetFields) { + assertEquals(expected.getIdentifier(), actual.getIdentifier()); + assertEquals(expected.getVersionCount(), actual.getVersionCount()); + assertEquals(expected.getCreatedTimestamp(), actual.getCreatedTimestamp()); + assertEquals(expected.getModifiedTimestamp(), actual.getModifiedTimestamp()); + assertEquals(expected.getType(), actual.getType()); + assertEquals(expected.getLink(), actual.getLink()); + } + } + + public static void assertFlowSnapshotsEqual(VersionedFlowSnapshot expected, VersionedFlowSnapshot actual, boolean checkServerSetFields) { + + assertNotNull(actual); + + if (expected.getSnapshotMetadata() != null) { + assertFlowSnapshotMetadataEqual(expected.getSnapshotMetadata(), actual.getSnapshotMetadata(), checkServerSetFields); + } + + if (expected.getFlowContents() != null) { + assertVersionedProcessGroupsEqual(expected.getFlowContents(), actual.getFlowContents()); + } + + if (checkServerSetFields) { + assertFlowsEqual(expected.getFlow(), actual.getFlow(), false); // false because if we are checking a newly created snapshot, the versionsCount won't match + assertBucketsEqual(expected.getBucket(), actual.getBucket(), true); + } + + } + + public static void assertFlowSnapshotMetadataEqual( + VersionedFlowSnapshotMetadata expected, VersionedFlowSnapshotMetadata actual, boolean checkServerSetFields) { + + assertNotNull(actual); + assertEquals(expected.getBucketIdentifier(), actual.getBucketIdentifier()); + assertEquals(expected.getFlowIdentifier(), actual.getFlowIdentifier()); + assertEquals(expected.getVersion(), actual.getVersion()); + assertEquals(expected.getComments(), actual.getComments()); + if (checkServerSetFields) { + assertEquals(expected.getTimestamp(), actual.getTimestamp()); + } + } + + private static void assertVersionedProcessGroupsEqual(VersionedProcessGroup expected, VersionedProcessGroup actual) { + assertNotNull(actual); + + assertEquals(((VersionedComponent)expected), ((VersionedComponent)actual)); + + // Poor man's set equality assertion as we are only checking the base type and not doing a recursive check + // TODO, this would be a stronger assertion by replacing this with a true VersionedProcessGroup.equals() method that does a deep equality check + assertSetsEqual(expected.getProcessGroups(), actual.getProcessGroups()); + assertSetsEqual(expected.getRemoteProcessGroups(), actual.getRemoteProcessGroups()); + assertSetsEqual(expected.getProcessors(), actual.getProcessors()); + assertSetsEqual(expected.getInputPorts(), actual.getInputPorts()); + assertSetsEqual(expected.getOutputPorts(), actual.getOutputPorts()); + assertSetsEqual(expected.getConnections(), actual.getConnections()); + assertSetsEqual(expected.getLabels(), actual.getLabels()); + assertSetsEqual(expected.getFunnels(), actual.getFunnels()); + assertSetsEqual(expected.getControllerServices(), actual.getControllerServices()); + } + + + private static void assertSetsEqual(Set<? extends VersionedComponent> expected, Set<? extends VersionedComponent> actual) { + if (expected != null) { + assertNotNull(actual); + assertEquals(expected.size(), actual.size()); + assertTrue(actual.containsAll(expected)); + } + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureFileIT.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureFileIT.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureFileIT.java index 2ca3caa..e3e0f21 100644 --- a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureFileIT.java +++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureFileIT.java @@ -52,7 +52,12 @@ public class SecureFileIT extends IntegrationTestBase { // Given: the client and server have been configured correctly for two-way TLS String expectedJson = "{" + "\"identity\":\"CN=user1, OU=nifi\"," + - "\"status\":\"ACTIVE\"" + + "\"anonymous\":false," + + "\"administrationPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"bucketsPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"tenantsPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"policiesPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"resourcesPermissions\":{\"canRead\":true}" + "}"; // When: the /access endpoint is queried @@ -75,7 +80,7 @@ public class SecureFileIT extends IntegrationTestBase { "{\"identifier\":\"/policies\",\"name\":\"Access Policies\"}," + "{\"identifier\":\"/tenants\",\"name\":\"Tenant\"}," + "{\"identifier\":\"/proxy\",\"name\":\"Proxy User Requests\"}," + - "{\"identifier\":\"/resources\",\"name\":\"NiFi Resources\"}," + + "{\"identifier\":\"/resources\",\"name\":\"Resources\"}," + "{\"identifier\":\"/buckets\",\"name\":\"Buckets\"}" + "]"; http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureKerberosIT.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureKerberosIT.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureKerberosIT.java index 550c729..e610a38 100644 --- a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureKerberosIT.java +++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureKerberosIT.java @@ -19,6 +19,7 @@ package org.apache.nifi.registry.web.api; import org.apache.commons.lang3.StringUtils; import org.apache.nifi.registry.NiFiRegistryTestApiApplication; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.skyscreamer.jsonassert.JSONAssert; @@ -99,6 +100,19 @@ public class SecureKerberosIT extends IntegrationTestBase { } + private String adminAuthToken; + + @Before + public void generateAuthToken() { + String validTicket = new String(Base64.getEncoder().encode(validKerberosTicket.getBytes(Charset.forName("UTF-8")))); + final String token = client + .target(createURL("/access/token/kerberos")) + .request() + .header("Authorization", "Negotiate " + validTicket) + .post(null, String.class); + adminAuthToken = token; + } + @Test public void testTokenGenerationAndAccessStatus() throws Exception { @@ -113,7 +127,7 @@ public class SecureKerberosIT extends IntegrationTestBase { "}"; String expectedAccessStatusJson = "{" + "\"identity\":\"kerberosUser@LOCALHOST\"," + - "\"status\":\"ACTIVE\"}"; + "\"anonymous\":false}"; // When: the /access/token/kerberos endpoint is accessed with no credentials final Response tokenResponse1 = client @@ -169,5 +183,33 @@ public class SecureKerberosIT extends IntegrationTestBase { } + @Test + public void testGetCurrentUser() throws Exception { + + // Given: the client is connected to an unsecured NiFi Registry + String expectedJson = "{" + + "\"identity\":\"kerberosUser@LOCALHOST\"," + + "\"anonymous\":false," + + "\"administrationPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"bucketsPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"tenantsPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"policiesPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"resourcesPermissions\":{\"canRead\":true}" + + "}"; + + // When: the /access endpoint is queried using a JWT for the kerberos 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); + + } + } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java index e84ee2b..7cd9138 100644 --- a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java +++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java @@ -21,10 +21,14 @@ import org.apache.nifi.registry.SecureLdapTestApiApplication; import org.apache.nifi.registry.bucket.Bucket; import org.apache.nifi.registry.extension.ExtensionManager; import org.apache.nifi.registry.model.authorization.AccessPolicy; +import org.apache.nifi.registry.model.authorization.AccessPolicySummary; +import org.apache.nifi.registry.model.authorization.CurrentUser; +import org.apache.nifi.registry.model.authorization.Permissions; import org.apache.nifi.registry.model.authorization.Tenant; import org.apache.nifi.registry.properties.NiFiRegistryProperties; import org.apache.nifi.registry.security.authorization.Authorizer; import org.apache.nifi.registry.security.authorization.AuthorizerFactory; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,10 +49,12 @@ 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.HashSet; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; import static org.junit.Assert.assertEquals; @@ -94,15 +100,23 @@ public class SecureLdapIT extends IntegrationTestBase { } private String adminAuthToken; + private List<AccessPolicy> beforeTestAccessPoliciesSnapshot; @Before - public void generateAuthToken() { + public void setup() { final Form form = encodeCredentialsForURLFormParams("nifiadmin", "password"); final String token = client .target(createURL(tokenLoginPath)) .request() .post(Entity.form(form), String.class); adminAuthToken = token; + + beforeTestAccessPoliciesSnapshot = createAccessPoliciesSnapshot(); + } + + @After + public void cleanup() { + restoreAccessPoliciesSnapshot(beforeTestAccessPoliciesSnapshot); } @Test @@ -119,7 +133,7 @@ public class SecureLdapIT extends IntegrationTestBase { "}"; String expectedAccessStatusJson = "{" + "\"identity\":\"nobel\"," + - "\"status\":\"ACTIVE\"" + + "\"anonymous\":false" + "}"; // When: the /access/token/login endpoint is queried @@ -164,7 +178,7 @@ public class SecureLdapIT extends IntegrationTestBase { "}"; String expectedAccessStatusJson = "{" + "\"identity\":\"nobel\"," + - "\"status\":\"ACTIVE\"" + + "\"anonymous\":false" + "}"; // When: the /access/token/identity-provider endpoint is queried @@ -199,24 +213,68 @@ public class SecureLdapIT extends IntegrationTestBase { } @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," + + "\"administrationPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"bucketsPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"tenantsPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"policiesPermissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," + + "\"resourcesPermissions\":{\"canRead\":true}" + + "}"; + + // 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\":[]}," + - "{\"identity\":\"euler\",\"userGroups\":[{\"identity\":\"mathematicians\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"euclid\",\"userGroups\":[{\"identity\":\"mathematicians\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"boyle\",\"userGroups\":[{\"identity\":\"chemists\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"newton\",\"userGroups\":[{\"identity\":\"scientists\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"riemann\",\"userGroups\":[{\"identity\":\"mathematicians\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"gauss\",\"userGroups\":[{\"identity\":\"mathematicians\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"galileo\",\"userGroups\":[{\"identity\":\"scientists\"},{\"identity\":\"italians\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"nobel\",\"userGroups\":[{\"identity\":\"chemists\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"pasteur\",\"userGroups\":[{\"identity\":\"chemists\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"tesla\",\"userGroups\":[{\"identity\":\"scientists\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"nogroup\",\"userGroups\":[],\"accessPolicies\":[]}," + - "{\"identity\":\"einstein\",\"userGroups\":[{\"identity\":\"scientists\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"curie\",\"userGroups\":[{\"identity\":\"chemists\"}],\"accessPolicies\":[]}]"; + "{\"identity\":\"nifiadmin\",\"userGroups\":[],\"configurable\":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 @@ -234,10 +292,30 @@ public class SecureLdapIT extends IntegrationTestBase { // 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\":[]}," + - "{\"identity\":\"mathematicians\",\"users\":[{\"identity\":\"gauss\"},{\"identity\":\"euclid\"},{\"identity\":\"riemann\"},{\"identity\":\"euler\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"scientists\",\"users\":[{\"identity\":\"einstein\"},{\"identity\":\"tesla\"},{\"identity\":\"newton\"},{\"identity\":\"galileo\"}],\"accessPolicies\":[]}," + - "{\"identity\":\"italians\",\"users\":[{\"identity\":\"galileo\"}],\"accessPolicies\":[]}]"; + "{" + + "\"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 @@ -292,6 +370,21 @@ public class SecureLdapIT extends IntegrationTestBase { .request() .post(Entity.form(form), 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.getAdministrationPermissions()); + assertEquals(new Permissions(), currentUser.getBucketsPermissions()); + assertEquals(new Permissions(), currentUser.getTenantsPermissions()); + assertEquals(new Permissions(), currentUser.getPoliciesPermissions()); + assertEquals(new Permissions(), currentUser.getResourcesPermissions()); + + // When: nifiadmin creates a bucket final Bucket bucket = new Bucket(); bucket.setName("Integration Test Bucket"); @@ -320,7 +413,6 @@ public class SecureLdapIT extends IntegrationTestBase { // When: nifiadmin grants read access on createdBucket to 'chemists' a group containing nobel - Set<String> policiesToCleanup = new HashSet<>(); AccessPolicy readPolicy = new AccessPolicy(); readPolicy.setResource("/buckets/" + createdBucket.getIdentifier()); readPolicy.setAction("read"); @@ -333,71 +425,53 @@ public class SecureLdapIT extends IntegrationTestBase { // Then: the server returns a 201 Created assertEquals(201, adminGrantsReadAccessResponse.getStatus()); - policiesToCleanup.add(adminGrantsReadAccessResponse.readEntity(AccessPolicy.class).getIdentifier()); - try { - // 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(1, buckets2[0].getAuthorizedActions().size()); - assertTrue(buckets2[0].getAuthorizedActions().contains("read")); - - - // 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); + // When: user nobel re-queries /buckets + final Bucket[] buckets2 = client + .target(createURL("buckets")) + .request() + .header("Authorization", "Bearer " + nobelAuthToken) + .get(Bucket[].class); - // Then: the server returns a 201 Created - assertEquals(201, adminGrantsWriteAccessResponse.getStatus()); - policiesToCleanup.add(adminGrantsWriteAccessResponse.readEntity(AccessPolicy.class).getIdentifier()); + // 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: 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(2, buckets3[0].getAuthorizedActions().size()); - assertTrue(buckets3[0].getAuthorizedActions().contains("read")); - assertTrue(buckets3[0].getAuthorizedActions().contains("write")); - - } finally { - // Teardown: delete the policy we made in case other tests assume they are starting with no policies - for (String policyId : policiesToCleanup) { - Response adminDeletesPolicyResponse = client - .target(createURL("policies/" + policyId)) - .request() - .header("Authorization", "Bearer " + adminAuthToken) - .delete(Response.class); - assertEquals(200, adminDeletesPolicyResponse.getStatus()); - } - } + // 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 + /** 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. @@ -416,7 +490,6 @@ public class SecureLdapIT extends IntegrationTestBase { .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() @@ -425,6 +498,109 @@ public class SecureLdapIT extends IntegrationTestBase { 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) http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureNiFiRegistryClientIT.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureNiFiRegistryClientIT.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureNiFiRegistryClientIT.java index 45c32c0..3abd276 100644 --- a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureNiFiRegistryClientIT.java +++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureNiFiRegistryClientIT.java @@ -30,7 +30,7 @@ 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.model.authorization.AccessStatus; +import org.apache.nifi.registry.model.authorization.CurrentUser; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -86,9 +86,9 @@ public class SecureNiFiRegistryClientIT extends IntegrationTestBase { @Test public void testGetAccessStatus() throws IOException, NiFiRegistryException { final UserClient userClient = client.getUserClient(); - final AccessStatus status = userClient.getAccessStatus(); + final CurrentUser status = userClient.getAccessStatus(); Assert.assertEquals("CN=user1, OU=nifi", status.getIdentity()); - Assert.assertEquals("ACTIVE", status.getStatus()); + Assert.assertFalse(status.isAnonymous()); } @Test @@ -138,9 +138,9 @@ public class SecureNiFiRegistryClientIT extends IntegrationTestBase { public void testGetAccessStatusWithProxiedEntity() throws IOException, NiFiRegistryException { final String proxiedEntity = "user2"; final UserClient userClient = client.getUserClient(proxiedEntity); - final AccessStatus status = userClient.getAccessStatus(); + final CurrentUser status = userClient.getAccessStatus(); Assert.assertEquals("user2", status.getIdentity()); - Assert.assertEquals("ACTIVE", status.getStatus()); + Assert.assertFalse(status.isAnonymous()); } @Test http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java index 8a2a920..cea5cb2 100644 --- a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java +++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java @@ -33,7 +33,7 @@ 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.model.authorization.AccessStatus; +import org.apache.nifi.registry.model.authorization.CurrentUser; import org.apache.nifi.registry.params.SortOrder; import org.apache.nifi.registry.params.SortParameter; import org.junit.After; @@ -88,13 +88,11 @@ public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase { } @Test - public void testUserClient() { + public void testGetAccessStatus() throws IOException, NiFiRegistryException { final UserClient userClient = client.getUserClient(); - try { - final AccessStatus status = userClient.getAccessStatus(); - Assert.fail("Should have thrown a 409"); - } catch (Exception e) { - } + final CurrentUser status = userClient.getAccessStatus(); + Assert.assertEquals("anonymous", status.getIdentity()); + Assert.assertTrue(status.isAnonymous()); } @Test
