[java-identity-provider] branch main updated: IDP-2073 Consider enabling the installer to download new versions

Rod Widdowson rdw at steadingsoftware.com
Mon Jun 12 13:04:55 UTC 2023


This is an automated email from the git hooks/post-receive script.

rdw 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=483d73013e6ba40e7d766fbf8e53aeb9ce86884b

The following commit(s) were added to refs/heads/main by this push:
     new 483d73013 IDP-2073 Consider enabling the installer to download new versions
483d73013 is described below

commit 483d73013e6ba40e7d766fbf8e53aeb9ce86884b
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Mon Jun 12 13:51:40 2023 +0100

    IDP-2073 Consider enabling the installer to download new versions
    
    https://shibboleth.atlassian.net/browse/IDP-2073
    
    Introduce a bean and associated wiring to reach out and check the update status
    at idp startup.
---
 .../net/shibboleth/idp/admin/impl/IdPInfo.java     |  57 +++++++
 .../idp/admin/impl/ReportUpdateStatus.java         | 165 +++++++++++++++++++++
 .../net/shibboleth/idp/conf/admin-system.xml       |  16 +-
 .../net/shibboleth/idp/module/conf/idp.properties  |   3 +
 idp-installer/pom.xml                              |   7 +
 .../idp/installer/impl/UpdateIdPCLI.java           |  36 +----
 6 files changed, 250 insertions(+), 34 deletions(-)

diff --git a/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/IdPInfo.java b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/IdPInfo.java
new file mode 100644
index 000000000..f2ba9fb01
--- /dev/null
+++ b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/IdPInfo.java
@@ -0,0 +1,57 @@
+/*
+ * 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.admin.impl;
+
+import java.util.Properties;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.profile.installablecomponent.InstallableComponentInfo;
+import net.shibboleth.profile.installablecomponent.InstallableComponentVersion;
+
+/** Implementation of {@link InstallableComponentInfo} for an IdP Version.  This is keyed in
+ * to the format of the idp-versions.properties file (which doesn't specify max and min "supported IdP versions". */
+public final class IdPInfo extends InstallableComponentInfo {
+
+    /** The "plugin Id" to look up idp versions with. */
+    @Nonnull public static String IDP_PLUGIN_ID = "net.shibboleth.idp";
+
+     /**
+      * Constructor.
+      * @param props The property file to populate from
+      */
+     public IdPInfo(@Nonnull Properties props) {
+         super(IDP_PLUGIN_ID, props);
+     }
+
+     /** {@inheritDoc} */
+     @Override
+     protected InstallableComponentVersion getMaxVersion(@Nonnull Properties props, @Nonnull String version) {
+         // The maximum version that version "us" can be installed in is "us" (a re-intall).
+         return new InstallableComponentVersion(version);
+     }
+
+     /** {@inheritDoc} */
+     @Override
+     @Nullable
+     protected InstallableComponentVersion getMinVersion(@Nonnull Properties props, @Nonnull String version) {
+         // We can always be on anything from V4.0.0
+         return new InstallableComponentVersion(4,0,0);
+     }
+}
diff --git a/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/ReportUpdateStatus.java b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/ReportUpdateStatus.java
new file mode 100644
index 000000000..5615b5cc5
--- /dev/null
+++ b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/ReportUpdateStatus.java
@@ -0,0 +1,165 @@
+/*
+ * 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.admin.impl;
+
+import java.net.URL;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.hc.client5.http.classic.HttpClient;
+import org.opensaml.security.httpclient.HttpClientSecurityParameters;
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.Version;
+import net.shibboleth.profile.installablecomponent.InstallableComponentInfo;
+import net.shibboleth.profile.installablecomponent.InstallableComponentInfo.VersionInfo;
+import net.shibboleth.profile.installablecomponent.InstallableComponentSupport;
+import net.shibboleth.profile.installablecomponent.InstallableComponentSupport.SupportLevel;
+import net.shibboleth.profile.installablecomponent.InstallableComponentVersion;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * A class to reach out and find out whether we are up to date.
+ */
+public class ReportUpdateStatus  extends AbstractIdentifiableInitializableComponent implements Runnable {
+
+    /** Logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ReportUpdateStatus.class);
+
+    /** Where to look for update information. */
+    @Nonnull private List<URL> updateUrls = CollectionSupport.emptyList(); 
+
+    /** Are we to run? */
+    private boolean enabled;
+
+    /** How to reach out. */
+    @NonnullAfterInit private HttpClient httpClient;
+
+    /** any security parameters needed. */
+    @Nullable private HttpClientSecurityParameters securityParams;
+
+    /** Set where to look.
+     * @param urls what to set.
+     */
+    public void setUpdateUrls(@Nullable final List<URL> urls) {
+        if (urls == null || urls.isEmpty()) {
+            log.error("Emopty URL update listr specified");
+        } else {
+            updateUrls = urls;
+        }
+    }
+
+    /** Set any {@link HttpClientSecurityParameters}.
+     * @param params what to set.
+     */
+    public void setSecurityParams(@Nullable final HttpClientSecurityParameters params) {
+        securityParams = params;
+    }
+
+    /** Set the {@link HttpClient} to use.
+     * @param client what to set.
+     */
+    public void setHttpClient(@Nonnull final HttpClient client) {
+        httpClient = Constraint.isNotNull(client, "HttpClient cannot be null");
+    }
+
+    /** Are we going to do anything?
+     * @param on are we enabled
+     */
+    public void setEnabled(final boolean on) {
+        enabled = on;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        if (!enabled) {
+            return;
+        }
+        if (httpClient == null) {
+            log.error("Http Client was not set");
+            throw new ComponentInitializationException("Http Client was not set");
+        }
+        if (updateUrls.isEmpty()) {
+            log.error("No Update Urls set");
+            throw new ComponentInitializationException("No Update Urls set");
+        }
+        
+        final ExecutorService svc =  Executors.newSingleThreadExecutor();
+        svc.execute(this);
+        svc.shutdown();
+    }
+
+    /** {@inheritDoc} 
+     * Do the lookup, but in a different thread so as to not slow down startup.
+     */
+    @Override
+    public void run() {
+        try {
+            String versionStr = Version.getVersion();
+            if (versionStr == null) {
+                log.error("Could not find Current IdP Version");
+                return;
+            }
+            @Nonnull final InstallableComponentVersion version = new InstallableComponentVersion(versionStr); 
+            assert httpClient!=null;
+            final Properties properties = InstallableComponentSupport.loadInfo(updateUrls, httpClient, securityParams);
+            if (properties == null) {
+                log.error("Could not located Idp update information");
+                return;
+            }
+            final InstallableComponentInfo info = new IdPInfo(properties);
+        
+            final InstallableComponentVersion newIdPVersion = InstallableComponentSupport.getBestVersion(version, version, info);
+            if (newIdPVersion == null) {
+                log.info("No Upgrade available from {}", version);
+            } else {
+                log.warn("Version {} can be upgraded to {}", version, newIdPVersion);
+            }
+            final VersionInfo verInfo = info.getAvailableVersions().get(version);
+            if (verInfo == null) {
+                log.warn("Could not locate version info for version {}", version);
+            } else {
+               final SupportLevel sl = verInfo.getSupportLevel();
+               switch (sl) {
+                   case Current:
+                       log.debug("Version {} is current");
+                       break;
+                   case Secadv:
+                       log.error("Version {} has secuorty alerts again it.", version);
+                       break;
+                   default:
+                       log.warn("Support level for {} is {}", version, sl);
+                       break;
+               }
+            }
+        } catch (final Throwable t) {
+            log.error("Check for update status failed unexpectedly", t);
+        }
+    }
+}
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml
index 501a2b6e6..e6342106b 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml
@@ -320,5 +320,19 @@
         class="net.shibboleth.shared.service.ReloadableServiceGaugeSet" lazy-init="true"
         c:metricName="net.shibboleth.idp.managedbean"
         p:service-ref="shibboleth.ManagedBeanService" />
-        
+
+    <util:list id="shibboleth.IdPUpdateCheckUrls">
+        <value>https://shibboleth.net/downloads/identity-provider/plugins/idp-versions.properties</value>
+        <value>http://plugins.shibboleth.net/idp-versions.properties</value>
+    </util:list>
+
+    <bean id="shibboleth.UpdateStatus"
+       class="net.shibboleth.idp.admin.impl.ReportUpdateStatus"
+       lazy-init="false"
+       depends-on="shibboleth.LoggingService"
+       p:updateUrls-ref="%{idp.updateCheck.urls:shibboleth.IdPUpdateCheckUrls}"
+       p:enabled="%{idp.updateCheck.enabled:true}"
+       p:httpClient-ref="%{idp.updateCheck.httpClient:shibboleth.InternalHttpClient}"
+       p:securityParams="#{ environment.containsProperty('idp.updateCheck.httpSecurityParameters') ? getObject('idp.updateCheck.httpSecurityParameters') :null}"/>
+
 </beans>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/idp.properties b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/idp.properties
index 1e37c9b71..3e2af2ba3 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/idp.properties
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/idp.properties
@@ -253,3 +253,6 @@ idp.ui.fallbackLanguages=en,fr,de
 
 # Set false if you want SAML bindings "spelled out" in audit log
 idp.audit.shortenBindings = true
+
+# Set false if you do not want the IdP to check (asynchronously) whether it can be updated when the container starts
+#idp.updateCheck.enable=true
diff --git a/idp-installer/pom.xml b/idp-installer/pom.xml
index 602985e87..c5f63eb21 100644
--- a/idp-installer/pom.xml
+++ b/idp-installer/pom.xml
@@ -51,6 +51,13 @@
             <scope>provided</scope>
         </dependency>
 
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>idp-admin-impl</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
         <dependency>
             <groupId>net.shibboleth</groupId>
             <artifactId>shib-metadata-api</artifactId>
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/UpdateIdPCLI.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/UpdateIdPCLI.java
index 517a615f4..32066d28b 100644
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/UpdateIdPCLI.java
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/UpdateIdPCLI.java
@@ -43,6 +43,7 @@ import org.springframework.core.io.ClassPathResource;
 import org.springframework.core.io.Resource;
 
 import net.shibboleth.idp.Version;
+import net.shibboleth.idp.admin.impl.IdPInfo;
 import net.shibboleth.idp.cli.AbstractIdPHomeAwareCommandLine;
 import net.shibboleth.idp.installer.InstallerSupport;
 import net.shibboleth.idp.installer.impl.UpdateIdPArguments.OperationType;
@@ -62,9 +63,6 @@ import net.shibboleth.shared.spring.httpclient.resource.HTTPResource;
  */
 public class UpdateIdPCLI extends AbstractIdPHomeAwareCommandLine<UpdateIdPArguments> {
 
-    /** The "plugin Id" to look up idp versions with. */
-    @Nonnull public static String IDP_PLUGIN_ID = "net.shibboleth.idp";
-
     /** The place we publish our keys. */
     @Nonnull public static String SHIBBOLETH_SIGNING_KEYS = "http://shibboleth.net/downloads/PGP_KEYS";
 
@@ -273,7 +271,7 @@ public class UpdateIdPCLI extends AbstractIdPHomeAwareCommandLine<UpdateIdPArgum
             assert idpHome != null;
             trust.setIdpHome(idpHome);
             trust.setTrustStore(args.getTruststore());
-            trust.setPluginId(IDP_PLUGIN_ID);
+            trust.setPluginId(IdPInfo.IDP_PLUGIN_ID);
             trust.initialize();
             final Signature sig = TrustStore.signatureOf(sigStream);
             if (!trust.contains(sig)) {
@@ -306,7 +304,7 @@ public class UpdateIdPCLI extends AbstractIdPHomeAwareCommandLine<UpdateIdPArgum
             }
 
         } catch (final ComponentInitializationException | IOException e) {
-            getLogger().error("Could not manage truststore for [{}, {}] ", args.getIdPHome(), IDP_PLUGIN_ID, e);
+            getLogger().error("Could not manage truststore for [{}, {}] ", args.getIdPHome(), IdPInfo.IDP_PLUGIN_ID, e);
             return RC_IO;
         }
         return RC_OK;
@@ -335,32 +333,4 @@ public class UpdateIdPCLI extends AbstractIdPHomeAwareCommandLine<UpdateIdPArgum
        System.exit(runMain(args));
    }
 
-   /** Local implementaion of {@link InstallableComponentInfo} for an IdP Version. */
-   private static class IdPInfo extends InstallableComponentInfo {
-
-    /**
-     * Constructor.
-     * @param props The property file to populate from
-     */
-    public IdPInfo(@Nonnull Properties props) {
-        super(IDP_PLUGIN_ID, props);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    @Nullable
-    protected InstallableComponentVersion getMaxVersion(@Nonnull Properties props, @Nonnull String version) {
-        // The maximum version that version "us" can be installed in is "us" (a re-intall).
-        return new InstallableComponentVersion(version);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    @Nullable
-    protected InstallableComponentVersion getMinVersion(@Nonnull Properties props, @Nonnull String version) {
-        // We can always be on anything from V4.0.0
-        return new InstallableComponentVersion(4,0,0);
-    }
-       
-   }
 }

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list