Skip to content

Commit

Permalink
feat(core): implement EnvCredentialProvider to obtain credentials f…
Browse files Browse the repository at this point in the history
…rom env variables (#14)

closes #11
  • Loading branch information
derevnjuk authored Nov 7, 2022
1 parent 9dd2d1e commit 3b720e0
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 4 deletions.
12 changes: 11 additions & 1 deletion src/SecTester.Core/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using SecTester.Core.CredentialProviders;
using SecTester.Core.Utils;

namespace SecTester.Core
Expand All @@ -29,12 +30,21 @@ public class Configuration

public Configuration(string? hostname, Credentials? credentials = null, List<CredentialProvider>? credentialProviders = null)
{
credentialProviders ??= new List<CredentialProvider> { new EnvCredentialProvider() };
hostname = hostname?.Trim();
hostname = hostname ?? throw new ArgumentNullException(nameof(hostname), "Please provide 'hostname' option.");

ResolveUrls(hostname);

if (credentials == null && (credentialProviders == null || !credentialProviders.Any()))
{
throw new InvalidOperationException(
$"Please provide either '{nameof(credentials)}' or '{nameof(credentialProviders)}'"
);
}

Credentials = credentials;
_credentialProviders = credentialProviders ?? new List<CredentialProvider>();
_credentialProviders = credentialProviders;
}

public async Task LoadCredentials()
Expand Down
16 changes: 16 additions & 0 deletions src/SecTester.Core/CredentialProviders/EnvCredentialProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Threading.Tasks;

namespace SecTester.Core.CredentialProviders;

public class EnvCredentialProvider : CredentialProvider
{
public const string BrightToken = "BRIGHT_TOKEN";

public Task<Credentials?> Get()
{
string token = Environment.GetEnvironmentVariable(BrightToken);

return Task.FromResult(!string.IsNullOrWhiteSpace(token) ? new Credentials(token) : null);
}
}
95 changes: 94 additions & 1 deletion src/SecTester.Core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,100 @@ $ dotnet add package SecTester.Core

## Usage

_TBU_
### Configuration

First, you need to generate a new instance of `Configuration`.

```csharp
var config = new Configuration(
hostname: "app.neuralegion.com",
credentials: new Credentials("your API key"));
```

You can also register the configuration using the dependency injection framework providing information that will be used to construct other clients.

```csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddSecTesterConfig("app.neuralegion.com");
// or
services.AddSecTesterConfig(config);
}
```

#### Options

Configuration can be customized using the following options:

```csharp
public interface ConfigurationOptions {
string hostname
{
get;
}
Credentials? credentials
{
get;
}
List<CredentialProvider>? credentialProviders
{
get;
}
}
```

The default configuration is as follows:

```csharp
{
credentialProviders = new List<CredentialProvider> { new EnvCredentialProvider() }
}
```

#### hostname

- type: `string`

Set the application name (domain name), that is used to establish connection with.

```csharp
var config = new Configuration(hostname: "app.neuralegion.com");
```

#### credentials

- type: `Credentials`

Set credentials to access the application.

```csharp
var config = new Configuration(
// ...
credentials: new Credential("your API key"));
```

More info about [setting up an API key](https://docs.brightsec.com/docs/manage-your-personal-account#manage-your-personal-api-keys-authentication-tokens)

#### credentialProviders

- type: `CredentialProvider[]`

Allows you to provide credentials and load it in runtime. The configuration will invoke one provider at a time and only
continue to the next if no credentials have been located. For example, if the process finds values defined via
the `BRIGHT_TOKEN` environment variables, the file at `.sectesterrc` will not be read.

#### EnvCredentialProvider

Use this provider to read credentials from the following environment variable: `BRIGHT_TOKEN`

If the `BRIGHT_TOKEN` environment variable is not set or contains a falsy value, it will return undefined.

```csharp
var credentialsProvider = new EnvCredentialProvider();
var config = new Configuration(
// ...
credentialProviders: new List<CredentialProvider> { credentialsProvider });
```

## License

Expand Down
1 change: 1 addition & 0 deletions src/SecTester.Core/SecTester.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</PropertyGroup>

<ItemGroup>
<Folder Include="CredentialProviders" />
<Folder Include="Extensions" />
</ItemGroup>
</Project>
17 changes: 15 additions & 2 deletions test/SecTester.Core.Tests/ConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ public void Configuration_HostnameIsInvalid_ThrowError()
act.Should().Throw<Exception>();
}

[Fact]
public void Configuration_CredentialsOrCredentialProvidersNoDefined_ThrowError()
{
// arrange
const string hostname = "app.neuralegion.com";

// act
Action act = () => new Configuration(hostname, credentials: null, credentialProviders: new List<CredentialProvider>());

// assert
act.Should().Throw<Exception>();
}

[Theory]
[MemberData(nameof(Hostnames))]
public void Configuration_ValidHostname_ResolveApiAndBus(string input, object address)
Expand Down Expand Up @@ -81,7 +94,7 @@ public async Task LoadCredentials_GivenProvider_LoadCredentials()
var credentialProviders = new List<CredentialProvider> { сredentialProvider };
var configuration = new Configuration(hostname: "app.neuralegion.com", credentialProviders: credentialProviders);

сredentialProvider.Get().Returns(Task.FromResult(credentials));
сredentialProvider.Get()!.Returns(Task.FromResult(credentials));

// act
await configuration.LoadCredentials();
Expand Down Expand Up @@ -115,7 +128,7 @@ public async Task LoadCredentials_MultipleProviders_SetCredentialsFromFirst()
var credentialProviders = new List<CredentialProvider> { сredentialProvider, сredentialProvider, сredentialProvider };
var configuration = new Configuration(hostname: "app.neuralegion.com", credentialProviders: credentialProviders);

сredentialProvider.Get().Returns(Task.FromResult<Credentials?>(null), Task.FromResult(credentials1), Task.FromResult(credentials2));
сredentialProvider.Get()!.Returns(Task.FromResult<Credentials?>(null)!, Task.FromResult(credentials1), Task.FromResult(credentials2));

// act
await configuration.LoadCredentials();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using SecTester.Core.CredentialProviders;

namespace SecTester.Core.Tests.CredentialProviders;

public class EnvCredentialProviderTests
{
[Fact]
public async Task Get_EnvVariableIsNotProvided_ReturnNull()
{
// arrange
var envCredentialProvider = new EnvCredentialProvider();

// act
var result = await envCredentialProvider.Get();

// assert
result.Should().BeNull();
}

[Fact]
public async Task Get_GivenEnvVariable_ReturnCredentials()
{
var oldValue = Environment.GetEnvironmentVariable(EnvCredentialProvider.BrightToken);

try
{
// arrange
const string token = "0zmcwpe.nexr.0vlon8mp7lvxzjuvgjy88olrhadhiukk";
Environment.SetEnvironmentVariable(EnvCredentialProvider.BrightToken, token);
var envCredentialProvider = new EnvCredentialProvider();

// act
var result = await envCredentialProvider.Get();

// assert
result.Should().BeEquivalentTo(new { Token = token });
}
finally
{
Environment.SetEnvironmentVariable(EnvCredentialProvider.BrightToken, oldValue);
}

}
}
5 changes: 5 additions & 0 deletions test/SecTester.Core.Tests/SecTester.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@
<ItemGroup>
<ProjectReference Include="..\..\src\SecTester.Core\SecTester.Core.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="CredentialProviders" />
<Folder Include="Extensions" />
</ItemGroup>
</Project>

0 comments on commit 3b720e0

Please sign in to comment.