Skip to content
This repository was archived by the owner on Nov 14, 2024. It is now read-only.

Commit 9c41f64

Browse files
MichielVanwelsenaeretomkerkhoveMichiel Vanwelsenaere
authored
Provide support for authentication with access token (#59)
Co-authored-by: Tom Kerkhove <kerkhove.tom@gmail.com> Co-authored-by: Michiel Vanwelsenaere <Michiel.Vanwelsenaere@codit.eu>
1 parent cd87db0 commit 9c41f64

File tree

6 files changed

+115
-4
lines changed

6 files changed

+115
-4
lines changed

build/ci-build.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ stages:
7474
inputs:
7575
artifact: 'Build'
7676
path: '$(Build.SourcesDirectory)'
77+
- task: AzureCLI@2
78+
displayName: 'Get Token for Azure Management API'
79+
inputs:
80+
azureSubscription: 'Invictus - Azure'
81+
scriptType: pscore
82+
scriptLocation: inlineScript
83+
inlineScript: |
84+
$token= & az account get-access-token --resource="https://management.azure.com/" --query accessToken
85+
Write-Host "##vso[task.setvariable variable=Azure.ManagementApi.AccessToken]$token"
7786
- template: test/run-integration-tests.yml@templates
7887
parameters:
7988
dotnetSdkVersion: '$(DotNet.Sdk.Version)'

docs/logic-apps/authentication.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ Before you can start using the Azure Logic App testing features, you need to aut
66

77
As of today, we provide the following authentication scenarios:
88

9+
- [**Prerequisites**](#Prerequisites)
910
- [**Using Service Principal**](#using-a-service-principal)
11+
- [**Using an Access Token**](#using-an-Access-Token)
1012

11-
## Using a Service Principal
13+
## Prerequisites
1214

1315
Before we can authenticate, you'll need to [create an Azure AD application](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal) which will be used as your service principle.
1416

1517
The service principal will need to have at least [`Logic App Contributor`](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#logic-app-contributor) permissions on all your Azure Logic App instances that you want to test.
1618

19+
## Using a Service Principal
20+
1721
When using a service principal, you need to provide the following information:
1822
- **Tenant Id** - Identifier of the Azure AD directory
1923
- **Subscription Id** - Identifier of the Azure subscription that contains your Azure Logic App
@@ -39,3 +43,31 @@ using (var logicApp = await LogicAppClient.CreateAsync(resourceGroup, logicAppNa
3943
{
4044
}
4145
```
46+
47+
## Using an Access Token
48+
49+
The main purpose of authenticating using a token is to avoid distributing sensitive service principle details. As the testing framework uses the Azure Management API, the `resource` scope when requesting a access token should be set to `https://management.azure.com/`.
50+
51+
*More details on requesting a token can be found [here](https://docs.microsoft.com/en-us/rest/api/azure/#acquire-an-access-token).*
52+
53+
When using a service principal, you need to provide the following information:
54+
- **Tenant Id** - Identifier of the Azure AD directory
55+
- **Access Token** - The token to be used to authenticate with the Azure Management API
56+
57+
Here is an example:
58+
```csharp
59+
string subscriptionId = "my-subscription-id";
60+
string accessToken = "my-accessToken";
61+
string resourceGroup = "my-resource-group";
62+
string logicAppName = "my-logic-app-name";
63+
64+
var authentication = LogicAppAuthentication.UsingAccessToken(subscriptionId, accessToken);
65+
66+
// For the Logic App provider
67+
var provider = LogicAppsProvider.LocatedAt(resourceGroupName, logicAppName, authentication);
68+
69+
// For the Logic App client
70+
using (var logicApp = await LogicAppClient.CreateAsync(resourceGroup, logicAppName, authentication))
71+
{
72+
}
73+
```

src/Invictus.Testing.LogicApps/LogicAppAuthentication.cs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,41 @@ public static LogicAppAuthentication UsingServicePrincipal(string tenantId, stri
6666
() => AuthenticateLogicAppsManagementAsync(subscriptionId, tenantId, clientId, clientSecret));
6767
}
6868

69+
/// <summary>
70+
/// Uses a accessToken to authenticate with Azure.
71+
/// </summary>
72+
/// <param name="subscriptionId">The ID that identifies the subscription on Azure.</param>
73+
/// <param name="accessToken">The token to use to call the Azure management API.</param>
74+
public static LogicAppAuthentication UsingAccessToken(string subscriptionId, string accessToken)
75+
{
76+
Guard.NotNullOrWhitespace(subscriptionId, nameof(subscriptionId));
77+
Guard.NotNullOrWhitespace(accessToken, nameof(accessToken));
78+
79+
return new LogicAppAuthentication(
80+
() => AuthenticateLogicAppsManagementAsync(subscriptionId, accessToken));
81+
}
82+
83+
/// <summary>
84+
/// Uses an access token to authenticate with Azure.
85+
/// </summary>
86+
/// <param name="subscriptionId">The ID that identifies the subscription on Azure.</param>
87+
/// <param name="accessTokenKey">The secret key to use to fetch access token from the secret provider. This will be used to call the Azure management API.</param>
88+
/// <param name="secretProvider">The provider to get the client secret; using the <paramref name="accessTokenKey"/>.</param>
89+
public static LogicAppAuthentication UsingAccessToken(string subscriptionId, string accessTokenKey, ISecretProvider secretProvider)
90+
{
91+
Guard.NotNullOrWhitespace(subscriptionId, nameof(subscriptionId));
92+
Guard.NotNullOrWhitespace(accessTokenKey, nameof(accessTokenKey));
93+
Guard.NotNull(secretProvider, nameof(secretProvider));
94+
95+
return new LogicAppAuthentication(async () =>
96+
{
97+
string accessToken = await secretProvider.GetRawSecretAsync(accessTokenKey);
98+
LogicManagementClient managementClient = await AuthenticateLogicAppsManagementAsync(subscriptionId, accessToken);
99+
100+
return managementClient;
101+
});
102+
}
103+
69104
/// <summary>
70105
/// Authenticate with Azure with the previously chosen authentication mechanism.
71106
/// </summary>
@@ -86,10 +121,18 @@ private static async Task<LogicManagementClient> AuthenticateLogicAppsManagement
86121

87122
AuthenticationResult token = await authContext.AcquireTokenAsync("https://management.azure.com/", credential);
88123

89-
return new LogicManagementClient(new TokenCredentials(token.AccessToken))
124+
return await AuthenticateLogicAppsManagementAsync(subscriptionId, token.AccessToken);
125+
}
126+
127+
private static async Task<LogicManagementClient> AuthenticateLogicAppsManagementAsync(string subscriptionId, string accessToken)
128+
{
129+
Guard.NotNullOrWhitespace(subscriptionId, nameof(subscriptionId));
130+
Guard.NotNullOrWhitespace(accessToken, nameof(accessToken));
131+
132+
return new LogicManagementClient(new TokenCredentials(accessToken))
90133
{
91134
SubscriptionId = subscriptionId
92135
};
93136
}
94137
}
95-
}
138+
}

src/Invictus.Testing.Tests.Integration/LogicAppAuthenticationTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.Azure.Management.Logic;
99
using Xunit;
1010
using Xunit.Abstractions;
11+
using Microsoft.IdentityModel.Clients.ActiveDirectory;
1112

1213
namespace Invictus.Testing.Tests.Integration
1314
{
@@ -43,6 +44,23 @@ public async Task AuthenticateLogicAppManagement_UsingSecretProvider_Succeeds()
4344
Assert.True(_isClientSecretRequested);
4445
}
4546

47+
[Fact]
48+
public async Task AuthenticateLogicAppManagement_UsingAccessToken_Succeeds()
49+
{
50+
// Arrange
51+
string subscriptionId = Configuration.GetAzureSubscriptionId();
52+
string accessToken = Configuration.GetAzureAccessToken();
53+
54+
var authentication = LogicAppAuthentication.UsingAccessToken(subscriptionId, accessToken);
55+
56+
// Act
57+
using (LogicManagementClient managementClient = await authentication.AuthenticateAsync())
58+
{
59+
// Assert
60+
Assert.NotNull(managementClient);
61+
}
62+
}
63+
4664
public Task<string> GetRawSecretAsync(string secretName)
4765
{
4866
Guard.For<ArgumentException>(() => !secretName.Equals(ClientSecretKey), "Should request for correct client secret key");

src/Invictus.Testing.Tests.Integration/TestConfig.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ public string GetAzureClientSecret()
104104
return GetRequiredValue("Azure:Authentication:ClientSecret");
105105
}
106106

107+
/// <summary>
108+
/// Gets the access token of the application registered to authenticate with the Azure Logic Apps.
109+
/// </summary>
110+
public string GetAzureAccessToken()
111+
{
112+
return GetRequiredValue("Azure:Authentication:AccessToken");
113+
}
114+
107115
private string GetRequiredValue(string key)
108116
{
109117
string value = _configuration[key];

src/Invictus.Testing.Tests.Integration/appsettings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77
"Authentication": {
88
"ClientId": "#{LogicApps.ClientId}#",
9-
"ClientSecret": "#{LogicApps.ClientSecret}#"
9+
"ClientSecret": "#{LogicApps.ClientSecret}#",
10+
"AccessToken": "#{Azure.ManagementApi.AccessToken}#"
1011
},
1112

1213
"LogicApps": {

0 commit comments

Comments
 (0)