From 6d190b0f329d095e910c76a60e8bf54b33c5699d Mon Sep 17 00:00:00 2001 From: Spencer Witt <3409780+spwitt@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:56:51 -0600 Subject: [PATCH 1/8] add AuditLog.tenantId --- src/main/java/io/fusionauth/domain/AuditLog.java | 10 +++++++--- .../domain/search/AuditLogSearchCriteria.java | 8 ++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/fusionauth/domain/AuditLog.java b/src/main/java/io/fusionauth/domain/AuditLog.java index ad215ac81..8747deb5c 100644 --- a/src/main/java/io/fusionauth/domain/AuditLog.java +++ b/src/main/java/io/fusionauth/domain/AuditLog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, FusionAuth, All Rights Reserved + * Copyright (c) 2018-2026, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; +import java.util.UUID; import com.inversoft.json.ToString; import io.fusionauth.domain.util.Normalizer; @@ -45,6 +46,8 @@ public class AuditLog implements Buildable { public String reason; + public UUID tenantId; + public AuditLog() { } @@ -69,12 +72,13 @@ public boolean equals(Object o) { Objects.equals(message, auditLog.message) && Objects.equals(newValue, auditLog.newValue) && Objects.equals(oldValue, auditLog.oldValue) && - Objects.equals(reason, auditLog.reason); + Objects.equals(reason, auditLog.reason) && + Objects.equals(tenantId, auditLog.tenantId); } @Override public int hashCode() { - return Objects.hash(data, id, insertInstant, insertUser, message, newValue, oldValue, reason); + return Objects.hash(data, id, insertInstant, insertUser, message, newValue, oldValue, reason, tenantId); } public void normalize() { diff --git a/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java b/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java index 983a21f88..cffbfd4e9 100644 --- a/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java +++ b/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2022, FusionAuth, All Rights Reserved + * Copyright (c) 2018-2026, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import java.util.UUID; import com.inversoft.json.JacksonConstructor; import io.fusionauth.domain.Buildable; @@ -43,16 +44,19 @@ public class AuditLogSearchCriteria extends BaseSearchCriteria implements Builda public ZonedDateTime start; + public UUID tenantId; + public String user; @JacksonConstructor public AuditLogSearchCriteria() { } - public AuditLogSearchCriteria(String message, String user, ZonedDateTime start, ZonedDateTime end, String orderBy) { + public AuditLogSearchCriteria(UUID tenantId, String message, String user, ZonedDateTime start, ZonedDateTime end, String orderBy) { this.end = end; this.message = message; this.start = start; + this.tenantId = tenantId; this.user = user; this.orderBy = orderBy; } From 6ffc181848a07ba566d16be7014b56dac4a39d74 Mon Sep 17 00:00:00 2001 From: Spencer Witt <3409780+spwitt@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:08:17 -0600 Subject: [PATCH 2/8] Merge spencer/eng-3773/idp-source (#177) add IdentityProvider.source and IdentityProviderSource enum to clients --- .../domain/provider/BaseIdentityProvider.java | 7 +++-- .../provider/IdentityProviderSource.java | 30 +++++++++++++++++++ .../IdentityProviderSearchCriteria.java | 5 +++- 3 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/fusionauth/domain/provider/IdentityProviderSource.java diff --git a/src/main/java/io/fusionauth/domain/provider/BaseIdentityProvider.java b/src/main/java/io/fusionauth/domain/provider/BaseIdentityProvider.java index 6ef994ebc..593e487b1 100644 --- a/src/main/java/io/fusionauth/domain/provider/BaseIdentityProvider.java +++ b/src/main/java/io/fusionauth/domain/provider/BaseIdentityProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2025, FusionAuth, All Rights Reserved + * Copyright (c) 2018-2026, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,6 +56,8 @@ public abstract class BaseIdentityProvider tenantConfiguration = new HashMap<>(); public UUID tenantId; @@ -81,6 +83,7 @@ public boolean equals(Object o) { Objects.equals(lastUpdateInstant, that.lastUpdateInstant) && linkingStrategy == that.linkingStrategy && Objects.equals(name, that.name) && + source == that.source && Objects.equals(tenantId, that.tenantId) && Objects.equals(tenantConfiguration, that.tenantConfiguration); } @@ -89,7 +92,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(super.hashCode(), data, applicationConfiguration, debug, id, insertInstant, lambdaConfiguration, lastUpdateInstant, linkingStrategy, name, tenantId, tenantConfiguration); + return Objects.hash(super.hashCode(), data, applicationConfiguration, debug, id, insertInstant, lambdaConfiguration, lastUpdateInstant, linkingStrategy, name, source, tenantId, tenantConfiguration); } @JsonIgnore diff --git a/src/main/java/io/fusionauth/domain/provider/IdentityProviderSource.java b/src/main/java/io/fusionauth/domain/provider/IdentityProviderSource.java new file mode 100644 index 000000000..f9dcd8559 --- /dev/null +++ b/src/main/java/io/fusionauth/domain/provider/IdentityProviderSource.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026, FusionAuth, All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ +package io.fusionauth.domain.provider; + +/** + * The source of an identity provider configuration. + */ +public enum IdentityProviderSource { + /** + * The configuration originated from the FusionAuth admin console or API + */ + System, + /** + * The configuration originated from the Tenant Manager application + */ + TenantManager +} diff --git a/src/main/java/io/fusionauth/domain/search/IdentityProviderSearchCriteria.java b/src/main/java/io/fusionauth/domain/search/IdentityProviderSearchCriteria.java index 7c9e01d61..979d9fb7d 100644 --- a/src/main/java/io/fusionauth/domain/search/IdentityProviderSearchCriteria.java +++ b/src/main/java/io/fusionauth/domain/search/IdentityProviderSearchCriteria.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2025, FusionAuth, All Rights Reserved + * Copyright (c) 2023-2026, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.util.UUID; import com.inversoft.json.JacksonConstructor; +import io.fusionauth.domain.provider.IdentityProviderSource; import io.fusionauth.domain.provider.IdentityProviderType; import static io.fusionauth.domain.util.SQLTools.normalizeOrderBy; import static io.fusionauth.domain.util.SQLTools.toSearchString; @@ -37,6 +38,8 @@ public class IdentityProviderSearchCriteria extends BaseSearchCriteria { public String name; + public IdentityProviderSource source; + public UUID tenantId; public IdentityProviderType type; From 9810c8130a74c2923222f899c77cf87fea67b6a1 Mon Sep 17 00:00:00 2001 From: Spencer Witt <3409780+spwitt@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:05:46 -0600 Subject: [PATCH 3/8] Merge spencer/eng-3772/key-source (#179) add KeySource and key.source to clients --- src/main/java/io/fusionauth/domain/Key.java | 18 +++++++++++++++++- .../domain/search/KeySearchCriteria.java | 5 ++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/fusionauth/domain/Key.java b/src/main/java/io/fusionauth/domain/Key.java index c37f6ca13..6a51dbe03 100644 --- a/src/main/java/io/fusionauth/domain/Key.java +++ b/src/main/java/io/fusionauth/domain/Key.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2025, FusionAuth, All Rights Reserved + * Copyright (c) 2019-2026, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,6 +63,8 @@ public class Key implements Buildable { public String secret; + public KeySource source = KeySource.System; + public KeyType type; @JacksonConstructor @@ -228,6 +230,20 @@ public String getName() { } } + /** + * The source of a key. + */ + public enum KeySource { + /** + * The key originated from the FusionAuth admin console or API + */ + System, + /** + * The key originated from the Tenant Manager application + */ + TenantManager + } + public enum KeyType { EC, RSA, diff --git a/src/main/java/io/fusionauth/domain/search/KeySearchCriteria.java b/src/main/java/io/fusionauth/domain/search/KeySearchCriteria.java index 7c733cbc1..6957eeac5 100644 --- a/src/main/java/io/fusionauth/domain/search/KeySearchCriteria.java +++ b/src/main/java/io/fusionauth/domain/search/KeySearchCriteria.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2023, FusionAuth, All Rights Reserved + * Copyright (c) 2023-2026, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import com.inversoft.json.JacksonConstructor; import io.fusionauth.domain.Key.KeyAlgorithm; +import io.fusionauth.domain.Key.KeySource; import io.fusionauth.domain.Key.KeyType; import static io.fusionauth.domain.util.SQLTools.normalizeOrderBy; import static io.fusionauth.domain.util.SQLTools.toSearchString; @@ -40,6 +41,8 @@ public class KeySearchCriteria extends BaseSearchCriteria { public String name; + public KeySource source; + public KeyType type; @JacksonConstructor From bd43e9242b626301aa3f9453f192ee57aabcded2 Mon Sep 17 00:00:00 2001 From: Jaret Hendrickson Date: Thu, 5 Feb 2026 10:28:10 -0600 Subject: [PATCH 4/8] Merge jaret/ENG-3777/tm-brand-reg-form-config (#181) --- .../domain/SystemConfiguration.java | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/fusionauth/domain/SystemConfiguration.java b/src/main/java/io/fusionauth/domain/SystemConfiguration.java index 44f8a7c4d..bd94d3975 100644 --- a/src/main/java/io/fusionauth/domain/SystemConfiguration.java +++ b/src/main/java/io/fusionauth/domain/SystemConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2025, FusionAuth, All Rights Reserved + * Copyright (c) 2018-2026, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.UUID; import com.inversoft.json.JacksonConstructor; import com.inversoft.json.ToString; @@ -50,6 +51,8 @@ public class SystemConfiguration implements Buildable { public ZoneId reportTimezone; + public TenantManagerConfiguration tenantManagerConfiguration = new TenantManagerConfiguration(); + public SystemTrustedProxyConfiguration trustedProxyConfiguration = new SystemTrustedProxyConfiguration(); public UIConfiguration uiConfiguration = new UIConfiguration(); @@ -74,6 +77,7 @@ public SystemConfiguration(SystemConfiguration other) { this.lastUpdateInstant = other.lastUpdateInstant; this.loginRecordConfiguration = new LoginRecordConfiguration(other.loginRecordConfiguration); this.reportTimezone = other.reportTimezone; + this.tenantManagerConfiguration = new TenantManagerConfiguration(other.tenantManagerConfiguration); this.trustedProxyConfiguration = new SystemTrustedProxyConfiguration(other.trustedProxyConfiguration); this.uiConfiguration = new UIConfiguration(other.uiConfiguration); this.usageDataConfiguration = new UsageDataConfiguration(other.usageDataConfiguration); @@ -97,6 +101,7 @@ public boolean equals(Object o) { Objects.equals(insertInstant, that.insertInstant) && Objects.equals(lastUpdateInstant, that.lastUpdateInstant) && Objects.equals(loginRecordConfiguration, that.loginRecordConfiguration) && + Objects.equals(tenantManagerConfiguration, that.tenantManagerConfiguration) && Objects.equals(trustedProxyConfiguration, that.trustedProxyConfiguration) && Objects.equals(reportTimezone, that.reportTimezone) && Objects.equals(uiConfiguration, that.uiConfiguration) && @@ -106,7 +111,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(auditLogConfiguration, cookieEncryptionKey, corsConfiguration, data, eventLogConfiguration, insertInstant, lastUpdateInstant, loginRecordConfiguration, reportTimezone, trustedProxyConfiguration, uiConfiguration, usageDataConfiguration, webhookEventLogConfiguration); + return Objects.hash(auditLogConfiguration, cookieEncryptionKey, corsConfiguration, data, eventLogConfiguration, insertInstant, lastUpdateInstant, loginRecordConfiguration, reportTimezone, tenantManagerConfiguration, trustedProxyConfiguration, uiConfiguration, usageDataConfiguration, webhookEventLogConfiguration); } public void normalize() { @@ -281,6 +286,45 @@ public String toString() { } } + public static class TenantManagerConfiguration implements Buildable { + + public UUID attributeFormId; + + public String brandName; + + @JacksonConstructor + public TenantManagerConfiguration() { + } + + public TenantManagerConfiguration(TenantManagerConfiguration other) { + this.brandName = other.brandName; + this.attributeFormId = other.attributeFormId; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TenantManagerConfiguration)) { + return false; + } + TenantManagerConfiguration that = (TenantManagerConfiguration) o; + return Objects.equals(brandName, that.brandName) && + Objects.equals(attributeFormId, that.attributeFormId); + } + + @Override + public int hashCode() { + return Objects.hash(brandName, attributeFormId); + } + + @Override + public String toString() { + return ToString.toString(this); + } + } + public static class UIConfiguration implements Buildable { public String headerColor; From 43cdf218aa2e8fc4e0aa96ad8c011e433f67b752 Mon Sep 17 00:00:00 2001 From: Spencer Witt <3409780+spwitt@users.noreply.github.com> Date: Thu, 5 Feb 2026 10:29:16 -0600 Subject: [PATCH 5/8] Merge spencer/eng-3775/complete-reg (#180) * add RegistrationConfiguration.completeRegistration * add UniversalConfiguration.allowTenantManagerIdentityProviders to domain --- src/main/java/io/fusionauth/domain/Application.java | 10 +++++++--- .../domain/UniversalApplicationConfiguration.java | 13 +++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/java/io/fusionauth/domain/Application.java b/src/main/java/io/fusionauth/domain/Application.java index 8d9ab271a..9ae62f80f 100644 --- a/src/main/java/io/fusionauth/domain/Application.java +++ b/src/main/java/io/fusionauth/domain/Application.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2025, FusionAuth, All Rights Reserved + * Copyright (c) 2019-2026, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -579,6 +579,8 @@ public String toString() { public static class RegistrationConfiguration extends Enableable implements Buildable { public Requirable birthDate = new Requirable(); + public boolean completeRegistration; + public boolean confirmPassword; public Requirable firstName = new Requirable(); @@ -605,6 +607,7 @@ public RegistrationConfiguration() { public RegistrationConfiguration(RegistrationConfiguration other) { this.birthDate = new Requirable(other.birthDate); + this.completeRegistration = other.completeRegistration; this.confirmPassword = other.confirmPassword; this.enabled = other.enabled; this.firstName = new Requirable(other.firstName); @@ -630,7 +633,8 @@ public boolean equals(Object o) { return false; } RegistrationConfiguration that = (RegistrationConfiguration) o; - return confirmPassword == that.confirmPassword && + return completeRegistration == that.completeRegistration && + confirmPassword == that.confirmPassword && Objects.equals(birthDate, that.birthDate) && Objects.equals(firstName, that.firstName) && Objects.equals(formId, that.formId) && @@ -645,7 +649,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(super.hashCode(), birthDate, confirmPassword, firstName, formId, fullName, lastName, loginIdType, middleName, mobilePhone, preferredLanguages, type); + return Objects.hash(super.hashCode(), birthDate, completeRegistration, confirmPassword, firstName, formId, fullName, lastName, loginIdType, middleName, mobilePhone, preferredLanguages, type); } public String toString() { diff --git a/src/main/java/io/fusionauth/domain/UniversalApplicationConfiguration.java b/src/main/java/io/fusionauth/domain/UniversalApplicationConfiguration.java index 810841896..a9e23d260 100644 --- a/src/main/java/io/fusionauth/domain/UniversalApplicationConfiguration.java +++ b/src/main/java/io/fusionauth/domain/UniversalApplicationConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, FusionAuth, All Rights Reserved + * Copyright (c) 2025-2026, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,16 +23,20 @@ * @author Lyle Schemmerling */ public class UniversalApplicationConfiguration { + public boolean allowTenantManagerIdentityProviders; + public boolean universal; @JacksonConstructor - public UniversalApplicationConfiguration() {} + public UniversalApplicationConfiguration() { + } public UniversalApplicationConfiguration(boolean universal) { this.universal = universal; } public UniversalApplicationConfiguration(UniversalApplicationConfiguration other) { + this.allowTenantManagerIdentityProviders = other.allowTenantManagerIdentityProviders; this.universal = other.universal; } @@ -42,11 +46,12 @@ public boolean equals(Object o) { return false; } UniversalApplicationConfiguration that = (UniversalApplicationConfiguration) o; - return universal == that.universal; + return allowTenantManagerIdentityProviders == that.allowTenantManagerIdentityProviders && + universal == that.universal; } @Override public int hashCode() { - return Objects.hashCode(universal); + return Objects.hash(allowTenantManagerIdentityProviders, universal); } } From f31ebc37c6abd74ea90ea8e299ad0d13b4539452 Mon Sep 17 00:00:00 2001 From: Jaret Hendrickson Date: Tue, 10 Feb 2026 09:51:46 -0600 Subject: [PATCH 6/8] add search criteria (#182) --- .../java/io/fusionauth/domain/search/AuditLogSearchCriteria.java | 1 + .../fusionauth/domain/search/IdentityProviderSearchCriteria.java | 1 + src/main/java/io/fusionauth/domain/search/KeySearchCriteria.java | 1 + 3 files changed, 3 insertions(+) diff --git a/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java b/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java index cffbfd4e9..afc8877d8 100644 --- a/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java +++ b/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java @@ -101,5 +101,6 @@ protected String defaultOrderBy() { SortableFields.put("insertInstant", "insert_instant"); SortableFields.put("insertUser", "insert_user"); SortableFields.put("message", "message"); + SortableFields.put("tenantId", "tenants_id"); } } diff --git a/src/main/java/io/fusionauth/domain/search/IdentityProviderSearchCriteria.java b/src/main/java/io/fusionauth/domain/search/IdentityProviderSearchCriteria.java index 979d9fb7d..351d68b28 100644 --- a/src/main/java/io/fusionauth/domain/search/IdentityProviderSearchCriteria.java +++ b/src/main/java/io/fusionauth/domain/search/IdentityProviderSearchCriteria.java @@ -74,6 +74,7 @@ protected String defaultOrderBy() { SortableFields.put("insertInstant", "insert_instant"); SortableFields.put("name", "name"); SortableFields.put("enabled", "enabled"); + SortableFields.put("source", "source"); SortableFields.put("tenantId", "tenants_id"); SortableFields.put("type", "type"); } diff --git a/src/main/java/io/fusionauth/domain/search/KeySearchCriteria.java b/src/main/java/io/fusionauth/domain/search/KeySearchCriteria.java index 6957eeac5..2d14333d7 100644 --- a/src/main/java/io/fusionauth/domain/search/KeySearchCriteria.java +++ b/src/main/java/io/fusionauth/domain/search/KeySearchCriteria.java @@ -80,5 +80,6 @@ protected String defaultOrderBy() { SortableFields.put("algorithm", "k.algorithm"); SortableFields.put("expiration", "k.expiration_instant"); SortableFields.put("insertInstant", "k.insert_instant"); + SortableFields.put("source", "k.source"); } } From b7772ac6fc0f0e519ea54b8edd8268cc2c3fe777 Mon Sep 17 00:00:00 2001 From: Jaret Hendrickson Date: Thu, 12 Feb 2026 13:30:54 -0600 Subject: [PATCH 7/8] PR feedback; sort by tenant name (#184) --- .../domain/search/AuditLogSearchCriteria.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java b/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java index afc8877d8..7d31a65b2 100644 --- a/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java +++ b/src/main/java/io/fusionauth/domain/search/AuditLogSearchCriteria.java @@ -16,6 +16,7 @@ package io.fusionauth.domain.search; import java.time.ZonedDateTime; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; @@ -30,6 +31,8 @@ * @author Brian Pontarelli */ public class AuditLogSearchCriteria extends BaseSearchCriteria implements Buildable { + public static final Set NullableFields = new HashSet<>(); + public static final Map SortableFields = new LinkedHashMap<>(); public ZonedDateTime end; @@ -78,7 +81,7 @@ public AuditLogSearchCriteria prepare() { orderBy = defaultOrderBy(); } - orderBy = SQLTools.normalizeOrderBy(orderBy, SortableFields); + orderBy = SQLTools.normalizeOrderBy(orderBy, SortableFields, NullableFields); user = toSearchString(user); message = toSearchString(message); newValue = toSearchString(newValue); @@ -98,9 +101,11 @@ protected String defaultOrderBy() { } static { - SortableFields.put("insertInstant", "insert_instant"); - SortableFields.put("insertUser", "insert_user"); - SortableFields.put("message", "message"); - SortableFields.put("tenantId", "tenants_id"); + NullableFields.add("tenant"); + + SortableFields.put("insertInstant", "al.insert_instant"); + SortableFields.put("insertUser", "al.insert_user"); + SortableFields.put("message", "al.message"); + SortableFields.put("tenant", "t.name"); } } From 83a65b706f19f3beb6dde65ef358e82688790e22 Mon Sep 17 00:00:00 2001 From: Spencer Witt <3409780+spwitt@users.noreply.github.com> Date: Fri, 13 Feb 2026 12:05:23 -0600 Subject: [PATCH 8/8] Merge spencer/eng-3779/tm-idp-types-api (#183) * add TenantManagerIdentityProviderTypeConfiguration domain object * add IdP type configs to SystemConfiguration.tenantManagerConfiguration * add /api/tenant-manager/identity-provider methods --- .../fusionauth/client/FusionAuthClient.java | 64 +++++++++++++ .../domain/SystemConfiguration.java | 13 ++- ...ntityProviderTypeConfigurationRequest.java | 30 +++++++ ...tityProviderTypeConfigurationResponse.java | 34 +++++++ ...agerIdentityProviderTypeConfiguration.java | 90 +++++++++++++++++++ 5 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 src/main/java/io/fusionauth/domain/api/tenantManager/TenantManagerIdentityProviderTypeConfigurationRequest.java create mode 100644 src/main/java/io/fusionauth/domain/api/tenantManager/TenantManagerIdentityProviderTypeConfigurationResponse.java create mode 100644 src/main/java/io/fusionauth/domain/tenantManager/TenantManagerIdentityProviderTypeConfiguration.java diff --git a/src/main/java/io/fusionauth/client/FusionAuthClient.java b/src/main/java/io/fusionauth/client/FusionAuthClient.java index bb8062cfd..94496fd97 100644 --- a/src/main/java/io/fusionauth/client/FusionAuthClient.java +++ b/src/main/java/io/fusionauth/client/FusionAuthClient.java @@ -212,6 +212,8 @@ import io.fusionauth.domain.api.report.MonthlyActiveUserReportResponse; import io.fusionauth.domain.api.report.RegistrationReportResponse; import io.fusionauth.domain.api.report.TotalsReportResponse; +import io.fusionauth.domain.api.tenantManager.TenantManagerIdentityProviderTypeConfigurationRequest; +import io.fusionauth.domain.api.tenantManager.TenantManagerIdentityProviderTypeConfigurationResponse; import io.fusionauth.domain.api.twoFactor.SecretResponse; import io.fusionauth.domain.api.twoFactor.TwoFactorLoginRequest; import io.fusionauth.domain.api.twoFactor.TwoFactorSendRequest; @@ -1167,6 +1169,22 @@ public ClientResponse createTenant(UUID tenantId, Tenant .go(); } + /** + * Creates a tenant manager identity provider type configuration for the given identity provider type. + * + * @param type The type of the identity provider. + * @param request The request object that contains all the information used to create the tenant manager identity provider type configuration. + * @return The ClientResponse object. + */ + public ClientResponse createTenantManagerIdentityProviderTypeConfiguration(IdentityProviderType type, TenantManagerIdentityProviderTypeConfigurationRequest request) { + return start(TenantManagerIdentityProviderTypeConfigurationResponse.class, Errors.class) + .uri("/api/tenant-manager/identity-provider") + .urlSegment(type) + .bodyHandler(new JSONBodyHandler(request, objectMapper())) + .post() + .go(); + } + /** * Creates a Theme. You can optionally specify an Id for the theme, if not provided one will be generated. * @@ -1747,6 +1765,20 @@ public ClientResponse deleteTenantAsync(UUID tenantId) { .go(); } + /** + * Deletes the tenant manager identity provider type configuration for the given identity provider type. + * + * @param type The type of the identity provider. + * @return The ClientResponse object. + */ + public ClientResponse deleteTenantManagerIdentityProviderTypeConfiguration(IdentityProviderType type) { + return start(Void.TYPE, Errors.class) + .uri("/api/tenant-manager/identity-provider") + .urlSegment(type) + .delete() + .go(); + } + /** * Deletes the tenant based on the given request (sent to the API as JSON). This permanently deletes all information, metrics, reports and data associated * with the tenant and everything under the tenant (applications, users, etc). @@ -3016,6 +3048,22 @@ public ClientResponse patchTenant(UUID tenantId, Map patchTenantManagerIdentityProviderTypeConfiguration(IdentityProviderType type, Map request) { + return start(TenantManagerIdentityProviderTypeConfigurationResponse.class, Errors.class) + .uri("/api/tenant-manager/identity-provider") + .urlSegment(type) + .bodyHandler(new JSONBodyHandler(request, objectMapper())) + .patch() + .go(); + } + /** * Updates, via PATCH, the theme with the given Id. * @@ -6106,6 +6154,22 @@ public ClientResponse updateTenant(UUID tenantId, Tenant .go(); } + /** + * Updates the tenant manager identity provider type configuration for the given identity provider type. + * + * @param type The type of the identity provider. + * @param request The request object that contains the updated tenant manager identity provider type configuration. + * @return The ClientResponse object. + */ + public ClientResponse updateTenantManagerIdentityProviderTypeConfiguration(IdentityProviderType type, TenantManagerIdentityProviderTypeConfigurationRequest request) { + return start(TenantManagerIdentityProviderTypeConfigurationResponse.class, Errors.class) + .uri("/api/tenant-manager/identity-provider") + .urlSegment(type) + .bodyHandler(new JSONBodyHandler(request, objectMapper())) + .put() + .go(); + } + /** * Updates the theme with the given Id. * diff --git a/src/main/java/io/fusionauth/domain/SystemConfiguration.java b/src/main/java/io/fusionauth/domain/SystemConfiguration.java index bd94d3975..64033219d 100644 --- a/src/main/java/io/fusionauth/domain/SystemConfiguration.java +++ b/src/main/java/io/fusionauth/domain/SystemConfiguration.java @@ -24,6 +24,7 @@ import com.inversoft.json.JacksonConstructor; import com.inversoft.json.ToString; +import io.fusionauth.domain.tenantManager.TenantManagerIdentityProviderTypeConfiguration; /** * @author Brian Pontarelli @@ -292,13 +293,16 @@ public static class TenantManagerConfiguration implements Buildable identityProviderTypeConfigurations = new HashMap<>(); + @JacksonConstructor public TenantManagerConfiguration() { } public TenantManagerConfiguration(TenantManagerConfiguration other) { - this.brandName = other.brandName; this.attributeFormId = other.attributeFormId; + this.brandName = other.brandName; + this.identityProviderTypeConfigurations.putAll(other.identityProviderTypeConfigurations); } @Override @@ -310,13 +314,14 @@ public boolean equals(Object o) { return false; } TenantManagerConfiguration that = (TenantManagerConfiguration) o; - return Objects.equals(brandName, that.brandName) && - Objects.equals(attributeFormId, that.attributeFormId); + return Objects.equals(attributeFormId, that.attributeFormId) && + Objects.equals(brandName, that.brandName) && + Objects.equals(identityProviderTypeConfigurations, that.identityProviderTypeConfigurations); } @Override public int hashCode() { - return Objects.hash(brandName, attributeFormId); + return Objects.hash(attributeFormId, brandName, identityProviderTypeConfigurations); } @Override diff --git a/src/main/java/io/fusionauth/domain/api/tenantManager/TenantManagerIdentityProviderTypeConfigurationRequest.java b/src/main/java/io/fusionauth/domain/api/tenantManager/TenantManagerIdentityProviderTypeConfigurationRequest.java new file mode 100644 index 000000000..1eee837ea --- /dev/null +++ b/src/main/java/io/fusionauth/domain/api/tenantManager/TenantManagerIdentityProviderTypeConfigurationRequest.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026, FusionAuth, All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ +package io.fusionauth.domain.api.tenantManager; + +import com.inversoft.json.JacksonConstructor; +import io.fusionauth.domain.tenantManager.TenantManagerIdentityProviderTypeConfiguration; + +/** + * The Tenant Manager IdP type configuration request object + */ +public class TenantManagerIdentityProviderTypeConfigurationRequest { + public TenantManagerIdentityProviderTypeConfiguration typeConfiguration; + + @JacksonConstructor + public TenantManagerIdentityProviderTypeConfigurationRequest() { + } +} diff --git a/src/main/java/io/fusionauth/domain/api/tenantManager/TenantManagerIdentityProviderTypeConfigurationResponse.java b/src/main/java/io/fusionauth/domain/api/tenantManager/TenantManagerIdentityProviderTypeConfigurationResponse.java new file mode 100644 index 000000000..5734e1364 --- /dev/null +++ b/src/main/java/io/fusionauth/domain/api/tenantManager/TenantManagerIdentityProviderTypeConfigurationResponse.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026, FusionAuth, All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ +package io.fusionauth.domain.api.tenantManager; + +import com.inversoft.json.JacksonConstructor; +import io.fusionauth.domain.tenantManager.TenantManagerIdentityProviderTypeConfiguration; + +/** + * The Tenant Manager IdP type configuration response object + */ +public class TenantManagerIdentityProviderTypeConfigurationResponse { + public TenantManagerIdentityProviderTypeConfiguration typeConfiguration; + + @JacksonConstructor + public TenantManagerIdentityProviderTypeConfigurationResponse() { + } + + public TenantManagerIdentityProviderTypeConfigurationResponse(TenantManagerIdentityProviderTypeConfiguration typeConfiguration) { + this.typeConfiguration = typeConfiguration; + } +} diff --git a/src/main/java/io/fusionauth/domain/tenantManager/TenantManagerIdentityProviderTypeConfiguration.java b/src/main/java/io/fusionauth/domain/tenantManager/TenantManagerIdentityProviderTypeConfiguration.java new file mode 100644 index 000000000..0a81a3bfd --- /dev/null +++ b/src/main/java/io/fusionauth/domain/tenantManager/TenantManagerIdentityProviderTypeConfiguration.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2026, FusionAuth, All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ +package io.fusionauth.domain.tenantManager; + +import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.inversoft.json.JacksonConstructor; +import com.inversoft.json.ToString; +import io.fusionauth.domain.Buildable; +import io.fusionauth.domain.Enableable; +import io.fusionauth.domain.provider.IdentityProviderLinkingStrategy; +import io.fusionauth.domain.provider.IdentityProviderType; + +/** + * Configuration object for identity provider types allowed in Tenant Manager + */ +public class TenantManagerIdentityProviderTypeConfiguration extends Enableable implements Buildable { + @JsonIgnore + public Map data = new LinkedHashMap<>(); + + public Map defaultAttributeMappings = new HashMap<>(); + + public ZonedDateTime insertInstant; + + public ZonedDateTime lastUpdateInstant; + + public IdentityProviderLinkingStrategy linkingStrategy; + + public IdentityProviderType type; + + @JacksonConstructor + public TenantManagerIdentityProviderTypeConfiguration() { + } + + public TenantManagerIdentityProviderTypeConfiguration(TenantManagerIdentityProviderTypeConfiguration other) { + this.data.putAll(other.data); + this.defaultAttributeMappings.putAll(other.defaultAttributeMappings); + this.insertInstant = other.insertInstant; + this.lastUpdateInstant = other.lastUpdateInstant; + this.linkingStrategy = other.linkingStrategy; + this.type = other.type; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + TenantManagerIdentityProviderTypeConfiguration that = (TenantManagerIdentityProviderTypeConfiguration) o; + return Objects.equals(defaultAttributeMappings, that.defaultAttributeMappings) && + Objects.equals(insertInstant, that.insertInstant) && + Objects.equals(lastUpdateInstant, that.lastUpdateInstant) && + linkingStrategy == that.linkingStrategy && + type == that.type; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), defaultAttributeMappings, insertInstant, lastUpdateInstant, linkingStrategy, type); + } + + @Override + public String toString() { + return ToString.toString(this); + } +}