From 2788bd55845d35ffb753f20ea1fee9711e85fe43 Mon Sep 17 00:00:00 2001 From: "Christopher L. Shannon (cshannon)" Date: Wed, 16 Mar 2016 14:48:42 +0000 Subject: [PATCH] https://issues.apache.org/jira/browse/AMQ-6214 Fixing ReloadableProperties so that the groups file will be properly reloaded on file modification. Added a test to verify. Thanks to Nanchang Yang for providing the fix. --- .../activemq/jaas/PropertiesLoader.java | 2 + .../activemq/jaas/ReloadableProperties.java | 1 + .../jaas/PropertiesLoginModuleTest.java | 119 ++++++++++++------ .../test/resources/groupsReload.properties | 20 +++ activemq-jaas/src/test/resources/login.config | 9 ++ .../src/test/resources/usersReload.properties | 21 ++++ 6 files changed, 132 insertions(+), 40 deletions(-) create mode 100644 activemq-jaas/src/test/resources/groupsReload.properties create mode 100644 activemq-jaas/src/test/resources/usersReload.properties diff --git a/activemq-jaas/src/main/java/org/apache/activemq/jaas/PropertiesLoader.java b/activemq-jaas/src/main/java/org/apache/activemq/jaas/PropertiesLoader.java index 80c65ea55b..56d205d180 100644 --- a/activemq-jaas/src/main/java/org/apache/activemq/jaas/PropertiesLoader.java +++ b/activemq-jaas/src/main/java/org/apache/activemq/jaas/PropertiesLoader.java @@ -73,6 +73,7 @@ public class PropertiesLoader { return other instanceof FileNameKey && this.absPath.equals(((FileNameKey) other).absPath); } + @Override public int hashCode() { return this.absPath.hashCode(); } @@ -113,6 +114,7 @@ public class PropertiesLoader { return baseDir; } + @Override public String toString() { return "PropsFile=" + absPath; } diff --git a/activemq-jaas/src/main/java/org/apache/activemq/jaas/ReloadableProperties.java b/activemq-jaas/src/main/java/org/apache/activemq/jaas/ReloadableProperties.java index 67a22a43a2..95781cc11c 100644 --- a/activemq-jaas/src/main/java/org/apache/activemq/jaas/ReloadableProperties.java +++ b/activemq-jaas/src/main/java/org/apache/activemq/jaas/ReloadableProperties.java @@ -50,6 +50,7 @@ public class ReloadableProperties { try { load(key.file(), props); invertedProps = null; + invertedValueProps = null; if (key.isDebug()) { LOG.debug("Load of: " + key); } diff --git a/activemq-jaas/src/test/java/org/apache/activemq/jaas/PropertiesLoginModuleTest.java b/activemq-jaas/src/test/java/org/apache/activemq/jaas/PropertiesLoginModuleTest.java index 82aef75835..478611b5c5 100644 --- a/activemq-jaas/src/test/java/org/apache/activemq/jaas/PropertiesLoginModuleTest.java +++ b/activemq-jaas/src/test/java/org/apache/activemq/jaas/PropertiesLoginModuleTest.java @@ -16,6 +16,7 @@ */ package org.apache.activemq.jaas; +import java.io.File; import java.io.IOException; import java.net.URL; @@ -29,6 +30,8 @@ import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; +import org.apache.commons.io.FileUtils; + import junit.framework.TestCase; @@ -36,7 +39,7 @@ import junit.framework.TestCase; * @version $Rev: $ $Date: $ */ public class PropertiesLoginModuleTest extends TestCase { - + static { String path = System.getProperty("java.security.auth.login.config"); if (path == null) { @@ -49,19 +52,7 @@ public class PropertiesLoginModuleTest extends TestCase { } public void testLogin() throws LoginException { - LoginContext context = new LoginContext("PropertiesLogin", new CallbackHandler() { - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (int i = 0; i < callbacks.length; i++) { - if (callbacks[i] instanceof NameCallback) { - ((NameCallback) callbacks[i]).setName("first"); - } else if (callbacks[i] instanceof PasswordCallback) { - ((PasswordCallback) callbacks[i]).setPassword("secret".toCharArray()); - } else { - throw new UnsupportedCallbackException(callbacks[i]); - } - } - } - }); + LoginContext context = new LoginContext("PropertiesLogin", new UserPassHandler("first", "secret")); context.login(); Subject subject = context.getSubject(); @@ -75,20 +66,55 @@ public class PropertiesLoginModuleTest extends TestCase { assertEquals("Should have zero principals", 0, subject.getPrincipals().size()); } + public void testLoginReload() throws Exception { + File targetPropDir = new File("target/loginReloadTest"); + File sourcePropDir = new File("src/test/resources"); + File usersFile = new File(targetPropDir, "users.properties"); + File groupsFile = new File(targetPropDir, "groups.properties"); + + //Set up initial properties + FileUtils.copyFile(new File(sourcePropDir, "users.properties"), usersFile); + FileUtils.copyFile(new File(sourcePropDir, "groups.properties"), groupsFile); + + LoginContext context = new LoginContext("PropertiesLoginReload", + new UserPassHandler("first", "secret")); + context.login(); + Subject subject = context.getSubject(); + + //test initial principals + assertEquals("Should have three principals", 3, subject.getPrincipals().size()); + assertEquals("Should have one user principal", 1, subject.getPrincipals(UserPrincipal.class).size()); + assertEquals("Should have two group principals", 2, subject.getPrincipals(GroupPrincipal.class).size()); + + context.logout(); + + assertEquals("Should have zero principals", 0, subject.getPrincipals().size()); + + //Modify the file and test that the properties are reloaded + Thread.sleep(1000); + FileUtils.copyFile(new File(sourcePropDir, "usersReload.properties"), usersFile); + FileUtils.copyFile(new File(sourcePropDir, "groupsReload.properties"), groupsFile); + FileUtils.touch(usersFile); + FileUtils.touch(groupsFile); + + //Use new password to verify users file was reloaded + context = new LoginContext("PropertiesLoginReload", new UserPassHandler("first", "secrets")); + context.login(); + subject = context.getSubject(); + + //Check that the principals changed + assertEquals("Should have three principals", 2, subject.getPrincipals().size()); + assertEquals("Should have one user principal", 1, subject.getPrincipals(UserPrincipal.class).size()); + assertEquals("Should have one group principals", 1, subject.getPrincipals(GroupPrincipal.class).size()); + + context.logout(); + + assertEquals("Should have zero principals", 0, subject.getPrincipals().size()); + } + public void testBadUseridLogin() throws Exception { - LoginContext context = new LoginContext("PropertiesLogin", new CallbackHandler() { - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (int i = 0; i < callbacks.length; i++) { - if (callbacks[i] instanceof NameCallback) { - ((NameCallback) callbacks[i]).setName("BAD"); - } else if (callbacks[i] instanceof PasswordCallback) { - ((PasswordCallback) callbacks[i]).setPassword("secret".toCharArray()); - } else { - throw new UnsupportedCallbackException(callbacks[i]); - } - } - } - }); + LoginContext context = new LoginContext("PropertiesLogin", new UserPassHandler("BAD", "secret")); + try { context.login(); fail("Should have thrown a FailedLoginException"); @@ -98,19 +124,8 @@ public class PropertiesLoginModuleTest extends TestCase { } public void testBadPWLogin() throws Exception { - LoginContext context = new LoginContext("PropertiesLogin", new CallbackHandler() { - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (int i = 0; i < callbacks.length; i++) { - if (callbacks[i] instanceof NameCallback) { - ((NameCallback) callbacks[i]).setName("first"); - } else if (callbacks[i] instanceof PasswordCallback) { - ((PasswordCallback) callbacks[i]).setPassword("BAD".toCharArray()); - } else { - throw new UnsupportedCallbackException(callbacks[i]); - } - } - } - }); + LoginContext context = new LoginContext("PropertiesLogin", new UserPassHandler("first", "BAD")); + try { context.login(); fail("Should have thrown a FailedLoginException"); @@ -118,4 +133,28 @@ public class PropertiesLoginModuleTest extends TestCase { } } + + private static class UserPassHandler implements CallbackHandler { + + private final String user; + private final String pass; + + public UserPassHandler(final String user, final String pass) { + this.user = user; + this.pass = pass; + } + + @Override + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + for (int i = 0; i < callbacks.length; i++) { + if (callbacks[i] instanceof NameCallback) { + ((NameCallback) callbacks[i]).setName(user); + } else if (callbacks[i] instanceof PasswordCallback) { + ((PasswordCallback) callbacks[i]).setPassword(pass.toCharArray()); + } else { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + } + } } diff --git a/activemq-jaas/src/test/resources/groupsReload.properties b/activemq-jaas/src/test/resources/groupsReload.properties new file mode 100644 index 0000000000..422eb3d9eb --- /dev/null +++ b/activemq-jaas/src/test/resources/groupsReload.properties @@ -0,0 +1,20 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +programmers=first +accounting=second + diff --git a/activemq-jaas/src/test/resources/login.config b/activemq-jaas/src/test/resources/login.config index d4ee114763..dee62a52c8 100644 --- a/activemq-jaas/src/test/resources/login.config +++ b/activemq-jaas/src/test/resources/login.config @@ -21,6 +21,15 @@ PropertiesLogin { org.apache.activemq.jaas.properties.group="groups.properties"; }; +PropertiesLoginReload { + org.apache.activemq.jaas.PropertiesLoginModule required + debug=true + reload=true + baseDir="target/loginReloadTest/" + org.apache.activemq.jaas.properties.user="users.properties" + org.apache.activemq.jaas.properties.group="groups.properties"; +}; + LDAPLogin { org.apache.activemq.jaas.LDAPLoginModule required debug=true diff --git a/activemq-jaas/src/test/resources/usersReload.properties b/activemq-jaas/src/test/resources/usersReload.properties new file mode 100644 index 0000000000..0c409013e3 --- /dev/null +++ b/activemq-jaas/src/test/resources/usersReload.properties @@ -0,0 +1,21 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +#different password than users.properties +first=secrets +second=password +