All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.provis.jenkins.runtime.EmbeddedJenkinsRuntime Maven / Gradle / Ivy

package io.provis.jenkins.runtime;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl;

import com.cloudbees.plugins.credentials.Credentials;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.SystemCredentialsProvider;
import com.cloudbees.plugins.credentials.domains.Domain;
import com.cloudbees.plugins.credentials.domains.DomainSpecification;
import com.cloudbees.plugins.credentials.domains.HostnameSpecification;
import com.cloudbees.plugins.credentials.domains.SchemeSpecification;
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;

import hudson.XmlFile;
import hudson.util.CopyOnWriteMap;
import hudson.util.Secret;
import hudson.util.TextFile;
import jenkins.model.Jenkins;
import jenkins.util.io.FileBoolean;

public class EmbeddedJenkinsRuntime implements JenkinsRuntime {

  private static final String CREDENTIALS = "credentials.xml";
  
  private File rootDir;

  public EmbeddedJenkinsRuntime(File rootDir, byte[] secretKey) {
    this.rootDir = rootDir;
    try {
      init(secretKey);
    } catch (IOException e) {
      throw new IllegalStateException("Unable to initialize jenkins runtime", e);
    }
  }
  
  public void init(byte[] secretKey) throws IOException {
    Jenkins jenkins = Jenkins.setup(rootDir, secretKey);
    
    TextFile secretFile = new TextFile(new File(rootDir, "secret.key"));
    secretFile.write(jenkins.getSecretKey());
    
    // don't let jenkins complain about old encryption secret scheme
    new FileBoolean(new File(rootDir, "secret.key.not-so-secret")).on();
    // but force rekey on start
    new FileBoolean(new File(new File(rootDir, "jenkins.security.RekeySecretAdminMonitor"), "scanOnBoot")).on();
  }
  
  @Override
  public void close() {
    Jenkins.teardown();
  }
  
  @Override
  public String encrypt(String value) {
    return Secret.fromString(value).getEncryptedValue();
  }
  
  public void writeCredentials(CredentialContainer creds) throws IOException {
    
    Map> domainCredentialsMap = new CopyOnWriteMap.Hash>();
    List globalCredentials = new CopyOnWriteArrayList();
    domainCredentialsMap.put(Domain.global(), globalCredentials);
    
    for (UsernamePassword up : creds.getUsernamePasswordCredentials()) {
      addUsernamePasswordCredential(globalCredentials, up);
    }
    for (SecretCredential secret : creds.getSecretCredentials()) {
      addSecretCredential(globalCredentials, secret);
    }
    for (GitHubCredential gitHubCredential : creds.getGitHubCredentials()) {
      addGitHubCredentialFromToken(domainCredentialsMap, gitHubCredential);
    }
    SystemCredentialsProvider systemCredentialProvider = new SystemCredentialsProvider();
    File credentialsFile = new File(rootDir, CREDENTIALS);
    XmlFile xml = new XmlFile(credentialsFile);
    
    // Add the field with reflection to avoid triggering more Jenkins internal machinery
    try {
      Field domainCredentialsMapField = systemCredentialProvider.getClass().getDeclaredField("domainCredentialsMap"); //NoSuchFieldException
      domainCredentialsMapField.setAccessible(true);
      domainCredentialsMapField.set(systemCredentialProvider, domainCredentialsMap); //IllegalAccessException
    } catch(IllegalAccessException | NoSuchFieldException e) {
      throw new IOException("Error accessing field " + systemCredentialProvider.getClass() + ".domainCredentialsMap", e);
    }
    xml.write(systemCredentialProvider);
  }

  private void addUsernamePasswordCredential(List globalCredentials, UsernamePassword secret) throws IOException {
    globalCredentials.add(new UsernamePasswordCredentialsImpl(
      CredentialsScope.GLOBAL,
      id(secret.getId()),
      secret.getId(),
      secret.getUsername(),
      secret.getPassword()));
  }

  private void addSecretCredential(List globalCredentials, SecretCredential secret) throws IOException {
    globalCredentials.add(new StringCredentialsImpl(
      CredentialsScope.GLOBAL,
      id(secret.getId()),
      secret.getId(),
      Secret.fromString(secret.getSecret())));
  }

  private void addGitHubCredentialFromToken(Map> domainCredentialsMap, GitHubCredential gitHubCredential) {
    List gitHubCredentialsForDomain = new CopyOnWriteArrayList();
    URI serverUri = URI.create(gitHubCredential.getGitHubApiUrl());
    List specifications = Arrays.asList(
      new SchemeSpecification(serverUri.getScheme()),
      new HostnameSpecification(serverUri.getHost(), null));
    
    Domain domain = new Domain(serverUri.getHost(), "GitHub domain (autogenerated)", specifications);
    String description = String.format("GitHub (%s) auto generated token credentials for %s", gitHubCredential.getGitHubApiUrl(), gitHubCredential.getUsername());
    StringCredentialsImpl creds = new StringCredentialsImpl(
      CredentialsScope.GLOBAL,
      id(gitHubCredential.getId()),
      description,
      Secret.fromString(gitHubCredential.getOauthToken()));
    gitHubCredentialsForDomain.add(creds);
    domainCredentialsMap.put(domain, gitHubCredentialsForDomain);
  }
  
  private static String id(String id) {
    return id != null ? id : UUID.randomUUID().toString();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy