Skip to content

Commit

Permalink
fixes #120 cf auth method support
Browse files Browse the repository at this point in the history
  • Loading branch information
rajanadar committed Apr 23, 2020
1 parent 4b52704 commit af8b026
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 137 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
By default, the ```Authorization: Bearer <vault-token>``` scheme is used.
You can override it using the ```VaultClientSettings.UseVaultTokenHeaderInsteadOfAuthorizationHeader``` flag.
* [GH-71] SSK Key Signing
* [GH-122] CloudFoundry Auth Method: Support for CloudFoundry login tokens including ability to create signatures.

**BREAKING CHANGES:**

Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,30 @@ IVaultClient vaultClient = new VaultClient(vaultClientSettings);
// vault token/policies mapped to the azure jwt
```

#### CloudFoundry Auth Method

```cs
// setup the CloudFoundry based auth to get the right token.
IAuthMethodInfo authMethod = new CloudFoundryAuthMethodInfo(roleName, instanceCertContent, instanceKeyContent);
var vaultClientSettings = new VaultClientSettings("https://MY_VAULT_SERVER:8200", authMethod);

IVaultClient vaultClient = new VaultClient(vaultClientSettings);

// any operations done using the vaultClient will use the
// vault token/policies mapped to the CloudFoundry jwt
```

##### CloudFoundry Signature Creation

- VaultSharp also provides a helper class to generate on-demand CloudFoundry signature.
- Use the ```CloudFoundrySignatureProvider``` class as follows

```cs
var signing_time = CloudFoundrySignatureProvider.GetFormattedSigningTime(DateTime.UtcNow);
var signature = CloudFoundrySignatureProvider.GetSignature(signingTime, cfInstanceCertContent, roleName, cfInstanceKeyContent);
```

#### GitHub Auth Method

```cs
Expand Down
3 changes: 3 additions & 0 deletions src/VaultSharp/V1/AuthMethods/AuthMethodProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using VaultSharp.V1.AuthMethods.AWS;
using VaultSharp.V1.AuthMethods.Azure;
using VaultSharp.V1.AuthMethods.Cert;
using VaultSharp.V1.AuthMethods.CloudFoundry;
using VaultSharp.V1.AuthMethods.GitHub;
using VaultSharp.V1.AuthMethods.Kerberos;
using VaultSharp.V1.AuthMethods.Kubernetes;
Expand Down Expand Up @@ -35,6 +36,8 @@ public AuthMethodProvider(Polymath polymath)

public IAzureAuthMethod Azure => throw new NotImplementedException();

public ICloudFoundryAuthMethod CloudFoundry => throw new NotImplementedException();

public IGitHubAuthMethod GitHub => throw new NotImplementedException();

public IGitHubAuthMethod GoogleCloud => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
using Newtonsoft.Json;
using VaultSharp.Core;
using VaultSharp.V1.AuthMethods.CloudFoundry.Signature;
using VaultSharp.Core;

namespace VaultSharp.V1.AuthMethods.CloudFoundry
{
public class CloudFoundryAuthMethodInfo : AbstractAuthMethodInfo
{
[JsonIgnore]
public override AuthMethodType AuthMethodType => AuthMethodType.CloudFoundry;

/// <summary>
Expand All @@ -16,7 +13,6 @@ public class CloudFoundryAuthMethodInfo : AbstractAuthMethodInfo
/// <value>
/// The mount point.
/// </value>
[JsonIgnore]
public string MountPoint { get; }

/// <summary>
Expand All @@ -26,32 +22,34 @@ public class CloudFoundryAuthMethodInfo : AbstractAuthMethodInfo
/// <value>
/// The role name.
/// </value>
[JsonProperty("role")]
public string RoleName { get; }

/// <summary>
/// [required]
/// Gets the Signature for getting a token for a service account.
/// The full body of the file available at the path denoted by CF_INSTANCE_CERT.
/// </summary>
/// <value>
/// The Signature.
/// </value>
[JsonProperty("signature")]
public CloudFoundrySignature Signature { get; }
public string CFInstanceCertContent { get; }

/// <summary>
/// [required]
/// The full body of the file available at the path denoted by CF_INSTANCE_KEY.
/// </summary>
public string CFInstanceKeyContent { get; }

/// <summary>
/// Initializes a new instance of the <see cref="CloudFoundryAuthMethodInfo"/> class.
/// </summary>
/// <param name="roleName">[required]
/// The name of the role against which the login is being attempted.
/// </param>
/// <param name="signature">
/// [required]
/// Gets the Signature for getting a token for a service account.
/// <param name="instanceCertContent">[required]
/// The full body of the file available at the path denoted by CF_INSTANCE_CERT.
/// </param>
/// <param name="instanceKeyContent">[required]
/// The full body of the file available at the path denoted by CF_INSTANCE_KEY.
/// </param>
public CloudFoundryAuthMethodInfo(string roleName, CloudFoundrySignature signature)
: this(AuthMethodType.CloudFoundry.Type, roleName, signature)
public CloudFoundryAuthMethodInfo(string roleName, string instanceCertContent, string instanceKeyContent)
: this(AuthMethodType.CloudFoundry.Type, roleName, instanceCertContent, instanceKeyContent)
{
}

Expand All @@ -62,20 +60,23 @@ public CloudFoundryAuthMethodInfo(string roleName, CloudFoundrySignature signatu
/// <param name="roleName">[required]
/// The name of the role against which the login is being attempted.
/// </param>
/// <param name="signature">
/// [required]
/// Gets the Signature for getting a token for a service account.
/// <param name="instanceCertContent">[required]
/// The full body of the file available at the path denoted by CF_INSTANCE_CERT.
/// </param>

public CloudFoundryAuthMethodInfo(string mountPoint, string roleName, CloudFoundrySignature signature)
/// <param name="instanceKeyContent">[required]
/// The full body of the file available at the path denoted by CF_INSTANCE_KEY.
/// </param>
public CloudFoundryAuthMethodInfo(string mountPoint, string roleName, string instanceCertContent, string instanceKeyContent)
{
Checker.NotNull(mountPoint, "mountPoint");
Checker.NotNull(roleName, "roleName");
Checker.NotNull(signature, "signature");
Checker.NotNull(instanceCertContent, "instanceCertContent");
Checker.NotNull(instanceKeyContent, "instanceKeyContent");

MountPoint = mountPoint;
RoleName = roleName;
Signature = signature;
CFInstanceCertContent = instanceCertContent;
CFInstanceKeyContent = instanceKeyContent;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
using System.Net.Http;
using System.Threading.Tasks;
using VaultSharp.Core;
using VaultSharp.V1.AuthMethods.CloudFoundry.Signature;
using VaultSharp.V1.Commons;

namespace VaultSharp.V1.AuthMethods.CloudFoundry
{
internal class CloudFoundryAuthMethodLoginProvider : IAuthMethodLoginProvider
{
private readonly CloudFoundryAuthMethodInfo _cloudFoundryAuthMethodInfo;
private readonly Polymath _polymath;

private readonly Polymath _polymath;

public CloudFoundryAuthMethodLoginProvider(CloudFoundryAuthMethodInfo cloudFoundryAuthMethodInfo, Polymath polymath)
{
Expand All @@ -23,10 +23,21 @@ public CloudFoundryAuthMethodLoginProvider(CloudFoundryAuthMethodInfo cloudFound

public async Task<string> GetVaultTokenAsync()
{
var requestData = _cloudFoundryAuthMethodInfo.Signature;
var signingTime = DateTime.UtcNow;
var signature = CloudFoundrySignatureProvider.GetSignature(signingTime, _cloudFoundryAuthMethodInfo.CFInstanceCertContent, _cloudFoundryAuthMethodInfo.RoleName, _cloudFoundryAuthMethodInfo.CFInstanceKeyContent);

var requestData = new
{
role = _cloudFoundryAuthMethodInfo.RoleName,
cf_instance_cert = _cloudFoundryAuthMethodInfo.CFInstanceCertContent,
signing_time = CloudFoundrySignatureProvider.GetFormattedSigningTime(signingTime),
signature
};

// make an unauthenticated call to Vault, since this is the call to get the token. It shouldn't need a token.
// make an unauthenticated call to Vault, since this is the call to get the token.
// It shouldn't need a token.
var response = await _polymath.MakeVaultApiRequest<Secret<Dictionary<string, object>>>(LoginResourcePath, HttpMethod.Post, requestData, unauthenticated: true).ConfigureAwait(_polymath.VaultClientSettings.ContinueAsyncTasksOnCapturedContext);

_cloudFoundryAuthMethodInfo.ReturnedLoginAuthInfo = response?.AuthInfo;

if (response?.AuthInfo != null && !string.IsNullOrWhiteSpace(response.AuthInfo.ClientToken))
Expand All @@ -35,7 +46,6 @@ public async Task<string> GetVaultTokenAsync()
}

throw new Exception("The call to the Vault authentication method backend did not yield a client token. Please verify your credentials.");

}

private string LoginResourcePath
Expand All @@ -46,8 +56,5 @@ private string LoginResourcePath
return endpoint;
}
}



}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Utilities.IO.Pem;

namespace VaultSharp.V1.AuthMethods.CloudFoundry.Signature
{
public class CloudFoundrySignatureProvider
{
public static string GetSignature(DateTime dateTime, string cfInstanceCertContent, string roleName, string cfInstanceKeyContent)
{
var formattedSigningTime = GetFormattedSigningTime(dateTime);
var stringToSign = $"{formattedSigningTime}{cfInstanceCertContent}{roleName}";

var data = Encoding.UTF8.GetBytes(stringToSign);

byte[] keyBytes;

using (var reader = new StringReader(cfInstanceKeyContent))
{
var pemReader = new PemReader(reader);
var pemObject = pemReader.ReadPemObject();
keyBytes = pemObject.Content;
}

var seq = (Asn1Sequence)Asn1Object.FromByteArray(keyBytes);
var rsa = RsaPrivateKeyStructure.GetInstance(seq);

var signer = new PssSigner(new RsaEngine(), new Sha256Digest(), 222);
signer.Init(true, new RsaKeyParameters(true, rsa.Modulus, rsa.PrivateExponent));
signer.BlockUpdate(data, 0, data.Length);
var signature = signer.GenerateSignature();

return $"v1:{Convert.ToBase64String(signature)}";
}

public static string GetFormattedSigningTime(DateTime signingTime)
{
return signingTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
}
}
}

This file was deleted.

This file was deleted.

6 changes: 6 additions & 0 deletions src/VaultSharp/V1/AuthMethods/IAuthMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using VaultSharp.V1.AuthMethods.AWS;
using VaultSharp.V1.AuthMethods.Azure;
using VaultSharp.V1.AuthMethods.Cert;
using VaultSharp.V1.AuthMethods.CloudFoundry;
using VaultSharp.V1.AuthMethods.GitHub;
using VaultSharp.V1.AuthMethods.Kerberos;
using VaultSharp.V1.AuthMethods.Kubernetes;
Expand Down Expand Up @@ -39,6 +40,11 @@ public interface IAuthMethod
/// </summary>
IAzureAuthMethod Azure { get; }

/// <summary>
///
/// </summary>
ICloudFoundryAuthMethod CloudFoundry { get; }

/// <summary>
/// Hmm.
/// </summary>
Expand Down

0 comments on commit af8b026

Please sign in to comment.