From 723dfca37bcf3fecd33c75eaca01ce0d07014d70 Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Thu, 2 Jun 2016 13:53:43 -0400 Subject: [PATCH] [FIXED JENKINS-34881] - Handle pre-configured security settings for new installs (#2364) * [FIXED JENKINS-34881] - handle non-default security settings for new installs * Ensure permissions * Initial security authentication token should still follow redirects --- core/src/main/java/hudson/PluginManager.java | 11 +++++- .../java/jenkins/install/InstallState.java | 11 +++++- .../java/jenkins/install/InstallUtil.java | 31 +-------------- .../java/jenkins/install/SetupWizard.java | 39 +++++++++++++++++-- .../authenticate-security-token.jelly | 1 + 5 files changed, 57 insertions(+), 36 deletions(-) diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index 03b5a8383e..1ee23f30dd 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -40,6 +40,7 @@ import hudson.model.UpdateCenter; import hudson.model.UpdateSite; import hudson.model.UpdateCenter.DownloadJob; import hudson.model.UpdateCenter.InstallationJob; +import hudson.security.ACL; import hudson.security.Permission; import hudson.security.PermissionScope; import hudson.util.CyclicGraphDetector; @@ -61,6 +62,8 @@ import jenkins.util.xml.RestrictiveEntityResolver; import net.sf.json.JSONArray; import net.sf.json.JSONObject; + +import org.acegisecurity.Authentication; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; @@ -1319,6 +1322,7 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas private void trackInitialPluginInstall(@Nonnull final List> installJobs) { final Jenkins jenkins = Jenkins.getInstance(); final UpdateCenter updateCenter = jenkins.getUpdateCenter(); + final Authentication currentAuth = Jenkins.getAuthentication(); if (!Jenkins.getInstance().getInstallState().isSetupComplete()) { jenkins.setInstallState(InstallState.INITIAL_PLUGINS_INSTALLING); @@ -1348,7 +1352,12 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas } updateCenter.persistInstallStatus(); if(!failures) { - InstallUtil.proceedToNextStateFrom(InstallState.INITIAL_PLUGINS_INSTALLING); + ACL.impersonate(currentAuth, new Runnable() { + @Override + public void run() { + InstallUtil.proceedToNextStateFrom(InstallState.INITIAL_PLUGINS_INSTALLING); + } + }); } } }.start(); diff --git a/core/src/main/java/jenkins/install/InstallState.java b/core/src/main/java/jenkins/install/InstallState.java index 27da766c28..7226c27df8 100644 --- a/core/src/main/java/jenkins/install/InstallState.java +++ b/core/src/main/java/jenkins/install/InstallState.java @@ -75,7 +75,16 @@ public class InstallState implements ExtensionPoint { * Creating an admin user for an initial Jenkins install. */ @Extension - public static final InstallState CREATE_ADMIN_USER = new InstallState("CREATE_ADMIN_USER", false); + public static final InstallState CREATE_ADMIN_USER = new InstallState("CREATE_ADMIN_USER", false) { + public void initializeState() { + Jenkins j = Jenkins.getInstance(); + // Skip this state if not using the security defaults + // e.g. in an init script set up security already + if (!j.getSetupWizard().isUsingSecurityDefaults()) { + InstallUtil.proceedToNextStateFrom(this); + } + } + }; /** * New Jenkins install. The user has kicked off the process of installing an diff --git a/core/src/main/java/jenkins/install/InstallUtil.java b/core/src/main/java/jenkins/install/InstallUtil.java index d611ba0b41..4914bfbf4b 100644 --- a/core/src/main/java/jenkins/install/InstallUtil.java +++ b/core/src/main/java/jenkins/install/InstallUtil.java @@ -50,11 +50,6 @@ import hudson.Functions; import hudson.Main; 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.security.csrf.DefaultCrumbIssuer; import hudson.model.UpdateCenter.InstallationJob; import hudson.model.UpdateCenter.UpdateCenterJob; import hudson.util.VersionNumber; @@ -193,7 +188,7 @@ 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 (!j.getItemMap().isEmpty() || !mayBeJenkins2SecurityDefaults(j) || !j.getNodes().isEmpty()) { + if (!j.getItemMap().isEmpty() || !j.getNodes().isEmpty()) { return InstallState.UPGRADE; } @@ -213,30 +208,6 @@ 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) { - // may be called before security set up first - if(j.getSecurityRealm() == SecurityRealm.NO_AUTHENTICATION && !(j.getCrumbIssuer() instanceof DefaultCrumbIssuer)) { - 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 6af23d6dff..0cf0735e5d 100644 --- a/core/src/main/java/jenkins/install/SetupWizard.java +++ b/core/src/main/java/jenkins/install/SetupWizard.java @@ -18,10 +18,12 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; +import org.acegisecurity.userdetails.UsernameNotFoundException; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.HttpResponse; @@ -155,7 +157,9 @@ public class SetupWizard extends PageDecorator { try { PluginServletFilter.addFilter(FORCE_SETUP_WIZARD_FILTER); - isUsingSecurityToken = true; + // if we're not using security defaults, we should not show the security token screen + // users will likely be sent to a login screen instead + isUsingSecurityToken = isUsingSecurityDefaults(); } catch (ServletException e) { throw new RuntimeException("Unable to add PluginServletFilter for the SetupWizard", e); } @@ -174,15 +178,41 @@ public class SetupWizard extends PageDecorator { */ public boolean isUsingSecurityToken() { try { - return isUsingSecurityToken // only ever show this if using the security token + return isUsingSecurityToken // only ever show the unlock page if using the security token && !Jenkins.getInstance().getInstallState().isSetupComplete() - && getInitialAdminPasswordFile().exists(); + && isUsingSecurityDefaults(); } catch (Exception e) { // ignore } return false; } - + + /** + * Determines if the security settings seem to match the defaults. Here, we only + * really care about and test for HudsonPrivateSecurityRealm and the user setup. + * Other settings are irrelevant. + */ + /*package*/ boolean isUsingSecurityDefaults() { + Jenkins j = Jenkins.getInstance(); + if (j.getSecurityRealm() instanceof HudsonPrivateSecurityRealm) { + HudsonPrivateSecurityRealm securityRealm = (HudsonPrivateSecurityRealm)j.getSecurityRealm(); + try { + if(securityRealm.getAllUsers().size() == 1) { + HudsonPrivateSecurityRealm.Details details = securityRealm.loadUserByUsername(SetupWizard.initialSetupAdminUserName); + FilePath iapf = getInitialAdminPasswordFile(); + if (iapf.exists()) { + if (details.isPasswordCorrect(iapf.readToString().trim())) { + return true; + } + } + } + } catch(UsernameNotFoundException | IOException | InterruptedException e) { + return false; // Not initial security setup if no transitional admin user / password found + } + } + return false; + } + /** * Called during the initial setup to create an admin user */ @@ -456,6 +486,7 @@ public class SetupWizard extends PageDecorator { if (request instanceof HttpServletRequest) { HttpServletRequest req = (HttpServletRequest)request; if((req.getContextPath() + "/").equals(req.getRequestURI())) { + Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); chain.doFilter(new HttpServletRequestWrapper(req) { public String getRequestURI() { return getContextPath() + "/setupWizard/"; diff --git a/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token.jelly b/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token.jelly index d2c5ea7263..02a02dc408 100644 --- a/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token.jelly +++ b/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token.jelly @@ -3,6 +3,7 @@

+