Skip to content
Open
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
109 changes: 109 additions & 0 deletions src/main/java/io/fusionauth/client/FusionAuthClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@
import io.fusionauth.domain.api.TwoFactorRecoveryCodeResponse;
import io.fusionauth.domain.api.TwoFactorRequest;
import io.fusionauth.domain.api.TwoFactorResponse;
import io.fusionauth.domain.api.UniversalApplicationTenantRequest;
import io.fusionauth.domain.api.UniversalApplicationTenantResponse;
import io.fusionauth.domain.api.UniversalApplicationTenantSearchRequest;
import io.fusionauth.domain.api.UniversalApplicationTenantSearchResponse;
import io.fusionauth.domain.api.UserActionReasonRequest;
import io.fusionauth.domain.api.UserActionReasonResponse;
import io.fusionauth.domain.api.UserActionRequest;
Expand Down Expand Up @@ -982,6 +986,25 @@ public ClientResponse<ThemeResponse, Errors> createTheme(UUID themeId, ThemeRequ
.go();
}

/**
* Adds the application tenants for universal applications.
*
* @param applicationId The Id of the application that the universal application tenant belongs to.
* @param universalApplicationTenantId (Optional) The Id of the universal application tenant.
* @param request The request object that contains all the information used to create the UniversalApplicationTenants.
* @return The ClientResponse object.
*/
public ClientResponse<UniversalApplicationTenantResponse, Errors> createUniversalApplicationTenant(UUID applicationId, UUID universalApplicationTenantId, UniversalApplicationTenantRequest request) {
return start(UniversalApplicationTenantResponse.class, Errors.class)
.uri("/api/application")
.urlSegment(applicationId)
.urlSegment("universal-application-tenant")
.urlSegment(universalApplicationTenantId)
.bodyHandler(new JSONBodyHandler(request, objectMapper()))
.post()
.go();
}

/**
* Creates a user. You can optionally specify an Id for the user, if not provided one will be generated.
*
Expand Down Expand Up @@ -1577,6 +1600,40 @@ public ClientResponse<Void, Errors> deleteTheme(UUID themeId) {
.go();
}

/**
* Deletes the universal application tenant.
*
* @param applicationId The Id of the application that the UniversalApplicationTenant belongs to.
* @param universalApplicationTenantId The Id of the UniversalApplicationTenant to delete.
* @return The ClientResponse object.
*/
public ClientResponse<Void, Errors> deleteUniversalApplicationTenant(UUID applicationId, UUID universalApplicationTenantId) {
return start(Void.TYPE, Errors.class)
.uri("/api/application")
.urlSegment(applicationId)
.urlSegment("universal-application-tenant")
.urlSegment(universalApplicationTenantId)
.delete()
.go();
}

/**
* Removes the specified tenants from the universal application tenants list.
*
* @param applicationId The Id of the universal application that the tenants are linked to.
* @param tenantIds The Ids of the tenants to delete from the universal application tenants list.
* @return The ClientResponse object.
*/
public ClientResponse<Void, Errors> deleteUniversalApplicationTenants(UUID applicationId, Collection<UUID> tenantIds) {
return start(Void.TYPE, Errors.class)
.uri("/api/application")
.urlSegment(applicationId)
.urlSegment("application-tenant")
.urlParameter("tenantIds", tenantIds)
.delete()
.go();
}

/**
* Deletes the user for the given Id. This permanently deletes all information, metrics, reports and data associated
* with the user.
Expand Down Expand Up @@ -4048,6 +4105,23 @@ public ClientResponse<TwoFactorStatusResponse, Errors> retrieveTwoFactorStatus(U
.go();
}

/**
* Retrieves the universal application tenant.
*
* @param applicationId The Id of the universal application that tenant is mapped to
* @param universalApplicationTenantId The Id of the universal application tenant.
* @return The ClientResponse object.
*/
public ClientResponse<UniversalApplicationTenantResponse, Errors> retrieveUniversalApplicationTenant(UUID applicationId, UUID universalApplicationTenantId) {
return start(UniversalApplicationTenantResponse.class, Errors.class)
.uri("/api/application")
.urlSegment(applicationId)
.urlSegment("application-tenant")
.urlSegment(universalApplicationTenantId)
.get()
.go();
}

/**
* Retrieves the user for the given Id.
*
Expand Down Expand Up @@ -4882,6 +4956,22 @@ public ClientResponse<ThemeSearchResponse, Errors> searchThemes(ThemeSearchReque
.go();
}

/**
* Searches universal application tenants for the specified applicationId and with the specified criteria and pagination.
*
* @param request The search criteria and pagination information.
* @return The ClientResponse object.
*/
public ClientResponse<UniversalApplicationTenantSearchResponse, Errors> searchUniversalApplicationTenants(UniversalApplicationTenantSearchRequest request) {
return start(UniversalApplicationTenantSearchResponse.class, Errors.class)
.uri("/api/application")
.urlSegment("universal-application-tenant")
.urlSegment("search")
.bodyHandler(new JSONBodyHandler(request, objectMapper()))
.post()
.go();
}

/**
* Searches user comments with the specified criteria and pagination.
*
Expand Down Expand Up @@ -5603,6 +5693,25 @@ public ClientResponse<ThemeResponse, Errors> updateTheme(UUID themeId, ThemeRequ
.go();
}

/**
* Adds the application tenants for universal applications.
*
* @param applicationId The Id of the application that the UniversalApplicationTenant belongs to.
* @param universalApplicationTenantId The Id of the universal application tenant.
* @param request The request object that contains all the information used to create the UniversalApplicationTenant.
* @return The ClientResponse object.
*/
public ClientResponse<UniversalApplicationTenantResponse, Errors> updateUniversalApplicationTenant(UUID applicationId, UUID universalApplicationTenantId, UniversalApplicationTenantRequest request) {
return start(UniversalApplicationTenantResponse.class, Errors.class)
.uri("/api/application")
.urlSegment(applicationId)
.urlSegment("universal-application-tenant")
.urlSegment(universalApplicationTenantId)
.bodyHandler(new JSONBodyHandler(request, objectMapper()))
.put()
.go();
}

/**
* Updates the user with the given Id.
*
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/io/fusionauth/domain/Application.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2024, FusionAuth, All Rights Reserved
* Copyright (c) 2019-2025, 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.
Expand Down Expand Up @@ -104,6 +104,8 @@ public class Application implements Buildable<Application>, Tenantable {

public UUID themeId;

public UniversalApplicationConfiguration universalConfiguration = new UniversalApplicationConfiguration();

public RegistrationUnverifiedOptions unverified = new RegistrationUnverifiedOptions();

public UUID verificationEmailTemplateId;
Expand Down Expand Up @@ -147,6 +149,7 @@ public Application(Application other) {
this.state = other.state;
this.tenantId = other.tenantId;
this.themeId = other.themeId;
this.universalConfiguration = new UniversalApplicationConfiguration(other.universalConfiguration);
this.unverified = new RegistrationUnverifiedOptions(other.unverified);
this.verificationEmailTemplateId = other.verificationEmailTemplateId;
this.verificationStrategy = other.verificationStrategy;
Expand Down Expand Up @@ -213,6 +216,7 @@ public boolean equals(Object o) {
state == that.state &&
Objects.equals(tenantId, that.tenantId) &&
Objects.equals(themeId, that.themeId) &&
Objects.equals(universalConfiguration, that.universalConfiguration) &&
Objects.equals(unverified, that.unverified) &&
Objects.equals(verificationEmailTemplateId, that.verificationEmailTemplateId) &&
Objects.equals(webAuthnConfiguration, that.webAuthnConfiguration) &&
Expand Down Expand Up @@ -256,7 +260,7 @@ public boolean hasDefaultRole() {
@Override
public int hashCode() {
// active is omitted
return Objects.hash(accessControlConfiguration, authenticationTokenConfiguration, cleanSpeakConfiguration, data, emailConfiguration, externalIdentifierConfiguration, formConfiguration, id, insertInstant, jwtConfiguration, lambdaConfiguration, lastUpdateInstant, loginConfiguration, multiFactorConfiguration, name, oauthConfiguration, passwordlessConfiguration, registrationConfiguration, registrationDeletePolicy, roles, samlv2Configuration, scopes, state, tenantId, themeId, unverified, verificationEmailTemplateId, verificationStrategy, verifyRegistration, webAuthnConfiguration);
return Objects.hash(accessControlConfiguration, authenticationTokenConfiguration, cleanSpeakConfiguration, data, emailConfiguration, externalIdentifierConfiguration, formConfiguration, id, insertInstant, jwtConfiguration, lambdaConfiguration, lastUpdateInstant, loginConfiguration, multiFactorConfiguration, name, oauthConfiguration, passwordlessConfiguration, registrationConfiguration, registrationDeletePolicy, roles, samlv2Configuration, scopes, state, tenantId, themeId, universalConfiguration, unverified, verificationEmailTemplateId, verificationStrategy, verifyRegistration, webAuthnConfiguration);
}

public void normalize() {
Expand Down Expand Up @@ -885,4 +889,5 @@ public String toString() {
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2025, 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;

import java.util.Objects;

import com.inversoft.json.JacksonConstructor;

/**
* @author Lyle Schemmerling
*/
public class UniversalApplicationConfiguration { // TODO move to sep file/class and change name to UniversalApplicationConfiguration

// This is a flag to indicate that all tenants can use this universal application
public boolean global;

// This is a flag to indicate that this application is universal and can be used by the configured application tenants
public boolean universal;

@JacksonConstructor
public UniversalApplicationConfiguration() {
}

public UniversalApplicationConfiguration(UniversalApplicationConfiguration other) {
this.global = other.global;
this.universal = other.universal;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
UniversalApplicationConfiguration that = (UniversalApplicationConfiguration) o;
return global == that.global && universal == that.universal;
}

@Override
public int hashCode() {
return Objects.hash(global, universal);
}
}
76 changes: 76 additions & 0 deletions src/main/java/io/fusionauth/domain/UniversalApplicationTenant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2025, 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;

import java.time.ZonedDateTime;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

import com.inversoft.json.JacksonConstructor;

/**
* An object that represents the mapping between a Universal Application and a Tenant.
*
* @author Lyle Schemmerling
*/
public class UniversalApplicationTenant implements Buildable<UniversalApplicationTenant> {
public UUID applicationId;

public Map<String, Object> data = new LinkedHashMap<>();

public UUID id;

public ZonedDateTime insertInstant;

public ZonedDateTime lastUpdateInstant;

public UUID tenantId;

@JacksonConstructor
public UniversalApplicationTenant() {
}

// copy constructor
public UniversalApplicationTenant(UniversalApplicationTenant other) {
this.id = other.id;
this.tenantId = other.tenantId;
this.applicationId = other.applicationId;
this.insertInstant = other.insertInstant;
this.lastUpdateInstant = other.lastUpdateInstant;
this.data = new LinkedHashMap<>(other.data);
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
UniversalApplicationTenant that = (UniversalApplicationTenant) o;
return Objects.equals(id, that.id)
&& Objects.equals(insertInstant, that.insertInstant)
&& Objects.equals(lastUpdateInstant, that.lastUpdateInstant)
&& Objects.equals(applicationId, that.applicationId)
&& Objects.equals(tenantId, that.tenantId)
&& Objects.equals(data, that.data);
}

@Override
public int hashCode() {
return Objects.hash(id, insertInstant, lastUpdateInstant, applicationId, tenantId, data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2025, 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;

import java.util.Objects;

import com.inversoft.json.JacksonConstructor;
import io.fusionauth.domain.Buildable;
import io.fusionauth.domain.UniversalApplicationTenant;

/**
* The request object for creating or updating a Universal Application Tenant.
*
* @author Lyle Schemmerling
*/
public class UniversalApplicationTenantRequest implements Buildable<UniversalApplicationTenantRequest> {
public UniversalApplicationTenant universalApplicationTenant;

@JacksonConstructor
public UniversalApplicationTenantRequest() {
}

public UniversalApplicationTenantRequest(UniversalApplicationTenant universalApplicationTenant) {
this.universalApplicationTenant = universalApplicationTenant;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
UniversalApplicationTenantRequest that = (UniversalApplicationTenantRequest) o;
return Objects.equals(universalApplicationTenant, that.universalApplicationTenant);
}

@Override
public int hashCode() {
return Objects.hashCode(universalApplicationTenant);
}
}
Loading