diff --git a/src/Auth0.AuthenticationApi/AuthenticationApiClient.cs b/src/Auth0.AuthenticationApi/AuthenticationApiClient.cs index 2d3c3297..275fdfb1 100644 --- a/src/Auth0.AuthenticationApi/AuthenticationApiClient.cs +++ b/src/Auth0.AuthenticationApi/AuthenticationApiClient.cs @@ -533,7 +533,7 @@ private Task AssertIdTokenValid(string idToken, string audience, JwtSignatureAlg private Uri BuildUri(string path) { - return Utils.BuildUri(BaseUri.AbsoluteUri, path, null, null); + return Utils.BuildUri(BaseUri.AbsoluteUri, path, null, queryStrings:null); } private IDictionary BuildHeaders(string accessToken) diff --git a/src/Auth0.Core/Utils.cs b/src/Auth0.Core/Utils.cs index 99a84d17..e198b8c8 100644 --- a/src/Auth0.Core/Utils.cs +++ b/src/Auth0.Core/Utils.cs @@ -36,39 +36,25 @@ internal static string Base64UrlEncode(byte[] input) internal static Uri BuildUri(string baseUrl, string resource, IDictionary urlSegments, IDictionary queryStrings, bool includeEmptyParameters = false) { - // Replace the URL Segments - if (urlSegments != null) - { - foreach (var urlSegment in urlSegments) - { - resource = resource.Replace($"{{{urlSegment.Key}}}", Uri.EscapeDataString(urlSegment.Value ?? String.Empty)); - } + resource = ReplaceUrlSegments(resource, urlSegments); - // Remove trailing slash - resource = resource.TrimEnd('/'); - } + var queryString = AddQueryString(queryStrings, includeEmptyParameters); - // Add the query strings - var queryString = queryStrings?.Aggregate(new StringBuilder(), (sb, kvp) => - { - if (kvp.Value != null) - { - if (sb.Length > 0) - sb = sb.Append("&"); + // If we have a querystring, append it to the resource + if (!string.IsNullOrEmpty(queryString)) + { + resource = resource.Contains("?") ? $"{resource}&{queryString}" : $"{resource}?{queryString}"; + } - sb.Append($"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}"); - } - else if (includeEmptyParameters) - { - if (sb.Length > 0) - sb = sb.Append("&"); + resource = CombineUriParts(baseUrl, resource); - sb.Append(Uri.EscapeDataString(kvp.Key)); - } + return new Uri(resource, UriKind.RelativeOrAbsolute); + } + internal static Uri BuildUri(string baseUrl, string resource, IDictionary urlSegments, IList> queryStringsTuple, bool includeEmptyParameters = false) + { + resource = ReplaceUrlSegments(resource, urlSegments); - return sb; - }) - .ToString(); + var queryString = AddQueryString(queryStringsTuple, includeEmptyParameters); // If we have a querystring, append it to the resource if (!string.IsNullOrEmpty(queryString)) @@ -101,6 +87,67 @@ internal static string CombineUriParts(params string[] uriParts) } return uri; } + private static string AddQueryString(IList> queryStrings, bool includeEmptyParameters) + { + var sb = new StringBuilder(); + // Add the query strings + foreach (var keyValuePair in queryStrings) + { + if (keyValuePair.Item2 != null) + { + if (sb.Length > 0) + sb = sb.Append("&"); + sb.Append($"{Uri.EscapeDataString(keyValuePair.Item1)}={Uri.EscapeDataString(keyValuePair.Item2)}"); + } + else if (includeEmptyParameters) + { + if (sb.Length > 0) + sb = sb.Append("&"); + + sb.Append(Uri.EscapeDataString(keyValuePair.Item1)); + } + } + return sb.ToString(); + } + private static string AddQueryString(IDictionary queryStrings, bool includeEmptyParameters) + { + // Add the query strings + var queryString = queryStrings?.Aggregate(new StringBuilder(), (sb, kvp) => + { + if (kvp.Value != null) + { + if (sb.Length > 0) + sb = sb.Append("&"); + + sb.Append($"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}"); + } + else if (includeEmptyParameters) + { + if (sb.Length > 0) + sb = sb.Append("&"); + + sb.Append(Uri.EscapeDataString(kvp.Key)); + } + + return sb; + }) + .ToString(); + return queryString; + } + private static string ReplaceUrlSegments(string resource, IDictionary urlSegments) + { + // Replace the URL Segments + if (urlSegments == null) return resource; + foreach (var urlSegment in urlSegments) + { + resource = + resource.Replace($"{{{urlSegment.Key}}}", Uri.EscapeDataString(urlSegment.Value ?? String.Empty)); + } + + // Remove trailing slash + resource = resource.TrimEnd('/'); + return resource; + } } } \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Clients/BaseClient.cs b/src/Auth0.ManagementApi/Clients/BaseClient.cs index e3bd4c1c..fa53df9c 100644 --- a/src/Auth0.ManagementApi/Clients/BaseClient.cs +++ b/src/Auth0.ManagementApi/Clients/BaseClient.cs @@ -48,6 +48,11 @@ protected Uri BuildUri(string resource, IDictionary queryStrings { return Utils.BuildUri(BaseUri.AbsoluteUri, resource, null, queryStrings); } + + protected Uri BuildUri(string resource, IList> queryStrings) + { + return Utils.BuildUri(BaseUri.AbsoluteUri, resource, null, queryStrings); + } /// /// Encode a value so it can be successfully used in the path. diff --git a/src/Auth0.ManagementApi/Clients/ClientsClient.cs b/src/Auth0.ManagementApi/Clients/ClientsClient.cs index f53fae87..862863f3 100644 --- a/src/Auth0.ManagementApi/Clients/ClientsClient.cs +++ b/src/Auth0.ManagementApi/Clients/ClientsClient.cs @@ -67,7 +67,8 @@ public Task> GetAllAsync(GetClientsRequest request, Paginatio {"fields", request.Fields}, {"include_fields", request.IncludeFields?.ToString().ToLower()}, {"is_global", request.IsGlobal?.ToString().ToLower()}, - {"is_first_party", request.IsFirstParty?.ToString().ToLower()} + {"is_first_party", request.IsFirstParty?.ToString().ToLower()}, + {"q", request.Query?.ToLower()} }; if (pagination != null) diff --git a/src/Auth0.ManagementApi/Clients/IResourceServersClient.cs b/src/Auth0.ManagementApi/Clients/IResourceServersClient.cs index 4e104f6c..1a5cab1f 100644 --- a/src/Auth0.ManagementApi/Clients/IResourceServersClient.cs +++ b/src/Auth0.ManagementApi/Clients/IResourceServersClient.cs @@ -31,6 +31,16 @@ public interface IResourceServersClient /// The that was requested. Task GetAsync(string id, CancellationToken cancellationToken = default); + /// + /// Gets a list of all the resource servers. + /// + /// Contains the information required to retrieve the Resource Servers + /// Specifies pagination info to use when requesting paged results. + /// The cancellation token to cancel operation. + /// A containing the list of resource servers. + Task> GetAllAsync(ResourceServerGetRequest request, PaginationInfo pagination = null, + CancellationToken cancellationToken = default); + /// /// Gets a list of all the resource servers. /// diff --git a/src/Auth0.ManagementApi/Clients/OrganizationsClient.cs b/src/Auth0.ManagementApi/Clients/OrganizationsClient.cs index 28ab4455..0daf7c9b 100644 --- a/src/Auth0.ManagementApi/Clients/OrganizationsClient.cs +++ b/src/Auth0.ManagementApi/Clients/OrganizationsClient.cs @@ -3,6 +3,7 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -435,17 +436,23 @@ public Task> GetAllClientGrantsAsync(string if (request == null) throw new ArgumentNullException(nameof(request)); - var queryStrings = new Dictionary + var queryStrings = new List>() { - {"audience", request.Audience}, - {"client_id", request.ClientId}, + new Tuple("audience", request.Audience), + new Tuple("client_id", request.ClientId) }; + if (request.GrantIds != null) + { + queryStrings.AddRange( + request.GrantIds.Select(grantId => new Tuple("grant_ids", grantId))); + } + if (pagination != null) { - queryStrings["page"] = pagination.PageNo.ToString(); - queryStrings["per_page"] = pagination.PerPage.ToString(); - queryStrings["include_totals"] = pagination.IncludeTotals.ToString().ToLower(); + queryStrings.Add(new Tuple("page", pagination.PageNo.ToString())); + queryStrings.Add(new Tuple("per_page", pagination.PerPage.ToString())); + queryStrings.Add(new Tuple("include_totals", pagination.IncludeTotals.ToString().ToLower())); } return Connection.GetAsync>(BuildUri($"organizations/{EncodePath(organizationId)}/client-grants", queryStrings), DefaultHeaders, clientGrantsConverters, cancellationToken); diff --git a/src/Auth0.ManagementApi/Clients/ResourceServersClient.cs b/src/Auth0.ManagementApi/Clients/ResourceServersClient.cs index a98753bc..f2b9ced7 100644 --- a/src/Auth0.ManagementApi/Clients/ResourceServersClient.cs +++ b/src/Auth0.ManagementApi/Clients/ResourceServersClient.cs @@ -3,6 +3,7 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -70,13 +71,37 @@ public Task> GetAllAsync(PaginationInfo pagination = { return Connection.GetAsync>(BuildUri("resource-servers", pagination != null ? new Dictionary - { + { {"page", pagination.PageNo.ToString()}, {"per_page", pagination.PerPage.ToString()}, {"include_totals", pagination.IncludeTotals.ToString().ToLower()} } : null), DefaultHeaders, converters, cancellationToken); } + /// + public Task> GetAllAsync(ResourceServerGetRequest request, + PaginationInfo pagination = null, CancellationToken cancellationToken = default) + { + var queryStrings = new List>(); + + if (request?.Identifiers != null) + { + queryStrings.AddRange( + request.Identifiers.Select( + identifier => new Tuple("identifiers", identifier))); + } + + if (pagination != null) + { + queryStrings.Add(new Tuple("page", pagination.PageNo.ToString())); + queryStrings.Add(new Tuple("per_page", pagination.PerPage.ToString())); + queryStrings.Add(new Tuple("include_totals", pagination.IncludeTotals.ToString().ToLower())); + } + + return Connection.GetAsync>( + BuildUri("resource-servers", queryStrings), DefaultHeaders, converters, cancellationToken); + } + /// /// Updates a resource server, /// diff --git a/src/Auth0.ManagementApi/Models/ClientBase.cs b/src/Auth0.ManagementApi/Models/ClientBase.cs index 44dbf964..9438491d 100644 --- a/src/Auth0.ManagementApi/Models/ClientBase.cs +++ b/src/Auth0.ManagementApi/Models/ClientBase.cs @@ -199,6 +199,12 @@ public abstract class ClientBase /// [JsonProperty("require_pushed_authorization_requests")] public bool? RequirePushedAuthorizationRequests { get; set; } + + /// + /// Defines the default Organization ID and flows + /// + [JsonProperty("default_organization")] + public DefaultOrganization DefaultOrganization { get; set; } } } diff --git a/src/Auth0.ManagementApi/Models/DefaultOrganization.cs b/src/Auth0.ManagementApi/Models/DefaultOrganization.cs new file mode 100644 index 00000000..68e6f5bb --- /dev/null +++ b/src/Auth0.ManagementApi/Models/DefaultOrganization.cs @@ -0,0 +1,25 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Auth0.ManagementApi.Models +{ + /// + /// Defines the default Organization ID and flows + /// + public class DefaultOrganization + { + /// + /// The default Organization ID to be used + /// + [JsonProperty("organization_id")] + public string OrganizationId { get; set; } + + /// + /// The default Organization usage + /// + [JsonProperty("flows", ItemConverterType = typeof(StringEnumConverter))] + public Flows[] Flows { get; set; } + + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Flows.cs b/src/Auth0.ManagementApi/Models/Flows.cs new file mode 100644 index 00000000..c0ff5115 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Flows.cs @@ -0,0 +1,16 @@ +using System.Runtime.Serialization; + +namespace Auth0.ManagementApi.Models +{ + /// + /// The default Organization usage + /// + public enum Flows + { + /// + /// Client-Credentials flow + /// + [EnumMember(Value = "client_credentials")] + ClientCredentials + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/GetClientsRequest.cs b/src/Auth0.ManagementApi/Models/GetClientsRequest.cs index d1c3ce71..6de7da27 100644 --- a/src/Auth0.ManagementApi/Models/GetClientsRequest.cs +++ b/src/Auth0.ManagementApi/Models/GetClientsRequest.cs @@ -29,5 +29,10 @@ public class GetClientsRequest /// Filter on whether or not a client is a first party client. /// public bool? IsFirstParty { get; set; } = null; + + /// + /// Query in Lucene query string syntax to search for clients. + /// + public string Query { get; set; } } } \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/OrganizationGetClientGrantsRequest.cs b/src/Auth0.ManagementApi/Models/OrganizationGetClientGrantsRequest.cs index 9ed4e92a..546e0a11 100644 --- a/src/Auth0.ManagementApi/Models/OrganizationGetClientGrantsRequest.cs +++ b/src/Auth0.ManagementApi/Models/OrganizationGetClientGrantsRequest.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace Auth0.ManagementApi.Models { public class OrganizationGetClientGrantsRequest @@ -10,6 +12,11 @@ public class OrganizationGetClientGrantsRequest /// /// The Id of a client to filter by. /// - public string ClientId { get; set; } + public string ClientId { get; set; } + + /// + /// List of GrantIds to filter results on + /// + public IList GrantIds { get; set; } } } \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/ResourceServerGetRequest.cs b/src/Auth0.ManagementApi/Models/ResourceServerGetRequest.cs new file mode 100644 index 00000000..75e0338a --- /dev/null +++ b/src/Auth0.ManagementApi/Models/ResourceServerGetRequest.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace Auth0.ManagementApi.Models +{ + /// + /// Request structure for creating a new resource server + /// + public class ResourceServerGetRequest + { + /// + /// List of Identifier IDs to retrieve + /// + public IList Identifiers { get; set; } + } +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/ClientGrantTests.cs b/tests/Auth0.ManagementApi.IntegrationTests/ClientGrantTests.cs index d332d545..f61ea572 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/ClientGrantTests.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/ClientGrantTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Auth0.IntegrationTests.Shared.CleanUp; using Auth0.ManagementApi.IntegrationTests.Testing; @@ -191,7 +192,6 @@ public async Task Organization_Client_Grants() OrganizationUsage = OrganizationUsage.Allow, AllowAnyOrganization = true }); - fixture.TrackIdentifier(CleanUpType.ClientGrants, newGrant.Id); var orgsBefore = await fixture.ApiClient.ClientGrants.GetAllOrganizationsAsync(newGrant.Id); @@ -223,10 +223,20 @@ public async Task Organization_Client_Grants() orgsAfter.Count.Should().Be(1); orgGrantsAfter.Count.Should().Be(1); - + + // Get client grants using a client-Grants filter + var grantsFilter = new List() { newGrant.Id, newGrant.Id }; + var filteredUsingClientGrants = + await fixture.ApiClient.Organizations.GetAllClientGrantsAsync(existingOrgId, + new OrganizationGetClientGrantsRequest() + { + GrantIds = grantsFilter + }); + + filteredUsingClientGrants.Count.Should().Be(1); + filteredUsingClientGrants.First().Id.Should().BeEquivalentTo(newGrant.Id); await fixture.ApiClient.ClientGrants.DeleteAsync(newGrant.Id); fixture.UnTrackIdentifier(CleanUpType.ClientGrants, newGrant.Id); } - } } \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/ClientTests.cs b/tests/Auth0.ManagementApi.IntegrationTests/ClientTests.cs index 010e7e71..aa6b4f3d 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/ClientTests.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/ClientTests.cs @@ -44,6 +44,7 @@ public ClientTests(ClientTestsFixture fixture) [Fact] public async Task Test_client_crud_sequence() { + string existingOrganizationId = "org_V6ojENVd1ERs5YY1"; // Add a new client var newClientRequest = new ClientCreateRequest { @@ -73,6 +74,11 @@ public async Task Test_client_crud_sequence() SelectedInitiators = new [] { LogoutInitiators.RpLogout, LogoutInitiators.IdpLogout, LogoutInitiators.PasswordChanged } }, BackchannelLogoutUrls = new [] { "https://create.com/logout" } + }, + DefaultOrganization = new DefaultOrganization() + { + OrganizationId = existingOrganizationId, + Flows = new[] { Flows.ClientCredentials } } }; var newClientResponse = await fixture.ApiClient.Clients.CreateAsync(newClientRequest); @@ -90,6 +96,7 @@ public async Task Test_client_crud_sequence() newClientResponse.OidcLogout.BackchannelLogoutInitiators.Mode.Should().Be(LogoutInitiatorModes.Custom); newClientResponse.OidcLogout.BackchannelLogoutInitiators.SelectedInitiators.Length.Should().Be(3); newClientResponse.OidcLogout.BackchannelLogoutInitiators.SelectedInitiators.Any(i => i == LogoutInitiators.PasswordChanged).Should().BeTrue(); + newClientResponse.DefaultOrganization.OrganizationId.Should().Be(existingOrganizationId); string prop1 = newClientResponse.ClientMetaData.Prop1; prop1.Should().Be("1"); @@ -132,11 +139,17 @@ public async Task Test_client_crud_sequence() updateClientResponse.OidcLogout.BackchannelLogoutInitiators.Mode.Should().Be(LogoutInitiatorModes.Custom); updateClientResponse.OidcLogout.BackchannelLogoutInitiators.SelectedInitiators.Length.Should().Be(3); updateClientResponse.OidcLogout.BackchannelLogoutInitiators.SelectedInitiators.Any(i => i == LogoutInitiators.PasswordChanged).Should().BeTrue(); + updateClientResponse.DefaultOrganization.OrganizationId.Should().Be(existingOrganizationId); + updateClientResponse.DefaultOrganization.Flows.Should().HaveCount(1); + updateClientResponse.DefaultOrganization.Flows.First().Should().Be(Flows.ClientCredentials); // Get a single client var client = await fixture.ApiClient.Clients.GetAsync(newClientResponse.ClientId); client.Should().NotBeNull(); client.Name.Should().Be(updateClientResponse.Name); + client.DefaultOrganization.OrganizationId.Should().Be(existingOrganizationId); + client.DefaultOrganization.Flows.Should().HaveCount(1); + client.DefaultOrganization.Flows.First().Should().Be(Flows.ClientCredentials); // Delete the client, and ensure we get exception when trying to fetch client again await fixture.ApiClient.Clients.DeleteAsync(client.ClientId); diff --git a/tests/Auth0.ManagementApi.IntegrationTests/ManagementApiClientTests.cs b/tests/Auth0.ManagementApi.IntegrationTests/ManagementApiClientTests.cs index 7719567b..b6b21c98 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/ManagementApiClientTests.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/ManagementApiClientTests.cs @@ -1,5 +1,4 @@ -using Auth0.Core.Http; -using Auth0.Tests.Shared; +using Auth0.Tests.Shared; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; @@ -23,7 +22,7 @@ public ManagementApiClientTests() management = new ManagementApiClient("fake", GetVariable("AUTH0_MANAGEMENT_API_URL"), grabber); management.TenantSettings.GetAsync(); // Cause headers to be "sent" to the grabber for testing - payload = JObject.Parse(Encoding.ASCII.GetString(Utils.Base64UrlDecode(grabber.LastHeaders["Auth0-Client"]))); + payload = JObject.Parse(Encoding.ASCII.GetString(Auth0.Core.Http.Utils.Base64UrlDecode(grabber.LastHeaders["Auth0-Client"]))); } [Fact] diff --git a/tests/Auth0.ManagementApi.IntegrationTests/OrganizationTests.cs b/tests/Auth0.ManagementApi.IntegrationTests/OrganizationTests.cs index 575e91cf..4d5e1947 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/OrganizationTests.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/OrganizationTests.cs @@ -4,9 +4,11 @@ using FluentAssertions; using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Auth0.IntegrationTests.Shared.CleanUp; using Auth0.ManagementApi.IntegrationTests.Testing; +using Auth0.ManagementApi.Paging; using Xunit; namespace Auth0.ManagementApi.IntegrationTests @@ -411,5 +413,64 @@ public async Task Test_organization_invitations_crud_sequence() } } + + [Fact] + public async Task Test_organization_client_grants_association_with_client() + { + // Given an Organization + var organization = await fixture.Utils.CreateOrganization(); + fixture.TrackIdentifier(CleanUpType.Organizations, organization.Id); + + var clientCreateRequest = new ClientCreateRequest() + { + Name = "Test-Client-" + Guid.NewGuid(), + Description = "This is a test client - TBD", + OrganizationUsage = OrganizationUsage.Allow, + DefaultOrganization = new DefaultOrganization() + { + Flows = new[] { Flows.ClientCredentials }, + OrganizationId = organization.Id.ToString() + }, + }; + + // Given a Client + var client = await fixture.Utils.CreateClient(clientCreateRequest); + fixture.TrackIdentifier(CleanUpType.Clients, client.ClientId); + // Given a Resource Server + var resourceServer = await fixture.Utils.CreateResourceServer(); + fixture.TrackIdentifier(CleanUpType.ResourceServers, resourceServer.Id); + + var clientGrantRequest = new ClientGrantCreateRequest() + { + AllowAnyOrganization = true, + OrganizationUsage = OrganizationUsage.Allow, + Audience = resourceServer.Identifier, + Scope = new List(new[] { "create:resource", "create:organization_client_grants" }), + ClientId = client.ClientId, + + }; + + // Given a Client Grant + var clientGrant = await fixture.ApiClient.ClientGrants.CreateAsync(clientGrantRequest); + fixture.TrackIdentifier(CleanUpType.ClientGrants, clientGrant.Id); + + // Associating the client grant with the organization + await fixture.ApiClient.Organizations.CreateClientGrantAsync(organization.Id, + new OrganizationCreateClientGrantRequest() + { + GrantId = clientGrant.Id, + }); + + var request = new GetClientsRequest() + { + Query = $"client_grant.organization_id:{organization.Id}" + }; + + // Act + var clients = await fixture.ApiClient.Clients.GetAllAsync(request, new PaginationInfo(0, 100)); + + // Assert + Assert.Contains(clients.ToList(), x => x.ClientId == client.ClientId); + } } } diff --git a/tests/Auth0.ManagementApi.IntegrationTests/ResourceServerTests.cs b/tests/Auth0.ManagementApi.IntegrationTests/ResourceServerTests.cs index 638a3642..76ca2e7b 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/ResourceServerTests.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/ResourceServerTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Auth0.Core.Exceptions; using Auth0.IntegrationTests.Shared.CleanUp; @@ -99,7 +100,22 @@ public async Task Test_resource_server_crud_sequence() // Get a single resource server var resourceServer = await fixture.ApiClient.ResourceServers.GetAsync(newResourceServerResponse.Id); resourceServer.Should().BeEquivalentTo(updateResourceServerRequest, options => options.ExcludingMissingMembers()); - + + // Get all resource servers with pagination + var pagination = new PaginationInfo(0, 10, true); + var request = new ResourceServerGetRequest() + { + Identifiers = new List() { resourceServer.Identifier, resourceServer.Identifier } + }; + var resourceServers = await fixture.ApiClient.ResourceServers.GetAllAsync(request, pagination); + resourceServers.Count.Should().Be(1); + resourceServers.First().Identifier.Should().BeEquivalentTo(resourceServer.Identifier); + + // Get all resource servers with pagination + pagination = new PaginationInfo(0, 10, true); + resourceServers = await fixture.ApiClient.ResourceServers.GetAllAsync(null, pagination); + resourceServers.Count.Should().BeGreaterThan(1); + // Delete the client, and ensure we get exception when trying to fetch client again await fixture.ApiClient.ResourceServers.DeleteAsync(resourceServer.Id); Func getFunc = async () => await fixture.ApiClient.ResourceServers.GetAsync(resourceServer.Id); diff --git a/tests/Auth0.ManagementApi.IntegrationTests/TestBaseFixture.cs b/tests/Auth0.ManagementApi.IntegrationTests/TestBaseFixture.cs index 2c42494c..5f6ffeed 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/TestBaseFixture.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/TestBaseFixture.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Auth0.IntegrationTests.Shared; using Auth0.IntegrationTests.Shared.CleanUp; using Auth0.ManagementApi.IntegrationTests.Testing; using Auth0.Tests.Shared; @@ -11,6 +12,8 @@ public class TestBaseFixture : IAsyncLifetime { public ManagementApiClient ApiClient { get; private set; } + public Utils Utils { get; private set; } + protected IDictionary> identifiers = new Dictionary>(); public virtual async Task InitializeAsync() @@ -18,6 +21,8 @@ public virtual async Task InitializeAsync() string token = await TestBaseUtils.GenerateManagementApiToken(); ApiClient = new ManagementApiClient(token, TestBaseUtils.GetVariable("AUTH0_MANAGEMENT_API_URL"), new HttpClientManagementConnection(options: new HttpClientManagementConnectionOptions { NumberOfHttpRetries = 9 })); + + Utils = new Utils(ApiClient); } public virtual async Task DisposeAsync() diff --git a/tests/Auth0.ManagementApi.IntegrationTests/Utils.cs b/tests/Auth0.ManagementApi.IntegrationTests/Utils.cs new file mode 100644 index 00000000..5c88f412 --- /dev/null +++ b/tests/Auth0.ManagementApi.IntegrationTests/Utils.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Auth0.IntegrationTests.Shared.CleanUp; +using Auth0.ManagementApi.Models; + +namespace Auth0.ManagementApi.IntegrationTests +{ + public class Utils + { + private readonly ManagementApiClient _apiClient; + + public Utils(ManagementApiClient apiClient) + { + _apiClient = apiClient; + } + + internal async Task CreateClient(ClientCreateRequest request = null) + { + request ??= new ClientCreateRequest() + { + Name = "Test client " + Guid.NewGuid(), + Description = "This is a dummy client - TBD" + }; + + var client = await _apiClient.Clients.CreateAsync(request); + return client; + } + + internal async Task CreateOrganization(OrganizationCreateRequest request = null) + { + request??= new OrganizationCreateRequest() + { + Name = "tbd-organisation", + DisplayName = "Test organization display name", + }; + + var organization = await _apiClient.Organizations.CreateAsync(request); + return organization; + } + + internal async Task CreateResourceServer(ResourceServerCreateRequest request = null) + { + var identifier = Guid.NewGuid(); + request??= new ResourceServerCreateRequest + { + Identifier = identifier.ToString("N"), + Name = $"{TestingConstants.ResourceServerPrefix} {identifier:N}", + TokenLifetime = 1, + TokenLifetimeForWeb = 1, + SigningAlgorithm = SigningAlgorithm.HS256, + SigningSecret = "thisismysecret0123456789", + Scopes = new List + { + new ResourceServerScope + { + Value = "scope1", + Description = "Scope number 1" + } + }, + AllowOfflineAccess = true, + VerificationLocation = "https://abc.auth0.com/def", + SkipConsentForVerifiableFirstPartyClients = true, + }; + var resourceServer = await _apiClient.ResourceServers.CreateAsync(request); + return resourceServer; + } + } +} \ No newline at end of file