diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index 8b320a088d..906f44fd7a 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -1194,7 +1194,6 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas } updateCenter.persistInstallStatus(); jenkins.setInstallState(InstallState.INITIAL_PLUGINS_INSTALLING.getNextState()); - InstallUtil.saveLastExecVersion(); } }.start(); } diff --git a/core/src/main/java/hudson/model/UpdateCenter.java b/core/src/main/java/hudson/model/UpdateCenter.java index 5cdf66cad7..ceddcb0b20 100644 --- a/core/src/main/java/hudson/model/UpdateCenter.java +++ b/core/src/main/java/hudson/model/UpdateCenter.java @@ -53,7 +53,6 @@ import hudson.util.IOUtils; import hudson.util.PersistedList; import hudson.util.XStream2; import jenkins.RestartRequiredException; -import jenkins.install.InstallState; import jenkins.install.InstallUtil; import jenkins.model.Jenkins; import jenkins.util.io.OnMaster; @@ -1913,18 +1912,14 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas @Initializer(after=PLUGINS_STARTED, fatal=false) public static void init(Jenkins h) throws IOException { h.getUpdateCenter().load(); - if (Jenkins.getActiveInstance().getInstallState() == InstallState.NEW) { - LOGGER.log(INFO, "This is a new Jenkins instance. The Plugin Install Wizard will be launched."); - // Force update of the default site file (updates/default.json). - updateDefaultSite(); - } } - private static void updateDefaultSite() { + @Restricted(NoExternalUse.class) + public static void updateDefaultSite() { try { // Need to do the following because the plugin manager will attempt to access // $JENKINS_HOME/updates/default.json. Needs to be up to date. - Jenkins.getActiveInstance().getUpdateCenter().getSite(UpdateCenter.ID_DEFAULT).updateDirectlyNow(true); + Jenkins.getInstance().getUpdateCenter().getSite(UpdateCenter.ID_DEFAULT).updateDirectlyNow(true); } catch (Exception e) { LOGGER.log(WARNING, "Upgrading Jenkins. Failed to update default UpdateSite. Plugin upgrades may fail.", e); } diff --git a/core/src/main/java/jenkins/install/InstallState.java b/core/src/main/java/jenkins/install/InstallState.java index c634180bc8..42d223815f 100644 --- a/core/src/main/java/jenkins/install/InstallState.java +++ b/core/src/main/java/jenkins/install/InstallState.java @@ -23,6 +23,8 @@ */ package jenkins.install; +import javax.annotation.CheckForNull; + import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -33,6 +35,10 @@ import org.kohsuke.accmod.restrictions.NoExternalUse; */ @Restricted(NoExternalUse.class) public enum InstallState { + /** + * Need InstallState != NEW for tests by default + */ + UNKNOWN(true, null), /** * The initial set up has been completed */ @@ -90,6 +96,7 @@ public enum InstallState { /** * Gets the next state */ + @CheckForNull public InstallState getNextState() { return nextState; } diff --git a/core/src/main/java/jenkins/install/InstallUtil.java b/core/src/main/java/jenkins/install/InstallUtil.java index 6de68ccd39..35e8cb95c6 100644 --- a/core/src/main/java/jenkins/install/InstallUtil.java +++ b/core/src/main/java/jenkins/install/InstallUtil.java @@ -45,6 +45,10 @@ import com.thoughtworks.xstream.XStream; import hudson.Functions; import hudson.model.UpdateCenter.DownloadJob.InstallationStatus; import hudson.model.UpdateCenter.DownloadJob.Installing; +import hudson.security.AuthorizationStrategy; +import hudson.security.FullControlOnceLoggedInAuthorizationStrategy; +import hudson.security.HudsonPrivateSecurityRealm; +import hudson.security.SecurityRealm; import hudson.model.UpdateCenter.InstallationJob; import hudson.model.UpdateCenter.UpdateCenterJob; import hudson.util.VersionNumber; @@ -98,7 +102,8 @@ public class InstallUtil { // Edge case: used Jenkins 1 but did not save the system config page, // the version is not persisted and returns 1.0, so try to check if // they actually did anything - if (!Jenkins.getInstance().getItemMap().isEmpty()) { + Jenkins j = Jenkins.getInstance(); + if (!j.getItemMap().isEmpty() || !mayBeJenkins2SecurityDefaults(j)) { return InstallState.UPGRADE; } return InstallState.NEW; @@ -117,6 +122,29 @@ public class InstallUtil { } } + /** + * This could be an upgrade, detect a non-default security realm for the stupid case + * where someone installed 1.x and did not save global config or create any items... + */ + private static boolean mayBeJenkins2SecurityDefaults(Jenkins j) { + if(j.getSecurityRealm() == SecurityRealm.NO_AUTHENTICATION) { // called before security set up first + return true; + } + if(j.getSecurityRealm() instanceof HudsonPrivateSecurityRealm) { // might be called after a restart, setup isn't complete + HudsonPrivateSecurityRealm securityRealm = (HudsonPrivateSecurityRealm)j.getSecurityRealm(); + if(securityRealm.getAllUsers().size() == 1 && securityRealm.getUser(SetupWizard.initialSetupAdminUserName) != null) { + AuthorizationStrategy authStrategy = j.getAuthorizationStrategy(); + if(authStrategy instanceof FullControlOnceLoggedInAuthorizationStrategy) { + // must have been using 2.0+ to set this, as it wasn't present in 1.x and the default is true, to _allow_ anon read + if(!((FullControlOnceLoggedInAuthorizationStrategy)authStrategy).isAllowAnonymousRead()) { + return true; + } + } + } + } + return false; + } + /** * Save the current Jenkins instance version as the last executed version. *
diff --git a/core/src/main/java/jenkins/install/SetupWizard.java b/core/src/main/java/jenkins/install/SetupWizard.java
index 95b78ced45..4b221f19f8 100644
--- a/core/src/main/java/jenkins/install/SetupWizard.java
+++ b/core/src/main/java/jenkins/install/SetupWizard.java
@@ -3,6 +3,7 @@ package jenkins.install;
import java.io.IOException;
import java.util.Locale;
import java.util.UUID;
+import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.Filter;
@@ -25,6 +26,7 @@ import org.kohsuke.stapler.StaplerResponse;
import hudson.BulkChange;
import hudson.FilePath;
+import hudson.model.UpdateCenter;
import hudson.model.User;
import hudson.security.FullControlOnceLoggedInAuthorizationStrategy;
import hudson.security.HudsonPrivateSecurityRealm;
@@ -55,6 +57,12 @@ public class SetupWizard {
public SetupWizard(Jenkins j) throws IOException, InterruptedException {
this.jenkins = j;
+
+ // this was determined to be a new install, don't run the update wizard here
+ UpgradeWizard uw = jenkins.getInjector().getInstance(UpgradeWizard.class);
+ if (uw!=null)
+ uw.setCurrentLevel(new VersionNumber("2.0"));
+
// Create an admin user by default with a
// difficult password
FilePath iapf = getInitialAdminPasswordFile();
@@ -96,29 +104,50 @@ public class SetupWizard {
}
}
- String setupKey = iapf.readToString().trim();
- String ls = System.lineSeparator();
- LOGGER.info(ls + ls + "*************************************************************" + ls
- + "*************************************************************" + ls
- + "*************************************************************" + ls
- + ls
- + "Jenkins initial setup is required. An admin user has been created and "
- + "a password generated." + ls
- + "Please use the following password to proceed to installation:" + ls
- + ls
- + setupKey + ls
- + ls
- + "This may also be found at: " + iapf.getRemote() + ls
- + ls
- + "*************************************************************" + ls
- + "*************************************************************" + ls
- + "*************************************************************" + ls);
+ if(iapf.exists()) {
+ String setupKey = iapf.readToString().trim();
+ String ls = System.lineSeparator();
+ LOGGER.info(ls + ls + "*************************************************************" + ls
+ + "*************************************************************" + ls
+ + "*************************************************************" + ls
+ + ls
+ + "Jenkins initial setup is required. An admin user has been created and "
+ + "a password generated." + ls
+ + "Please use the following password to proceed to installation:" + ls
+ + ls
+ + setupKey + ls
+ + ls
+ + "This may also be found at: " + iapf.getRemote() + ls
+ + ls
+ + "*************************************************************" + ls
+ + "*************************************************************" + ls
+ + "*************************************************************" + ls);
+ }
try {
PluginServletFilter.addFilter(FORCE_SETUP_WIZARD_FILTER);
} catch (ServletException e) {
throw new AssertionError(e);
}
+
+ try {
+ // Make sure plugin metadata is up to date
+ UpdateCenter.updateDefaultSite();
+ } catch (Exception e) {
+ LOGGER.log(Level.WARNING, e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Indicates a generated password should be used - e.g. this is a new install, no security realm set up
+ */
+ public boolean useGeneratedPassword() {
+ try {
+ return getInitialAdminPasswordFile().exists();
+ } catch (Exception e) {
+ // ignore
+ }
+ return false;
}
/**
@@ -143,6 +172,13 @@ public class SetupWizard {
admin = null;
}
+ // Success! Delete the temporary password file:
+ try {
+ getInitialAdminPasswordFile().delete();
+ } catch (InterruptedException e) {
+ throw new IOException(e);
+ }
+
j.setInstallState(InstallState.CREATE_ADMIN_USER.getNextState());
// ... and then login
@@ -174,10 +210,6 @@ public class SetupWizard {
// Also, clean up the setup wizard if it's completed
jenkins.setSetupWizard(null);
- UpgradeWizard uw = jenkins.getInjector().getInstance(UpgradeWizard.class);
- if (uw!=null)
- uw.setCurrentLevel(new VersionNumber("2.0"));
-
return HttpResponses.okJSON();
}
diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java
index 59dcf89383..660a229135 100644
--- a/core/src/main/java/jenkins/model/Jenkins.java
+++ b/core/src/main/java/jenkins/model/Jenkins.java
@@ -342,7 +342,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
/**
* The Jenkins instance startup type i.e. NEW, UPGRADE etc
*/
- private transient InstallState installState = InstallState.NEW;
+ private transient InstallState installState = InstallState.UNKNOWN;
/**
* If we're in the process of an initial setup,
@@ -810,11 +810,6 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
throw new IllegalStateException("second instance");
theInstance = this;
- installState = InstallUtil.getInstallState();
- if (installState == InstallState.RESTART || installState == InstallState.DOWNGRADE) {
- InstallUtil.saveLastExecVersion();
- }
-
if (!new File(root,"jobs").exists()) {
// if this is a fresh install, use more modern default layout that's consistent with agents
workspaceDir = "${JENKINS_HOME}/workspace/${ITEM_FULLNAME}";
@@ -875,6 +870,11 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
if(KILL_AFTER_LOAD)
System.exit(0);
+ installState = InstallUtil.getInstallState();
+ if (installState == InstallState.RESTART || installState == InstallState.DOWNGRADE) {
+ InstallUtil.saveLastExecVersion();
+ }
+
if(!installState.isSetupComplete()) {
// Start immediately with the setup wizard for new installs
setupWizard = new SetupWizard(this);
diff --git a/core/src/main/resources/jenkins/model/Jenkins/login.jelly b/core/src/main/resources/jenkins/model/Jenkins/login.jelly
index b3c91c7b5b..29d9192eda 100644
--- a/core/src/main/resources/jenkins/model/Jenkins/login.jelly
+++ b/core/src/main/resources/jenkins/model/Jenkins/login.jelly
@@ -24,10 +24,11 @@ THE SOFTWARE.