You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2019/08/01 09:47:39 UTC

[isis] branch v2 updated: ISIS-2156 adds smoketest for Isis' Shiro/Ldap integration

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch v2
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/v2 by this push:
     new 8bd3f24  ISIS-2156 adds smoketest for Isis' Shiro/Ldap integration
8bd3f24 is described below

commit 8bd3f246eab21ff2c2e2bcac74f574fd48baaf09
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Aug 1 11:47:30 2019 +0200

    ISIS-2156 adds smoketest for Isis' Shiro/Ldap integration
---
 examples/smoketest/log4j2-test.xml                 |  3 +
 .../isis/testdomain/jdo/JdoTestDomainModule.java   |  4 +-
 ...ity.java => JdoTestDomainModule_withShiro.java} | 18 ++----
 .../testdomain/ldap/LdapEmbeddedServerTest.java    | 56 ++++++++++++++-----
 ...ShiroIsisSecmanTest.java => ShiroLdapTest.java} | 56 +++++++++++++++----
 ...iroIsisSecmanTest.java => ShiroSecmanTest.java} | 50 ++++++++++++++---
 .../smoketest/src/test/resources/shiro-ldap.ini    | 64 ++++++++++++++++++++++
 .../resources/{shiro-isis.ini => shiro-secman.ini} |  0
 8 files changed, 201 insertions(+), 50 deletions(-)

diff --git a/examples/smoketest/log4j2-test.xml b/examples/smoketest/log4j2-test.xml
index 3cb094e..56e8ad6 100644
--- a/examples/smoketest/log4j2-test.xml
+++ b/examples/smoketest/log4j2-test.xml
@@ -23,6 +23,9 @@
 		<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
 		<logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
 		
+		<logger name="org.apache.directory" level="warn"/>
+		<logger name="org.apache.directory.api.ldap.model.entry.Value" level="off"/>
+		
 		<logger name="DataNucleus.Persistence" level="info"/>
 		<logger name="DataNucleus.Transaction" level="info"/>
 		<logger name="DataNucleus.Datastore.Schema" level="info"/>
diff --git a/examples/smoketest/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule.java b/examples/smoketest/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule.java
index 7f05ca8..3a44b12 100644
--- a/examples/smoketest/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule.java
+++ b/examples/smoketest/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule.java
@@ -56,8 +56,8 @@ import org.springframework.context.annotation.PropertySources;
     @PropertySource(name=Presets.H2InMemory, factory = Presets.Factory.class, value = { "" }),
     @PropertySource(name=Presets.NoTranslations, factory = Presets.Factory.class, value = { "" }),
 })
-//by default disable security specific config to be picked up by Spring 
-@ConditionalOnProperty(value = "smoketest.withSecurity", havingValue = "false", matchIfMissing = true)
+//by default disable shiro specific config to be picked up by Spring 
+@ConditionalOnProperty(value = "smoketest.withShiro", havingValue = "false", matchIfMissing = true)
 public class JdoTestDomainModule {
     
    @Bean @Singleton
diff --git a/examples/smoketest/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule_withSecurity.java b/examples/smoketest/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule_withShiro.java
similarity index 81%
rename from examples/smoketest/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule_withSecurity.java
rename to examples/smoketest/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule_withShiro.java
index b57c29d..76470b3 100644
--- a/examples/smoketest/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule_withSecurity.java
+++ b/examples/smoketest/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule_withShiro.java
@@ -27,10 +27,6 @@ import org.apache.isis.extensions.fixtures.IsisBootFixtures;
 import org.apache.isis.extensions.secman.api.SecurityModuleConfig;
 import org.apache.isis.extensions.secman.api.permission.PermissionsEvaluationService;
 import org.apache.isis.extensions.secman.api.permission.PermissionsEvaluationServiceAllowBeatsVeto;
-import org.apache.isis.extensions.secman.encryption.jbcrypt.IsisBootSecmanEncryptionJbcrypt;
-import org.apache.isis.extensions.secman.jdo.IsisBootSecmanPersistenceJdo;
-import org.apache.isis.extensions.secman.model.IsisBootSecmanModel;
-import org.apache.isis.extensions.secman.shiro.IsisBootSecmanRealmShiro;
 import org.apache.isis.jdo.IsisBootDataNucleus;
 import org.apache.isis.runtime.spring.IsisBoot;
 import org.apache.isis.security.shiro.IsisBootSecurityShiro;
@@ -50,18 +46,12 @@ import org.springframework.context.annotation.PropertySources;
 	
 	IsisBootSecurityShiro.class,
     
-    // Security Manager Extension (secman)
-    IsisBootSecmanModel.class,
-    IsisBootSecmanRealmShiro.class,
-    IsisBootSecmanPersistenceJdo.class,
-    IsisBootSecmanEncryptionJbcrypt.class,
-	
 	IsisBootDataNucleus.class,
 	IsisBootFixtures.class
 })
 @ComponentScan(
         basePackageClasses= {        		
-        		JdoTestDomainModule_withSecurity.class
+        		JdoTestDomainModule_withShiro.class
         },
         includeFilters= {
                 @Filter(type = FilterType.CUSTOM, classes= {IsisBeanScanInterceptorForSpring.class})
@@ -71,9 +61,9 @@ import org.springframework.context.annotation.PropertySources;
     @PropertySource(name=Presets.H2InMemory, factory = Presets.Factory.class, value = { "" }),
     @PropertySource(name=Presets.NoTranslations, factory = Presets.Factory.class, value = { "" }),
 })
-// enable security specific config to be picked up by Spring
-@ConditionalOnProperty(value = "smoketest.withSecurity", havingValue = "true", matchIfMissing = false)
-public class JdoTestDomainModule_withSecurity {
+// enable shiro specific config to be picked up by Spring
+@ConditionalOnProperty(value = "smoketest.withShiro", havingValue = "true", matchIfMissing = false)
+public class JdoTestDomainModule_withShiro {
     
    @Bean @Singleton
    public WebAppConfigBean webAppConfigBean() {
diff --git a/examples/smoketest/src/test/java/org/apache/isis/testdomain/ldap/LdapEmbeddedServerTest.java b/examples/smoketest/src/test/java/org/apache/isis/testdomain/ldap/LdapEmbeddedServerTest.java
index 69a665d..2d658d8 100644
--- a/examples/smoketest/src/test/java/org/apache/isis/testdomain/ldap/LdapEmbeddedServerTest.java
+++ b/examples/smoketest/src/test/java/org/apache/isis/testdomain/ldap/LdapEmbeddedServerTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.isis.testdomain.ldap;
 
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.util.Hashtable;
@@ -26,28 +26,27 @@ import java.util.Hashtable;
 import javax.inject.Inject;
 import javax.naming.Context;
 import javax.naming.InitialContext;
-import javax.naming.NameClassPair;
-import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 
 import org.junit.jupiter.api.Test;
 import org.junit.runners.model.InitializationError;
 import org.springframework.boot.test.context.SpringBootTest;
 
+import lombok.val;
+
 @SpringBootTest(
 		classes = {LdapServerService.class},
 		properties = {
 	        "logging.config=log4j2-test.xml",
-	        "logging.level.org.apache.directory.api.ldap.model.entry.Value=OFF",
 })
 class LdapEmbeddedServerTest {
 	
 	@Inject LdapServerService ldapServerService;
 
     @Test
-    void authenticateAgainstLdap() throws InitializationError, InterruptedException {
+    void authenticate_Sven() throws InitializationError, InterruptedException {
     	
-        Hashtable<String, String> env = new Hashtable<>();
+        val env = new Hashtable<String, String>();
         env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
         env.put(Context.PROVIDER_URL, "ldap://localhost:" + LdapEmbeddedServer.PORT);
 
@@ -56,16 +55,47 @@ class LdapEmbeddedServerTest {
         env.put(Context.SECURITY_CREDENTIALS, "pass");
         
         try {
-            Context ctx = new InitialContext(env);
-            NamingEnumeration<NameClassPair> enm = ctx.list("");
+            val ctx = new InitialContext(env);
+            val namingEnumeration = ctx.list("");
+
+            int entryCount = 0;
+            while (namingEnumeration.hasMore()) {
+            	namingEnumeration.next();
+            	++entryCount;
+            }
+            assertEquals(3, entryCount);
+
+            namingEnumeration.close();
+            ctx.close();
+        } catch (NamingException e) {
+            fail(e.getMessage());
+        } 
+    	
+    }
+    
+    @Test
+    void authenticate_Admin() throws InitializationError, InterruptedException {
+    	
+        val env = new Hashtable<String, String>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+        env.put(Context.PROVIDER_URL, "ldap://localhost:" + LdapEmbeddedServer.PORT);
+
+        env.put( Context.SECURITY_AUTHENTICATION, "simple" );
+        env.put( Context.SECURITY_PRINCIPAL, "uid=admin,ou=system" );
+        env.put( Context.SECURITY_CREDENTIALS, "secret" );
+        
+        try {
+            val ctx = new InitialContext(env);
+            val namingEnumeration = ctx.list("");
 
-            assertTrue(enm.hasMore());
-            
-            while (enm.hasMore()) {
-                System.out.println(enm.next());
+            int entryCount = 0;
+            while (namingEnumeration.hasMore()) {
+            	namingEnumeration.next();
+            	++entryCount;
             }
+            assertEquals(3, entryCount);
 
-            enm.close();
+            namingEnumeration.close();
             ctx.close();
         } catch (NamingException e) {
             fail(e.getMessage());
diff --git a/examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroIsisSecmanTest.java b/examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroLdapTest.java
similarity index 69%
copy from examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroIsisSecmanTest.java
copy to examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroLdapTest.java
index c2f1e72..6cbcf4a 100644
--- a/examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroIsisSecmanTest.java
+++ b/examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroLdapTest.java
@@ -23,8 +23,10 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-import org.apache.isis.extensions.secman.jdo.seed.scripts.IsisModuleSecurityAdminUser;
-import org.apache.isis.testdomain.jdo.JdoTestDomainModule_withSecurity;
+import javax.inject.Inject;
+
+import org.apache.isis.testdomain.jdo.JdoTestDomainModule_withShiro;
+import org.apache.isis.testdomain.ldap.LdapServerService;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.AuthenticationToken;
 import org.apache.shiro.authc.UsernamePasswordToken;
@@ -33,25 +35,33 @@ import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Import;
 
 import lombok.val;
+import lombok.extern.log4j.Log4j2;
 
 @SpringBootTest(
 		classes = { 
-				JdoTestDomainModule_withSecurity.class, 
+				JdoTestDomainModule_withShiro.class, 
 		}, 
 		properties = {
 				"logging.config=log4j2-test.xml",
-				"smoketest.withSecurity=true", // enable security specific config to be picked up by Spring 
+				"smoketest.withShiro=true", // enable shiro specific config to be picked up by Spring 
 		})
-class ShiroIsisSecmanTest extends AbstractShiroTest {
+@Import({
+	LdapServerService.class,
+})
+@Log4j2
+class ShiroLdapTest extends AbstractShiroTest {
+	
+	@Inject LdapServerService ldapServerService;
 
 	@BeforeAll
 	static void beforeClass() {
 		//0.  Build and set the SecurityManager used to build Subject instances used in your tests
 		//    This typically only needs to be done once per class if your shiro.ini doesn't change,
 		//    otherwise, you'll need to do this logic in each test that is different
-		val factory = new IniSecurityManagerFactory("classpath:shiro-isis.ini");
+		val factory = new IniSecurityManagerFactory("classpath:shiro-ldap.ini");
 		setSecurityManager(factory.getInstance());
 	}
 
@@ -62,6 +72,8 @@ class ShiroIsisSecmanTest extends AbstractShiroTest {
 
 	@Test
 	void loginLogoutRoundtrip() {
+		
+		log.info("starting login/logout roundtrip");
 
 		val secMan = SecurityUtils.getSecurityManager();
 		assertNotNull(secMan);
@@ -71,8 +83,8 @@ class ShiroIsisSecmanTest extends AbstractShiroTest {
 		assertFalse(subject.isAuthenticated());
 
 		val token = (AuthenticationToken) new UsernamePasswordToken(
-				IsisModuleSecurityAdminUser.USER_NAME,
-				IsisModuleSecurityAdminUser.PASSWORD);
+				"cn=Sven Tester,ou=Users,dc=myorg,dc=com",
+				"pass");
 
 		subject.login(token);
 		assertTrue(subject.isAuthenticated());
@@ -83,7 +95,29 @@ class ShiroIsisSecmanTest extends AbstractShiroTest {
 	}
 
 	@Test
-	void invalidLogin() {
+	void login_withInvalidPassword() {
+
+		val secMan = SecurityUtils.getSecurityManager();
+		assertNotNull(secMan);
+
+		val subject = SecurityUtils.getSubject(); 
+		assertNotNull(subject);
+		assertFalse(subject.isAuthenticated());
+
+		val token = (AuthenticationToken) new UsernamePasswordToken(
+				"cn=Sven Tester,ou=Users,dc=myorg,dc=com",
+				"invalid-pass");
+		
+		assertThrows(Exception.class, ()->{
+			subject.login(token);
+		});
+		
+		assertFalse(subject.isAuthenticated());
+
+	}
+	
+	@Test
+	void login_withNonExistentUser() {
 
 		val secMan = SecurityUtils.getSecurityManager();
 		assertNotNull(secMan);
@@ -94,7 +128,7 @@ class ShiroIsisSecmanTest extends AbstractShiroTest {
 
 		val token = (AuthenticationToken) new UsernamePasswordToken(
 				"non-existent-user",
-				"pass");
+				"invalid-pass");
 		
 		assertThrows(Exception.class, ()->{
 			subject.login(token);
@@ -105,7 +139,5 @@ class ShiroIsisSecmanTest extends AbstractShiroTest {
 
 	}
 
-	
-
 
 }
diff --git a/examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroIsisSecmanTest.java b/examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroSecmanTest.java
similarity index 67%
rename from examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroIsisSecmanTest.java
rename to examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroSecmanTest.java
index c2f1e72..0f0d64c 100644
--- a/examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroIsisSecmanTest.java
+++ b/examples/smoketest/src/test/java/org/apache/isis/testdomain/shiro/ShiroSecmanTest.java
@@ -23,8 +23,12 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
+import org.apache.isis.extensions.secman.encryption.jbcrypt.IsisBootSecmanEncryptionJbcrypt;
+import org.apache.isis.extensions.secman.jdo.IsisBootSecmanPersistenceJdo;
 import org.apache.isis.extensions.secman.jdo.seed.scripts.IsisModuleSecurityAdminUser;
-import org.apache.isis.testdomain.jdo.JdoTestDomainModule_withSecurity;
+import org.apache.isis.extensions.secman.model.IsisBootSecmanModel;
+import org.apache.isis.extensions.secman.shiro.IsisBootSecmanRealmShiro;
+import org.apache.isis.testdomain.jdo.JdoTestDomainModule_withShiro;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.AuthenticationToken;
 import org.apache.shiro.authc.UsernamePasswordToken;
@@ -33,25 +37,33 @@ import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Import;
 
 import lombok.val;
 
 @SpringBootTest(
 		classes = { 
-				JdoTestDomainModule_withSecurity.class, 
+				JdoTestDomainModule_withShiro.class, 
 		}, 
 		properties = {
 				"logging.config=log4j2-test.xml",
-				"smoketest.withSecurity=true", // enable security specific config to be picked up by Spring 
+				"smoketest.withShiro=true", // enable shiro specific config to be picked up by Spring 
 		})
-class ShiroIsisSecmanTest extends AbstractShiroTest {
+@Import({
+    // Security Manager Extension (secman)
+    IsisBootSecmanModel.class,
+    IsisBootSecmanRealmShiro.class,
+    IsisBootSecmanPersistenceJdo.class,
+    IsisBootSecmanEncryptionJbcrypt.class,
+})
+class ShiroSecmanTest extends AbstractShiroTest {
 
 	@BeforeAll
 	static void beforeClass() {
 		//0.  Build and set the SecurityManager used to build Subject instances used in your tests
 		//    This typically only needs to be done once per class if your shiro.ini doesn't change,
 		//    otherwise, you'll need to do this logic in each test that is different
-		val factory = new IniSecurityManagerFactory("classpath:shiro-isis.ini");
+		val factory = new IniSecurityManagerFactory("classpath:shiro-secman.ini");
 		setSecurityManager(factory.getInstance());
 	}
 
@@ -83,7 +95,29 @@ class ShiroIsisSecmanTest extends AbstractShiroTest {
 	}
 
 	@Test
-	void invalidLogin() {
+	void login_withInvalidPassword() {
+
+		val secMan = SecurityUtils.getSecurityManager();
+		assertNotNull(secMan);
+
+		val subject = SecurityUtils.getSubject(); 
+		assertNotNull(subject);
+		assertFalse(subject.isAuthenticated());
+
+		val token = (AuthenticationToken) new UsernamePasswordToken(
+				IsisModuleSecurityAdminUser.USER_NAME,
+				"invalid-pass");
+		
+		assertThrows(Exception.class, ()->{
+			subject.login(token);
+		});
+		
+		assertFalse(subject.isAuthenticated());
+
+	}
+	
+	@Test
+	void login_withNonExistentUser() {
 
 		val secMan = SecurityUtils.getSecurityManager();
 		assertNotNull(secMan);
@@ -94,7 +128,7 @@ class ShiroIsisSecmanTest extends AbstractShiroTest {
 
 		val token = (AuthenticationToken) new UsernamePasswordToken(
 				"non-existent-user",
-				"pass");
+				"invalid-pass");
 		
 		assertThrows(Exception.class, ()->{
 			subject.login(token);
@@ -105,7 +139,5 @@ class ShiroIsisSecmanTest extends AbstractShiroTest {
 
 	}
 
-	
-
 
 }
diff --git a/examples/smoketest/src/test/resources/shiro-ldap.ini b/examples/smoketest/src/test/resources/shiro-ldap.ini
new file mode 100644
index 0000000..02d1bb8
--- /dev/null
+++ b/examples/smoketest/src/test/resources/shiro-ldap.ini
@@ -0,0 +1,64 @@
+#
+# 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.
+#
+
+[main]
+
+contextFactory = org.apache.isis.security.shiro.IsisLdapContextFactory
+contextFactory.url = ldap://localhost:10389
+contextFactory.authenticationMechanism = simple
+contextFactory.systemAuthenticationMechanism = simple
+contextFactory.systemUsername = uid=admin,ou=system
+contextFactory.systemPassword = secret
+
+ldapRealm = org.apache.isis.security.shiro.IsisLdapRealm   
+ldapRealm.contextFactory = $contextFactory
+
+ldapRealm.searchBase = ou=groups,o=mojo                    
+ldapRealm.groupObjectClass = groupOfUniqueNames            
+ldapRealm.uniqueMemberAttribute = uniqueMember             
+ldapRealm.uniqueMemberAttributeValueTemplate = uid={0}
+
+# optional mapping from physical groups to logical application roles
+ldapRealm.rolesByGroup = \                                 
+    LDN_USERS: user_role,\
+    NYK_USERS: user_role,\
+    HKG_USERS: user_role,\
+    GLOBAL_ADMIN: admin_role,\
+    DEMOS: self-install_role
+
+ldapRealm.permissionsByRole=\
+   user_role = *:SimpleObjectMenu:*:*,\
+               *:SimpleObject:*:*; \
+   self-install_role = *:FixtureScriptsDefault:*:* ; \
+   admin_role = *
+
+securityManager.realms = $ldapRealm
+
+#authenticationStrategy=org.apache.isis.extensions.secman.shiro.AuthenticationStrategyForIsisModuleSecurityRealm
+#isisModuleSecurityRealm=org.apache.isis.extensions.secman.shiro.IsisModuleSecurityRealm
+
+#securityManager.authenticator.authenticationStrategy = $authenticationStrategy
+#securityManager.realms = $isisModuleSecurityRealm
+
+[users]
+[roles]
+
+
+
+
diff --git a/examples/smoketest/src/test/resources/shiro-isis.ini b/examples/smoketest/src/test/resources/shiro-secman.ini
similarity index 100%
rename from examples/smoketest/src/test/resources/shiro-isis.ini
rename to examples/smoketest/src/test/resources/shiro-secman.ini