Skip to content

Commit 7fb7681

Browse files
authored
fix(or-multiple-auth): applying only the first available auth for OR cases (#57)
1 parent ad755f8 commit 7fb7681

File tree

3 files changed

+90
-20
lines changed

3 files changed

+90
-20
lines changed

APIMatic.Core.Test/AuthenticationTest.cs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Net.Http;
44
using APIMatic.Core.Authentication;
55
using APIMatic.Core.Test.MockTypes.Authentication;
6+
using APIMatic.Core.Types.Sdk.Exceptions;
67
using NUnit.Framework;
78

89
namespace APIMatic.Core.Test
@@ -11,17 +12,16 @@ namespace APIMatic.Core.Test
1112
public class AuthenticationTest : TestBase
1213
{
1314
[Test]
14-
public void Multiple_Authentication_Success()
15+
public void Multiple_Authentication_Success_WithFirstAuth()
1516
{
16-
var basicAuthManager = new BasicAuthManager("username", "password");
1717
var globalConfiguration = new GlobalConfiguration.Builder()
1818
.ServerUrls(new Dictionary<Enum, string>
1919
{
2020
{MockServer.Server1, "http://my/path:3000/{one}"},
2121
}, MockServer.Server1)
2222
.AuthManagers(new Dictionary<string, AuthManager>()
2323
{
24-
{"basic", basicAuthManager},
24+
{"basic", new BasicAuthManager("username", "password")},
2525
{"header", new HeaderAuthManager("my api key", "test token")},
2626
{"query", new QueryAuthManager("my api key", "test token")}
2727
})
@@ -31,19 +31,53 @@ public void Multiple_Authentication_Success()
3131
var request = globalConfiguration.GlobalRequestBuilder()
3232
.Setup(HttpMethod.Get, "/auth")
3333
.WithOrAuth(auth => auth
34-
.Add("basic")
3534
.AddAndGroup(innerGroup => innerGroup
3635
.Add("header")
37-
.Add("query")))
36+
.Add("query"))
37+
.Add("basic"))
3838
.Build();
3939

40-
Assert.AreEqual(basicAuthManager.GetBasicAuthHeader(), request.Headers["Authorization"]);
40+
Assert.False(request.Headers.ContainsKey("Authorization"));
4141
Assert.AreEqual("my api key", request.Headers["API-KEY"]);
4242
Assert.AreEqual("test token", request.Headers["TOKEN"]);
4343
Assert.AreEqual("my api key", request.QueryParameters["API-KEY"]);
4444
Assert.AreEqual("test token", request.QueryParameters["TOKEN"]);
4545
}
4646

47+
[Test]
48+
public void Multiple_Authentication_Success_WithSecondAuth()
49+
{
50+
var basicAuthManager = new BasicAuthManager("username", "password");
51+
var globalConfiguration = new GlobalConfiguration.Builder()
52+
.ServerUrls(new Dictionary<Enum, string>
53+
{
54+
{MockServer.Server1, "http://my/path:3000/{one}"},
55+
}, MockServer.Server1)
56+
.AuthManagers(new Dictionary<string, AuthManager>()
57+
{
58+
{"basic", basicAuthManager},
59+
{"header", new HeaderAuthManager(null, null)},
60+
{"query", new QueryAuthManager("my api key", "test token")}
61+
})
62+
.HttpConfiguration(_clientConfiguration)
63+
.Build();
64+
65+
var request = globalConfiguration.GlobalRequestBuilder()
66+
.Setup(HttpMethod.Get, "/auth")
67+
.WithOrAuth(auth => auth
68+
.AddAndGroup(innerGroup => innerGroup
69+
.Add("header")
70+
.Add("query"))
71+
.Add("basic"))
72+
.Build();
73+
74+
Assert.AreEqual(basicAuthManager.GetBasicAuthHeader(), request.Headers["Authorization"]);
75+
Assert.False(request.Headers.ContainsKey("API-KEY"));
76+
Assert.False(request.Headers.ContainsKey("TOKEN"));
77+
Assert.False(request.QueryParameters.ContainsKey("API-KEY"));
78+
Assert.False(request.QueryParameters.ContainsKey("TOKEN"));
79+
}
80+
4781
[Test]
4882
public void Multiple_Authentication_OR_Validation_Failure()
4983
{
@@ -61,7 +95,7 @@ public void Multiple_Authentication_OR_Validation_Failure()
6195
.HttpConfiguration(_clientConfiguration)
6296
.Build();
6397

64-
var exp = Assert.Throws<ArgumentNullException>(() => globalConfiguration.GlobalRequestBuilder()
98+
var exp = Assert.Throws<AuthValidationException>(() => globalConfiguration.GlobalRequestBuilder()
6599
.Setup(HttpMethod.Get, "/auth")
66100
.WithOrAuth(auth => auth
67101
.Add("basic")
@@ -92,7 +126,7 @@ public void Multiple_Authentication_AND_Validation_Failure()
92126
.HttpConfiguration(_clientConfiguration)
93127
.Build();
94128

95-
var exp = Assert.Throws<ArgumentNullException>(() => globalConfiguration.GlobalRequestBuilder()
129+
var exp = Assert.Throws<AuthValidationException>(() => globalConfiguration.GlobalRequestBuilder()
96130
.Setup(HttpMethod.Get, "/auth")
97131
.WithAndAuth(auth => auth
98132
.Add("query")
@@ -119,7 +153,7 @@ public void Multiple_Authentication_AND_All_Missing_Validation_Failure()
119153
.HttpConfiguration(_clientConfiguration)
120154
.Build();
121155

122-
var exp = Assert.Throws<ArgumentNullException>(() => globalConfiguration.GlobalRequestBuilder()
156+
var exp = Assert.Throws<AuthValidationException>(() => globalConfiguration.GlobalRequestBuilder()
123157
.Setup(HttpMethod.Get, "/auth")
124158
.WithAndAuth(auth => auth
125159
.Add("query")
@@ -150,7 +184,7 @@ public void Multiple_Authentication_AND_with_nested_OR_Validation_Failure()
150184
.HttpConfiguration(_clientConfiguration)
151185
.Build();
152186

153-
var exp = Assert.Throws<ArgumentNullException>(() => globalConfiguration.GlobalRequestBuilder()
187+
var exp = Assert.Throws<AuthValidationException>(() => globalConfiguration.GlobalRequestBuilder()
154188
.Setup(HttpMethod.Get, "/auth")
155189
.WithAndAuth(auth => auth
156190
.Add("query")

APIMatic.Core/Authentication/AuthGroupBuilder.cs

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
using System.Collections.Generic;
66
using System.Linq;
77
using APIMatic.Core.Request;
8+
using APIMatic.Core.Types.Sdk.Exceptions;
89

910
namespace APIMatic.Core.Authentication
1011
{
1112
public class AuthGroupBuilder : AuthManager
1213
{
1314
private readonly Dictionary<string, AuthManager> authManagersMap;
1415
private readonly List<AuthManager> authManagers = new List<AuthManager>();
16+
private readonly List<AuthManager> validatedAuthManagers = new List<AuthManager>();
1517
private bool isAndGroup = false;
1618

1719
internal AuthGroupBuilder(Dictionary<string, AuthManager> authManagers)
@@ -72,31 +74,48 @@ internal AuthGroupBuilder ToOrGroup()
7274
}
7375

7476
/// <summary>
75-
/// Add authentication group information to the RequestBuilder.
77+
/// Validates the selected authentication managers for the HTTP Request.
7678
/// </summary>
77-
/// <param name="requestBuilder">The RequestBuilder object on which authentication will be applied.</param>
78-
internal override void Apply(RequestBuilder requestBuilder)
79+
public override void Validate()
7980
{
81+
if (validatedAuthManagers.Any())
82+
{
83+
return;
84+
}
8085
var errors = new List<string>();
8186
foreach (var authManager in authManagers)
8287
{
8388
try
8489
{
85-
authManager.Apply(requestBuilder);
90+
authManager.Validate();
91+
validatedAuthManagers.Add(authManager);
92+
if (!isAndGroup)
93+
{
94+
// return early if any authentication in OR group gets applied
95+
return;
96+
}
8697
}
8798
catch (ArgumentNullException ex)
8899
{
89100
errors.Add(ex.Message);
90101
}
91102
}
92-
93-
if (errors.Any() && (errors.Count == authManagers.Count || isAndGroup))
103+
if (errors.Any())
94104
{
95-
// throw exception if unable to apply All authentications in OR group
96-
// OR if unable to apply Any Single authentication in AND group
97-
var messagePrefix = $"Following authentication credentials are required:\n-> ";
98-
throw new ArgumentNullException(null, messagePrefix + string.Join("\n-> ", errors.Select(e => e.TrimStart(messagePrefix.ToCharArray()))));
105+
// throw exception if unable to apply Any Single authentication in AND group
106+
// OR if unable to apply All authentication in OR group
107+
throw new AuthValidationException(errors);
99108
}
100109
}
110+
111+
/// <summary>
112+
/// Add authentication group information to the RequestBuilder.
113+
/// </summary>
114+
/// <param name="requestBuilder">The RequestBuilder object on which authentication will be applied.</param>
115+
internal override void Apply(RequestBuilder requestBuilder)
116+
{
117+
Validate();
118+
validatedAuthManagers.ForEach(authManager => authManager.Apply(requestBuilder));
119+
}
101120
}
102121
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace APIMatic.Core.Types.Sdk.Exceptions
6+
{
7+
public class AuthValidationException : ArgumentNullException
8+
{
9+
private const string ErrorMessagePrefix = "Following authentication credentials are required:\n-> ";
10+
11+
public AuthValidationException(List<string> errors)
12+
: base(null, ErrorMessagePrefix + string.Join("\n-> ", errors.Select(e => e.TrimStart(ErrorMessagePrefix.ToCharArray()))))
13+
{
14+
}
15+
}
16+
17+
}

0 commit comments

Comments
 (0)