Skip to content

Commit

Permalink
[FIXED JENKINS-34881] - Handle pre-configured security settings for n…
Browse files Browse the repository at this point in the history
…ew installs (#2364)

* [FIXED JENKINS-34881] - handle non-default security settings for new installs

* Ensure permissions

* Initial security authentication token should still follow redirects
  • Loading branch information
kzantow authored and oleg-nenashev committed Jun 2, 2016
1 parent 61be0cd commit 723dfca
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 36 deletions.
11 changes: 10 additions & 1 deletion core/src/main/java/hudson/PluginManager.java
Expand Up @@ -40,6 +40,7 @@
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;
Expand All @@ -61,6 +62,8 @@

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;
Expand Down Expand Up @@ -1319,6 +1322,7 @@ private List<Future<UpdateCenter.UpdateCenterJob>> install(@Nonnull Collection<S
private void trackInitialPluginInstall(@Nonnull final List<Future<UpdateCenter.UpdateCenterJob>> 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);
Expand Down Expand Up @@ -1348,7 +1352,12 @@ public void run() {
}
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();
Expand Down
11 changes: 10 additions & 1 deletion core/src/main/java/jenkins/install/InstallState.java
Expand Up @@ -75,7 +75,16 @@ public void initializeState() {
* 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
Expand Down
31 changes: 1 addition & 30 deletions core/src/main/java/jenkins/install/InstallUtil.java
Expand Up @@ -50,11 +50,6 @@
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;
Expand Down Expand Up @@ -193,7 +188,7 @@ private static InstallState getDefaultInstallState() {
// 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;
}

Expand All @@ -213,30 +208,6 @@ private static InstallState getDefaultInstallState() {
}
}

/**
* 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.
* <p>
Expand Down
39 changes: 35 additions & 4 deletions core/src/main/java/jenkins/install/SetupWizard.java
Expand Up @@ -18,10 +18,12 @@
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;
Expand Down Expand Up @@ -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);
}
Expand All @@ -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
*/
Expand Down Expand Up @@ -456,6 +486,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
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/";
Expand Down
Expand Up @@ -3,6 +3,7 @@
<l:main-panel>
<st:include page="client-scripts" />
<form action="${app.instance.securityRealm.authenticationGatewayUrl}" method="POST">
<input type="hidden" name="from" value="${request.getParameter('from')}" />
<div class="plugin-setup-wizard bootstrap-3">
<div class="modal fade in" style="display: block;">
<div class="modal-dialog">
Expand Down

0 comments on commit 723dfca

Please sign in to comment.