diff --git a/CHANGELOG.md b/CHANGELOG.md index 08a0f8da..a1a4c137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ -## 1.12.2 (TBD) +## 1.12.2 (December 09, 2022) **FEATURES:** * secret/kubernetes: Add kubernetes secrets engine. + * auth/jwt(oidc): Added OIDC methods to get auth url and generate vault token by exchanging auth code. ## 1.8.12 (December 09, 2022) diff --git a/src/VaultSharp/V1/AuthMethods/AuthMethodProvider.cs b/src/VaultSharp/V1/AuthMethods/AuthMethodProvider.cs index 53635a79..4f3ed94b 100644 --- a/src/VaultSharp/V1/AuthMethods/AuthMethodProvider.cs +++ b/src/VaultSharp/V1/AuthMethods/AuthMethodProvider.cs @@ -8,6 +8,7 @@ using VaultSharp.V1.AuthMethods.Cert; using VaultSharp.V1.AuthMethods.CloudFoundry; using VaultSharp.V1.AuthMethods.GitHub; +using VaultSharp.V1.AuthMethods.JWT; using VaultSharp.V1.AuthMethods.Kerberos; using VaultSharp.V1.AuthMethods.Kubernetes; using VaultSharp.V1.AuthMethods.LDAP; @@ -28,6 +29,7 @@ public AuthMethodProvider(Polymath polymath) _polymath = polymath; AppRole = new AppRoleAuthMethodProvider(_polymath); + JWT = new JWTAuthMethodProvider(_polymath); LDAP = new LDAPAuthMethodProvider(_polymath); Okta = new OktaAuthMethodProvider(_polymath); Token = new TokenAuthMethodProvider(_polymath); @@ -47,6 +49,8 @@ public AuthMethodProvider(Polymath polymath) public IGitHubAuthMethod GoogleCloud => throw new NotImplementedException(); + public IJWTAuthMethod JWT { get; } + public IKubernetesAuthMethod Kubernetes => throw new NotImplementedException(); public ILDAPAuthMethod LDAP { get; } diff --git a/src/VaultSharp/V1/AuthMethods/IAuthMethod.cs b/src/VaultSharp/V1/AuthMethods/IAuthMethod.cs index 7d8e0463..c627aedf 100644 --- a/src/VaultSharp/V1/AuthMethods/IAuthMethod.cs +++ b/src/VaultSharp/V1/AuthMethods/IAuthMethod.cs @@ -6,6 +6,7 @@ using VaultSharp.V1.AuthMethods.Cert; using VaultSharp.V1.AuthMethods.CloudFoundry; using VaultSharp.V1.AuthMethods.GitHub; +using VaultSharp.V1.AuthMethods.JWT; using VaultSharp.V1.AuthMethods.Kerberos; using VaultSharp.V1.AuthMethods.Kubernetes; using VaultSharp.V1.AuthMethods.LDAP; @@ -57,6 +58,8 @@ public interface IAuthMethod /// IGitHubAuthMethod GoogleCloud { get; } + IJWTAuthMethod JWT { get; } + /// /// /// diff --git a/src/VaultSharp/V1/AuthMethods/JWT/IJWTAuthMethod.cs b/src/VaultSharp/V1/AuthMethods/JWT/IJWTAuthMethod.cs index 767c6a69..e521b986 100644 --- a/src/VaultSharp/V1/AuthMethods/JWT/IJWTAuthMethod.cs +++ b/src/VaultSharp/V1/AuthMethods/JWT/IJWTAuthMethod.cs @@ -1,9 +1,67 @@ -namespace VaultSharp.V1.AuthMethods.JWT +using System.Threading.Tasks; +using VaultSharp.V1.AuthMethods.JWT.Models; +using VaultSharp.V1.Commons; + +namespace VaultSharp.V1.AuthMethods.JWT { /// - /// + /// Non Login methods /// public interface IJWTAuthMethod { + /// + /// Obtain an authorization URL from Vault to start an OIDC login flow. + /// + /// + /// [required] + /// Path to the callback to complete the login. + /// This will be of the form, "https://.../oidc/callback" where the leading portion is dependent on + /// your Vault server location, port, and the mount of the JWT plugin. + /// This must be configured with Vault and the provider. + /// + /// + /// [optional] + /// Name of the role against which the login is being attempted. + /// Defaults to configured default_role if not provided. + /// + /// + /// [optional] + /// Optional client-provided nonce that must match the client_nonce value provided + /// during a subsequent request to the callback API. + /// + /// + /// Mount point of the JWT Auth method + /// + /// The OIDC Auth URL + Task> GetOIDCAuthURLAsync(string redirectUri, string roleName = null, string clientNonce = null, string mountPoint = AuthMethodDefaultPaths.JWT); + + /// + /// Exchange an authorization code for an OIDC ID Token. + /// The ID token will be further validated against any bound claims, and if valid a Vault token will be returned. + /// + /// + /// [required] + /// Opaque state ID that is part of the Authorization URL and will be included in + /// the the redirect following successful authentication on the provider. + /// + /// + /// [required] + /// Opaque nonce that is part of the Authorization URL and will be + /// included in the the redirect following successful authentication on the provider. + /// + /// + /// [required] + /// Provider-generated authorization code that Vault will exchange for an ID token. + /// + /// + /// [optional] + /// Optional client-provided nonce that must match the client_nonce value + /// provided during the prior request to the auth API. + /// + /// + /// Mount point of the JWT Auth method + /// + /// The OIDC Vault Token + Task> DoOIDCCallbackAsync(string state, string nonce, string code, string clientNonce = null, string mountPoint = AuthMethodDefaultPaths.JWT); } } \ No newline at end of file diff --git a/src/VaultSharp/V1/AuthMethods/JWT/JWTAuthMethodProvider.cs b/src/VaultSharp/V1/AuthMethods/JWT/JWTAuthMethodProvider.cs new file mode 100644 index 00000000..bcee5e02 --- /dev/null +++ b/src/VaultSharp/V1/AuthMethods/JWT/JWTAuthMethodProvider.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using VaultSharp.Core; +using VaultSharp.V1.AuthMethods.JWT.Models; +using VaultSharp.V1.Commons; + +namespace VaultSharp.V1.AuthMethods.JWT +{ + internal class JWTAuthMethodProvider : IJWTAuthMethod + { + private readonly Polymath _polymath; + + public JWTAuthMethodProvider(Polymath polymath) + { + Checker.NotNull(polymath, "polymath"); + this._polymath = polymath; + } + + public async Task> GetOIDCAuthURLAsync(string redirectUri, string roleName = null, string clientNonce = null, string mountPoint = AuthMethodDefaultPaths.JWT) + { + Checker.NotNull(mountPoint, "mountPoint"); + Checker.NotNull(redirectUri, "redirectUri"); + + var requestData = new Dictionary + { + { "redirect_uri", redirectUri } + }; + + if (!string.IsNullOrWhiteSpace(roleName)) + { + requestData.Add("role", roleName); + } + + if (!string.IsNullOrWhiteSpace(clientNonce)) + { + requestData.Add("client_nonce", clientNonce); + } + + return await _polymath.MakeVaultApiRequest>("v1/auth/" + mountPoint.Trim('/') + "/oidc/auth_url", HttpMethod.Post, requestData: requestData).ConfigureAwait(_polymath.VaultClientSettings.ContinueAsyncTasksOnCapturedContext); + } + + public async Task> DoOIDCCallbackAsync(string state, string nonce, string code, string clientNonce = null, string mountPoint = AuthMethodDefaultPaths.JWT) + { + Checker.NotNull(state, "state"); + Checker.NotNull(nonce, "nonce"); + Checker.NotNull(code, "code"); + + Checker.NotNull(mountPoint, "mountPoint"); + + var queryStrings = new List + { + "state=" + state, + "nonce=" + nonce, + "code=" + code + }; + + if (!string.IsNullOrWhiteSpace(clientNonce)) + { + queryStrings.Add("client_nonce=" + clientNonce); + } + + var queryString = "?" + string.Join("&", queryStrings); + + return await _polymath.MakeVaultApiRequest>("v1/auth/" + mountPoint.Trim('/') + "/oidc/callback" + queryString, HttpMethod.Get).ConfigureAwait(_polymath.VaultClientSettings.ContinueAsyncTasksOnCapturedContext); + } + } +} \ No newline at end of file diff --git a/src/VaultSharp/V1/AuthMethods/JWT/Models/OIDCAuthURLInfo.cs b/src/VaultSharp/V1/AuthMethods/JWT/Models/OIDCAuthURLInfo.cs new file mode 100644 index 00000000..0f7363b7 --- /dev/null +++ b/src/VaultSharp/V1/AuthMethods/JWT/Models/OIDCAuthURLInfo.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace VaultSharp.V1.AuthMethods.JWT.Models +{ + public class OIDCAuthURLInfo + { + [JsonProperty("auth_url")] + public string AuthorizationURL { get; set; } + } +} \ No newline at end of file