You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by kd...@apache.org on 2018/09/22 02:11:27 UTC

[28/51] [partial] nifi-registry git commit: NIFIREG-201 Refactoring project structure to better isolate extensions

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProviderTest.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProviderTest.java b/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProviderTest.java
new file mode 100644
index 0000000..242cf28
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProviderTest.java
@@ -0,0 +1,639 @@
+/*
+ * 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.security.ldap.tenants;
+
+import org.apache.directory.server.annotations.CreateLdapServer;
+import org.apache.directory.server.annotations.CreateTransport;
+import org.apache.directory.server.core.annotations.ApplyLdifFiles;
+import org.apache.directory.server.core.annotations.CreateDS;
+import org.apache.directory.server.core.annotations.CreatePartition;
+import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
+import org.apache.directory.server.core.integ.FrameworkRunner;
+import org.apache.nifi.registry.properties.NiFiRegistryProperties;
+import org.apache.nifi.registry.security.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.registry.security.authorization.Group;
+import org.apache.nifi.registry.security.authorization.UserAndGroups;
+import org.apache.nifi.registry.security.authorization.UserGroupProviderInitializationContext;
+import org.apache.nifi.registry.security.exception.SecurityProviderCreationException;
+import org.apache.nifi.registry.security.ldap.LdapAuthenticationStrategy;
+import org.apache.nifi.registry.security.ldap.ReferralStrategy;
+import org.apache.nifi.registry.util.StandardPropertyValue;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import java.util.Properties;
+import java.util.Set;
+
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_AUTHENTICATION_STRATEGY;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_CONNECT_TIMEOUT;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_GROUP_MEMBER_ATTRIBUTE;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_GROUP_MEMBER_REFERENCED_USER_ATTRIBUTE;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_GROUP_NAME_ATTRIBUTE;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_GROUP_OBJECT_CLASS;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_GROUP_SEARCH_BASE;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_GROUP_SEARCH_FILTER;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_GROUP_SEARCH_SCOPE;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_MANAGER_DN;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_MANAGER_PASSWORD;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_PAGE_SIZE;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_READ_TIMEOUT;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_REFERRAL_STRATEGY;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_SYNC_INTERVAL;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_URL;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_USER_GROUP_ATTRIBUTE;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_USER_GROUP_REFERENCED_GROUP_ATTRIBUTE;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_USER_IDENTITY_ATTRIBUTE;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_USER_OBJECT_CLASS;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_USER_SEARCH_BASE;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_USER_SEARCH_FILTER;
+import static org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider.PROP_USER_SEARCH_SCOPE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(FrameworkRunner.class)
+@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP")})
+@CreateDS(name = "nifi-example", partitions = {@CreatePartition(name = "example", suffix = "o=nifi")})
+@ApplyLdifFiles("nifi-example.ldif")
+public class LdapUserGroupProviderTest extends AbstractLdapTestUnit {
+
+    private static final String USER_SEARCH_BASE = "ou=users,o=nifi";
+    private static final String GROUP_SEARCH_BASE = "ou=groups,o=nifi";
+
+    private LdapUserGroupProvider ldapUserGroupProvider;
+
+    @Before
+    public void setup() {
+        final UserGroupProviderInitializationContext initializationContext = mock(UserGroupProviderInitializationContext.class);
+        when(initializationContext.getIdentifier()).thenReturn("identifier");
+
+        ldapUserGroupProvider = new LdapUserGroupProvider();
+        ldapUserGroupProvider.setNiFiProperties(getNiFiProperties(new Properties()));
+        ldapUserGroupProvider.initialize(initializationContext);
+    }
+
+    @Test(expected = SecurityProviderCreationException.class)
+    public void testNoSearchBasesSpecified() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, null);
+        ldapUserGroupProvider.onConfigured(configurationContext);
+    }
+
+    @Test(expected = SecurityProviderCreationException.class)
+    public void testUserSearchBaseSpecifiedButNoUserObjectClass() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_USER_OBJECT_CLASS)).thenReturn(new StandardPropertyValue(null));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+    }
+
+    @Test(expected = SecurityProviderCreationException.class)
+    public void testUserSearchBaseSpecifiedButNoUserSearchScope() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_USER_SEARCH_SCOPE)).thenReturn(new StandardPropertyValue(null));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+    }
+
+    @Test(expected = SecurityProviderCreationException.class)
+    public void testInvalidUserSearchScope() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_USER_SEARCH_SCOPE)).thenReturn(new StandardPropertyValue("not-valid"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+    }
+
+    @Test
+    public void testSearchUsersWithNoIdentityAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(8, ldapUserGroupProvider.getUsers().size());
+        assertNotNull(ldapUserGroupProvider.getUserByIdentity("cn=User 1,ou=users,o=nifi"));
+        assertTrue(ldapUserGroupProvider.getGroups().isEmpty());
+    }
+
+    @Test
+    public void testSearchUsersWithUidIdentityAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(8, ldapUserGroupProvider.getUsers().size());
+        assertNotNull(ldapUserGroupProvider.getUserByIdentity("user1"));
+        assertTrue(ldapUserGroupProvider.getGroups().isEmpty());
+    }
+
+    @Test
+    public void testSearchUsersWithCnIdentityAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(8, ldapUserGroupProvider.getUsers().size());
+        assertNotNull(ldapUserGroupProvider.getUserByIdentity("User 1"));
+        assertTrue(ldapUserGroupProvider.getGroups().isEmpty());
+    }
+
+    @Test
+    public void testSearchUsersObjectSearchScope() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_USER_SEARCH_SCOPE)).thenReturn(new StandardPropertyValue(SearchScope.OBJECT.name()));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertTrue(ldapUserGroupProvider.getUsers().isEmpty());
+        assertTrue(ldapUserGroupProvider.getGroups().isEmpty());
+    }
+
+    @Test
+    public void testSearchUsersSubtreeSearchScope() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration("o=nifi", null);
+        when(configurationContext.getProperty(PROP_USER_SEARCH_SCOPE)).thenReturn(new StandardPropertyValue(SearchScope.SUBTREE.name()));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(9, ldapUserGroupProvider.getUsers().size());
+        assertTrue(ldapUserGroupProvider.getGroups().isEmpty());
+    }
+
+    @Test
+    public void testSearchUsersWithFilter() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        when(configurationContext.getProperty(PROP_USER_SEARCH_FILTER)).thenReturn(new StandardPropertyValue("(uid=user1)"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(1, ldapUserGroupProvider.getUsers().size());
+        assertNotNull(ldapUserGroupProvider.getUserByIdentity("user1"));
+        assertTrue(ldapUserGroupProvider.getGroups().isEmpty());
+    }
+
+    @Test
+    public void testSearchUsersWithPaging() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_PAGE_SIZE)).thenReturn(new StandardPropertyValue("1"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(8, ldapUserGroupProvider.getUsers().size());
+        assertTrue(ldapUserGroupProvider.getGroups().isEmpty());
+    }
+
+    @Test
+    public void testSearchUsersWithGroupingNoGroupName() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        when(configurationContext.getProperty(PROP_USER_GROUP_ATTRIBUTE)).thenReturn(new StandardPropertyValue("description")); // using description in lieu of memberof
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(8, ldapUserGroupProvider.getUsers().size());
+        assertEquals(2, ldapUserGroupProvider.getGroups().size());
+
+        final UserAndGroups userAndGroups = ldapUserGroupProvider.getUserAndGroups("user4");
+        assertNotNull(userAndGroups.getUser());
+        assertEquals(1, userAndGroups.getGroups().size());
+        assertEquals("cn=team1,ou=groups,o=nifi", userAndGroups.getGroups().iterator().next().getName());
+    }
+
+    @Test
+    public void testSearchUsersWithGroupingAndGroupName() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        when(configurationContext.getProperty(PROP_USER_GROUP_ATTRIBUTE)).thenReturn(new StandardPropertyValue("description")); // using description in lieu of memberof
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(8, ldapUserGroupProvider.getUsers().size());
+        assertEquals(2, ldapUserGroupProvider.getGroups().size());
+
+        final UserAndGroups userAndGroups = ldapUserGroupProvider.getUserAndGroups("user4");
+        assertNotNull(userAndGroups.getUser());
+        assertEquals(1, userAndGroups.getGroups().size());
+        assertEquals("team1", userAndGroups.getGroups().iterator().next().getName());
+    }
+
+    @Test(expected = SecurityProviderCreationException.class)
+    public void testSearchGroupsWithoutMemberAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        ldapUserGroupProvider.onConfigured(configurationContext);
+    }
+
+    @Test(expected = SecurityProviderCreationException.class)
+    public void testGroupSearchBaseSpecifiedButNoGroupObjectClass() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_GROUP_OBJECT_CLASS)).thenReturn(new StandardPropertyValue(null));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+    }
+
+    @Test(expected = SecurityProviderCreationException.class)
+    public void testUserSearchBaseSpecifiedButNoGroupSearchScope() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_GROUP_SEARCH_SCOPE)).thenReturn(new StandardPropertyValue(null));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+    }
+
+    @Test(expected = SecurityProviderCreationException.class)
+    public void testInvalidGroupSearchScope() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_GROUP_SEARCH_SCOPE)).thenReturn(new StandardPropertyValue("not-valid"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+    }
+
+    @Test
+    public void testSearchGroupsWithNoNameAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(4, groups.size());
+        assertEquals(1, groups.stream().filter(group -> "cn=admins,ou=groups,o=nifi".equals(group.getName())).count());
+    }
+
+    @Test
+    public void testSearchGroupsWithPaging() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_PAGE_SIZE)).thenReturn(new StandardPropertyValue("1"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(4, ldapUserGroupProvider.getGroups().size());
+    }
+
+    @Test
+    public void testSearchGroupsObjectSearchScope() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_GROUP_SEARCH_SCOPE)).thenReturn(new StandardPropertyValue(SearchScope.OBJECT.name()));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertTrue(ldapUserGroupProvider.getUsers().isEmpty());
+        assertTrue(ldapUserGroupProvider.getGroups().isEmpty());
+    }
+
+    @Test
+    public void testSearchGroupsSubtreeSearchScope() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, "o=nifi");
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_GROUP_SEARCH_SCOPE)).thenReturn(new StandardPropertyValue(SearchScope.SUBTREE.name()));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(4, ldapUserGroupProvider.getGroups().size());
+    }
+
+    @Test
+    public void testSearchGroupsWithNameAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(4, groups.size());
+
+        final Group admins = groups.stream().filter(group -> "admins".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(admins);
+        assertFalse(admins.getUsers().isEmpty());
+        assertEquals(1, admins.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                        user -> "cn=User 1,ou=users,o=nifi".equals(user.getIdentity())).count());
+    }
+
+    @Test
+    public void testSearchGroupsWithNoNameAndUserIdentityUidAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(4, groups.size());
+
+        final Group admins = groups.stream().filter(group -> "cn=admins,ou=groups,o=nifi".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(admins);
+        assertFalse(admins.getUsers().isEmpty());
+        assertEquals(1, admins.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user1".equals(user.getIdentity())).count());
+    }
+
+    @Test
+    public void testSearchGroupsWithNameAndUserIdentityCnAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(4, groups.size());
+
+        final Group admins = groups.stream().filter(group -> "admins".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(admins);
+        assertFalse(admins.getUsers().isEmpty());
+        assertEquals(1, admins.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "User 1".equals(user.getIdentity())).count());
+    }
+
+    @Test
+    public void testSearchGroupsWithFilter() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_GROUP_SEARCH_FILTER)).thenReturn(new StandardPropertyValue("(cn=admins)"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(1, groups.size());
+        assertEquals(1, groups.stream().filter(group -> "cn=admins,ou=groups,o=nifi".equals(group.getName())).count());
+    }
+
+    @Test
+    public void testSearchUsersAndGroupsNoMembership() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, GROUP_SEARCH_BASE);
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(8, ldapUserGroupProvider.getUsers().size());
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(4, groups.size());
+        groups.forEach(group -> assertTrue(group.getUsers().isEmpty()));
+    }
+
+    @Test
+    public void testSearchUsersAndGroupsMembershipThroughUsers() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        when(configurationContext.getProperty(PROP_USER_GROUP_ATTRIBUTE)).thenReturn(new StandardPropertyValue("description")); // using description in lieu of memberof
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(8, ldapUserGroupProvider.getUsers().size());
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(4, groups.size());
+
+        final Group team1 = groups.stream().filter(group -> "team1".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(team1);
+        assertEquals(2, team1.getUsers().size());
+        assertEquals(2, team1.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user4".equals(user.getIdentity()) || "user5".equals(user.getIdentity())).count());
+
+        final Group team2 = groups.stream().filter(group -> "team2".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(team2);
+        assertEquals(2, team2.getUsers().size());
+        assertEquals(2, team2.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user6".equals(user.getIdentity()) || "user7".equals(user.getIdentity())).count());
+    }
+
+    @Test
+    public void testSearchUsersAndGroupsMembershipThroughGroups() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(8, ldapUserGroupProvider.getUsers().size());
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(4, groups.size());
+
+        final Group admins = groups.stream().filter(group -> "admins".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(admins);
+        assertEquals(2, admins.getUsers().size());
+        assertEquals(2, admins.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user1".equals(user.getIdentity()) || "user3".equals(user.getIdentity())).count());
+
+        final Group readOnly = groups.stream().filter(group -> "read-only".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(readOnly);
+        assertEquals(1, readOnly.getUsers().size());
+        assertEquals(1, readOnly.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user2".equals(user.getIdentity())).count());
+
+        final Group team1 = groups.stream().filter(group -> "team1".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(team1);
+        assertEquals(1, team1.getUsers().size());
+        assertEquals(1, team1.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user1".equals(user.getIdentity())).count());
+
+        final Group team2 = groups.stream().filter(group -> "team2".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(team2);
+        assertEquals(1, team2.getUsers().size());
+        assertEquals(1, team2.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user1".equals(user.getIdentity())).count());
+    }
+
+    @Test
+    public void testSearchUsersAndGroupsMembershipThroughUsersAndGroups() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, GROUP_SEARCH_BASE);
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        when(configurationContext.getProperty(PROP_USER_GROUP_ATTRIBUTE)).thenReturn(new StandardPropertyValue("description")); // using description in lieu of memberof
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("member"));
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(8, ldapUserGroupProvider.getUsers().size());
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(4, groups.size());
+
+        final Group admins = groups.stream().filter(group -> "admins".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(admins);
+        assertEquals(2, admins.getUsers().size());
+        assertEquals(2, admins.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user1".equals(user.getIdentity()) || "user3".equals(user.getIdentity())).count());
+
+        final Group readOnly = groups.stream().filter(group -> "read-only".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(readOnly);
+        assertEquals(1, readOnly.getUsers().size());
+        assertEquals(1, readOnly.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user2".equals(user.getIdentity())).count());
+
+        final Group team1 = groups.stream().filter(group -> "team1".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(team1);
+        assertEquals(3, team1.getUsers().size());
+        assertEquals(3, team1.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user1".equals(user.getIdentity()) || "user4".equals(user.getIdentity()) || "user5".equals(user.getIdentity())).count());
+
+        final Group team2 = groups.stream().filter(group -> "team2".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(team2);
+        assertEquals(3, team2.getUsers().size());
+        assertEquals(3, team2.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user1".equals(user.getIdentity()) || "user6".equals(user.getIdentity()) || "user7".equals(user.getIdentity())).count());
+    }
+
+    @Test
+    public void testUserIdentityMapping() throws Exception {
+        final Properties props = new Properties();
+        props.setProperty("nifi.registry.security.identity.mapping.pattern.dn1", "^cn=(.*?),o=(.*?)$");
+        props.setProperty("nifi.registry.security.identity.mapping.value.dn1", "$1");
+
+        final NiFiRegistryProperties properties = getNiFiProperties(props);
+        ldapUserGroupProvider.setNiFiProperties(properties);
+
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null);
+        when(configurationContext.getProperty(PROP_USER_SEARCH_FILTER)).thenReturn(new StandardPropertyValue("(uid=user1)"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        assertEquals(1, ldapUserGroupProvider.getUsers().size());
+        assertNotNull(ldapUserGroupProvider.getUserByIdentity("User 1,ou=users"));
+    }
+
+    @Test(expected = SecurityProviderCreationException.class)
+    public void testReferencedGroupAttributeWithoutGroupSearchBase() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration("ou=users-2,o=nifi", null);
+        when(configurationContext.getProperty(PROP_USER_GROUP_REFERENCED_GROUP_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+    }
+
+    @Test
+    public void testReferencedGroupWithoutDefiningReferencedAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration("ou=users-2,o=nifi", "ou=groups-2,o=nifi");
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        when(configurationContext.getProperty(PROP_USER_OBJECT_CLASS)).thenReturn(new StandardPropertyValue("room")); // using room due to reqs of groupOfNames
+        when(configurationContext.getProperty(PROP_USER_GROUP_ATTRIBUTE)).thenReturn(new StandardPropertyValue("description")); // using description in lieu of member
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        when(configurationContext.getProperty(PROP_GROUP_OBJECT_CLASS)).thenReturn(new StandardPropertyValue("room")); // using room due to reqs of groupOfNames
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(1, groups.size());
+
+        final Group team3 = groups.stream().filter(group -> "team3".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(team3);
+        assertTrue(team3.getUsers().isEmpty());
+    }
+
+    @Test
+    public void testReferencedGroupUsingReferencedAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration("ou=users-2,o=nifi", "ou=groups-2,o=nifi");
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        when(configurationContext.getProperty(PROP_USER_GROUP_ATTRIBUTE)).thenReturn(new StandardPropertyValue("description")); // using description in lieu of member
+        when(configurationContext.getProperty(PROP_USER_GROUP_REFERENCED_GROUP_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        when(configurationContext.getProperty(PROP_GROUP_OBJECT_CLASS)).thenReturn(new StandardPropertyValue("room")); // using room because groupOfNames requires a member
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(1, groups.size());
+
+        final Group team3 = groups.stream().filter(group -> "team3".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(team3);
+        assertEquals(1, team3.getUsers().size());
+        assertEquals(1, team3.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "user9".equals(user.getIdentity())).count());
+    }
+
+    @Test(expected = SecurityProviderCreationException.class)
+    public void testReferencedUserWithoutUserSearchBase() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(null, "ou=groups-2,o=nifi");
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_REFERENCED_USER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+    }
+
+    @Test
+    public void testReferencedUserWithoutDefiningReferencedAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration("ou=users-2,o=nifi", "ou=groups-2,o=nifi");
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid"));
+        when(configurationContext.getProperty(PROP_GROUP_OBJECT_CLASS)).thenReturn(new StandardPropertyValue("room")); // using room due to reqs of groupOfNames
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("description")); // using description in lieu of member
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(1, groups.size());
+
+        final Group team3 = groups.stream().filter(group -> "team3".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(team3);
+        assertTrue(team3.getUsers().isEmpty());
+    }
+
+    @Test
+    public void testReferencedUserUsingReferencedAttribute() throws Exception {
+        final AuthorizerConfigurationContext configurationContext = getBaseConfiguration("ou=users-2,o=nifi", "ou=groups-2,o=nifi");
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue("sn"));
+        when(configurationContext.getProperty(PROP_GROUP_OBJECT_CLASS)).thenReturn(new StandardPropertyValue("room")); // using room due to reqs of groupOfNames
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("description")); // using description in lieu of member
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue("cn"));
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_REFERENCED_USER_ATTRIBUTE)).thenReturn(new StandardPropertyValue("uid")); // does not need to be the same as user id attr
+        ldapUserGroupProvider.onConfigured(configurationContext);
+
+        final Set<Group> groups = ldapUserGroupProvider.getGroups();
+        assertEquals(1, groups.size());
+
+        final Group team3 = groups.stream().filter(group -> "team3".equals(group.getName())).findFirst().orElse(null);
+        assertNotNull(team3);
+        assertEquals(1, team3.getUsers().size());
+        assertEquals(1, team3.getUsers().stream().map(
+                userIdentifier -> ldapUserGroupProvider.getUser(userIdentifier)).filter(
+                user -> "User9".equals(user.getIdentity())).count());
+    }
+
+    private AuthorizerConfigurationContext getBaseConfiguration(final String userSearchBase, final String groupSearchBase) {
+        final AuthorizerConfigurationContext configurationContext = mock(AuthorizerConfigurationContext.class);
+        when(configurationContext.getProperty(PROP_URL)).thenReturn(new StandardPropertyValue("ldap://127.0.0.1:" + getLdapServer().getPort()));
+        when(configurationContext.getProperty(PROP_CONNECT_TIMEOUT)).thenReturn(new StandardPropertyValue("30 secs"));
+        when(configurationContext.getProperty(PROP_READ_TIMEOUT)).thenReturn(new StandardPropertyValue("30 secs"));
+        when(configurationContext.getProperty(PROP_REFERRAL_STRATEGY)).thenReturn(new StandardPropertyValue(ReferralStrategy.FOLLOW.name()));
+        when(configurationContext.getProperty(PROP_PAGE_SIZE)).thenReturn(new StandardPropertyValue(null));
+        when(configurationContext.getProperty(PROP_SYNC_INTERVAL)).thenReturn(new StandardPropertyValue("30 mins"));
+
+        when(configurationContext.getProperty(PROP_AUTHENTICATION_STRATEGY)).thenReturn(new StandardPropertyValue(LdapAuthenticationStrategy.SIMPLE.name()));
+        when(configurationContext.getProperty(PROP_MANAGER_DN)).thenReturn(new StandardPropertyValue("uid=admin,ou=system"));
+        when(configurationContext.getProperty(PROP_MANAGER_PASSWORD)).thenReturn(new StandardPropertyValue("secret"));
+
+        when(configurationContext.getProperty(PROP_USER_SEARCH_BASE)).thenReturn(new StandardPropertyValue(userSearchBase));
+        when(configurationContext.getProperty(PROP_USER_OBJECT_CLASS)).thenReturn(new StandardPropertyValue("person"));
+        when(configurationContext.getProperty(PROP_USER_SEARCH_SCOPE)).thenReturn(new StandardPropertyValue(SearchScope.ONE_LEVEL.name()));
+        when(configurationContext.getProperty(PROP_USER_SEARCH_FILTER)).thenReturn(new StandardPropertyValue(null));
+        when(configurationContext.getProperty(PROP_USER_IDENTITY_ATTRIBUTE)).thenReturn(new StandardPropertyValue(null));
+        when(configurationContext.getProperty(PROP_USER_GROUP_ATTRIBUTE)).thenReturn(new StandardPropertyValue(null));
+        when(configurationContext.getProperty(PROP_USER_GROUP_REFERENCED_GROUP_ATTRIBUTE)).thenReturn(new StandardPropertyValue(null));
+
+        when(configurationContext.getProperty(PROP_GROUP_SEARCH_BASE)).thenReturn(new StandardPropertyValue(groupSearchBase));
+        when(configurationContext.getProperty(PROP_GROUP_OBJECT_CLASS)).thenReturn(new StandardPropertyValue("groupOfNames"));
+        when(configurationContext.getProperty(PROP_GROUP_SEARCH_SCOPE)).thenReturn(new StandardPropertyValue(SearchScope.ONE_LEVEL.name()));
+        when(configurationContext.getProperty(PROP_GROUP_SEARCH_FILTER)).thenReturn(new StandardPropertyValue(null));
+        when(configurationContext.getProperty(PROP_GROUP_NAME_ATTRIBUTE)).thenReturn(new StandardPropertyValue(null));
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_ATTRIBUTE)).thenReturn(new StandardPropertyValue(null));
+        when(configurationContext.getProperty(PROP_GROUP_MEMBER_REFERENCED_USER_ATTRIBUTE)).thenReturn(new StandardPropertyValue(null));
+
+        return configurationContext;
+    }
+
+    private NiFiRegistryProperties getNiFiProperties(final Properties properties) {
+        final NiFiRegistryProperties registryProperties = Mockito.mock(NiFiRegistryProperties.class);
+        when(registryProperties.getPropertyKeys()).thenReturn(properties.stringPropertyNames());
+        when(registryProperties.getProperty(anyString())).then(invocationOnMock -> properties.getProperty((String) invocationOnMock.getArguments()[0]));
+        return registryProperties;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/serialization/TestVersionedProcessGroupSerializer.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/serialization/TestVersionedProcessGroupSerializer.java b/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/serialization/TestVersionedProcessGroupSerializer.java
new file mode 100644
index 0000000..584e2f7
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/serialization/TestVersionedProcessGroupSerializer.java
@@ -0,0 +1,130 @@
+/*
+ * 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.serialization;
+
+import org.apache.nifi.registry.flow.VersionedProcessGroup;
+import org.apache.nifi.registry.flow.VersionedProcessor;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class TestVersionedProcessGroupSerializer {
+
+    @Test
+    public void testSerializeDeserializeFlowSnapshot() throws SerializationException {
+        final Serializer<VersionedProcessGroup> serializer = new VersionedProcessGroupSerializer();
+
+        final VersionedProcessGroup processGroup1 = new VersionedProcessGroup();
+        processGroup1.setIdentifier("pg1");
+        processGroup1.setName("My Process Group");
+
+        final VersionedProcessor processor1 = new VersionedProcessor();
+        processor1.setIdentifier("processor1");
+        processor1.setName("My Processor 1");
+
+        // make sure nested objects are serialized/deserialized
+        processGroup1.getProcessors().add(processor1);
+
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        serializer.serialize(processGroup1, out);
+
+        final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+        final VersionedProcessGroup deserializedProcessGroup1 = serializer.deserialize(in);
+
+        Assert.assertEquals(processGroup1.getIdentifier(), deserializedProcessGroup1.getIdentifier());
+        Assert.assertEquals(processGroup1.getName(), deserializedProcessGroup1.getName());
+
+        Assert.assertEquals(1, deserializedProcessGroup1.getProcessors().size());
+
+        final VersionedProcessor deserializedProcessor1 = deserializedProcessGroup1.getProcessors().iterator().next();
+        Assert.assertEquals(processor1.getIdentifier(), deserializedProcessor1.getIdentifier());
+        Assert.assertEquals(processor1.getName(), deserializedProcessor1.getName());
+
+    }
+
+    @Test
+    public void testDeserializeJsonNonIntegerVersion() throws IOException {
+        final String file = "/serialization/json/non-integer-version.snapshot";
+        final VersionedProcessGroupSerializer serializer = new VersionedProcessGroupSerializer();
+        try (final InputStream is = this.getClass().getResourceAsStream(file)) {
+            try {
+                serializer.deserialize(is);
+                fail("Should fail");
+            } catch (SerializationException e) {
+                assertEquals("Unable to find a process group serializer compatible with the input.", e.getMessage());
+            }
+        }
+    }
+
+    @Test
+    public void testDeserializeJsonNoVersion() throws IOException {
+        final String file = "/serialization/json/no-version.snapshot";
+        final VersionedProcessGroupSerializer serializer = new VersionedProcessGroupSerializer();
+        try (final InputStream is = this.getClass().getResourceAsStream(file)) {
+            try {
+                serializer.deserialize(is);
+                fail("Should fail");
+            } catch (SerializationException e) {
+                assertEquals("Unable to find a process group serializer compatible with the input.", e.getMessage());
+            }
+        }
+    }
+
+    @Test
+    public void testDeserializeVer1() throws IOException {
+        final String file = "/serialization/ver1.snapshot";
+        final VersionedProcessGroupSerializer serializer = new VersionedProcessGroupSerializer();
+        final VersionedProcessGroup processGroup;
+        try (final InputStream is = this.getClass().getResourceAsStream(file)) {
+            processGroup = serializer.deserialize(is);
+        }
+        System.out.printf("processGroup=" + processGroup);
+    }
+
+    @Test
+    public void testDeserializeVer2() throws IOException {
+        final String file = "/serialization/ver2.snapshot";
+        final VersionedProcessGroupSerializer serializer = new VersionedProcessGroupSerializer();
+        final VersionedProcessGroup processGroup;
+        try (final InputStream is = this.getClass().getResourceAsStream(file)) {
+            processGroup = serializer.deserialize(is);
+        }
+        System.out.printf("processGroup=" + processGroup);
+    }
+
+    @Test
+    public void testDeserializeVer3() throws IOException {
+        final String file = "/serialization/ver3.snapshot";
+        final VersionedProcessGroupSerializer serializer = new VersionedProcessGroupSerializer();
+        try (final InputStream is = this.getClass().getResourceAsStream(file)) {
+            try {
+                serializer.deserialize(is);
+                fail("Should fail");
+            } catch (SerializationException e) {
+                assertEquals("Unable to find a process group serializer compatible with the input.", e.getMessage());
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/serialization/jaxb/TestJAXBVersionedProcessGroupSerializer.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/serialization/jaxb/TestJAXBVersionedProcessGroupSerializer.java b/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/serialization/jaxb/TestJAXBVersionedProcessGroupSerializer.java
new file mode 100644
index 0000000..916e053
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/serialization/jaxb/TestJAXBVersionedProcessGroupSerializer.java
@@ -0,0 +1,72 @@
+/*
+ * 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.serialization.jaxb;
+
+import org.apache.nifi.registry.flow.VersionedProcessGroup;
+import org.apache.nifi.registry.flow.VersionedProcessor;
+import org.apache.nifi.registry.serialization.SerializationException;
+import org.apache.nifi.registry.serialization.VersionedSerializer;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+
+public class TestJAXBVersionedProcessGroupSerializer {
+
+    @Test
+    public void testSerializeDeserializeFlowSnapshot() throws SerializationException {
+        final VersionedSerializer<VersionedProcessGroup> serializer = new JAXBVersionedProcessGroupSerializer();
+
+        final VersionedProcessGroup processGroup1 = new VersionedProcessGroup();
+        processGroup1.setIdentifier("pg1");
+        processGroup1.setName("My Process Group");
+
+        final VersionedProcessor processor1 = new VersionedProcessor();
+        processor1.setIdentifier("processor1");
+        processor1.setName("My Processor 1");
+
+        // make sure nested objects are serialized/deserialized
+        processGroup1.getProcessors().add(processor1);
+
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        serializer.serialize(1, processGroup1, out);
+
+        final String snapshotStr = new String(out.toByteArray(), StandardCharsets.UTF_8);
+        //System.out.println(snapshotStr);
+
+        final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+        in.mark(1024);
+        final int version = serializer.readDataModelVersion(in);
+
+        Assert.assertEquals(1, version);
+
+        in.reset();
+        final VersionedProcessGroup deserializedProcessGroup1 = serializer.deserialize(in);
+
+        Assert.assertEquals(processGroup1.getIdentifier(), deserializedProcessGroup1.getIdentifier());
+        Assert.assertEquals(processGroup1.getName(), deserializedProcessGroup1.getName());
+
+        Assert.assertEquals(1, deserializedProcessGroup1.getProcessors().size());
+
+        final VersionedProcessor deserializedProcessor1 = deserializedProcessGroup1.getProcessors().iterator().next();
+        Assert.assertEquals(processor1.getIdentifier(), deserializedProcessor1.getIdentifier());
+        Assert.assertEquals(processor1.getName(), deserializedProcessor1.getName());
+    }
+
+}