Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 44 additions & 10 deletions APIMatic.Core.Test/AuthenticationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Net.Http;
using APIMatic.Core.Authentication;
using APIMatic.Core.Test.MockTypes.Authentication;
using APIMatic.Core.Types.Sdk.Exceptions;
using NUnit.Framework;

namespace APIMatic.Core.Test
Expand All @@ -11,17 +12,16 @@ namespace APIMatic.Core.Test
public class AuthenticationTest : TestBase
{
[Test]
public void Multiple_Authentication_Success()
public void Multiple_Authentication_Success_WithFirstAuth()
{
var basicAuthManager = new BasicAuthManager("username", "password");
var globalConfiguration = new GlobalConfiguration.Builder()
.ServerUrls(new Dictionary<Enum, string>
{
{MockServer.Server1, "http://my/path:3000/{one}"},
}, MockServer.Server1)
.AuthManagers(new Dictionary<string, AuthManager>()
{
{"basic", basicAuthManager},
{"basic", new BasicAuthManager("username", "password")},
{"header", new HeaderAuthManager("my api key", "test token")},
{"query", new QueryAuthManager("my api key", "test token")}
})
Expand All @@ -31,19 +31,53 @@ public void Multiple_Authentication_Success()
var request = globalConfiguration.GlobalRequestBuilder()
.Setup(HttpMethod.Get, "/auth")
.WithOrAuth(auth => auth
.Add("basic")
.AddAndGroup(innerGroup => innerGroup
.Add("header")
.Add("query")))
.Add("query"))
.Add("basic"))
.Build();

Assert.AreEqual(basicAuthManager.GetBasicAuthHeader(), request.Headers["Authorization"]);
Assert.False(request.Headers.ContainsKey("Authorization"));
Assert.AreEqual("my api key", request.Headers["API-KEY"]);
Assert.AreEqual("test token", request.Headers["TOKEN"]);
Assert.AreEqual("my api key", request.QueryParameters["API-KEY"]);
Assert.AreEqual("test token", request.QueryParameters["TOKEN"]);
}

[Test]
public void Multiple_Authentication_Success_WithSecondAuth()
{
var basicAuthManager = new BasicAuthManager("username", "password");
var globalConfiguration = new GlobalConfiguration.Builder()
.ServerUrls(new Dictionary<Enum, string>
{
{MockServer.Server1, "http://my/path:3000/{one}"},
}, MockServer.Server1)
.AuthManagers(new Dictionary<string, AuthManager>()
{
{"basic", basicAuthManager},
{"header", new HeaderAuthManager(null, null)},
{"query", new QueryAuthManager("my api key", "test token")}
})
.HttpConfiguration(_clientConfiguration)
.Build();

var request = globalConfiguration.GlobalRequestBuilder()
.Setup(HttpMethod.Get, "/auth")
.WithOrAuth(auth => auth
.AddAndGroup(innerGroup => innerGroup
.Add("header")
.Add("query"))
.Add("basic"))
.Build();

Assert.AreEqual(basicAuthManager.GetBasicAuthHeader(), request.Headers["Authorization"]);
Assert.False(request.Headers.ContainsKey("API-KEY"));
Assert.False(request.Headers.ContainsKey("TOKEN"));
Assert.False(request.QueryParameters.ContainsKey("API-KEY"));
Assert.False(request.QueryParameters.ContainsKey("TOKEN"));
}

[Test]
public void Multiple_Authentication_OR_Validation_Failure()
{
Expand All @@ -61,7 +95,7 @@ public void Multiple_Authentication_OR_Validation_Failure()
.HttpConfiguration(_clientConfiguration)
.Build();

var exp = Assert.Throws<ArgumentNullException>(() => globalConfiguration.GlobalRequestBuilder()
var exp = Assert.Throws<AuthValidationException>(() => globalConfiguration.GlobalRequestBuilder()
.Setup(HttpMethod.Get, "/auth")
.WithOrAuth(auth => auth
.Add("basic")
Expand Down Expand Up @@ -92,7 +126,7 @@ public void Multiple_Authentication_AND_Validation_Failure()
.HttpConfiguration(_clientConfiguration)
.Build();

var exp = Assert.Throws<ArgumentNullException>(() => globalConfiguration.GlobalRequestBuilder()
var exp = Assert.Throws<AuthValidationException>(() => globalConfiguration.GlobalRequestBuilder()
.Setup(HttpMethod.Get, "/auth")
.WithAndAuth(auth => auth
.Add("query")
Expand All @@ -119,7 +153,7 @@ public void Multiple_Authentication_AND_All_Missing_Validation_Failure()
.HttpConfiguration(_clientConfiguration)
.Build();

var exp = Assert.Throws<ArgumentNullException>(() => globalConfiguration.GlobalRequestBuilder()
var exp = Assert.Throws<AuthValidationException>(() => globalConfiguration.GlobalRequestBuilder()
.Setup(HttpMethod.Get, "/auth")
.WithAndAuth(auth => auth
.Add("query")
Expand Down Expand Up @@ -150,7 +184,7 @@ public void Multiple_Authentication_AND_with_nested_OR_Validation_Failure()
.HttpConfiguration(_clientConfiguration)
.Build();

var exp = Assert.Throws<ArgumentNullException>(() => globalConfiguration.GlobalRequestBuilder()
var exp = Assert.Throws<AuthValidationException>(() => globalConfiguration.GlobalRequestBuilder()
.Setup(HttpMethod.Get, "/auth")
.WithAndAuth(auth => auth
.Add("query")
Expand Down
39 changes: 29 additions & 10 deletions APIMatic.Core/Authentication/AuthGroupBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
using System.Collections.Generic;
using System.Linq;
using APIMatic.Core.Request;
using APIMatic.Core.Types.Sdk.Exceptions;

namespace APIMatic.Core.Authentication
{
public class AuthGroupBuilder : AuthManager
{
private readonly Dictionary<string, AuthManager> authManagersMap;
private readonly List<AuthManager> authManagers = new List<AuthManager>();
private readonly List<AuthManager> validatedAuthManagers = new List<AuthManager>();
private bool isAndGroup = false;

internal AuthGroupBuilder(Dictionary<string, AuthManager> authManagers)
Expand Down Expand Up @@ -72,31 +74,48 @@ internal AuthGroupBuilder ToOrGroup()
}

/// <summary>
/// Add authentication group information to the RequestBuilder.
/// Validates the selected authentication managers for the HTTP Request.
/// </summary>
/// <param name="requestBuilder">The RequestBuilder object on which authentication will be applied.</param>
internal override void Apply(RequestBuilder requestBuilder)
public override void Validate()
{
if (validatedAuthManagers.Any())
{
return;
}
var errors = new List<string>();
foreach (var authManager in authManagers)
{
try
{
authManager.Apply(requestBuilder);
authManager.Validate();
validatedAuthManagers.Add(authManager);
if (!isAndGroup)
{
// return early if any authentication in OR group gets applied
return;
}
}
catch (ArgumentNullException ex)
{
errors.Add(ex.Message);
}
}

if (errors.Any() && (errors.Count == authManagers.Count || isAndGroup))
if (errors.Any())
{
// throw exception if unable to apply All authentications in OR group
// OR if unable to apply Any Single authentication in AND group
var messagePrefix = $"Following authentication credentials are required:\n-> ";
throw new ArgumentNullException(null, messagePrefix + string.Join("\n-> ", errors.Select(e => e.TrimStart(messagePrefix.ToCharArray()))));
// throw exception if unable to apply Any Single authentication in AND group
// OR if unable to apply All authentication in OR group
throw new AuthValidationException(errors);
}
}

/// <summary>
/// Add authentication group information to the RequestBuilder.
/// </summary>
/// <param name="requestBuilder">The RequestBuilder object on which authentication will be applied.</param>
internal override void Apply(RequestBuilder requestBuilder)
{
Validate();
validatedAuthManagers.ForEach(authManager => authManager.Apply(requestBuilder));
}
}
}
17 changes: 17 additions & 0 deletions APIMatic.Core/Types/Sdk/Exceptions/AuthValidationException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace APIMatic.Core.Types.Sdk.Exceptions
{
public class AuthValidationException : ArgumentNullException
{
private const string ErrorMessagePrefix = "Following authentication credentials are required:\n-> ";

public AuthValidationException(List<string> errors)
: base(null, ErrorMessagePrefix + string.Join("\n-> ", errors.Select(e => e.TrimStart(ErrorMessagePrefix.ToCharArray()))))
{
}
}

}