feat: create initial admin user + add vendor to new tenant orgs
When creating a tenant, the vendor can specify adminUsername + adminPassword. The backend creates the user in Logto and assigns them the owner org role. The vendor user is also auto-added to every new org for support access. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -189,6 +189,42 @@ public class LogtoManagementClient {
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a user with username/password and add to org with role. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public String createUserWithPassword(String username, String password, String orgId, String roleId) {
|
||||
if (!isAvailable()) return null;
|
||||
try {
|
||||
var userResp = (Map<String, Object>) restClient.post()
|
||||
.uri(config.getLogtoEndpoint() + "/api/users")
|
||||
.header("Authorization", "Bearer " + getAccessToken())
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(Map.of("username", username, "password", password, "name", username))
|
||||
.retrieve()
|
||||
.body(Map.class);
|
||||
String userId = String.valueOf(userResp.get("id"));
|
||||
addUserToOrganization(orgId, userId);
|
||||
if (roleId != null) {
|
||||
assignOrganizationRole(orgId, userId, roleId);
|
||||
}
|
||||
log.info("Created user '{}' and added to org {} with role {}", username, orgId, roleId);
|
||||
return userId;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to create user '{}': {}", username, e.getMessage());
|
||||
throw new RuntimeException("User creation failed: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Find org role ID by name (e.g., "owner", "operator", "viewer"). */
|
||||
@SuppressWarnings("unchecked")
|
||||
public String findOrgRoleIdByName(String roleName) {
|
||||
var roles = listOrganizationRoles();
|
||||
return roles.stream()
|
||||
.filter(r -> roleName.equals(r.get("name")))
|
||||
.map(r -> String.valueOf(r.get("id")))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/** List available organization roles. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Map<String, Object>> listOrganizationRoles() {
|
||||
|
||||
@@ -7,5 +7,7 @@ import jakarta.validation.constraints.Size;
|
||||
public record CreateTenantRequest(
|
||||
@NotBlank @Size(max = 255) String name,
|
||||
@NotBlank @Size(max = 100) @Pattern(regexp = "^[a-z0-9][a-z0-9-]*[a-z0-9]$", message = "Slug must be lowercase alphanumeric with hyphens") String slug,
|
||||
String tier
|
||||
String tier,
|
||||
String adminUsername,
|
||||
String adminPassword
|
||||
) {}
|
||||
|
||||
@@ -58,13 +58,40 @@ public class VendorTenantService {
|
||||
|
||||
@Transactional
|
||||
public TenantEntity createAndProvision(CreateTenantRequest request, UUID actorId) {
|
||||
// 1. Create tenant record (sets status = PROVISIONING)
|
||||
// 1. Create tenant record (sets status = PROVISIONING) + Logto org
|
||||
TenantEntity tenant = tenantService.create(request, actorId);
|
||||
|
||||
// 2. Generate license
|
||||
// 2. Create initial admin user in Logto org (if credentials provided)
|
||||
if (tenant.getLogtoOrgId() != null && logtoClient.isAvailable()) {
|
||||
String ownerRoleId = logtoClient.findOrgRoleIdByName("owner");
|
||||
|
||||
// Create tenant admin
|
||||
if (request.adminUsername() != null && request.adminPassword() != null) {
|
||||
try {
|
||||
logtoClient.createUserWithPassword(
|
||||
request.adminUsername(), request.adminPassword(),
|
||||
tenant.getLogtoOrgId(), ownerRoleId);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to create admin user for tenant {}: {}", tenant.getSlug(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Add the current vendor user to the new org for support access
|
||||
try {
|
||||
String vendorUserId = actorId.toString();
|
||||
logtoClient.addUserToOrganization(tenant.getLogtoOrgId(), vendorUserId);
|
||||
if (ownerRoleId != null) {
|
||||
logtoClient.assignOrganizationRole(tenant.getLogtoOrgId(), vendorUserId, ownerRoleId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to add vendor to org for tenant {}: {}", tenant.getSlug(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Generate license
|
||||
LicenseEntity license = licenseService.generateLicense(tenant, DEFAULT_LICENSE_VALIDITY, actorId);
|
||||
|
||||
// 3. Provision server if provisioner is available
|
||||
// 4. Provision server if provisioner is available
|
||||
if (tenantProvisioner.isAvailable()) {
|
||||
var provisionRequest = new TenantProvisionRequest(
|
||||
tenant.getId(), tenant.getSlug(),
|
||||
|
||||
Reference in New Issue
Block a user