Skip to content

Commit

Permalink
Add custom binding for AzureCredentials (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
chenkennt committed Jun 16, 2017
1 parent 6c80977 commit 7af350e
Show file tree
Hide file tree
Showing 11 changed files with 257 additions and 4 deletions.
2 changes: 1 addition & 1 deletion checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sf.net/config_sizes.html -->
<module name="LineLength">
<property name="max" value="100"/>
<property name="max" value="120"/>
</module>
<module name="MethodLength"/>
<module name="ParameterNumber">
Expand Down
11 changes: 10 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,17 @@
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>credentials-binding</artifactId>
<version>1.11</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>structs</artifactId>
<version>1.5</version>
</dependency>
</dependencies>

<repositories>
<repository>
<id>repo.jenkins-ci.org</id>
Expand Down
11 changes: 9 additions & 2 deletions src/main/java/com/microsoft/azure/util/AzureCredentials.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*/
package com.microsoft.azure.util;

Expand Down Expand Up @@ -298,6 +297,14 @@ public final String getClientSecret() {
return data.clientSecret.getEncryptedValue();
}

public final String getPlainClientSecret() {
return data.clientSecret.getPlainText();
}

public final String getTenant() {
return data.getTenant();
}

public final String getOauth2TokenEndpoint() {
return data.oauth2TokenEndpoint.getPlainText();
}
Expand Down
178 changes: 178 additions & 0 deletions src/main/java/com/microsoft/azure/util/AzureCredentialsBinding.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*/
package com.microsoft.azure.util;

import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.Run;
import hudson.model.TaskListener;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.credentialsbinding.BindingDescriptor;
import org.jenkinsci.plugins.credentialsbinding.MultiBinding;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
* Custom binding for AzureCredentials to support reading Azure service principal in both freestyle
* and pipeline using Credentials Binding plugin.
* There're two ways to construct this binding:
* 1. With defaults, which will read specified service principal into four predefined environment
* variables: AZURE_SUBSCRIPTION_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID.
* Sample pipeline code:
* withCredentials([azureServicePrincipal('credentials_id')]) {
* sh 'az login --service-principal -u $AZURE_CLIENT_ID -p $AZURE_CLIENT_SECRET -t $AZURE_TENANT_ID'
* }
* 2. With custom name, where you can control the names of the variables.
* Sample pipeline code:
* withCredentials([azureServicePrincipal(credentialsId: 'credentials_id',
* subscriptionIdVariable: 'SUBS_ID',
* clientIdVariable: 'CLIENT_ID',
* clientSecretVariable: 'CLIENT_SECRET',
* tenantIdVariable: 'TENANT_ID')]) {
* sh 'az login --service-principal -u $CLIENT_ID -p $CLIENT_SECRET -t $TENANT_ID'
* }
*/
public class AzureCredentialsBinding extends MultiBinding<AzureCredentials> {
public static final String DEFAULT_SUBSCRIPTION_ID_VARIABLE = "AZURE_SUBSCRIPTION_ID";
public static final String DEFAULT_CLIENT_ID_VARIABLE = "AZURE_CLIENT_ID";
public static final String DEFAULT_CLIENT_SECRET_VARIABLE = "AZURE_CLIENT_SECRET";
public static final String DEFAULT_TENANT_ID_VARIABLE = "AZURE_TENANT_ID";

private String subscriptionIdVariable;
private String clientIdVariable;
private String clientSecretVariable;
private String tenantIdVariable;

@DataBoundConstructor
public AzureCredentialsBinding(final String credentialsId) {
super(credentialsId);
}

@DataBoundSetter
public final void setSubscriptionIdVariable(final String subscriptionIdVariable) {
this.subscriptionIdVariable = subscriptionIdVariable;
}

@DataBoundSetter
public final void setClientIdVariable(final String clientIdVariable) {
this.clientIdVariable = clientIdVariable;
}

@DataBoundSetter
public final void setClientSecretVariable(final String clientSecretVariable) {
this.clientSecretVariable = clientSecretVariable;
}

@DataBoundSetter
public final void setTenantIdVariable(final String tenantIdVariable) {
this.tenantIdVariable = tenantIdVariable;
}

public final String getSubscriptionIdVariable() {
if (!StringUtils.isBlank(subscriptionIdVariable)) {
return subscriptionIdVariable;
}

return DEFAULT_SUBSCRIPTION_ID_VARIABLE;
}

public final String getClientIdVariable() {
if (!StringUtils.isBlank(clientIdVariable)) {
return clientIdVariable;
}

return DEFAULT_CLIENT_ID_VARIABLE;
}

public final String getClientSecretVariable() {
if (!StringUtils.isBlank(clientSecretVariable)) {
return clientSecretVariable;
}

return DEFAULT_CLIENT_SECRET_VARIABLE;
}

public final String getTenantIdVariable() {
if (!StringUtils.isBlank(tenantIdVariable)) {
return tenantIdVariable;
}

return DEFAULT_TENANT_ID_VARIABLE;
}

@Override
protected final Class<AzureCredentials> type() {
return AzureCredentials.class;
}

@Override
public final MultiEnvironment bind(@Nonnull final Run<?, ?> build,
final FilePath workspace,
final Launcher launcher,
final TaskListener listener)
throws IOException, InterruptedException {
AzureCredentials credentials = getCredentials(build);
Map<String, String> map = new HashMap<>();
map.put(getSubscriptionIdVariable(), credentials.getSubscriptionId());
map.put(getClientIdVariable(), credentials.getClientId());
map.put(getClientSecretVariable(), credentials.getPlainClientSecret());
map.put(getTenantIdVariable(), credentials.getTenant());
return new MultiEnvironment(map);
}

@Override
public final Set<String> variables() {
return new HashSet<String>(Arrays.asList(
getSubscriptionIdVariable(),
getClientIdVariable(),
getClientSecretVariable(),
getTenantIdVariable()));
}

@Symbol("azureServicePrincipal")
@Extension
public static class DescriptorImpl extends BindingDescriptor<AzureCredentials> {
@Override
protected final Class<AzureCredentials> type() {
return AzureCredentials.class;
}

@Override
public final String getDisplayName() {
return Messages.Azure_Credentials_Binding_Diaplay_Name();
}

@Override
public final boolean requiresWorkspace() {
return false;
}

public final String getDefaultSubscriptionIdVariable() {
return DEFAULT_SUBSCRIPTION_ID_VARIABLE;
}

public final String getDefaultClientIdVariable() {
return DEFAULT_CLIENT_ID_VARIABLE;
}

public final String getDefaultClientSecretVariable() {
return DEFAULT_CLIENT_SECRET_VARIABLE;
}

public final String getDefaultTenantIdVariable() {
return DEFAULT_TENANT_ID_VARIABLE;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See LICENSE file in the project root for license information.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:st="jelly:stapler" xmlns:c="/lib/credentials">
<f:entry title="${%SubscriptionIdVariable}" field="subscriptionIdVariable" help="/plugin/azure-credentials/help-subscriptionIdVariable.html">
<f:textbox default="${descriptor.getDefaultSubscriptionIdVariable()}"/>
</f:entry>
<f:entry title="${%ClientIdVariable}" field="clientIdVariable" help="/plugin/azure-credentials/help-clientIdVariable.html">
<f:textbox default="${descriptor.getDefaultClientIdVariable()}"/>
</f:entry>
<f:entry title="${%ClientSecretVariable}" field="clientSecretVariable" help="/plugin/azure-credentials/help-clientSecretVariable.html">
<f:textbox default="${descriptor.getDefaultClientSecretVariable()}"/>
</f:entry>
<f:entry title="${%TenantIdVariable}" field="tenantIdVariable" help="/plugin/azure-credentials/help-tenantIdVariable.html">
<f:textbox default="${descriptor.getDefaultTenantIdVariable()}"/>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE file in the project root for license information.

SubscriptionIdVariable=Subscription ID Variable
ClientIdVariable=Client ID Variable
ClientSecretVariable=Client Secret Variable
TenantIdVariable=Tenant ID Variable
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE file in the project root for license information.

// CHECKSTYLE:OFF
Azure_Config_Success=Successfully verified the Microsoft Azure Service Principal.
Azure_CantValidate=The provided credentials are not valid
Expand All @@ -7,3 +10,4 @@ Azure_ClientID_Missing=Error: Client ID is missing.
Azure_ClientSecret_Missing=Error: Client Secret is missing.
Azure_OAuthToken_Missing=Error: OAuth 2.0 Token Endpoint is missing.
Azure_OAuthToken_Malformed=Error: OAuth 2.0 Token Endpoint is malformed.
Azure_Credentials_Binding_Diaplay_Name=Microsoft Azure Service Principal
7 changes: 7 additions & 0 deletions src/main/webapp/help-clientIdVariable.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See LICENSE file in the project root for license information.
-->
<div>
Name of the environment variable to store Azure Client ID during build. If empty, default value is AZURE_CLIENT_ID.
</div>
7 changes: 7 additions & 0 deletions src/main/webapp/help-clientSecretVariable.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See LICENSE file in the project root for license information.
-->
<div>
Name of the environment variable to store Azure client secret during build. If empty, default value is AZURE_CLIENT_SECRET.
</div>
7 changes: 7 additions & 0 deletions src/main/webapp/help-subscriptionIdVariable.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See LICENSE file in the project root for license information.
-->
<div>
Name of the environment variable to store Azure subscription ID during build. If empty, default value is AZURE_SUBSCRIPTION_ID.
</div>
7 changes: 7 additions & 0 deletions src/main/webapp/help-tenantIdVariable.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See LICENSE file in the project root for license information.
-->
<div>
Name of the environment variable to store Azure tenant ID during build. If empty, default value is AZURE_TENANT_ID.
</div>

0 comments on commit 7af350e

Please sign in to comment.