From 939f53e3d157cbee731376d2e4d7abf2afa3b83f Mon Sep 17 00:00:00 2001 From: "Yevgen Kreshchenko (ykreshch)" Date: Tue, 23 Apr 2024 14:17:12 -0400 Subject: [PATCH] Moving the issuer parameter to the ClientBuilder and renaming it to audienceIssuer --- DuoUniversal.Tests/TestGenerateAuthUrl.cs | 9 ++++--- DuoUniversal/Client.cs | 32 ++++++++++++++++------- DuoUniversal/Labels.cs | 2 +- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/DuoUniversal.Tests/TestGenerateAuthUrl.cs b/DuoUniversal.Tests/TestGenerateAuthUrl.cs index 7e6dc00..c62a58d 100644 --- a/DuoUniversal.Tests/TestGenerateAuthUrl.cs +++ b/DuoUniversal.Tests/TestGenerateAuthUrl.cs @@ -36,7 +36,8 @@ public void TestSuccess(string username) [TestCase("user@foo.bar")] public void TestSuccessWithIssuer(string username) { - string authUri = client.GenerateAuthUri(username, STATE, "http://issuer"); + Client clientWithIssuer = new ClientBuilder(CLIENT_ID, CLIENT_SECRET, API_HOST, REDIRECT_URI).UseAudienceIssuer("http://issuer").Build(); + string authUri = clientWithIssuer.GenerateAuthUri(username, STATE); Assert.True(Uri.IsWellFormedUriString(authUri, UriKind.Absolute)); Assert.True(authUri.StartsWith($"https://{API_HOST}")); } @@ -45,14 +46,16 @@ public void TestSuccessWithIssuer(string username) [TestCase(" ")] public void TestInvalidIssuer(string issuer) { - Assert.Throws(() => client.GenerateAuthUri("username", STATE, issuer)); + Client clientWithIssuer = new ClientBuilder(CLIENT_ID, CLIENT_SECRET, API_HOST, REDIRECT_URI).UseAudienceIssuer(issuer).Build(); + Assert.Throws(() => clientWithIssuer.GenerateAuthUri("username", STATE)); } [Test] [TestCase(null)] public void TestNullIssuer(string issuer) { - string authUri = client.GenerateAuthUri("username", STATE, issuer); + Client clientWithIssuer = new ClientBuilder(CLIENT_ID, CLIENT_SECRET, API_HOST, REDIRECT_URI).UseAudienceIssuer(issuer).Build(); + string authUri = clientWithIssuer.GenerateAuthUri("username", STATE); Assert.True(Uri.IsWellFormedUriString(authUri, UriKind.Absolute)); } diff --git a/DuoUniversal/Client.cs b/DuoUniversal/Client.cs index 22d1027..3846922 100644 --- a/DuoUniversal/Client.cs +++ b/DuoUniversal/Client.cs @@ -39,6 +39,8 @@ public class Client internal bool UseDuoCodeAttribute { get; set; } = false; + internal string AudienceIssuer { get; set; } = null; + internal Client() { } @@ -80,15 +82,14 @@ public async Task DoHealthCheck(bool handleException = true) /// /// The username to authenticate. Must match a Duo username or alias /// A unique identifier for the authentication attempt - /// A specific parameter used for the Epic Hyperdrive integration to generate the samlResponse /// A URL to redirect the user's browser to - public string GenerateAuthUri(string username, string state, string issuer = null) + public string GenerateAuthUri(string username, string state) { - ValidateAuthUriInputs(username, state, issuer); + ValidateAuthUriInputs(username, state, AudienceIssuer); string authEndpoint = CustomizeApiUri(AUTH_ENDPOINT); - string authJwt = GenerateAuthJwt(username, state, authEndpoint, issuer); + string authJwt = GenerateAuthJwt(username, state, authEndpoint); return BuildAuthUri(authEndpoint, authJwt); } @@ -187,9 +188,8 @@ private void ValidateAuthUriInputs(string username, string state, string issuer) /// The username to authenticate. Must match a Duo username or alias /// A unique identifier for the authentication attempt /// The Duo endpoint URI - /// A specific parameter used for the Epic Hyperdrive to generate the samlResponse /// A signed JWT - private string GenerateAuthJwt(string username, string state, string authEndpoint, string issuer = null) + private string GenerateAuthJwt(string username, string state, string authEndpoint) { var additionalClaims = new Dictionary { @@ -203,9 +203,9 @@ private string GenerateAuthJwt(string username, string state, string authEndpoin }; // issuer parameter is used for the Epic Hyperdrive integration only - if (issuer != null) + if (AudienceIssuer != null) { - additionalClaims[Labels.ISSUER] = issuer; + additionalClaims[Labels.AUDIENCE_ISSUER] = AudienceIssuer; } if (UseDuoCodeAttribute) @@ -311,6 +311,7 @@ public class ClientBuilder private bool _sslCertValidation = true; private X509Certificate2Collection _customRoots = null; private IWebProxy proxy = null; + private string _audienceIssuer = null; // For testing only @@ -423,6 +424,18 @@ public ClientBuilder UseHttpProxy(IWebProxy proxy) return this; } + /// + /// Set an audienceIssuer value to generate a SAML response for the Epic integration + /// + /// Specific parameter for the Epic integration for the SAML response generation + /// The ClientBuilder + public ClientBuilder UseAudienceIssuer(string audienceIssuer) + { + _audienceIssuer = audienceIssuer; + + return this; + } + /// /// Build the Client based on the settings provided to the Builder /// @@ -437,7 +450,8 @@ public Client Build() ClientSecret = _clientSecret, ApiHost = _apiHost, RedirectUri = _redirectUri, - UseDuoCodeAttribute = _useDuoCodeAttribute + UseDuoCodeAttribute = _useDuoCodeAttribute, + AudienceIssuer = _audienceIssuer }; var httpClient = BuildHttpClient(); diff --git a/DuoUniversal/Labels.cs b/DuoUniversal/Labels.cs index 1d59894..0ce7d33 100644 --- a/DuoUniversal/Labels.cs +++ b/DuoUniversal/Labels.cs @@ -24,7 +24,6 @@ internal class Labels public const string RESPONSE_TYPE = "response_type"; public const string SCOPE = "scope"; public const string STATE = "state"; - public const string ISSUER = "issuer"; // Labels for standard JWT claims public const string AUD = JwtRegisteredClaimNames.Aud; @@ -42,5 +41,6 @@ internal class Labels public const string DUO_UNAME = "duo_uname"; public const string PREFERRED_USERNAME = "preferred_username"; public const string USE_DUO_CODE_ATTRIBUTE = "use_duo_code_attribute"; + public const string AUDIENCE_ISSUER = "issuer"; } }