Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-56774] Add JCasC support #129

Merged
merged 1 commit into from
Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@
<artifactId>workflow-cps</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jenkins</groupId>
<artifactId>configuration-as-code</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jenkins.configuration-as-code</groupId>
<artifactId>test-harness</artifactId>
<scope>test</scope>
</dependency>
<!-- Required to avoid cyclic dependency -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import hudson.Extension;
import hudson.model.DescriptorVisibilityFilter;
Expand All @@ -41,6 +44,7 @@
import net.sf.json.JSONObject;

import org.acegisecurity.Authentication;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;

import jenkins.security.QueueItemAuthenticatorConfiguration;
Expand All @@ -51,23 +55,42 @@
* Authorize builds of projects configured with {@link AuthorizeProjectProperty}.
*/
public class ProjectQueueItemAuthenticator extends QueueItemAuthenticator {
private final Map<String,Boolean> strategyEnabledMap;
private final Set<String> enabledStrategies;
private final Set<String> disabledStrategies;

@Deprecated
private transient Map<String,Boolean> strategyEnabledMap;

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

@Deprecated
public ProjectQueueItemAuthenticator(Map<String,Boolean> strategyEnabledMap) {
this.strategyEnabledMap = strategyEnabledMap;
this(
strategyEnabledMap.entrySet().stream()
.filter(e -> e.getValue().equals(true))
.map(Map.Entry::getKey)
.collect(Collectors.toSet()),
strategyEnabledMap.entrySet().stream()
.filter(e -> e.getValue().equals(false))
.map(Map.Entry::getKey)
.collect(Collectors.toSet()));
}

@DataBoundConstructor
public ProjectQueueItemAuthenticator(Set<String> enabledStrategies, Set<String> disabledStrategies) {
this.enabledStrategies = enabledStrategies;
this.disabledStrategies = disabledStrategies;
}

protected Object readResolve() {
if(strategyEnabledMap == null) {
return new ProjectQueueItemAuthenticator(Collections.<String, Boolean>emptyMap());
if (strategyEnabledMap != null) {
return new ProjectQueueItemAuthenticator(strategyEnabledMap);
}
return this;
}
Expand All @@ -94,20 +117,41 @@ public Authentication authenticate(Queue.Item item) {
return prop.authenticate(item);
}

@Deprecated
public Map<String, Boolean> getStrategyEnabledMap() {
Map<String,Boolean> strategyEnabledMap = new HashMap<>();
for (String strategy : enabledStrategies) {
strategyEnabledMap.put(strategy, true);
}
for (String strategy : disabledStrategies) {
strategyEnabledMap.put(strategy, false);
}
return strategyEnabledMap;
}

public Set<String> getEnabledStrategies() {
return enabledStrategies;
}

public Set<String> getDisabledStrategies() {
return disabledStrategies;
}

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

if (disabledStrategies.contains(d.getId())) {
return false;
}

if (d instanceof AuthorizeProjectStrategyDescriptor) {
return ((AuthorizeProjectStrategyDescriptor) d).isEnabledByDefault();
}

return true;
}

/**
Expand Down Expand Up @@ -150,24 +194,25 @@ public List<Descriptor<AuthorizeProjectStrategy>> getAvailableDescriptorList() {
public ProjectQueueItemAuthenticator newInstance(StaplerRequest req, JSONObject formData)
throws FormException
{
Map<String,Boolean> strategyEnabledMap = new HashMap<String, Boolean>();
Set<String> enabledStrategies = new HashSet<>();
Set<String> disabledStrategies = new HashSet<>();

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

return new ProjectQueueItemAuthenticator(strategyEnabledMap);
return new ProjectQueueItemAuthenticator(enabledStrategies, disabledStrategies);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.jenkinsci.plugins.authorizeproject.AuthorizeProjectStrategyDescriptor;
import org.jenkinsci.plugins.authorizeproject.AuthorizeProjectUtil;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
Expand All @@ -63,6 +64,20 @@ public class SpecificUsersAuthorizationStrategy extends AuthorizeProjectStrategy
private static Logger LOGGER = Logger.getLogger(SpecificUsersAuthorizationStrategy.class.getName());
private final String userid;

/*
* The fields "useApitoken", "apitoken", and "password" are part of the @DataBoundConstructor annotated constructor,
* but they are only required for validation during form submission. They are put here and marked restricted and
* transient to make Configuration as Code ignore them when exporting the configuration.
*/
@Restricted(DoNotUse.class)
private transient Boolean useApitoken;

@Restricted(DoNotUse.class)
private transient String apitoken;

@Restricted(DoNotUse.class)
private transient String password;

private final static Authentication[] BUILTIN_USERS = {
ACL.SYSTEM,
Jenkins.ANONYMOUS,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package org.jenkinsci.plugins.authorizeproject;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertThat;

import hudson.util.DescribableList;
import io.jenkins.plugins.casc.ConfigurationContext;
import io.jenkins.plugins.casc.ConfiguratorRegistry;
import io.jenkins.plugins.casc.misc.ConfiguredWithCode;
import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule;
import io.jenkins.plugins.casc.misc.Util;
import io.jenkins.plugins.casc.model.CNode;
import java.util.Arrays;
import java.util.HashSet;
import jenkins.security.QueueItemAuthenticator;
import jenkins.security.QueueItemAuthenticatorConfiguration;
import jenkins.security.QueueItemAuthenticatorDescriptor;
import org.jenkinsci.plugins.authorizeproject.strategy.AnonymousAuthorizationStrategy;
import org.jenkinsci.plugins.authorizeproject.strategy.SpecificUsersAuthorizationStrategy;
import org.jenkinsci.plugins.authorizeproject.strategy.SystemAuthorizationStrategy;
import org.jenkinsci.plugins.authorizeproject.strategy.TriggeringUsersAuthorizationStrategy;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.recipes.LocalData;

public class ConfigurationAsCodeTest {

@Rule public JenkinsConfiguredWithCodeRule r = new JenkinsConfiguredWithCodeRule();

@Test
@ConfiguredWithCode("ConfigurationAsCodeTest/global.config.AnonymousAuthorizationStrategy.yml")
public void importGlobalAnonymousAuthorizationStrategy() {
DescribableList<QueueItemAuthenticator, QueueItemAuthenticatorDescriptor> authenticators = QueueItemAuthenticatorConfiguration.get().getAuthenticators();
GlobalQueueItemAuthenticator queueItemAuthenticator = authenticators.get(GlobalQueueItemAuthenticator.class);

assertThat(authenticators, hasSize(1));
assertThat(queueItemAuthenticator.getStrategy(), instanceOf(AnonymousAuthorizationStrategy.class));
}

@Test
@ConfiguredWithCode("ConfigurationAsCodeTest/global.config.AnonymousAuthorizationStrategy.yml")
public void exportGlobalAnonymousAuthorizationStrategy() throws Exception {
assertExport("ConfigurationAsCodeTest/global.export.AnonymousAuthorizationStrategy.yml");
}

@Test
@ConfiguredWithCode("ConfigurationAsCodeTest/global.config.SpecificUsersAuthorizationStrategy.yml")
public void importGlobalSpecificUsersAuthorizationStrategy() {
DescribableList<QueueItemAuthenticator, QueueItemAuthenticatorDescriptor> authenticators = QueueItemAuthenticatorConfiguration.get().getAuthenticators();
GlobalQueueItemAuthenticator queueItemAuthenticator = authenticators.get(GlobalQueueItemAuthenticator.class);

assertThat(authenticators, hasSize(1));
assertThat(queueItemAuthenticator.getStrategy(), instanceOf(SpecificUsersAuthorizationStrategy.class));
assertThat(((SpecificUsersAuthorizationStrategy) queueItemAuthenticator.getStrategy()).getUserid(), equalTo("some-user"));
}

@Test
@ConfiguredWithCode("ConfigurationAsCodeTest/global.config.SpecificUsersAuthorizationStrategy.yml")
public void exportGlobalSpecificUsersAuthorizationStrategy() throws Exception {
assertExport("ConfigurationAsCodeTest/global.export.SpecificUsersAuthorizationStrategy.yml");
}

@Test
@ConfiguredWithCode("ConfigurationAsCodeTest/global.config.SystemAuthorizationStrategy.yml")
public void importGlobalSystemAuthorizationStrategy() {
DescribableList<QueueItemAuthenticator, QueueItemAuthenticatorDescriptor> authenticators = QueueItemAuthenticatorConfiguration.get().getAuthenticators();
GlobalQueueItemAuthenticator queueItemAuthenticator = authenticators.get(GlobalQueueItemAuthenticator.class);

assertThat(authenticators, hasSize(1));
assertThat(queueItemAuthenticator.getStrategy(), instanceOf(SystemAuthorizationStrategy.class));
}

@Test
@ConfiguredWithCode("ConfigurationAsCodeTest/global.config.SystemAuthorizationStrategy.yml")
public void exportGlobalSystemAuthorizationStrategy() throws Exception {
assertExport("ConfigurationAsCodeTest/global.export.SystemAuthorizationStrategy.yml");
}

@Test
@ConfiguredWithCode("ConfigurationAsCodeTest/global.config.TriggeringUsersAuthorizationStrategy.yml")
public void importGlobalTriggeringUsersAuthorizationStrategy() {
DescribableList<QueueItemAuthenticator, QueueItemAuthenticatorDescriptor> authenticators = QueueItemAuthenticatorConfiguration.get().getAuthenticators();
GlobalQueueItemAuthenticator queueItemAuthenticator = authenticators.get(GlobalQueueItemAuthenticator.class);

assertThat(authenticators, hasSize(1));
assertThat(queueItemAuthenticator.getStrategy(), instanceOf(TriggeringUsersAuthorizationStrategy.class));
}

@Test
@ConfiguredWithCode("ConfigurationAsCodeTest/global.config.TriggeringUsersAuthorizationStrategy.yml")
public void exportGlobalTriggeringUsersAuthorizationStrategy() throws Exception {
assertExport("ConfigurationAsCodeTest/global.export.TriggeringUsersAuthorizationStrategy.yml");
}

@Test
@ConfiguredWithCode("ConfigurationAsCodeTest/project.config.all.yml")
public void importProjectTriggeringUsersAuthorizationStrategy() {
DescribableList<QueueItemAuthenticator, QueueItemAuthenticatorDescriptor> authenticators = QueueItemAuthenticatorConfiguration.get().getAuthenticators();
ProjectQueueItemAuthenticator queueItemAuthenticator = authenticators.get(ProjectQueueItemAuthenticator.class);

assertThat(authenticators, hasSize(1));
assertThat(queueItemAuthenticator.getDisabledStrategies(), equalTo(new HashSet<>(Arrays.asList("org.jenkinsci.plugins.authorizeproject.strategy.SystemAuthorizationStrategy", "org.jenkinsci.plugins.authorizeproject.strategy.SpecificUsersAuthorizationStrategy", "org.jenkinsci.plugins.authorizeproject.strategy.TriggeringUsersAuthorizationStrategy"))));
assertThat(queueItemAuthenticator.getEnabledStrategies(), equalTo(new HashSet<>(Arrays.asList("org.jenkinsci.plugins.authorizeproject.strategy.AnonymousAuthorizationStrategy"))));
}

@Test
@ConfiguredWithCode("ConfigurationAsCodeTest/project.config.all.yml")
public void exportProjectTriggeringUsersAuthorizationStrategy() throws Exception {
assertExport("ConfigurationAsCodeTest/project.export.all.yml");
}

private void assertExport(String resourcePath) throws Exception {
ConfiguratorRegistry registry = ConfiguratorRegistry.get();
ConfigurationContext context = new ConfigurationContext(registry);
CNode queueItemAuthenticator = Util.getSecurityRoot(context).get("queueItemAuthenticator");

String exported = Util.toYamlString(queueItemAuthenticator);
String expected = Util.toStringFromYamlFile(this, resourcePath);

assertThat(exported, equalTo(expected));
}

@LocalData
@Test
public void strategyEnabledMapMigration() {
DescribableList<QueueItemAuthenticator, QueueItemAuthenticatorDescriptor> authenticators = QueueItemAuthenticatorConfiguration.get().getAuthenticators();
ProjectQueueItemAuthenticator queueItemAuthenticator = authenticators.get(ProjectQueueItemAuthenticator.class);

assertThat(authenticators, hasSize(1));
assertThat(queueItemAuthenticator.getDisabledStrategies(), equalTo(new HashSet<>(Arrays.asList(SpecificUsersAuthorizationStrategy.class.getName(), SystemAuthorizationStrategy.class.getName()))));
assertThat(queueItemAuthenticator.getEnabledStrategies(), equalTo(new HashSet<>(Arrays.asList(AnonymousAuthorizationStrategy.class.getName(), TriggeringUsersAuthorizationStrategy.class.getName()))));
}
}
Loading