Skip to content

Commit

Permalink
Merge pull request #57 from oleg-nenashev/JENKINS-29867-hide-envvars
Browse files Browse the repository at this point in the history
[JENKINS-29867] - Permissions engine + global option for disabling the Injected vars
  • Loading branch information
oleg-nenashev committed Aug 16, 2015
2 parents 8ba5040 + 40a2c53 commit cff077f
Show file tree
Hide file tree
Showing 13 changed files with 545 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -38,7 +38,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<envinject.lib.version>1.22</envinject.lib.version>
<envinject.lib.version>1.23</envinject.lib.version>
<ivy.plugin.version>1.21</ivy.plugin.version>
<junit.version>4.12</junit.version>
<mockito.version>1.10.19</mockito.version>
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/jenkinsci/plugins/envinject/EnvInjectAction.java
Expand Up @@ -15,6 +15,7 @@

/**
* @author Gregory Boissinot
* @deprecated Replaced by {@link EnvInjectPluginAction}.
*/
@Deprecated
public class EnvInjectAction implements Action, StaplerProxy {
Expand Down Expand Up @@ -45,20 +46,38 @@ public Map<String, String> getEnvMap() {
return UnmodifiableMap.decorate(envMap);
}

@Override
public String getIconFileName() {
if (!EnvInjectPlugin.canViewInjectedVars(build)) {
return null;
}
return "document-properties.gif";
}

@Override
public String getDisplayName() {
return "Environment Variables";
}

@Override
public String getUrlName() {
if (!EnvInjectPlugin.canViewInjectedVars(build)) {
return null;
}
return URL_NAME;
}

protected AbstractBuild getBuild() {
return build;
}

@Override
public Object getTarget() {
final Set sensitiveVariables = build.getSensitiveBuildVariables();
if (!EnvInjectPlugin.canViewInjectedVars(build)) {
return EnvInjectVarList.HIDDEN;
}

return new EnvInjectVarList(Maps.transformEntries(envMap,
new Maps.EntryTransformer<String, String, String>() {
public String transformEntry(String key, String value) {
Expand Down
113 changes: 113 additions & 0 deletions src/main/java/org/jenkinsci/plugins/envinject/EnvInjectPlugin.java
@@ -0,0 +1,113 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugins.envinject;

import hudson.Plugin;
import hudson.model.Run;
import hudson.security.Permission;
import hudson.security.PermissionGroup;
import hudson.security.PermissionScope;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import jenkins.model.Jenkins;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.export.ExportedBean;

/**
* Stores permissions for EnvInject plugin.
* @author Oleg Nenashev
* @since 1.92
*/
@ExportedBean
public class EnvInjectPlugin extends Plugin {

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

public static final PermissionGroup PERMISSIONS = new PermissionGroup(EnvInjectPlugin.class, Messages._envinject_permissions_title());

/**
* Allows to view injected variables.
* Even Jenkins admins may have no such permission in particular installations.
*/
public static final Permission VIEW_INJECTED_VARS = new Permission(PERMISSIONS, "ViewVars", Messages._envinject_permissions_viewVars_description(), null, PermissionScope.RUN);

/**
* Retrieves the plugin instance.
* @return {@link EnvInjectPlugin}
* @throws IllegalStateException the plugin has not been loaded yet
*/
public static @Nonnull EnvInjectPlugin getInstance() {
Jenkins j = Jenkins.getInstance();
EnvInjectPlugin plugin = j != null ? j.getPlugin(EnvInjectPlugin.class) : null;
if (plugin == null) { // Fail horribly
// TODO: throw a graceful error
throw new IllegalStateException("Cannot get the plugin's instance. Jenkins or the plugin have not been initialized yet");
}
return plugin;
}

/*package*/ void onConfigChange(@Nonnull EnvInjectPluginConfiguration config) {
VIEW_INJECTED_VARS.setEnabled(config.isEnablePermissions());
}

@Nonnull
public EnvInjectPluginConfiguration getConfiguration() {
final EnvInjectPluginConfiguration config = EnvInjectPluginConfiguration.getInstance();
return config != null ? config : EnvInjectPluginConfiguration.getDefault();
}

/**
* Checks if the current user can view injected variables in the run.
* @param run Run to be checked
* @return true if the injected variables can be displayed.
*/
@Restricted(NoExternalUse.class)
public static boolean canViewInjectedVars(@Nonnull Run<?,?> run) {
// We allow security engines to block the output
if (VIEW_INJECTED_VARS.getEnabled() && !run.hasPermission(VIEW_INJECTED_VARS)) {
return false;
}

// Last check - global configs
final EnvInjectPluginConfiguration configuration = getInstance().getConfiguration();
return !configuration.isHideInjectedVars();
}

@Override
public void start() throws Exception {
VIEW_INJECTED_VARS.setEnabled(getConfiguration().isEnablePermissions());
}

// TODO: Replace by Jenkins::getActiveInstance() in 1.590+
@Nonnull
@Restricted(NoExternalUse.class)
public static Jenkins getJenkinsInstance() throws IllegalStateException {
final Jenkins jenkins = Jenkins.getInstance();
if (jenkins == null) {
throw new IllegalStateException("Jenkins instance is not ready");
}
return jenkins;
}
}
Expand Up @@ -8,6 +8,7 @@

import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;

/**
* @author Gregory Boissinot
Expand All @@ -18,7 +19,32 @@ public EnvInjectPluginAction(AbstractBuild build, Map<String, String> envMap) {
super(build, envMap);
}

@Override
public String getIconFileName() {
if (!EnvInjectPlugin.canViewInjectedVars(getOwner())) {
return null;
}
return super.getIconFileName();
}

@Override
public String getUrlName() {
if (!EnvInjectPlugin.canViewInjectedVars(getOwner())) {
return null;
}
return super.getUrlName();
}

@Override
public Object getTarget() {
if (!EnvInjectPlugin.canViewInjectedVars(getOwner())) {
return EnvInjectVarList.HIDDEN;
}
return getEnvInjectVarList();
}

@Nonnull
private EnvInjectVarList getEnvInjectVarList() {
return new EnvInjectVarList(Maps.transformEntries(envMap,
new Maps.EntryTransformer<String, String, String>() {
public String transformEntry(String key, String value) {
Expand All @@ -29,7 +55,7 @@ public String transformEntry(String key, String value) {
}

public void buildEnvVars(AbstractBuild<?, ?> build, EnvVars env) {
EnvInjectVarList varList = (EnvInjectVarList) getTarget();
final EnvInjectVarList varList = getEnvInjectVarList();
Map<String, String> envMap = varList.getEnvMap();
if (envMap != null) {
env.putAll(envMap);
Expand Down
@@ -0,0 +1,116 @@
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugins.envinject;

import com.google.common.annotations.VisibleForTesting;
import hudson.Extension;
import hudson.XmlFile;
import java.io.File;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jenkins.model.GlobalConfiguration;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import static org.jenkinsci.plugins.envinject.EnvInjectPlugin.getJenkinsInstance;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;

/**
* Configuration of {@link EnvInjectPlugin}.
* @author Oleg Nenashev
* @since 1.92
*/
@Extension
public class EnvInjectPluginConfiguration extends GlobalConfiguration {

private static final EnvInjectPluginConfiguration DEFAULT =
new EnvInjectPluginConfiguration(false, false);

private boolean hideInjectedVars;

private boolean enablePermissions;

public EnvInjectPluginConfiguration() {
load();
}

public EnvInjectPluginConfiguration(boolean hideInjectedVars, boolean enablePermissions) {
this.hideInjectedVars = hideInjectedVars;
this.enablePermissions = enablePermissions;
}

public boolean isHideInjectedVars() {
return hideInjectedVars;
}

public boolean isEnablePermissions() {
return enablePermissions;
}

/**
* Gets the default configuration of {@link EnvInjectPlugin}
* @return Default configuration
*/
public static final @Nonnull EnvInjectPluginConfiguration getDefault() {
return DEFAULT;
}

@Override
protected XmlFile getConfigFile() {
return new XmlFile(Jenkins.XSTREAM, new File(getJenkinsInstance().getRootDir(),
"envinject-plugin-configuration.xml"));
}

@Override
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
final boolean newEnablePermissions = json.getBoolean("enablePermissions");
final boolean newHideInjectedVars = json.getBoolean("hideInjectedVars");
return configure(newHideInjectedVars, newEnablePermissions);
}

/**
* Configuration method for testing purposes.
* @param hideInjectedVars Hide injected variables actions
* @param enablePermissions Enables permissions in {@link EnvInjectPlugin}.
* @return true if the configuration successful
* @throws IllegalStateException Cannot retrieve the plugin config instance
*/
@VisibleForTesting
/*package*/ static boolean configure(boolean hideInjectedVars, boolean enablePermissions) {
EnvInjectPluginConfiguration instance = getInstance();
if (instance == null) {
throw new IllegalStateException("Cannot retrieve the plugin config instance");
}
instance.hideInjectedVars = hideInjectedVars;
instance.enablePermissions = enablePermissions;
EnvInjectPlugin.getInstance().onConfigChange(instance);
instance.save();
return true;
}

@CheckForNull
public static EnvInjectPluginConfiguration getInstance() {
return EnvInjectPluginConfiguration.all().get(EnvInjectPluginConfiguration.class);
}
}
Expand Up @@ -10,6 +10,7 @@
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;

Expand All @@ -20,6 +21,12 @@
public class EnvInjectVarList implements Serializable {

private Map<String, String> envVars = new TreeMap<String, String>();

/**
* Empty variables list, which should be returned if the variables are hidden
* due to the security settings.
*/
public static final EnvInjectVarList HIDDEN = new Hidden();

public EnvInjectVarList(Map<String, String> envMap) {
if (envMap != null) {
Expand Down Expand Up @@ -125,5 +132,17 @@ private void writeJsonResponse(StaplerResponse response) throws IOException {
outputStream.write(sb.toString().getBytes());
outputStream.write("]}}".getBytes());
}

//TODO: Throw errors in responses?
/**
* Implements an {@link EnvInjectVarList}, which does not provide any variables.
*/
private static class Hidden extends EnvInjectVarList {
private static final long serialVersionUID = 1L;

public Hidden() {
super(Collections.<String,String>emptyMap());
}
}

}

0 comments on commit cff077f

Please sign in to comment.