[java-identity-provider] branch main updated: First draft of a property-based plugin base class.
Scott Cantor
cantor.2 at osu.edu
Fri Oct 2 00:41:30 UTC 2020
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=b2b5287313667276441cfc734ac107b6fdfc1097
The following commit(s) were added to refs/heads/main by this push:
new b2b528731 First draft of a property-based plugin base class.
b2b528731 is described below
commit b2b5287313667276441cfc734ac107b6fdfc1097
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Oct 1 20:41:24 2020 -0400
First draft of a property-based plugin base class.
---
.../shibboleth/idp/plugin/AbstractIdPPlugin.java | 42 +++-
.../java/net/shibboleth/idp/plugin/IdPPlugin.java | 2 +
.../net/shibboleth/idp/plugin/PluginException.java | 67 +++++++
.../idp/plugin/PropertyDrivenIdPPlugin.java | 211 +++++++++++++++++++++
.../net/shibboleth/idp/plugin/IdPPluginTest.java | 66 +++++++
.../java/net/shibboleth/idp/plugin/TestPlugin.java | 50 +++++
.../services/net.shibboleth.idp.plugin.IdPPlugin | 1 +
.../net/shibboleth/idp/plugin/plugin.properties | 7 +
8 files changed, 444 insertions(+), 2 deletions(-)
diff --git a/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/AbstractIdPPlugin.java b/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/AbstractIdPPlugin.java
index 05356b938..2dd027a90 100644
--- a/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/AbstractIdPPlugin.java
+++ b/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/AbstractIdPPlugin.java
@@ -29,13 +29,33 @@ import javax.annotation.Nonnull;
import net.shibboleth.idp.module.IdPModule;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.collection.Pair;
/**
* A base class implementing {@link IdPPlugin} that defaults common settings.
+ *
+ * @since 4.1.0
*/
public abstract class AbstractIdPPlugin implements IdPPlugin {
+ /** Modules to enable on install. */
+ @Nonnull @NonnullElements private Set<IdPModule> enableModules;
+
+ /** Modules to disable on removal. */
+ @Nonnull @NonnullElements private Set<IdPModule> disableModules;
+
+ /** Constructor. */
+ public AbstractIdPPlugin() {
+ enableModules = Collections.emptySet();
+ disableModules = Collections.emptySet();
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull @NotEmpty public String getPluginId() {
+ return getClass().getPackageName();
+ }
+
/** {@inheritDoc} */
@Nonnull @NonnullElements public List<Path> getFilePathsToCopy() {
return Collections.emptyList();
@@ -58,12 +78,30 @@ public abstract class AbstractIdPPlugin implements IdPPlugin {
/** {@inheritDoc} */
@Nonnull @NonnullElements public Set<IdPModule> getEnableOnInstall() {
- return Collections.emptySet();
+ return enableModules;
+ }
+
+ /**
+ * Set the modules to enable on install.
+ *
+ * @param modules modules to enable
+ */
+ protected void setEnableOnInstall(@Nonnull @NonnullElements final Set<IdPModule> modules) {
+ enableModules = Set.copyOf(modules);
}
/** {@inheritDoc} */
@Nonnull @NonnullElements public Set<IdPModule> getDisableOnRemoval() {
- return Collections.emptySet();
+ return disableModules;
+ }
+
+ /**
+ * Set the modules to disable on removal.
+ *
+ * @param modules modules to disable
+ */
+ protected void setDisableOnRemoval(@Nonnull @NonnullElements final Set<IdPModule> modules) {
+ disableModules = Set.copyOf(modules);
}
/** {@inheritDoc} */
diff --git a/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/IdPPlugin.java b/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/IdPPlugin.java
index 582961d26..29378b446 100644
--- a/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/IdPPlugin.java
+++ b/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/IdPPlugin.java
@@ -33,6 +33,8 @@ import net.shibboleth.utilities.java.support.collection.Pair;
/**
* This interface is exported (via the service API) by every IdP plugin.
+ *
+ * @since 4.1.0
*/
public interface IdPPlugin {
diff --git a/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/PluginException.java b/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/PluginException.java
new file mode 100644
index 000000000..a2f9e58f6
--- /dev/null
+++ b/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/PluginException.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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 net.shibboleth.idp.plugin;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * Plugin exception class.
+ *
+ * @since 4.1.0
+ */
+ at ThreadSafe
+public class PluginException extends Exception {
+
+ /** Serial number. */
+ private static final long serialVersionUID = 3469763471281379002L;
+
+ /** Constructor. */
+ public PluginException() {
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message exception message
+ */
+ public PluginException(@Nullable final String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param wrappedException exception to be wrapped by this one
+ */
+ public PluginException(@Nullable final Exception wrappedException) {
+ super(wrappedException);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message exception message
+ * @param wrappedException exception to be wrapped by this one
+ */
+ public PluginException(@Nullable final String message, @Nullable final Exception wrappedException) {
+ super(message, wrappedException);
+ }
+
+}
\ No newline at end of file
diff --git a/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/PropertyDrivenIdPPlugin.java b/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/PropertyDrivenIdPPlugin.java
new file mode 100644
index 000000000..3e95c3491
--- /dev/null
+++ b/idp-admin-api/src/main/java/net/shibboleth/idp/plugin/PropertyDrivenIdPPlugin.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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 net.shibboleth.idp.plugin;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.module.PropertyDrivenIdPModule;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonNegative;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * Implementation of {@link IdPPlugin} relying on Java {@link Properties}.
+ *
+ * @since 4.1.0
+ */
+public abstract class PropertyDrivenIdPPlugin extends AbstractIdPPlugin {
+
+ /** Default name of plugin properties resource. */
+ @Nonnull @NotEmpty public static final String DEFAULT_RESOURCE = "plugin.properties";
+
+ /** Property for plugin ID. */
+ @Nonnull @NotEmpty public static final String PLUGIN_ID_PROPERTY = "plugin.id";
+
+ /** Property for plugin version. */
+ @Nonnull @NotEmpty public static final String PLUGIN_VERSION_PROPERTY = "plugin.version";
+
+ /** Prefix of property for plugin update URL. */
+ @Nonnull @NotEmpty public static final String PLUGIN_URL_PROPERTY = "plugin.url.";
+
+ /** Property for plugin's required modules. */
+ @Nonnull @NotEmpty public static final String PLUGIN_REQ_MODULES_PROPERTY = "plugin.modules.required";
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(PropertyDrivenIdPModule.class);
+
+ /** Properties describing plugin. */
+ @Nonnull private final Properties pluginProperties;
+
+ /** Non-defaulted plugin ID. */
+ @Nullable private String pluginId;
+
+ /** Handles parsing of plugin version. */
+ @Nullable private PluginVersion pluginVersion;
+
+ /** Plugin update URLs. */
+ @Nonnull @NonnullElements private List<URL> updateURLs = Collections.emptyList();
+
+ /** Required modules. */
+ @Nonnull @NonnullElements private Set<String> requiredModules = Collections.emptySet();
+
+ /**
+ * Constructor.
+ *
+ * @param claz type of object used to locate default module.properties resource
+ *
+ * @throws IOException if unable to read file
+ * @throws PluginException if the plugin is not in a valid state
+ */
+ public PropertyDrivenIdPPlugin(@Nonnull final Class<? extends IdPPlugin> claz) throws IOException, PluginException {
+ this(claz.getResourceAsStream(DEFAULT_RESOURCE));
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param inputStream property stream
+ *
+ * @throws IOException if unable to read file
+ * @throws PluginException if the plugin is not in a valid state
+ */
+ public PropertyDrivenIdPPlugin(@Nonnull final InputStream inputStream)
+ throws IOException, PluginException {
+ pluginProperties = new Properties();
+ pluginProperties.load(inputStream);
+ load();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param properties property set
+ *
+ * @throws PluginException if the plugin is not in a valid state
+ */
+ public PropertyDrivenIdPPlugin(@Nonnull final Properties properties) throws PluginException {
+ pluginProperties = Constraint.isNotNull(properties, "Properties cannot be null");
+ load();
+ }
+
+ protected void load() throws PluginException {
+
+ pluginId = StringSupport.trimOrNull(pluginProperties.getProperty(PLUGIN_ID_PROPERTY));
+
+ String version = StringSupport.trimOrNull(pluginProperties.getProperty(PLUGIN_VERSION_PROPERTY));
+ if (version == null) {
+ version = getClass().getPackage().getImplementationVersion();
+ }
+
+ if (version == null) {
+ throw new PluginException("No plugin version property or package attribute available");
+ }
+
+ try {
+ pluginVersion = new PluginVersion(version);
+ } catch (final NumberFormatException e) {
+ throw new PluginException(e);
+ }
+
+ final List<URL> urls = new ArrayList<>();
+
+ for (Integer urlnum = 1; ; ++urlnum) {
+
+ String urlstr = pluginProperties.getProperty(PLUGIN_URL_PROPERTY + urlnum.toString());
+ if (urlstr == null) {
+ break;
+ } else if (urlstr.startsWith("/")) {
+ urlstr = getUpdatePrefix() + urlstr;
+ }
+
+ try {
+ urls.add(new URL(urlstr));
+ } catch (final MalformedURLException e) {
+ log.error("Unable to convert property value '{}' to URL", urlstr, e);
+ }
+ }
+
+ updateURLs = List.copyOf(urls);
+
+ requiredModules = Set.copyOf(StringSupport.normalizeStringCollection(
+ StringSupport.stringToList(pluginProperties.getProperty(PLUGIN_REQ_MODULES_PROPERTY, ""), ",")));
+
+ log.debug("Plugin {} loaded", getPluginId());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nonnull @NotEmpty public String getPluginId() {
+ if (pluginId != null) {
+ return pluginId;
+ }
+ return super.getPluginId();
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull @NonnullElements public List<URL> getUpdateURLs() {
+ return updateURLs;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nonnull @NonnullElements public Set<String> getRequiredModules() {
+ return requiredModules;
+ }
+
+ /** {@inheritDoc} */
+ @NonNegative public int getMajorVersion() {
+ return pluginVersion.getMajor();
+ }
+
+ /** {@inheritDoc} */
+ @NonNegative public int getMinorVersion() {
+ return pluginVersion.getMinor();
+ }
+
+ /** {@inheritDoc} */
+ @NonNegative public int getPatchVersion() {
+ return pluginVersion.getPatch();
+ }
+
+ /**
+ * Gets the default update URL prefix for any relative update locations.
+ *
+ * @return update URL prefix
+ */
+ @Nonnull protected String getUpdatePrefix() {
+ return "";
+ }
+
+}
\ No newline at end of file
diff --git a/idp-admin-api/src/test/java/net/shibboleth/idp/plugin/IdPPluginTest.java b/idp-admin-api/src/test/java/net/shibboleth/idp/plugin/IdPPluginTest.java
new file mode 100644
index 000000000..8aed7d902
--- /dev/null
+++ b/idp-admin-api/src/test/java/net/shibboleth/idp/plugin/IdPPluginTest.java
@@ -0,0 +1,66 @@
+package net.shibboleth.idp.plugin;
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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.
+ */
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.ServiceLoader;
+import java.util.ServiceLoader.Provider;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.module.IdPModule;
+import net.shibboleth.idp.module.ModuleException;
+import net.shibboleth.idp.module.TestModule;
+
+/**
+ * Unit tests exercising plugin code.
+ */
+public class IdPPluginTest {
+
+ private IdPPlugin testPlugin;
+
+ @BeforeMethod
+ public void setUp() throws Exception {
+ final ServiceLoader<IdPPlugin> loader = ServiceLoader.load(IdPPlugin.class);
+ final Optional<Provider<IdPPlugin>> opt =
+ loader.stream().filter(p -> TestPlugin.class.equals(p.type())).findFirst();
+ Assert.assertTrue(opt.isPresent());
+
+ testPlugin = opt.get().get();
+ }
+
+ @Test
+ public void testModule() throws IOException, ModuleException {
+ Assert.assertEquals(testPlugin.getPluginId(), "net.shibboleth.idp.plugin.TestPlugIn");
+
+ final List<URL> urls = testPlugin.getUpdateURLs();
+ Assert.assertEquals(urls.size(), 2);
+ Assert.assertEquals(urls.get(0).toString(), "https://www.example.org/plugin");
+ Assert.assertEquals(urls.get(1).toString(), "https://backup.example.org/plugin");
+
+ final IdPModule test = new TestModule();
+ Assert.assertEquals(testPlugin.getEnableOnInstall(), Collections.singleton(test));
+ Assert.assertEquals(testPlugin.getDisableOnRemoval(), Collections.singleton(test));
+ }
+
+}
\ No newline at end of file
diff --git a/idp-admin-api/src/test/java/net/shibboleth/idp/plugin/TestPlugin.java b/idp-admin-api/src/test/java/net/shibboleth/idp/plugin/TestPlugin.java
new file mode 100644
index 000000000..ed1f12fe2
--- /dev/null
+++ b/idp-admin-api/src/test/java/net/shibboleth/idp/plugin/TestPlugin.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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 net.shibboleth.idp.plugin;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import net.shibboleth.idp.module.IdPModule;
+import net.shibboleth.idp.module.ModuleException;
+import net.shibboleth.idp.module.TestModule;
+
+/**
+ * Test plugin for unit test.
+ */
+public class TestPlugin extends PropertyDrivenIdPPlugin {
+
+ /**
+ * Constructor.
+ *
+ * @throws IOException on error
+ * @throws PluginException on error
+ */
+ public TestPlugin() throws IOException, PluginException {
+ super(TestPlugin.class);
+
+ try {
+ final IdPModule module = new TestModule();
+ setEnableOnInstall(Collections.singleton(module));
+ setDisableOnRemoval(Collections.singleton(module));
+ } catch (final IOException | ModuleException e) {
+ throw new PluginException(e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/idp-admin-api/src/test/resources/META-INF/services/net.shibboleth.idp.plugin.IdPPlugin b/idp-admin-api/src/test/resources/META-INF/services/net.shibboleth.idp.plugin.IdPPlugin
new file mode 100644
index 000000000..abc52d47f
--- /dev/null
+++ b/idp-admin-api/src/test/resources/META-INF/services/net.shibboleth.idp.plugin.IdPPlugin
@@ -0,0 +1 @@
+net.shibboleth.idp.plugin.TestPlugin
diff --git a/idp-admin-api/src/test/resources/net/shibboleth/idp/plugin/plugin.properties b/idp-admin-api/src/test/resources/net/shibboleth/idp/plugin/plugin.properties
new file mode 100644
index 000000000..510e32ae7
--- /dev/null
+++ b/idp-admin-api/src/test/resources/net/shibboleth/idp/plugin/plugin.properties
@@ -0,0 +1,7 @@
+# Unit test plugin
+
+plugin.version = 1.2.3
+plugin.id = net.shibboleth.idp.plugin.TestPlugIn
+plugin.url.1 = https://www.example.org/plugin
+plugin.url.2 = https://backup.example.org/plugin
+plugin.modules.required = foo,bar
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list