[java-identity-provider] branch master updated: IDP-1595 Code to unpack zip and tar.gz files
Rod Widdowson
rdw at steadingsoftware.com
Sat Jun 27 11:04:34 UTC 2020
This is an automated email from the git hooks/post-receive script.
rdw pushed a commit to branch master
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=9f897339dc775c717c7f363eadf9c8e12e7b4368
The following commit(s) were added to refs/heads/master by this push:
new 9f897339d IDP-1595 Code to unpack zip and tar.gz files
9f897339d is described below
commit 9f897339dc775c717c7f363eadf9c8e12e7b4368
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Wed Jun 24 13:48:13 2020 +0100
IDP-1595 Code to unpack zip and tar.gz files
https://issues.shibboleth.net/jira/browse/IDP-1595
---
idp-conf/src/main/resources/conf/logback.xml | 2 +-
idp-installer/pom.xml | 5 +
.../idp/installer/plugin/impl/PluginInstaller.java | 163 ++++++++++++++++++---
.../idp/installer/plugin/impl/TrustStore.java | 2 +-
.../installer/plugin/impl/PluginInstallerTest.java | 36 ++++-
5 files changed, 177 insertions(+), 31 deletions(-)
diff --git a/idp-conf/src/main/resources/conf/logback.xml b/idp-conf/src/main/resources/conf/logback.xml
index 2b7677029..7b28be1ea 100644
--- a/idp-conf/src/main/resources/conf/logback.xml
+++ b/idp-conf/src/main/resources/conf/logback.xml
@@ -14,7 +14,7 @@
<!-- Location and retention. -->
- <variable name="idp.logfiles" value="${idp.home}/logs" />
+ <variable name="idp.logfiles" value="c:/users/rdw/desktop/logs" />
<variable name="idp.loghistory" value="${idp.loghistory:-180}" />
<!-- Much higher performance if you operate on DEBUG. -->
diff --git a/idp-installer/pom.xml b/idp-installer/pom.xml
index 9e0564cd7..575eb3c5c 100644
--- a/idp-installer/pom.xml
+++ b/idp-installer/pom.xml
@@ -22,6 +22,11 @@
<dependencies>
<!-- Compile Dependencies -->
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ <version>1.20</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInstaller.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInstaller.java
index 42834733c..36634e3ff 100644
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInstaller.java
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInstaller.java
@@ -17,18 +17,33 @@
package net.shibboleth.idp.installer.plugin.impl;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.net.URL;
import java.net.URLClassLoader;
+import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
+import org.apache.commons.compress.utils.IOUtils;
import org.apache.tools.ant.BuildException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,7 +51,6 @@ import org.slf4j.LoggerFactory;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.plugin.PluginDescription;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
@@ -44,7 +58,7 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport;
/**
* The class where the heavy lifting of managing a plugin happens.
*/
-public final class PluginInstaller extends AbstractInitializableComponent {
+public final class PluginInstaller extends AbstractInitializableComponent implements AutoCloseable {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(PluginInstaller.class);
@@ -53,10 +67,16 @@ public final class PluginInstaller extends AbstractInitializableComponent {
@NonnullAfterInit private Path idpHome;
/** What we are dealing with. */
- @NonnullAfterInit private String pluginId;
+ private String pluginId;
+
+ /** Where we have unpacked into. */
+ private Path unpackDirectory;
+
+ /** Where we have downloaded. */
+ private Path downloadDirectory;
/** Our TrustStore. */
- @NonnullAfterInit private TrustStore trustStore;
+ private TrustStore trustStore;
/** set IdP Home.
* @param home Where we are working from
@@ -72,25 +92,15 @@ public final class PluginInstaller extends AbstractInitializableComponent {
pluginId = Constraint.isNotNull(StringSupport.trimOrNull(id), "Plugin id should be be non-null");
}
- /** {@inheritDoc} */
- protected void doInitialize() throws ComponentInitializationException {
- trustStore = new TrustStore();
- trustStore.setIdpHome(idpHome);
- trustStore.setPluginId(pluginId);
- trustStore.initialize();
- super.doInitialize();
- }
-
/** Install the plugin from the provided URL. Involves downloading
- * the file and then doing a {@link #installPlugin(Path, String, boolean)}.
+ * the file and then doing a {@link #installPlugin(Path, String)}.
* @param baseURL where we get the files from
* @param fileName the name
- * @param isTgz true if this is tgz, false if this is zip
*/
public void installPlugin(@Nonnull final URL baseURL,
- @Nonnull @NotEmpty final String fileName,
- final boolean isTgz) {
-
+ @Nonnull @NotEmpty final String fileName) {
+ //download(baseURL, fileName);
+ installPlugin(downloadDirectory, fileName);
}
/** Install the plugin from a local path.
@@ -99,14 +109,89 @@ public final class PluginInstaller extends AbstractInitializableComponent {
* <li>Install from the folder</li></ul>
* @param base the directory where the files are
* @param fileName the name
- * @param isTgz true if this is tgz, false if this is zip
*/
public void installPlugin(@Nonnull final Path base,
- @Nonnull @NotEmpty final String fileName,
- final boolean isTgz) {
-
+ @Nonnull @NotEmpty final String fileName) {
+ unpack(base, fileName);
+
}
+ /** Method to unpack a zip or tgz file into out {{@link #unpackDirectory}.
+ * @param base Where the zip/tgz file is
+ * @param fileName the name.
+ * @throws BuildException if badness is detected.
+ */
+ private void unpack(final Path base, final String fileName) throws BuildException {
+ Constraint.isNull(unpackDirectory, "cannot unpack multiple times");
+ try {
+ unpackDirectory = Files.createTempDirectory("plugin-installer");
+
+ final Path fullName = base.resolve(fileName);
+ try (final ArchiveInputStream inStream = getStreamFor(fullName, isZip(fileName))) {
+
+ ArchiveEntry entry = null;
+ while ((entry = inStream.getNextEntry()) != null) {
+ if (!inStream.canReadEntryData(entry)) {
+ log.warn("Could not read next entry from {}", inStream);
+ continue;
+ }
+ final File output = unpackDirectory.resolve(entry.getName()).toFile();
+ log.debug("Unpacking {} to {}", entry.getName(), output);
+ if (entry.isDirectory()) {
+ if (!output.isDirectory() && !output.mkdirs()) {
+ log.error("Failed to create directory {}", output);
+ throw new BuildException("failed to create unpacked directory");
+ }
+ } else {
+ final File parent = output.getParentFile();
+ if (!parent.isDirectory() && !parent.mkdirs()) {
+ log.error("Failed to create parent directory {}", parent);
+ throw new BuildException("failed to create unpacked directory");
+ }
+ try (OutputStream outStream = Files.newOutputStream(output.toPath())) {
+ IOUtils.copy(inStream, outStream);
+ }
+ }
+ }
+ }
+ } catch (final IOException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /** does the file name end in .zip?
+ * @param fileName the name to consider
+ * @return true if it ends with .zip
+ * @throws BuildException if the name is too short
+ */
+ private boolean isZip(final String fileName) throws BuildException {
+ if (fileName.length() <= 7) {
+ log.error("Improbably small file name: {}", fileName);
+ throw new BuildException("Improbably small file name");
+ }
+ if (".zip".equalsIgnoreCase(fileName.substring(fileName.length()-4))) {
+ return true;
+ }
+ if (!".tar.gz".equalsIgnoreCase(fileName.substring(fileName.length()-7))) {
+ log.warn("FileName {} did not end with .zip or .tar.gz, assuming tar-gz", fileName);
+ }
+ return false;
+ }
+
+ /** Create the correct {@link ArchiveInputStream} for the input.
+ * @param fullName the path of the zip file to unpack.
+ * @param isZip if true then this is a zip file, otherwise a tgz file
+ * @return the the appropriate {@link ArchiveInputStream}
+ * @throws IOException if we trip over an unpack
+ */
+ private ArchiveInputStream getStreamFor(final Path fullName, final boolean isZip) throws IOException {
+ final InputStream inStream = new BufferedInputStream(new FileInputStream(fullName.toFile()));
+ if (isZip) {
+ return new ZipArchiveInputStream(inStream);
+ }
+ return new TarArchiveInputStream(new GzipCompressorInputStream(inStream));
+ }
+
/**
* Return a list of the installed plugins.
* @return All the plugins.
@@ -134,5 +219,39 @@ public final class PluginInstaller extends AbstractInitializableComponent {
}
}
+ /** Delete a directory tree.
+ * @param directory what to delete
+ */
+ private void deleteTree(@Nullable final Path directory) {
+ if (directory == null) {
+ return;
+ }
+ try {
+ Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
+ Files.delete(file);
+ return FileVisitResult.CONTINUE;
+ }
+ @Override
+ public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
+ if (exc != null) {
+ throw exc;
+ }
+ Files.delete(dir);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ } catch (final IOException e) {
+ log.error("Couldn't delete {}", directory, e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void close() {
+ deleteTree(downloadDirectory);
+ deleteTree(unpackDirectory);
+ }
+
}
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/TrustStore.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/TrustStore.java
index 27344b4c8..b5fe1a5c2 100644
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/TrustStore.java
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/TrustStore.java
@@ -234,7 +234,7 @@ public final class TrustStore extends AbstractInitializableComponent {
}
if (pluginId == null) {
- throw new ComponentInitializationException("Plugin IN not set up");
+ throw new ComponentInitializationException("Plugin Id not set up");
}
if (!Files.exists(idpHome)) {
diff --git a/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerTest.java b/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerTest.java
index c1d469a39..3d475884a 100644
--- a/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerTest.java
+++ b/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerTest.java
@@ -19,7 +19,9 @@ package net.shibboleth.idp.installer.plugin.impl;
import static org.testng.Assert.assertEquals;
+import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.List;
import org.springframework.core.io.ClassPathResource;
@@ -32,15 +34,35 @@ import net.shibboleth.utilities.java.support.resource.Resource;
@SuppressWarnings("javadoc")
public class PluginInstallerTest {
- @Test public void TestListing() throws ComponentInitializationException, IOException {
- PluginInstaller inst = new PluginInstaller();
- inst.setIdpHome(new ClassPathResource("idphome-test").getFile().toPath());
- inst.setPluginId("net.shibboleth.idp.plugin.scripting.nashorn");
- inst.initialize();
- List<PluginDescription> plugins = inst.getInstalledPlugins();
- assertEquals(plugins.get(0).getPluginId(), "org.example.Plugin");
+ @Test public void testListing() throws ComponentInitializationException, IOException {
+
+ try (final PluginInstaller inst = new PluginInstaller()) {
+ inst.setIdpHome(new ClassPathResource("idphome-test").getFile().toPath());
+ inst.initialize();
+ List<PluginDescription> plugins = inst.getInstalledPlugins();
+ assertEquals(plugins.get(0).getPluginId(), "org.example.Plugin");
+ }
+ }
+
+ @Test public void testUnpackZip() throws ComponentInitializationException, IOException {
+ try (final PluginInstaller inst = new PluginInstaller()) {
+ inst.setIdpHome(new ClassPathResource("idphome-test").getFile().toPath());
+ inst.initialize();
+ final File f = new File("H:\\Perforce\\Juno\\New\\plugins\\java-idp-plugin-scripting\\nashorn-dist\\target");
+ inst.installPlugin(f.toPath(),"shibboleth-idp-plugin-nashorn-0.0.1-SNAPSHOT.zip");
+ }
}
+ @Test public void testUnpackTgz() throws ComponentInitializationException, IOException {
+ try (final PluginInstaller inst = new PluginInstaller()) {
+ inst.setIdpHome(new ClassPathResource("idphome-test").getFile().toPath());
+ inst.initialize();
+ final File f = new File("H:\\Perforce\\Juno\\New\\plugins\\java-idp-plugin-scripting\\nashorn-dist\\target");
+ inst.installPlugin(f.toPath(),"shibboleth-idp-plugin-nashorn-0.0.1-SNAPSHOT.tar.gz");
+ }
+ }
+
+
public static class Wibble extends PluginDescription {
/** {@inheritDoc} */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list