diff --git a/src/Auth0.ManagementApi/Clients/ISelfServiceProfilesClient.cs b/src/Auth0.ManagementApi/Clients/ISelfServiceProfilesClient.cs new file mode 100644 index 00000000..d2b23678 --- /dev/null +++ b/src/Auth0.ManagementApi/Clients/ISelfServiceProfilesClient.cs @@ -0,0 +1,98 @@ +using System.Threading; +using System.Threading.Tasks; +using Auth0.ManagementApi.Models.SelfServiceProfiles; +using Auth0.ManagementApi.Paging; + +namespace Auth0.ManagementApi.Clients +{ + public interface ISelfServiceProfilesClient + { + /// + /// Retrieve self-service-profile information. + /// + /// + /// + /// of + Task> GetAllAsync(PaginationInfo pagination = null, CancellationToken cancellationToken = default); + + /// + /// Create self-service-profile. + /// + /// + /// + /// + Task CreateAsync(SelfServiceProfileCreateRequest request, CancellationToken cancellationToken = default); + + /// + /// Retrieve self-service-profile by id. + /// + /// Self-Service-Profile ID + /// + /// + Task GetAsync(string id, CancellationToken cancellationToken = default); + + /// + /// Delete a self-service-profile by id. + /// + /// Self-Service-Profile ID + /// + Task DeleteAsync(string id, CancellationToken cancellationToken = default); + + /// + /// Retrieve self-service-profile by id. + /// + /// Self-Service-Profile ID + /// + /// + /// + Task UpdateAsync(string id, SelfServiceProfileUpdateRequest request, CancellationToken cancellationToken = default); + + /// + /// Creates an sso-access ticket to initiate the Self Service SSO Flow using a self-service profile + /// + /// The id of the sso-profile to retrieve + /// + /// + /// + Task CreateSsoTicketAsync(string id, SelfServiceSsoTicketCreateRequest request, CancellationToken cancellationToken = default); + + /// + /// Revokes an SSO access ticket and invalidates associated sessions. + /// The ticket will no longer be accepted to initiate a Self-Service SSO session. + /// If any users have already started a session through this ticket, their session will be terminated. + /// Clients should expect a 202 Accepted response upon successful processing, indicating that the request + /// has been acknowledged and that the revocation is underway but may not be fully completed at the time of response. + /// If the specified ticket does not exist, a 202 Accepted response is also returned, + /// signaling that no further action is required. + /// Clients should treat these 202 responses as an acknowledgment that the request has been accepted and + /// is in progress, even if the ticket was not found. + /// + /// The id of the ticket to revoke + /// The id of the self-service profile + /// + /// + Task RevokeSsoTicketAsync(string profileId, string ticketId, CancellationToken cancellationToken = default); + + /// + /// Retrieves text customizations for a given self-service profile, language and Self Service SSO Flow page + /// + /// The id of the self-service profile. + /// The language of the custom text. + /// The page where the custom text is shown. + /// + /// The list of custom text keys and values. + Task GetCustomTextForSelfServiceProfileAsync(string id, string language, string page, CancellationToken cancellationToken = default); + + /// + /// Updates text customizations for a given self-service profile, language and Self Service SSO Flow page. + /// + /// The id of the self-service profile. + /// The language of the custom text. + /// The page where the custom text is shown. + /// The list of text keys and values to customize the self-service SSO page. + /// Values can be plain text or rich HTML content limited to basic styling tags and hyperlinks. + /// + /// The resulting list of custom text keys and values. + Task SetCustomTextForSelfServiceProfileAsync(string id, string language, string page, object body, CancellationToken cancellationToken = default); + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Clients/SelfServiceProfilesClient.cs b/src/Auth0.ManagementApi/Clients/SelfServiceProfilesClient.cs new file mode 100644 index 00000000..9b4a373c --- /dev/null +++ b/src/Auth0.ManagementApi/Clients/SelfServiceProfilesClient.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Auth0.ManagementApi.Models.SelfServiceProfiles; +using Auth0.ManagementApi.Paging; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Clients +{ + /// + /// Client to manage Self Service Profiles. + /// + public class SelfServiceProfilesClient : BaseClient, ISelfServiceProfilesClient + { + readonly JsonConverter[] converters = { new PagedListConverter("self_service_profiles") }; + public SelfServiceProfilesClient( + IManagementConnection connection, + Uri baseUri, + IDictionary defaultHeaders) : base(connection, baseUri, defaultHeaders) + { + } + + /// + public Task> GetAllAsync(PaginationInfo pagination = null, CancellationToken cancellationToken = default) + { + var queryStrings = new Dictionary(); + + if (pagination != null) + { + queryStrings["page"] = pagination.PageNo.ToString(); + queryStrings["per_page"] = pagination.PerPage.ToString(); + queryStrings["include_totals"] = pagination.IncludeTotals.ToString().ToLower(); + } + + return Connection.GetAsync>( + BuildUri("self-service-profiles", queryStrings), + DefaultHeaders, + converters, + cancellationToken); + } + + /// + public Task CreateAsync(SelfServiceProfileCreateRequest request, CancellationToken cancellationToken = default) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + return Connection.SendAsync( + HttpMethod.Post, + BuildUri("self-service-profiles"), + request, + DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task GetAsync(string id, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(id)) + throw new ArgumentNullException(nameof(id)); + + return Connection.GetAsync( + BuildUri($"self-service-profiles/{EncodePath(id)}"), + DefaultHeaders, + null, + cancellationToken); + } + + /// + public Task DeleteAsync(string id, CancellationToken cancellationToken = default) + { + return Connection.SendAsync( + HttpMethod.Delete, + BuildUri($"self-service-profiles/{EncodePath(id)}"), + body: null, + headers: DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task UpdateAsync(string id, SelfServiceProfileUpdateRequest request, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(id)) + throw new ArgumentNullException(nameof(id)); + + return Connection.SendAsync( + new HttpMethod("PATCH"), + BuildUri($"self-service-profiles/{EncodePath(id)}"), + request, + DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task CreateSsoTicketAsync(string id, SelfServiceSsoTicketCreateRequest request, CancellationToken cancellationToken = default) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + if (string.IsNullOrEmpty(id)) + throw new ArgumentNullException(nameof(id)); + + return Connection.SendAsync( + HttpMethod.Post, + BuildUri($"self-service-profiles/{EncodePath(id)}/sso-ticket"), + request, + DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task RevokeSsoTicketAsync(string profileId, string ticketId, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(profileId)) + throw new ArgumentNullException(nameof(profileId)); + + if (string.IsNullOrEmpty(ticketId)) + throw new ArgumentNullException(nameof(ticketId)); + + return Connection.SendAsync( + HttpMethod.Post, + BuildUri($"self-service-profiles/{EncodePath(profileId)}/sso-ticket/{EncodePath(ticketId)}/revoke"), + null, + DefaultHeaders, + cancellationToken: cancellationToken); + } + + /// + public Task GetCustomTextForSelfServiceProfileAsync(string id, string language, string page, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(id)) + throw new ArgumentNullException(nameof(id)); + + if (string.IsNullOrEmpty(language)) + throw new ArgumentNullException(nameof(language)); + + if (string.IsNullOrEmpty(page)) + throw new ArgumentNullException(nameof(page)); + + return Connection.GetAsync( + BuildUri($"self-service-profiles/{EncodePath(id)}/custom-text/{EncodePath(language)}/{EncodePath(page)}"), + DefaultHeaders, + null, + cancellationToken); + } + + /// + public Task SetCustomTextForSelfServiceProfileAsync(string id, string language, string page, object body, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(id)) + throw new ArgumentNullException(nameof(id)); + + if (string.IsNullOrEmpty(language)) + throw new ArgumentNullException(nameof(language)); + + if (string.IsNullOrEmpty(page)) + throw new ArgumentNullException(nameof(page)); + + return Connection + .SendAsync( + HttpMethod.Put, + BuildUri($"self-service-profiles/{EncodePath(id)}/custom-text/{EncodePath(language)}/{EncodePath(page)}"), + body, + DefaultHeaders, + cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/IManagementApiClient.cs b/src/Auth0.ManagementApi/IManagementApiClient.cs index 064220da..4ceaf0e8 100644 --- a/src/Auth0.ManagementApi/IManagementApiClient.cs +++ b/src/Auth0.ManagementApi/IManagementApiClient.cs @@ -160,6 +160,11 @@ public interface IManagementApiClient : IDisposable /// Contains all the methods to call the /sessions endpoints. /// ISessionsClient Sessions { get; } + + /// + /// Contains all the methods to call the /self-service-profile endpoints. + /// + ISelfServiceProfilesClient SelfServiceProfilesClient { get; } /// /// Update the Access Token used with every request. diff --git a/src/Auth0.ManagementApi/ManagementApiClient.cs b/src/Auth0.ManagementApi/ManagementApiClient.cs index fb49b109..c985313b 100644 --- a/src/Auth0.ManagementApi/ManagementApiClient.cs +++ b/src/Auth0.ManagementApi/ManagementApiClient.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Text; +using Auth0.ManagementApi.Models.SelfServiceProfiles; namespace Auth0.ManagementApi { @@ -168,6 +169,9 @@ public class ManagementApiClient : IManagementApiClient /// public ISessionsClient Sessions { get; } + + /// + public ISelfServiceProfilesClient SelfServiceProfilesClient { get; } private Dictionary DefaultHeaders { get; set; } @@ -221,6 +225,7 @@ public ManagementApiClient(string token, Uri baseUri, IManagementConnection mana Users = new UsersClient(managementConnection, baseUri, DefaultHeaders); RefreshTokens = new RefreshTokenClient(managementConnection, baseUri, DefaultHeaders); Sessions = new SessionsClient(managementConnection, baseUri, DefaultHeaders); + SelfServiceProfilesClient = new SelfServiceProfilesClient(managementConnection, baseUri, DefaultHeaders); } /// diff --git a/src/Auth0.ManagementApi/Models/SelfServiceProfiles/Branding.cs b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/Branding.cs new file mode 100644 index 00000000..22dbfd19 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/Branding.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.SelfServiceProfiles +{ + public class Branding + { + /// + /// Logo Url + /// + [JsonProperty("logo_url")] + public string LogoUrl { get; set; } + + /// + /// Branding Colors + /// + [JsonProperty("colors")] + public Color Color { get; set; } + } + + public class Color + { + [JsonProperty("primary")] + public string Primary { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/SelfServiceProfiles/EnabledOrganization.cs b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/EnabledOrganization.cs new file mode 100644 index 00000000..5ee34df0 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/EnabledOrganization.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.SelfServiceProfiles +{ + /// + /// List of organizations that the connection will be enabled for. + /// + public class EnabledOrganization + { + /// + /// Organization identifier + /// + [JsonProperty("organization_id")] + public string OrganizationId { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfile.cs b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfile.cs new file mode 100644 index 00000000..2699e217 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfile.cs @@ -0,0 +1,26 @@ +using System; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.SelfServiceProfiles +{ + public class SelfServiceProfile : SelfServiceProfileBase + { + /// + /// The unique ID of the self-service profile. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The time when this self-service Profile was created. + /// + [JsonProperty("created_at")] + public DateTime CreatedAt { get; set; } + + /// + /// The time when this self-service Profile was updated. + /// + [JsonProperty("updated_at")] + public DateTime UpdatedAt { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfileBase.cs b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfileBase.cs new file mode 100644 index 00000000..490d352f --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfileBase.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.SelfServiceProfiles +{ + /// + /// Represents the Self Service Profile. + /// + public class SelfServiceProfileBase + { + /// + /// Name of the self-service profile. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Description of the self-service profile. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + [JsonProperty("user_attributes")] + public IList UserAttributes { get; set; } + + [JsonProperty("branding")] + public Branding Branding { get; set; } + + /// + /// List of IdP strategies that will be shown to users during the Self-Service SSO flow. + /// Possible values: [oidc, samlp, waad, google-apps, adfs, okta, keycloak-samlp, pingfederate] + /// + [JsonProperty("allowed_strategies")] + public string[] AllowedStrategies { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfileCreateRequest.cs b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfileCreateRequest.cs new file mode 100644 index 00000000..0e066995 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfileCreateRequest.cs @@ -0,0 +1,10 @@ +namespace Auth0.ManagementApi.Models.SelfServiceProfiles +{ + /// + /// Represents information required for creating a Self Service Profile + /// + public class SelfServiceProfileCreateRequest : SelfServiceProfileBase + { + + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfileUpdateRequest.cs b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfileUpdateRequest.cs new file mode 100644 index 00000000..8321cf66 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceProfileUpdateRequest.cs @@ -0,0 +1,10 @@ +namespace Auth0.ManagementApi.Models.SelfServiceProfiles +{ + /// + /// Contains information required for updating Self-Service-Profile + /// + public class SelfServiceProfileUpdateRequest : SelfServiceProfileBase + { + + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceSsoConnectionConfig.cs b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceSsoConnectionConfig.cs new file mode 100644 index 00000000..3b170de0 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceSsoConnectionConfig.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.SelfServiceProfiles +{ + /// + /// If provided, this will create a new connection for the SSO flow with the given configuration. + /// + public class SelfServiceSsoConnectionConfig + { + /// + /// Name of the connection that will be created as part of the SSO flow. + /// + [JsonProperty("name")] + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceSsoTicket.cs b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceSsoTicket.cs new file mode 100644 index 00000000..b379e9f2 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceSsoTicket.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.SelfServiceProfiles +{ + /// + /// SSO-access ticket + /// + public class SelfServiceSsoTicket + { + /// + /// The URL for the created ticket. + /// + [JsonProperty("ticket")] + public string Ticket { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceSsoTicketCreateRequest.cs b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceSsoTicketCreateRequest.cs new file mode 100644 index 00000000..255e8299 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/SelfServiceSsoTicketCreateRequest.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.SelfServiceProfiles +{ + public class SelfServiceSsoTicketCreateRequest + { + /// + /// If provided, this will allow editing of the provided connection during the SSO Flow + /// + [JsonProperty("connection_id")] + public string ConnectionId { get; set; } + + /// + [JsonProperty("connection_config")] + public SelfServiceSsoConnectionConfig ConnectionConfig { get; set; } + + /// + /// List of client_ids that the connection will be enabled for. + /// + [JsonProperty("enabled_clients")] + public string[] EnabledClients { get; set; } + + /// + [JsonProperty("enabled_organizations")] + public IList EnabledOrganizations { get; set; } + + /// + /// Number of seconds for which the ticket is valid before expiration. + /// If unspecified or set to 0, this value defaults to 432000 seconds (5 days). + /// + [JsonProperty("ttl_sec")] + public int? TtlSec { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/SelfServiceProfiles/UserAttribute.cs b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/UserAttribute.cs new file mode 100644 index 00000000..2386b2d1 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SelfServiceProfiles/UserAttribute.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.SelfServiceProfiles +{ + /// + /// Attribute to be mapped that will be shown to the user during the SS-SSO workflow. + /// + public class UserAttribute + { + /// + /// Identifier of this attribute. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Description of this attribute + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// Determines if the attribute is required. + /// + [JsonProperty("is_optional")] + public bool? IsOptional { get; set; } + } +} \ No newline at end of file diff --git a/tests/Auth0.AuthenticationApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs b/tests/Auth0.AuthenticationApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs index 452f3679..a72166a8 100644 --- a/tests/Auth0.AuthenticationApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs +++ b/tests/Auth0.AuthenticationApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Auth0.IntegrationTests.Shared.CleanUp; using Auth0.ManagementApi; +using Auth0.ManagementApi.Clients; namespace Auth0.AuthenticationApi.IntegrationTests.Testing { @@ -23,7 +24,8 @@ public static async Task CleanupAsync(ManagementApiClient client, CleanUpType ty new RulesCleanUpStrategy(client), new LogStreamsCleanUpStrategy(client), new RolesCleanUpStrategy(client), - new EncryptionKeysCleanupStrategy(client) + new EncryptionKeysCleanupStrategy(client), + new SelfServiceProviderCleanUpStrategy(client) }; var cleanUpStrategy = strategies.Single(s => s.Type == type); diff --git a/tests/Auth0.IntegrationTests.Shared/CleanUp/CleanUpType.cs b/tests/Auth0.IntegrationTests.Shared/CleanUp/CleanUpType.cs index a2b0ec83..413a81be 100644 --- a/tests/Auth0.IntegrationTests.Shared/CleanUp/CleanUpType.cs +++ b/tests/Auth0.IntegrationTests.Shared/CleanUp/CleanUpType.cs @@ -13,6 +13,7 @@ public enum CleanUpType Roles, Rules, LogStreams, - EncryptionKeys + EncryptionKeys, + SelfServiceProvider } } \ No newline at end of file diff --git a/tests/Auth0.IntegrationTests.Shared/CleanUp/SelfServiceProviderCleanUpStrategy.cs b/tests/Auth0.IntegrationTests.Shared/CleanUp/SelfServiceProviderCleanUpStrategy.cs new file mode 100644 index 00000000..7bcceeb6 --- /dev/null +++ b/tests/Auth0.IntegrationTests.Shared/CleanUp/SelfServiceProviderCleanUpStrategy.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using Auth0.ManagementApi; + +namespace Auth0.IntegrationTests.Shared.CleanUp +{ + public class SelfServiceProviderCleanUpStrategy : CleanUpStrategy + { + public SelfServiceProviderCleanUpStrategy(ManagementApiClient apiClient) : base(CleanUpType.SelfServiceProvider, apiClient) + { + + } + + public override async Task Run(string id) + { + System.Diagnostics.Debug.WriteLine("Running SelfServiceProviderCleanup"); + await ApiClient.SelfServiceProfilesClient.DeleteAsync(id); + } + } +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/SelfServiceProfileTest.cs b/tests/Auth0.ManagementApi.IntegrationTests/SelfServiceProfileTest.cs new file mode 100644 index 00000000..e986d171 --- /dev/null +++ b/tests/Auth0.ManagementApi.IntegrationTests/SelfServiceProfileTest.cs @@ -0,0 +1,189 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Auth0.IntegrationTests.Shared.CleanUp; +using Auth0.ManagementApi.IntegrationTests.Testing; +using Auth0.ManagementApi.Models.SelfServiceProfiles; +using FluentAssertions; +using Newtonsoft.Json; +using Xunit; + +namespace Auth0.ManagementApi.IntegrationTests; + +public class SelfServiceProfileTestFixture : TestBaseFixture +{ + public override async Task DisposeAsync() + { + foreach (KeyValuePair> entry in identifiers) + { + await ManagementTestBaseUtils.CleanupAsync(ApiClient, entry.Key, entry.Value); + } + + ApiClient.Dispose(); + } +} + +public class SelfServiceProfileTest : IClassFixture +{ + private SelfServiceProfileTestFixture _fixture; + + public SelfServiceProfileTest(SelfServiceProfileTestFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async void Test_self_service_profile_crud_operation() + { + // Create a self-service provider + var createRequest = GetASelfServiceProfileCreateRequest(); + var ssp = await _fixture.ApiClient.SelfServiceProfilesClient.CreateAsync(createRequest); + _fixture.TrackIdentifier(CleanUpType.SelfServiceProvider, ssp.Id); + ssp.Should().BeEquivalentTo(createRequest); + + // Get the created self-service provider + var sspAfterCreation = await _fixture.ApiClient.SelfServiceProfilesClient.GetAsync(ssp.Id); + sspAfterCreation.Should().BeEquivalentTo(createRequest); + + // update the self-service provider + var sspUpdateRequest = GetASelfServiceProfileUpdateRequest(); + var sspUpdated = await _fixture.ApiClient.SelfServiceProfilesClient.UpdateAsync(ssp.Id, sspUpdateRequest); + sspUpdated.Should().BeEquivalentTo(sspUpdateRequest); + + // Get All self-service providers + var allSsps = await _fixture.ApiClient.SelfServiceProfilesClient.GetAllAsync(); + allSsps.Count.Should().BeGreaterOrEqualTo(1); + + // Delete the self-service provider + await _fixture.ApiClient.SelfServiceProfilesClient.DeleteAsync(ssp.Id); + } + + [Fact] + public async void Test_self_service_sso_ticket_generation_revocation() + { + var createRequest = GetASelfServiceProfileCreateRequest(); + var ssp = await CreateASelfServiceProfile(createRequest); + + var existingOrganizationId = "org_V6ojENVd1ERs5YY1"; + var ssoTicket = await _fixture.ApiClient.SelfServiceProfilesClient.CreateSsoTicketAsync( + ssp.Id, new SelfServiceSsoTicketCreateRequest() + { + ConnectionConfig = new SelfServiceSsoConnectionConfig() + { + Name = "Test-Connection-For-SSO" + }, + EnabledOrganizations = new List() + { + new EnabledOrganization() + { + OrganizationId = existingOrganizationId + } + } + }); + + ssoTicket.Should().NotBeNull(); + + // Revoke the SSO ticket + await _fixture.ApiClient.SelfServiceProfilesClient.RevokeSsoTicketAsync(ssp.Id, ssoTicket.Ticket.Split('=').Last()); + + // Delete the self-service profile + await _fixture.ApiClient.SelfServiceProfilesClient.DeleteAsync(ssp.Id); + } + + [Fact] + public async void Test_self_service_custom_text_get_set() + { + var ssp = await CreateASelfServiceProfile(); + + var customTextBody = new Dictionary() + { + { "introduction", "Hello this is welcome page" } + }; + + var customText = + await _fixture.ApiClient.SelfServiceProfilesClient.SetCustomTextForSelfServiceProfileAsync( + ssp.Id, "en", "get-started", customTextBody); + + customText.Should().NotBeNull(); + customTextBody.Should() + .BeEquivalentTo(JsonConvert.DeserializeObject>(customText.ToString())); + + // Fetch the custom text and validate + var getCustomText = + await _fixture.ApiClient.SelfServiceProfilesClient.GetCustomTextForSelfServiceProfileAsync( + ssp.Id, "en", "get-started"); + getCustomText.Should().BeEquivalentTo(customText); + + // Delete the self-service profile + await _fixture.ApiClient.SelfServiceProfilesClient.DeleteAsync(ssp.Id); + } + + + private SelfServiceProfileCreateRequest GetASelfServiceProfileCreateRequest() + { + var createRequest = new SelfServiceProfileCreateRequest() + { + Name = "Test Self Service Profile", + Description = "Test Self Service Profile Description", + UserAttributes = new List() + { + new UserAttribute() + { + Name = "email", + Description = "Email", + IsOptional = false + } + }, + Branding = new Branding() + { + LogoUrl = "https://example.com/logo.png", + Color = new Color() + { + Primary = "#FF0000" + } + }, + AllowedStrategies = new string[] { "oidc" } + }; + return createRequest; + } + + private SelfServiceProfileUpdateRequest GetASelfServiceProfileUpdateRequest() + { + var sspUpdateRequest = new SelfServiceProfileUpdateRequest() + { + Name = "Test Self Service Profile Updated", + Description = "Test Self Service Profile Description Updated", + UserAttributes = new List() + { + new UserAttribute() + { + Name = "email", + Description = "Email", + IsOptional = true + } + }, + Branding = new Branding() + { + LogoUrl = "https://example.com/logo-updated.png", + Color = new Color() + { + Primary = "#00FF00" + } + }, + AllowedStrategies = new string[] { "samlp" } + }; + return sspUpdateRequest; + } + + private async Task CreateASelfServiceProfile( + SelfServiceProfileCreateRequest createRequest = null) + { + createRequest ??= GetASelfServiceProfileCreateRequest(); + + // Given a self-service profile + var ssp = await _fixture.ApiClient.SelfServiceProfilesClient.CreateAsync(createRequest); + _fixture.TrackIdentifier(CleanUpType.SelfServiceProvider, ssp.Id); + ssp.Should().BeEquivalentTo(createRequest); + return ssp; + } +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs b/tests/Auth0.ManagementApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs index 4e18d514..e6f1df45 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/Testing/ManagementTestBaseUtils.cs @@ -22,7 +22,8 @@ public static async Task CleanupAsync(ManagementApiClient client, CleanUpType ty new RulesCleanUpStrategy(client), new LogStreamsCleanUpStrategy(client), new RolesCleanUpStrategy(client), - new EncryptionKeysCleanupStrategy(client) + new EncryptionKeysCleanupStrategy(client), + new SelfServiceProviderCleanUpStrategy(client) }; var cleanUpStrategy = strategies.Single(s => s.Type == type);