Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Regional Deployment] Changes need for regional console with federation option #5738

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
22 changes: 11 additions & 11 deletions apps/console/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
import { Redirect, Route, RouteComponentProps, Router, Switch } from "react-router-dom";
import { Dispatch } from "redux";
import { commonConfig } from "./extensions";
import { useGetAllFeatures } from "./extensions/components/feature-gate/api/feature-gate";

Check warning on line 50 in apps/console/src/app.tsx

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

'useGetAllFeatures' is defined but never used. Allowed unused vars must match /^_/u
import { featureGateConfig } from "./extensions/configs/feature-gate";
import { AccessControlUtils } from "./features/access-control/configs/access-control";
import { EventPublisher, PreLoader } from "./features/core";
Expand Down Expand Up @@ -93,16 +93,16 @@

const [ baseRoutes, setBaseRoutes ] = useState<RouteInterface[]>(getBaseRoutes());
const [ sessionTimedOut, setSessionTimedOut ] = useState<boolean>(false);
const [ orgId, setOrgId ] = useState<string>();

Check warning on line 96 in apps/console/src/app.tsx

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

'orgId' is assigned a value but never used. Allowed unused vars must match /^_/u
const [ featureGateConfigData, setFeatureGateConfigData ] =
const [ featureGateConfigData, setFeatureGateConfigData ] =
useState<FeatureGateInterface | null>(featureGateConfigUpdated);

const {
data: allFeatures,
error: featureGateAPIException
} = useGetAllFeatures(orgId, state.isAuthenticated);

// const {
// data: allFeatures,
// error: featureGateAPIException
// } = useGetAllFeatures(orgId, state.isAuthenticated);
const allFeatures = []

Check warning on line 104 in apps/console/src/app.tsx

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

Expected allFeatures to have a type annotation

Check warning on line 104 in apps/console/src/app.tsx

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

Missing semicolon
useEffect(() => {

Check warning on line 105 in apps/console/src/app.tsx

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

Expected blank line before this statement
if(state.isAuthenticated) {
if (OrganizationUtils.isSuperOrganization(store.getState().organization.organization)
|| store.getState().organization.isFirstLevelOrganization) {
Expand All @@ -121,7 +121,7 @@
}, [ state ]);

useEffect(() => {
if (allFeatures instanceof IdentityAppsApiException || featureGateAPIException) {
if (allFeatures instanceof IdentityAppsApiException) {
return;
}

Expand All @@ -135,13 +135,13 @@
const path: string = feature.featureIdentifier.replace(/-/g, ".");
// Obtain the status and set it to the feature gate config.
const featureStatusPath: string = `${ path }.status`;

set(featureGateConfigUpdated,featureStatusPath, feature.featureStatus);

const featureTagPath: string = `${ path }.tags`;

set(featureGateConfigUpdated,featureTagPath, feature.featureTags);

setFeatureGateConfigData(featureGateConfigUpdated);
});
}
Expand Down
33 changes: 25 additions & 8 deletions apps/console/src/auth.html
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,22 @@
? userAccessedPath.split("utype=")[1]
: null;

const urlParams = new URLSearchParams(window.location.search);
if (userTenant) {
sessionStorage.setItem("user_tenant", userTenant);
}

const urlParams = new URLSearchParams(window.location.search);
var isPrivilegedUser = false;
var tenantReplacement = "a";
var serverOrigin = startupConfig.serverUrl;
if (userTenant) {
isPrivilegedUser = true;
serverOrigin = startupConfig.serverUrl;
tenantReplacement = userTenant;
} else {
isPrivilegedUser = false;
serverOrigin = "https://api.eu.asg.io";
}
var authorizationCode = urlParams.get("code");
var authSessionState = urlParams.get("session_state");

Expand Down Expand Up @@ -213,7 +226,7 @@

var basePath = applicationDomain.replace(/\/+$/, '') + getOrganizationPath();
var baseRedirectURL = "<%= htmlWebpackPlugin.options.basename%>" ? basePath + '/' + "<%= htmlWebpackPlugin.options.basename%>" : basePath;

var loginTenant = userTenant.replace(/\/+$/, "");
var authConfig = {
signInRedirectURL: baseRedirectURL,
signOutRedirectURL: baseRedirectURL,
Expand All @@ -227,20 +240,24 @@
endpoints: {
authorizationEndpoint: getApiPath(
userTenant
? "/" + startupConfig.tenantPrefix + "/" + startupConfig.superTenantProxy + startupConfig.pathExtension + "/oauth2/authorize" + "?ut=" +
? "/" + startupConfig.tenantPrefix + "/" + loginTenant + startupConfig.pathExtension + "/oauth2/authorize" + "?ut=" +
userTenant.replace(/\/+$/, "") +
(utype ? "&utype=" + utype : "")
: "/" + startupConfig.tenantPrefix + "/" + startupConfig.superTenantProxy + startupConfig.pathExtension + "/oauth2/authorize"
: "/" + startupConfig.tenantPrefix + "/" + loginTenant + startupConfig.pathExtension + "/oauth2/authorize"
),
clockTolerance: 300,
jwksEndpointURL: undefined,
jwksEndpointURL: getApiPath(
"/" + startupConfig.tenantPrefix + "/" + loginTenant + startupConfig.pathExtension + "/oauth2/jwks"
),
logoutEndpointURL: getApiPath(
"/" + startupConfig.tenantPrefix + "/" + startupConfig.superTenantProxy + startupConfig.pathExtension + "/oidc/logout"
"/" + startupConfig.tenantPrefix + "/" + loginTenant + startupConfig.pathExtension + "/oidc/logout"
),
oidcSessionIFrameEndpointURL: getApiPath(
"/" + startupConfig.tenantPrefix + "/" + startupConfig.superTenantProxy + startupConfig.pathExtension + "/oidc/checksession"
"/" + startupConfig.tenantPrefix + "/" + loginTenant + startupConfig.pathExtension + "/oidc/checksession"
),
tokenEndpointURL: getApiPath(
"/" + startupConfig.tenantPrefix + "/" + loginTenant + startupConfig.pathExtension + "/oauth2/token"
),
tokenEndpointURL: undefined,
tokenRevocationEndpointURL: undefined
},
enablePKCE: true
Expand Down
66 changes: 53 additions & 13 deletions apps/console/src/extensions/components/tenants/api/tenants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,28 @@
import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios";
import { store } from "../../../../features/core/store";
import { getTenantResourceEndpoints } from "../configs";
import { TenantRequestResponse } from "../models";

Check warning on line 25 in apps/console/src/extensions/components/tenants/api/tenants.ts

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

'TenantRequestResponse' is defined but never used. Allowed unused vars must match /^_/u
import { EnvironmentRequestResponse } from "../models";

Check warning on line 26 in apps/console/src/extensions/components/tenants/api/tenants.ts

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

'../models' import is duplicated

export const getDomainQueryParam = (): string => {
const tenantDomain: string = store.getState().auth.tenantDomain;

return `?domain=${ tenantDomain }`;
};

const getUsernameQueryParam = (): string => {
// const username: string = store.getState()?.auth?.username;
const userId: string = store.getState()?.environment?.loggedInUserId;

return `&userUUID=${ userId }`;
};

const getUserIdQueryParam = (): string => {
const userId: string = store.getState()?.environment?.loggedInUserId;

return `&userId=${ userId }`;
};

const isPrivilegedUser = (): boolean => {
const isPrivileged: boolean = store.getState()?.auth?.isPrivilegedUser ?? false;

Expand All @@ -48,17 +62,21 @@
*
* @param tenantName - new tenant name
*/
export const addNewTenant = (tenantName: string): Promise<AxiosResponse> => {
export const addNewTenant = (tenantName: string, deploymentUUID: string): Promise<AxiosResponse> => {
const requestConfig: AxiosRequestConfig = {
data: {
domain: tenantName
},
"orgName": tenantName,

Check warning on line 68 in apps/console/src/extensions/components/tenants/api/tenants.ts

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

Expected indentation of 12 spaces but found 20
"defaultEnvName": "prod",

Check warning on line 69 in apps/console/src/extensions/components/tenants/api/tenants.ts

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

Expected indentation of 12 spaces but found 20

Check warning on line 69 in apps/console/src/extensions/components/tenants/api/tenants.ts

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

Expected object keys to be in ascending order. 'defaultEnvName' should be before 'orgName'
"deploymentUUIDForDefaultEnv": deploymentUUID,
"isDefault": false
},

headers: {
"Access-Control-Allow-Origin": store.getState().config.deployment.clientOrigin,
"Content-Type": "application/json"
},
method: HttpMethods.POST,
url: getTenantResourceEndpoints().tenantManagementApi + getDomainQueryParam()
url: getTenantResourceEndpoints().tenantManagementApi + "/organization" + getDomainQueryParam()
};

return httpClient(requestConfig)
Expand Down Expand Up @@ -104,7 +122,8 @@
"Access-Control-Allow-Origin": store.getState().config.deployment.clientOrigin
},
method: HttpMethods.HEAD,
url: getTenantResourceEndpoints().tenantManagementApi + "/" + tenantName + getDomainQueryParam()
url: getTenantResourceEndpoints().tenantManagementApi + "/organization/check-org" + getDomainQueryParam() +
"&orgName=" + tenantName + getUsernameQueryParam()
};

return httpClient(requestConfig)
Expand All @@ -121,23 +140,26 @@
*
* @returns - A promise that resolves with the tenant request response object.
*/
export const getAssociatedTenants = (): Promise<TenantRequestResponse> => {
export const getAssociatedTenants = (): Promise<EnvironmentRequestResponse []> => {
const orgType: OrganizationType = store.getState().organization.organizationType;

// If the user is a privileged user or the function is being called inside a suborganization,
// return an empty response.
if (isPrivilegedUser() || orgType === OrganizationType.SUBORGANIZATION) {
return Promise.resolve({
associatedTenants: [],
count: 0,
startIndex: 0,
totalResults: 0
});
return Promise.resolve([{
orgName: "",
orgUUID: "",
environments: []
}]);
}

const requestConfig: AxiosRequestConfig = {
headers: {
"Access-Control-Allow-Origin": store.getState().config.deployment.clientOrigin
},
method: HttpMethods.GET,
url: getTenantResourceEndpoints().tenantAssociationApi + getDomainQueryParam()
// url: getTenantResourceEndpoints().tenantAssociationApi + getDomainQueryParam()
url: getTenantResourceEndpoints().tenantManagementApi + "/user-association/user/me" + getDomainQueryParam() + getUserIdQueryParam()
};

return httpClient(requestConfig)
Expand All @@ -148,3 +170,21 @@
return Promise.reject(error?.response?.data);
});
};

/**
* Get the deployments associated with the current user.
*/
export const getDeployments = (): Promise<AxiosResponse> => {

const requestConfig: AxiosRequestConfig = {
url: getTenantResourceEndpoints().tenantManagementApi + "/deployment" + getDomainQueryParam()
};

return httpClient(requestConfig)
.then((response: AxiosResponse) => {
return Promise.resolve(response);
})
.catch((error: AxiosError) => {
return Promise.reject(error?.response?.data);
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* under the License.
*/

import { useAuthContext } from "@asgardeo/auth-react";
import { AlertInterface, AlertLevels, TestableComponentInterface } from "@wso2is/core/models";
import { addAlert } from "@wso2is/core/store";
import { useTrigger } from "@wso2is/forms";
Expand Down Expand Up @@ -78,6 +79,8 @@ export const AddTenantWizard: FunctionComponent<AddTenantWizardPropsInterface> =
}
}, [ submissionValue, finishSubmit ]);

const { updateConfig } = useAuthContext();

const handleFormSubmit = (): void => {
setIsNewTenantLoading(true);
setTenantLoaderText(
Expand All @@ -99,7 +102,7 @@ export const AddTenantWizard: FunctionComponent<AddTenantWizardPropsInterface> =
.catch((error: AxiosError) => {
if (error.response.status == 404) {
// Proceed to tenant creation if tenant does not exist.
addTenant(submissionValue.tenantName);
addTenant(submissionValue.tenantName, submissionValue.deploymentUUID);
} else {
setIsNewTenantLoading(false);
setAlert({
Expand Down Expand Up @@ -140,10 +143,10 @@ export const AddTenantWizard: FunctionComponent<AddTenantWizardPropsInterface> =
title: t("extensions:manage.features.tenant.wizards.addTenant.heading")
} ];

const addTenant = (tenantName: string): void => {
const addTenant = (tenantName: string, deploymentUUID: string): void => {
setIsNewTenantLoading(true);
setTenantLoaderText(t("extensions:manage.features.tenant.wizards.addTenant.forms.loaderMessages.tenantCreate"));
addNewTenant(tenantName)
addNewTenant(tenantName, deploymentUUID)
.then((response: AxiosResponse) => {
if (response.status === 201) {
eventPublisher.publish("create-new-organization");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import { OrganizationType } from "../../../../../features/organizations/constant
import { useGetCurrentOrganizationType } from "../../../../../features/organizations/hooks/use-get-organization-type";
import { FeatureGateConstants } from "../../../feature-gate/constants/feature-gate";
import { getAssociatedTenants, makeTenantDefault } from "../../api";
import { TenantInfo, TenantRequestResponse, TriggerPropTypesInterface } from "../../models";
import { TenantInfo, TenantRequestResponse, TriggerPropTypesInterface, EnvironmentInfo, EnvironmentRequestResponse } from "../../models";
import { handleTenantSwitch } from "../../utils";
import { AddTenantWizard } from "../add-modal";

Expand Down Expand Up @@ -124,19 +124,27 @@ const TenantDropdown: FunctionComponent<TenantDropdownInterface> = (props: Tenan
useEffect(() => {
if (!isPrivilegedUser && saasFeatureStatus !== FeatureStatus.DISABLED) {
getAssociatedTenants()
.then((response: TenantRequestResponse) => {
.then((response: EnvironmentRequestResponse []) => {
let defaultDomain: string = "";
const tenants: string[] = [];
const associatedTenants: TenantInfo[] = [];

response.associatedTenants.forEach((tenant: TenantInfo) => {
if (tenant.default) {
defaultDomain = tenant.domain;
response.forEach((environmentRequestResponse: EnvironmentRequestResponse) => {
environmentRequestResponse.environments.forEach((environment: EnvironmentInfo) => {
if (environment.isDefault) {
defaultDomain = environmentRequestResponse.orgName;
}

tenants.push(tenant.domain);
});
tenants.push(environmentRequestResponse.orgName);
associatedTenants.push({
id: environmentRequestResponse.orgUUID,
domain: environmentRequestResponse.orgName,
default: defaultDomain == environmentRequestResponse.orgName,
associationType: "member"
});
});

dispatch(setTenants<TenantInfo>(response.associatedTenants));
dispatch(setTenants<TenantInfo>(associatedTenants));
setAssociatedTenants(tenants);
setDefaultTenant(defaultDomain);
})
Expand Down Expand Up @@ -383,7 +391,7 @@ const TenantDropdown: FunctionComponent<TenantDropdownInterface> = (props: Tenan
<Dropdown.Menu className="tenant-dropdown-menu" onClick={ handleDropdownClick }>
<Item.Group className="current-tenant" unstackable>
<Item
className={ isSubOrg ? "header sub-org-header" : "header" }
className={ isSubOrg ? "header sub-org-header" : "header" }
key={ "current-tenant" }
>
{
Expand Down Expand Up @@ -434,7 +442,7 @@ const TenantDropdown: FunctionComponent<TenantDropdownInterface> = (props: Tenan
data-inverted
data-tooltip={ isCopying
? t("extensions:manage.features.tenant." +
"header.copied")
"header.copied")
: t("extensions:manage.features.tenant." +
"header.copyOrganizationId")
}
Expand Down Expand Up @@ -474,7 +482,7 @@ const TenantDropdown: FunctionComponent<TenantDropdownInterface> = (props: Tenan
disabled={ true }
>
<BuildingCircleCheckIcon fill="black" />
{
{
t("extensions:manage.features.tenant." +
"header.makeDefaultOrganization")
}
Expand All @@ -490,7 +498,7 @@ const TenantDropdown: FunctionComponent<TenantDropdownInterface> = (props: Tenan
disabled={ isSetDefaultTenantInProgress }
>
<BuildingCircleCheckIcon fill="black" />
{
{
t("extensions:manage.features.tenant." +
"header.makeDefaultOrganization")
}
Expand Down
Loading
Loading