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

Adding connectedApp authentication to HTTP Wrapper #39

Merged
merged 6 commits into from
Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ schema.json
evaluate.gdsl
maven-plugin/stuff.groovy
cli/stuff.groovy
.DS_Store
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ Both approaches 1 and 2 lean on using a Groovy DSL to supply your deployment spe

ALL of these methods assume your CI/CD tool white lists secrets from output. If it does not, it's on YOU to deal with that. Jenkins and Azure DevOps should do this out of the box with no further configuration.

# Authentication
The tool supports two type of authentication methods -
1. Basic Anypoint Platform Credentials
2. Anypoint [Connected App Credentials](https://help.mulesoft.com/s/article/How-to-deploy-an-application-to-CloudHub-using-Connected-App-functionality)

# Maven plugin

NOTE: The Maven plugin has 2 goals (deploy and validate). Regardless of whether you use it to actually perform the deployment, it's highly recommended you use the validate goal to ensure your DSL file is correct during the build pipeline.
Expand Down Expand Up @@ -66,7 +71,12 @@ If you have no strong preference, then stick with the "with POM" approach which
mvn clean deploy -DmuleDeploy.env=DEV -Danypoint.username=bob -Danypoint.password=asecret -DmuleDeploy.cryptoKey=hello -DmuleDeploy.autoDiscClientId=theId -DmuleDeploy.autoDiscClientSecret=theSecret
```

See maven-plugin/README.md for more information.
To see all parameters, run help goal of the plugin:
```shell
mvn com.avioconsulting.mule:mule-deploy-maven-plugin:help -Ddetail=true
```

See [maven-plugin/README.md](./maven-plugin/README.md) for more information.

# CLI

Expand Down
14 changes: 10 additions & 4 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ You can get an idea of available options by running `./muleDeploy --help`:

```
Missing required parameter: <groovyFile>
Usage: deploy [-V] [-m=<dryRunMode>] [-o=<anypointOrganizationName>]
-p=<anypointPassword> -u=<anypointUsername>
[-a=<String=String>]...
Usage: deploy ([-u=<anypointUsername> -p=<anypointPassword>]
[-caid=<anypointConnectedAppId>
-casec=<anypointConnectedAppSecret>]) [-V] [-m=<dryRunMode>]
[-o=<anypointOrganizationName>] [-a=<String=String>]...
[-e=<environmentsToDoDesignCenterDeploymentOn>]... <groovyFile>
Will deploy using your Mule DSL
<groovyFile> The path to your DSL file
Expand All @@ -57,11 +58,16 @@ Will deploy using your Mule DSL
-o, --anypoint-org-name=<anypointOrganizationName>
The org/business group to use. If you do not specify it,
the default for your user will be used
-V, --version print version info
Basic auth credentials of Anypoint Platform
-p, --anypoint-password=<anypointPassword>

-u, --anypoint-username=<anypointUsername>

-V, --version print version info
Connected App credentials
-caid, --anypoint-connected-app-id=<anypointConnectedAppId>

-casec, --anypoint-connected-app-secret=<anypointConnectedAppSecret>

```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import com.avioconsulting.mule.deployment.api.DeployerFactory
import com.avioconsulting.mule.deployment.api.DryRunMode
import com.avioconsulting.mule.deployment.api.IDeployerFactory
import com.avioconsulting.mule.deployment.api.ILogger
import com.avioconsulting.mule.deployment.api.models.credentials.ConnectedAppCredential
import com.avioconsulting.mule.deployment.api.models.credentials.Credential
import com.avioconsulting.mule.deployment.api.models.credentials.UsernamePasswordCredential
import com.avioconsulting.mule.deployment.dsl.DeploymentPackage
import com.avioconsulting.mule.deployment.dsl.MuleDeployContext
import com.avioconsulting.mule.deployment.dsl.MuleDeployScript
Expand All @@ -21,10 +24,10 @@ import java.util.concurrent.Callable
class DeployerCommandLine implements Callable<Integer> {
@Parameters(index = '0', description = 'The path to your DSL file')
private File groovyFile
@Option(names = ['-u', '--anypoint-username'], required = true)
private String anypointUsername
@Option(names = ['-p', '--anypoint-password'], required = true)
private String anypointPassword

@CommandLine.ArgGroup(exclusive = false, multiplicity = "1")
CredentialOptGroup credential;

@Option(names = ['-o', '--anypoint-org-name'],
description = 'The org/business group to use. If you do not specify it, the default for your user will be used')
private String anypointOrganizationName
Expand All @@ -46,6 +49,44 @@ class DeployerCommandLine implements Callable<Integer> {
private static IDeployerFactory deployerFactory = new DeployerFactory()
private static ILogger logger = new SimpleLogger()

static class CredentialOptGroup {
@CommandLine.ArgGroup(exclusive = false, multiplicity = "0..1", order = 1, heading = "Basic auth credentials of Anypoint Platform%n", headingKey = "Basic Credentials")
UsernamePasswordCredentialOptGroup usernamePasswordCredential

@CommandLine.ArgGroup(exclusive = false, multiplicity = "0..1", order = 2, heading = "Connected App credentials%n", headingKey = "Connected App Credentials")
ConnectedAppCredentialOptGroup connectedAppCredential

Credential getCoreCredential(){
return usernamePasswordCredential != null ? usernamePasswordCredential.getCoreCredential() : connectedAppCredential.getCoreCredential()
}
}

static abstract class BaseCredential {
abstract Credential getCoreCredential()
}
static class UsernamePasswordCredentialOptGroup extends BaseCredential {
@Option(names = ['-u', '--anypoint-username'], required = true, order = 1)
String anypointUsername
@Option(names = ['-p', '--anypoint-password'], required = true, order = 2)
String anypointPassword

Credential getCoreCredential() {
return new UsernamePasswordCredential(anypointUsername,anypointPassword)
}
}

static class ConnectedAppCredentialOptGroup {
@Option(names = ['-caid', '--anypoint-connected-app-id'], required = true, order = 1)
String anypointConnectedAppId
@Option(names = ['-casec', '--anypoint-connected-app-secret'], required = true, order = 2)
String anypointConnectedAppSecret

Credential getCoreCredential() {
return new ConnectedAppCredential(anypointConnectedAppId,anypointConnectedAppSecret)
}
}


static void main(String... args) {
def commandLine = new CommandLine(new DeployerCommandLine())
if (commandLine.versionHelpRequested) {
Expand All @@ -60,8 +101,7 @@ class DeployerCommandLine implements Callable<Integer> {
Integer call() throws Exception {
def deploymentPackage = processDsl()
logger.println "Successfully processed ${groovyFile} through DSL"
def deployer = deployerFactory.create(this.anypointUsername,
this.anypointPassword,
def deployer = deployerFactory.create(this.credential.getCoreCredential(),
logger,
this.dryRunMode,
this.anypointOrganizationName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.avioconsulting.mule.deployment.api.IDeployer
import com.avioconsulting.mule.deployment.api.IDeployerFactory
import com.avioconsulting.mule.deployment.api.ILogger
import com.avioconsulting.mule.deployment.api.models.*
import com.avioconsulting.mule.deployment.api.models.credentials.Credential
import com.avioconsulting.mule.deployment.api.models.policies.Policy
import org.apache.commons.io.FileUtils
import org.junit.BeforeClass
Expand All @@ -25,6 +26,8 @@ class DeployerCommandLineTest implements MavenInvoke {
String groovyFileText,
String user = 'our user',
String pass = 'our pass',
String connId = null,
String connSecret = null,
DryRunMode dryRunMode = DryRunMode.Run,
String orgName = null,
Map<String, String> otherArgs = [:]) {
Expand All @@ -35,14 +38,25 @@ class DeployerCommandLineTest implements MavenInvoke {
groovyFile.text = groovyFileText
}
DeployerCommandLine.deployerFactory = mockDeployerFactory
def args = [
'-u',
"\"${user}\"".toString(),
'-p',
"\"${pass}\"".toString(),
'-m',
dryRunMode.name(),
]
def args
if (connId != null && connSecret != null)
args = [
'-caid',
"\"${connId}\"".toString(),
'-casec',
"\"${connSecret}\"".toString(),
'-m',
dryRunMode.name()
]
else
args = [
'-u',
"\"${user}\"".toString(),
'-p',
"\"${pass}\"".toString(),
'-m',
dryRunMode.name(),
]
if (orgName) {
args += [
'-o',
Expand Down Expand Up @@ -78,8 +92,7 @@ class DeployerCommandLineTest implements MavenInvoke {
}
] as IDeployer
def mock = [
create: { String username,
String password,
create: { Credential credential,
ILogger logger,
DryRunMode dryRunMode,
String anypointOrganizationName,
Expand Down Expand Up @@ -120,6 +133,64 @@ muleDeploy {
}
}

@Test
void runs_with_connected_application() {
// arrange
FileBasedAppDeploymentRequest actualApp
ApiSpecificationList actualApiSpec
List<Features> actualFeatures
def mockDeployer = [
deployApplication: { FileBasedAppDeploymentRequest appDeploymentRequest,
ApiSpecificationList apiSpecification,
List<Policy> desiredPolicies,
List<Features> enabledFeatures ->
actualApp = appDeploymentRequest
actualApiSpec = apiSpecification
actualFeatures = enabledFeatures
}
] as IDeployer
def mock = [
create: { Credential credential,
ILogger logger,
DryRunMode dryRunMode,
String anypointOrganizationName,
List<String> environmentsToDoDesignCenterDeploymentOn ->
return mockDeployer
}
] as IDeployerFactory
def dslText = """
muleDeploy {
version '1.0'

onPremApplication {
environment 'DEV'
applicationName 'the-app'
appVersion '1.2.3'
file '${builtFile}'
targetServerOrClusterName 'theServer'
}
}
"""

// act
executeCommandLine(mock,
dslText)

// assert
assertThat 'No policies since we omitted that section',
actualFeatures,
is(equalTo([Features.AppDeployment, Features.DesignCenterSync, Features.ApiManagerDefinitions]))
assertThat actualApiSpec,
is(equalTo([]))
assert actualApp instanceof OnPremDeploymentRequest
actualApp.with {
assertThat it.appName,
is(equalTo('the-app'))
assertThat it.environment,
is(equalTo('DEV'))
}
}

@Test
void offline_validate() {
// arrange
Expand All @@ -133,8 +204,7 @@ muleDeploy {
}
] as IDeployer
def mock = [
create: { String username,
String password,
create: { Credential credential,
ILogger logger,
DryRunMode dryRunMode,
String anypointOrganizationName,
Expand All @@ -160,6 +230,8 @@ muleDeploy {
dslText,
'user',
'pass',
null,
null,
DryRunMode.OfflineValidate)

// assert
Expand All @@ -180,8 +252,7 @@ muleDeploy {
}
] as IDeployer
def mock = [
create: { String username,
String password,
create: { Credential credential,
ILogger logger,
DryRunMode dryRunMode,
String anypointOrganizationName,
Expand Down Expand Up @@ -216,6 +287,8 @@ muleDeploy {
dslText,
'our user',
'our pass',
null,
null,
DryRunMode.Run,
null,
[
Expand Down Expand Up @@ -243,8 +316,7 @@ muleDeploy {
}
] as IDeployer
def mock = [
create: { String username,
String password,
create: { Credential credential,
ILogger logger,
DryRunMode dryRunMode,
String anypointOrganizationName,
Expand Down Expand Up @@ -274,8 +346,7 @@ muleDeploy {
}
] as IDeployer
def mock = [
create: { String username,
String password,
create: { Credential credential,
ILogger logger,
DryRunMode dryRunMode,
String anypointOrganizationName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.avioconsulting.mule.deployment.api.models.ApiSpecificationList
import com.avioconsulting.mule.deployment.api.models.CloudhubDeploymentRequest
import com.avioconsulting.mule.deployment.api.models.Features
import com.avioconsulting.mule.deployment.api.models.FileBasedAppDeploymentRequest
import com.avioconsulting.mule.deployment.api.models.credentials.Credential
import com.avioconsulting.mule.deployment.api.models.policies.Policy
import com.avioconsulting.mule.deployment.internal.http.EnvironmentLocator
import com.avioconsulting.mule.deployment.internal.http.HttpClientWrapper
Expand All @@ -30,24 +31,21 @@ class Deployer implements IDeployer {

/**
*
* @param username anypoint creds to deploy with
* @param password anypoint creds to deploy with
* @param credential {@link Credential } to access anypoint platform.
* @param logger all messages will be logged like this. This is Jenkins plugins friendly (or you can supply System.out)
* @param dryRunMode Should we do a real run?
* @param anypointOrganizationName Optional parameter. If null, the default organization/biz group for the user will be used. Otherwise supply name (NOT GUID) of the biz group or organization you want to use
* @param baseUrl Base URL, optional
* @param environmentsToDoDesignCenterDeploymentOn Normally workflow wise you'd only want to do this on DEV
*/
Deployer(String username,
String password,
Deployer(Credential credential,
ILogger logger,
DryRunMode dryRunMode,
String anypointOrganizationName = null,
String baseUrl = 'https://anypoint.mulesoft.com',
List<String> environmentsToDoDesignCenterDeploymentOn = ['DEV']) {
this(new HttpClientWrapper(baseUrl,
username,
password,
credential,
logger,
anypointOrganizationName),
dryRunMode,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package com.avioconsulting.mule.deployment.api

import com.avioconsulting.mule.deployment.api.models.credentials.Credential

class DeployerFactory implements IDeployerFactory {
@Override
IDeployer create(String username,
String password,
IDeployer create(Credential credential,
ILogger logger,
DryRunMode dryRunMode,
String anypointOrganizationName,
List<String> environmentsToDoDesignCenterDeploymentOn) {
new Deployer(username,
password,
new Deployer(credential,
logger,
dryRunMode,
anypointOrganizationName,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.avioconsulting.mule.deployment.api

import com.avioconsulting.mule.deployment.api.models.credentials.Credential

interface IDeployerFactory {
IDeployer create(String username,
String password,
IDeployer create(Credential credential,
ILogger logger,
DryRunMode dryRunMode,
String anypointOrganizationName,
Expand Down
Loading