Skip to content

Commit

Permalink
Merge pull request #10 from ikedam/feature/JENKINS-28298_WorkaroundFo…
Browse files Browse the repository at this point in the history
…rAuthenticationBypass

[JENKINS-28298] Administrators can disable specific strategies
  • Loading branch information
ikedam committed Aug 2, 2015
2 parents 9365f68 + 396f3ea commit 34ab307
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 19 deletions.
Expand Up @@ -24,6 +24,12 @@

package org.jenkinsci.plugins.authorizeproject;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import jenkins.model.Jenkins;
import jenkins.security.QueueItemAuthenticatorConfiguration;

Expand All @@ -36,6 +42,7 @@
import hudson.DescriptorExtensionList;
import hudson.Extension;
import hudson.model.Describable;
import hudson.model.DescriptorVisibilityFilter;
import hudson.model.Job;
import hudson.model.JobProperty;
import hudson.model.JobPropertyDescriptor;
Expand All @@ -52,6 +59,8 @@ public class AuthorizeProjectProperty extends JobProperty<Job<?,?>> {
*/
public static final String PROPERTYNAME = "authorize_project_property";

private static final Logger LOGGER = Logger.getLogger(AuthorizeProjectProperty.class.getName());

private AuthorizeProjectStrategy strategy;

/**
Expand All @@ -74,6 +83,28 @@ public AuthorizeProjectProperty(AuthorizeProjectStrategy strategy) {
this.strategy = strategy;
}

/**
* @return strategy only when it's enabled. null otherwise.
*/
public AuthorizeProjectStrategy getEnabledStrategy() {
AuthorizeProjectStrategy strategy = getStrategy();
if(strategy == null) {
return null;
}
if(DescriptorVisibilityFilter.apply(
ProjectQueueItemAuthenticator.getConfigured(),
Arrays.asList(strategy.getDescriptor())
).isEmpty()) {
LOGGER.log(
Level.WARNING,
"{0} is configured but disabled in the globel-security configuration.",
strategy.getDescriptor().getDisplayName()
);
return null;
}
return strategy;
}

/**
* Return the authorization for a build.
*
Expand All @@ -82,10 +113,11 @@ public AuthorizeProjectProperty(AuthorizeProjectStrategy strategy) {
* @see AuthorizeProjectStrategy#authenticate(hudson.model.Job, hudson.model.Queue.Item)
*/
public Authentication authenticate(Queue.Item item) {
if (getStrategy() == null) {
AuthorizeProjectStrategy strategy = getEnabledStrategy();
if (strategy == null) {
return null;
}
return getStrategy().authenticate(owner, item);
return strategy.authenticate(owner, item);
}

/**
Expand Down Expand Up @@ -129,10 +161,22 @@ public String getPropertyName() {
/**
* @return all the registered {@link AuthorizeProjectStrategy}.
*/
@Deprecated
public DescriptorExtensionList<AuthorizeProjectStrategy, Descriptor<AuthorizeProjectStrategy>> getStrategyList() {
return AuthorizeProjectStrategy.all();
}

/**
* @return enabled {@link AuthorizeProjectStrategy}, empty if authorize-project is not enabled.
*/
public List<Descriptor<AuthorizeProjectStrategy>> getEnabledAuthorizeProjectStrategyDescriptorList() {
ProjectQueueItemAuthenticator authenticator = ProjectQueueItemAuthenticator.getConfigured();
if (authenticator == null) {
return Collections.emptyList();
}
return DescriptorVisibilityFilter.apply(authenticator, AuthorizeProjectStrategy.all());
}

/**
* Create a new {@link AuthorizeProjectProperty} from user inputs.
*
Expand Down
Expand Up @@ -63,7 +63,7 @@ protected final XmlFile getConfigFile() {
}

/**
* @return return a page to shown in "Configure Global Security" as a child of {@link ProjectQueueItemAuthenticator}.
* @return descriptors with configuration views in "Configure Global Security" as a child of {@link ProjectQueueItemAuthenticator}.
*/
public String getGlobalSecurityConfigPage() {
for (String cand: getPossibleViewNames("global-security")) {
Expand Down Expand Up @@ -107,4 +107,11 @@ public static List<AuthorizeProjectStrategyDescriptor> getDescriptorsForGlobalSe
*/
public void configureFromGlobalSecurity(StaplerRequest req, JSONObject js) throws FormException {
}

/**
* @return this strategy can be enabled by default.
*/
public boolean isEnabledByDefault() {
return true;
}
}
Expand Up @@ -24,10 +24,15 @@

package org.jenkinsci.plugins.authorizeproject;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import hudson.Extension;
import hudson.model.DescriptorVisibilityFilter;
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.model.Job;
import hudson.model.Queue;

Expand All @@ -39,6 +44,7 @@
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;

import jenkins.model.Jenkins;
import jenkins.security.QueueItemAuthenticatorConfiguration;
import jenkins.security.QueueItemAuthenticatorDescriptor;
import jenkins.security.QueueItemAuthenticator;
Expand All @@ -47,11 +53,25 @@
* Authorize builds of projects configured with {@link AuthorizeProjectProperty}.
*/
public class ProjectQueueItemAuthenticator extends QueueItemAuthenticator {
private final Map<String,Boolean> strategyEnabledMap;

/**
*
*/
@DataBoundConstructor
@Deprecated
public ProjectQueueItemAuthenticator() {
this(Collections.<String, Boolean>emptyMap());
}

public ProjectQueueItemAuthenticator(Map<String,Boolean> strategyEnabledMap) {
this.strategyEnabledMap = strategyEnabledMap;
}

public Object readResolve() {
if(strategyEnabledMap == null) {
return new ProjectQueueItemAuthenticator(Collections.<String, Boolean>emptyMap());
}
return this;
}

/**
Expand All @@ -76,6 +96,22 @@ public Authentication authenticate(Queue.Item item) {
return prop.authenticate(item);
}

public Map<String, Boolean> getStrategyEnabledMap() {
return strategyEnabledMap;
}

public boolean isStrategyEnabled(Descriptor<?> d)
{
Boolean b = getStrategyEnabledMap().get(d.getId());
if(b != null) {
return b.booleanValue();
}
if(!(d instanceof AuthorizeProjectStrategyDescriptor)) {
return true;
}
return ((AuthorizeProjectStrategyDescriptor)d).isEnabledByDefault();
}

/**
*
*/
Expand All @@ -90,10 +126,18 @@ public String getDisplayName() {
return Messages.ProjectQueueItemAuthenticator_DisplayName();
}

@Deprecated
public List<AuthorizeProjectStrategyDescriptor> getDescriptorsForGlobalSecurityConfigPage() {
return AuthorizeProjectStrategyDescriptor.getDescriptorsForGlobalSecurityConfigPage();
}

/**
* @return all installed {@link AuthorizeProjectStrategy}
*/
public List<Descriptor<AuthorizeProjectStrategy>> getAvailableDescriptorList() {
return AuthorizeProjectStrategy.all();
}

/**
* Creates new {@link ProjectQueueItemAuthenticator} from inputs.
* Additional to that, configure global configurations of {@link AuthorizeProjectStrategy}.
Expand All @@ -108,27 +152,57 @@ public List<AuthorizeProjectStrategyDescriptor> getDescriptorsForGlobalSecurityC
public ProjectQueueItemAuthenticator newInstance(StaplerRequest req, JSONObject formData)
throws FormException
{
ProjectQueueItemAuthenticator r = (ProjectQueueItemAuthenticator)super.newInstance(req, formData);
Map<String,Boolean> strategyEnabledMap = new HashMap<String, Boolean>();

for (AuthorizeProjectStrategyDescriptor d : getDescriptorsForGlobalSecurityConfigPage()) {
for (Descriptor<AuthorizeProjectStrategy> d : getAvailableDescriptorList()) {
String name = d.getJsonSafeClassName();
JSONObject js = formData.has(name) ? formData.getJSONObject(name) : new JSONObject();
d.configureFromGlobalSecurity(req, js);
if (formData.has(name)) {
strategyEnabledMap.put(d.getId(), true);
if (
d instanceof AuthorizeProjectStrategyDescriptor
&& ((AuthorizeProjectStrategyDescriptor)d).getGlobalSecurityConfigPage() != null
) {
((AuthorizeProjectStrategyDescriptor)d).configureFromGlobalSecurity(req, formData.getJSONObject(name));
}
} else {
strategyEnabledMap.put(d.getId(), false);
}
}

return r;
return new ProjectQueueItemAuthenticator(strategyEnabledMap);
}
}

/**
* @return whether Jenkins is configured to use {@link ProjectQueueItemAuthenticator}.
* @return instance configured in Global Security configuration.
*/
public static boolean isConfigured() {
public static ProjectQueueItemAuthenticator getConfigured() {
for (QueueItemAuthenticator authenticator: QueueItemAuthenticatorConfiguration.get().getAuthenticators()) {
if (authenticator instanceof ProjectQueueItemAuthenticator) {
return (ProjectQueueItemAuthenticator)authenticator;
}
}
return null;
}

/**
* @return whether Jenkins is configured to use {@link ProjectQueueItemAuthenticator}.
*/
public static boolean isConfigured() {
return getConfigured() != null;
}

@Extension
public static class DescriptorVisibilityFilterImpl extends DescriptorVisibilityFilter
{
@Override
public boolean filter(Object context, @SuppressWarnings("rawtypes") Descriptor descriptor)
{
if(!(context instanceof ProjectQueueItemAuthenticator))
{
return true;
}
return ((ProjectQueueItemAuthenticator)context).isStrategyEnabled(descriptor);
}
return false;
}
}
Expand Up @@ -424,5 +424,15 @@ public FormValidation doCheckNoNeedReauthentication(@QueryParameter boolean noNe
}
return FormValidation.ok();
}

/**
* {@link SpecificUsersAuthorizationStrategy} should be disabled by default for JENKINS-28298
* @return false
* @see org.jenkinsci.plugins.authorizeproject.AuthorizeProjectStrategyDescriptor#isEnabledByDefault()
*/
@Override
public boolean isEnabledByDefault() {
return false;
}
}
}
Expand Up @@ -25,6 +25,6 @@ THE SOFTWARE.
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<st:adjunct includes="org.jenkinsci.plugins.authorizeproject.nestedHelp"/>
<f:optionalBlock name="${descriptor.propertyName}" title="${descriptor.displayName}" checked="${instance != null}">
<f:dropdownDescriptorSelector title="${%Authorize Strategy}" field="strategy" descriptors="${descriptor.strategyList}" />
<f:dropdownDescriptorSelector title="${%Authorize Strategy}" field="strategy" descriptors="${descriptor.enabledAuthorizeProjectStrategyDescriptorList}" />
</f:optionalBlock>
</j:jelly>
Expand Up @@ -24,10 +24,15 @@ THE SOFTWARE.
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<!-- configurations for AuthorizeProjectStrategy -->
<j:forEach var="d" items="${descriptor.descriptorsForGlobalSecurityConfigPage}">
<j:forEach var="d" items="${descriptor.availableDescriptorList}">
<j:scope>
<j:set var="checked" value="${instance.isStrategyEnabled(d)}" />
<j:set var="instance" value="${d}" />
<f:rowSet name="${d.jsonSafeClassName}">
<st:include page="${d.globalSecurityConfigPage}" from="${d}" />
</f:rowSet>
<j:set var="descriptor" value="${d}" />
<f:optionalBlock name="${d.jsonSafeClassName}" checked="${checked}" help="${d.helpFile}" title="${d.displayName}">
<j:set var="instance" value="${d}" />
<st:include page="${d.globalSecurityConfigPage}" class="${d.clazz}" optional="true" />
</f:optionalBlock>
</j:scope>
</j:forEach>
</j:jelly>

0 comments on commit 34ab307

Please sign in to comment.