diff --git a/apps/console/CHANGELOG.md b/apps/console/CHANGELOG.md index 0f9402e6852..4df5145b852 100644 --- a/apps/console/CHANGELOG.md +++ b/apps/console/CHANGELOG.md @@ -1,5 +1,17 @@ # @wso2is/console +## 2.5.7 + +### Patch Changes + +- [#4427](https://github.com/wso2/identity-apps/pull/4427) [`728741fb00`](https://github.com/wso2/identity-apps/commit/728741fb00bab58d7736c1e9365631944fd1aa8b) Thanks [@brionmario](https://github.com/brionmario)! - Fix RBAC issues + +## 2.5.6 + +### Patch Changes + +- [#4426](https://github.com/wso2/identity-apps/pull/4426) [`580864ec22`](https://github.com/wso2/identity-apps/commit/580864ec220f997cbacf41956f051aa0f1ed4e9c) Thanks [@DonOmalVindula](https://github.com/DonOmalVindula)! - Hide org switch breadcrumb in Super org + ## 2.5.5 ### Patch Changes diff --git a/apps/console/java/org.wso2.identity.apps.console.server.feature/pom.xml b/apps/console/java/org.wso2.identity.apps.console.server.feature/pom.xml index a199743481b..757637291cd 100644 --- a/apps/console/java/org.wso2.identity.apps.console.server.feature/pom.xml +++ b/apps/console/java/org.wso2.identity.apps.console.server.feature/pom.xml @@ -23,7 +23,7 @@ org.wso2.identity.apps identity-apps-console - 2.5.3-SNAPSHOT + 2.5.8-SNAPSHOT ../pom.xml diff --git a/apps/console/java/org.wso2.identity.apps.console.server.feature/resources/deployment.config.json.j2 b/apps/console/java/org.wso2.identity.apps.console.server.feature/resources/deployment.config.json.j2 index 2965cc730e1..6808fc50b63 100644 --- a/apps/console/java/org.wso2.identity.apps.console.server.feature/resources/deployment.config.json.j2 +++ b/apps/console/java/org.wso2.identity.apps.console.server.feature/resources/deployment.config.json.j2 @@ -187,7 +187,7 @@ "appWhiteLogoPath": "{{ console.ui.app_white_logo_path }}", "emailTemplates": { "defaultLogoUrl": "{{ console.ui.email_templates.default_logo_url }}", - "defaultWhiteLogoUrl": "{{ console.ui.email_templates.default_white_logo_url }}", + "defaultWhiteLogoUrl": "{{ console.ui.email_templates.default_white_logo_url }}" }, "appFaviconPath": "{{ console.ui.app_favicon_path }}", "googleOneTapEnabledTenants": [ diff --git a/apps/console/java/pom.xml b/apps/console/java/pom.xml index 8c18ab07fea..12c52f2ffb4 100644 --- a/apps/console/java/pom.xml +++ b/apps/console/java/pom.xml @@ -24,7 +24,7 @@ org.wso2.identity.apps identity-apps-console pom - 2.5.3-SNAPSHOT + 2.5.8-SNAPSHOT WSO2 Identity Server Console - Parent WSO2 Identity Server Console Parent diff --git a/apps/console/java/webapp/pom.xml b/apps/console/java/webapp/pom.xml index 99e57129364..6644f918d37 100644 --- a/apps/console/java/webapp/pom.xml +++ b/apps/console/java/webapp/pom.xml @@ -23,7 +23,7 @@ org.wso2.identity.apps identity-apps-console - 2.5.3-SNAPSHOT + 2.5.8-SNAPSHOT ../pom.xml diff --git a/apps/console/package.json b/apps/console/package.json index 97ab80fd129..ce03876604c 100644 --- a/apps/console/package.json +++ b/apps/console/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@wso2is/console", - "version": "2.5.5", + "version": "2.5.7", "description": "WSO2 Identity Server Console", "author": "WSO2", "license": "Apache-2.0", diff --git a/apps/console/src/extensions/configs/identity-provider.tsx b/apps/console/src/extensions/configs/identity-provider.tsx index 52ca238f422..0b9e70ddbbe 100644 --- a/apps/console/src/extensions/configs/identity-provider.tsx +++ b/apps/console/src/extensions/configs/identity-provider.tsx @@ -245,7 +245,7 @@ export const identityProviderConfig: IdentityProviderConfig = { AuthenticatorLabels.PASSKEY ], filterFidoTags: (tags: string[]): string[] => { - return tags.filter((tag: string) => + return tags.filter((tag: string) => tag === AuthenticatorLabels.PASSWORDLESS || tag === AuthenticatorLabels.PASSKEY); }, generalDetailsForm: { @@ -265,7 +265,7 @@ export const identityProviderConfig: IdentityProviderConfig = { }, jitProvisioningSettings: { enableAssociateLocalUserField: { - show: !!window[ "AppUtils" ].getConfig().organizationName + show: !!window[ "AppUtils" ]?.getConfig()?.organizationName }, enableJitProvisioningField: { show: true diff --git a/apps/console/src/features/authentication-flow-builder/components/script-editor-side-panel/secret-selection-dropdown.tsx b/apps/console/src/features/authentication-flow-builder/components/script-editor-side-panel/secret-selection-dropdown.tsx index e84be9b3fc2..dee05b3f75e 100644 --- a/apps/console/src/features/authentication-flow-builder/components/script-editor-side-panel/secret-selection-dropdown.tsx +++ b/apps/console/src/features/authentication-flow-builder/components/script-editor-side-panel/secret-selection-dropdown.tsx @@ -146,7 +146,7 @@ const SecretSelectionDropdown = (props: SecretSelectionDropdownPropsInterface): > - ) : secretsList.length === 0 ? ( + ) : secretsList?.length === 0 ? ( ) : ( - secretsList.map((secret: SecretModel, index: number) => ( + secretsList?.map((secret: SecretModel, index: number) => ( <> - { index !== secretsList.length - 1 && } + { index !== secretsList?.length - 1 && } )) ) } diff --git a/apps/console/src/features/authentication/hooks/use-sign-in.ts b/apps/console/src/features/authentication/hooks/use-sign-in.ts index 02823dcdb39..044641903cb 100644 --- a/apps/console/src/features/authentication/hooks/use-sign-in.ts +++ b/apps/console/src/features/authentication/hooks/use-sign-in.ts @@ -42,7 +42,6 @@ import { ThunkDispatch } from "redux-thunk"; import useAuthorization from "../../authorization/hooks/use-authorization"; import { Config } from "../../core/configs/app"; import { AppConstants, CommonConstants } from "../../core/constants"; -import { MultitenantConstants } from "../../core/constants/multitenant-constants"; import { DeploymentConfigInterface } from "../../core/models/config"; import { AppState } from "../../core/store"; import { @@ -56,6 +55,7 @@ import { } from "../../core/store/actions/organization"; import { OrganizationType } from "../../organizations/constants"; import useOrganizationSwitch from "../../organizations/hooks/use-organization-switch"; +import useOrganizations from "../../organizations/hooks/use-organizations"; import { getProfileInformation } from "../store/actions"; import { AuthenticateUtils } from "../utils/authenticate-utils"; @@ -70,11 +70,9 @@ const LOGOUT_URL: string = "sign_out_url"; export type UseSignInInterface = { onSignIn: ( response: BasicUserInfo, - updateOrgPaths: boolean, onTenantResolve: (tenantDomain: string) => void, onSignInSuccessRedirect: (idToken: DecodedIDTokenPayload) => void, onAppReady: () => void, - _isFirstLevelOrg?: boolean, ) => Promise; }; @@ -96,13 +94,13 @@ const useSignIn = (): UseSignInInterface => { const { legacyAuthzRuntime } = useAuthorization(); + const { transformTenantDomain } = useOrganizations(); + const onSignIn = async ( response: BasicUserInfo, - updateOrgPaths: boolean, onTenantResolve: (tenantDomain: string) => void, onSignInSuccessRedirect: (idToken: DecodedIDTokenPayload) => void, - onAppReady: () => void, - _isFirstLevelOrg?: boolean + onAppReady: () => void ): Promise => { let logoutUrl: string; let logoutRedirectUrl: string; @@ -119,12 +117,9 @@ const useSignIn = (): UseSignInInterface => { const orgIdIdToken: string = idToken.org_id; const orgName: string = idToken.org_name; const userOrganizationId: string = idToken.user_org; + const isFirstLevelOrg: boolean = !idToken.user_org || idToken.user_org === idToken.org_id; - let tenantDomain: string = orgName; - - if (tenantDomain === MultitenantConstants.SUPER_TENANT_DISPLAY_NAME) { - tenantDomain = MultitenantConstants.SUPER_TENANT_DOMAIN_NAME; - } + let tenantDomain: string = transformTenantDomain(orgName); if (legacyAuthzRuntime) { tenantDomain = CommonAuthenticateUtils.deriveTenantDomainFromSubject( @@ -136,38 +131,26 @@ const useSignIn = (): UseSignInInterface => { let orgType: OrganizationType; - if (window["AppUtils"].getConfig().organizationName) { - orgType = OrganizationType.SUBORGANIZATION; - } else if (tenantDomain === AppConstants.getSuperTenant()) { + // Update the organization name with the newly resolved org. + if (!isFirstLevelOrg) { + window["AppUtils"].updateOrganizationName(orgIdIdToken); + } else { + // Update the app base name with the newly resolved tenant. + window[ "AppUtils" ].updateTenantQualifiedBaseName(tenantDomain); + } + + if (isFirstLevelOrg && tenantDomain === AppConstants.getSuperTenant()) { orgType = OrganizationType.SUPER_ORGANIZATION; - } else if (orgIdIdToken) { + } else if (isFirstLevelOrg) { orgType = OrganizationType.FIRST_LEVEL_ORGANIZATION; } else { - orgType = OrganizationType.TENANT; + orgType = OrganizationType.SUBORGANIZATION; } - // TODO: Remove this once the hasRequiredScopes() function is moved as a hook. - window["AppUtils"].updateOrganizationType(orgType); - dispatch(setOrganizationType(orgType)); dispatch(setUserOrganizationId(userOrganizationId)); - let isFirstLevelOrg: boolean = !window["AppUtils"].getConfig().organizationName && !!orgIdIdToken; - - // TODO: Redux store async issue here. Fix this properly. - if (_isFirstLevelOrg === false) { - isFirstLevelOrg = false; - } - dispatch(setIsFirstLevelOrganization(isFirstLevelOrg)); - - // Update the organization name with the newly resolved org. - if (updateOrgPaths) { - window["AppUtils"].updateOrganizationName(orgIdIdToken); - } else { - // Update the app base name with the newly resolved tenant. - window[ "AppUtils" ].updateTenantQualifiedBaseName(tenantDomain); - } if (window["AppUtils"].getConfig().organizationName || isFirstLevelOrg) { // We are actually getting the orgId here rather than orgName @@ -332,12 +315,16 @@ const useSignIn = (): UseSignInInterface => { dispatch( setSignIn( - Object.assign(CommonAuthenticateUtils.getSignInState(response, response.orgName), { - associatedTenants: isPrivilegedUser ? tenantDomain : idToken?.associated_tenants, - defaultTenant: isPrivilegedUser ? tenantDomain : idToken?.default_tenant, - fullName: fullName, - isPrivilegedUser: isPrivilegedUser - }) + Object.assign( + CommonAuthenticateUtils.getSignInState( + response, + transformTenantDomain(response.orgName) + ), { + associatedTenants: isPrivilegedUser ? tenantDomain : idToken?.associated_tenants, + defaultTenant: isPrivilegedUser ? tenantDomain : idToken?.default_tenant, + fullName: fullName, + isPrivilegedUser: isPrivilegedUser + }) ) ); diff --git a/apps/console/src/features/branding/api/branding-preferences.ts b/apps/console/src/features/branding/api/branding-preferences.ts index f5811a9ac7f..acd5ebdccc5 100644 --- a/apps/console/src/features/branding/api/branding-preferences.ts +++ b/apps/console/src/features/branding/api/branding-preferences.ts @@ -22,6 +22,7 @@ import { HttpMethods } from "@wso2is/core/models"; import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; import { I18nConstants } from "../../core/constants"; import { store } from "../../core/store"; +import { OrganizationType } from "../../organizations/constants/organization-constants"; import { BrandingPreferencesConstants } from "../constants"; import { BrandingPreferenceAPIResponseInterface, @@ -36,61 +37,6 @@ const httpClient: HttpClientInstance = AsgardeoSPAClient.getInstance() .httpRequest.bind(AsgardeoSPAClient.getInstance()) .bind(AsgardeoSPAClient.getInstance()); -/** - * Get the branding preference via Branding Preferences API. - * - * @param name - Resource Name. - * @param type - Resource Type. - * @param locale - Resource Locale. - * @returns Branding Preference. - * @throws IdentityAppsApiException. - */ -export const getBrandingPreference = ( - name: string, - type: BrandingPreferenceTypes = BrandingPreferenceTypes.ORG, - locale: string = I18nConstants.DEFAULT_FALLBACK_LANGUAGE -): Promise => { - - const requestConfig: AxiosRequestConfig = { - headers: { - "Accept": "application/json", - "Content-Type": "application/json" - }, - method: HttpMethods.GET, - params: { - locale, - name, - type - }, - url: store.getState().config.endpoints.brandingPreference - }; - - return httpClient(requestConfig) - .then((response: AxiosResponse) => { - if (response.status !== 200) { - throw new IdentityAppsApiException( - BrandingPreferencesConstants.ErrorMessages.BRANDING_PREFERENCE_FETCH_INVALID_STATUS_CODE_ERROR - .getErrorMessage(), - null, - response.status, - response.request, - response, - response.config); - } - - return Promise.resolve(response.data); - }).catch((error: AxiosError) => { - throw new IdentityAppsApiException( - error.response?.data?.message ?? BrandingPreferencesConstants - .ErrorMessages.BRANDING_PREFERENCE_FETCH_ERROR.getErrorMessage(), - error.stack, - error.response?.data?.code, - error.request, - error.response, - error.config); - }); -}; - /** * Update the branding preference via Branding Preferences API. * @@ -109,11 +55,14 @@ export const updateBrandingPreference = ( type: BrandingPreferenceTypes = BrandingPreferenceTypes.ORG, locale: string = I18nConstants.DEFAULT_FALLBACK_LANGUAGE ): Promise => { + const tenantDomain: string = store.getState().organization.organizationType === OrganizationType.SUBORGANIZATION + ? store.getState()?.organization?.organization?.id + : name; const requestConfig: AxiosRequestConfig = { data: { locale, - name, + name: tenantDomain, preference, type }, @@ -164,6 +113,9 @@ export const deleteBrandingPreference = ( type: BrandingPreferenceTypes = BrandingPreferenceTypes.ORG, locale: string = I18nConstants.DEFAULT_FALLBACK_LANGUAGE ): Promise => { + const tenantDomain: string = store.getState().organization.organizationType === OrganizationType.SUBORGANIZATION + ? store.getState()?.organization?.organization?.id + : name; const requestConfig: AxiosRequestConfig = { headers: { @@ -173,7 +125,7 @@ export const deleteBrandingPreference = ( method: HttpMethods.DELETE, params: { locale, - name, + name: tenantDomain, type }, url: store.getState().config.endpoints.brandingPreference diff --git a/apps/console/src/features/branding/api/delete-custom-text-preference.ts b/apps/console/src/features/branding/api/delete-custom-text-preference.ts index fd9921616ec..d10f17d5be7 100644 --- a/apps/console/src/features/branding/api/delete-custom-text-preference.ts +++ b/apps/console/src/features/branding/api/delete-custom-text-preference.ts @@ -22,6 +22,7 @@ import { HttpMethods } from "@wso2is/core/models"; import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; import { I18nConstants } from "../../core/constants/i18n-constants"; import { store } from "../../core/store"; +import { OrganizationType } from "../../organizations/constants/organization-constants"; import { CustomTextPreferenceConstants } from "../constants/custom-text-preference-constants"; import { BrandingPreferenceTypes } from "../models/branding-preferences"; import { CustomTextPreferenceAPIResponseInterface } from "../models/custom-text-preference"; @@ -48,6 +49,10 @@ const deleteCustomTextPreference = ( locale: string = I18nConstants.DEFAULT_FALLBACK_LANGUAGE, type: BrandingPreferenceTypes = BrandingPreferenceTypes.ORG ): Promise => { + const tenantDomain: string = store.getState().organization.organizationType === OrganizationType.SUBORGANIZATION + ? store.getState()?.organization?.organization?.id + : name; + const requestConfig: AxiosRequestConfig = { headers: { "Accept": "application/json", @@ -56,7 +61,7 @@ const deleteCustomTextPreference = ( method: HttpMethods.DELETE, params: { locale, - name, + name: tenantDomain, screen, type }, diff --git a/apps/console/src/features/branding/api/update-custom-text-preference.ts b/apps/console/src/features/branding/api/update-custom-text-preference.ts index 204337f7024..32d74cee47b 100644 --- a/apps/console/src/features/branding/api/update-custom-text-preference.ts +++ b/apps/console/src/features/branding/api/update-custom-text-preference.ts @@ -22,6 +22,7 @@ import { HttpMethods } from "@wso2is/core/models"; import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; import { I18nConstants } from "../../core/constants/i18n-constants"; import { store } from "../../core/store"; +import { OrganizationType } from "../../organizations/constants/organization-constants"; import { CustomTextPreferenceConstants } from "../constants/custom-text-preference-constants"; import { BrandingPreferenceTypes } from "../models/branding-preferences"; import { @@ -55,10 +56,14 @@ const updateCustomTextPreference = ( locale: string = I18nConstants.DEFAULT_FALLBACK_LANGUAGE, type: BrandingPreferenceTypes = BrandingPreferenceTypes.ORG ): Promise => { + const tenantDomain: string = store.getState().organization.organizationType === OrganizationType.SUBORGANIZATION + ? store.getState()?.organization?.organization?.id + : name; + const requestConfig: AxiosRequestConfig = { data: { locale, - name, + name: tenantDomain, preference, screen, type diff --git a/apps/console/src/features/branding/api/use-get-branding-preference-resolve.ts b/apps/console/src/features/branding/api/use-get-branding-preference-resolve.ts index e5882dd9689..6c57e6ac70c 100644 --- a/apps/console/src/features/branding/api/use-get-branding-preference-resolve.ts +++ b/apps/console/src/features/branding/api/use-get-branding-preference-resolve.ts @@ -24,7 +24,12 @@ import useRequest, { RequestErrorInterface, RequestResultInterface } from "../../core/hooks/use-request"; -import { BrandingPreferenceAPIResponseInterface, BrandingPreferenceTypes } from "../models/branding-preferences"; +import { OrganizationType } from "../../organizations/constants/organization-constants"; +import { useGetOrganizationType } from "../../organizations/hooks/use-get-organization-type"; +import { + BrandingPreferenceAPIResponseInterface, + BrandingPreferenceTypes +} from "../models/branding-preferences"; /** * Hook to get the branding preference via Branding Preferences API. @@ -34,12 +39,17 @@ import { BrandingPreferenceAPIResponseInterface, BrandingPreferenceTypes } from * @param locale - Resource Locale. * @returns `RequestResultInterface` */ -const useGetBrandingPreferenceResolve = ( name: string, type: BrandingPreferenceTypes = BrandingPreferenceTypes.ORG, locale: string = I18nConstants.DEFAULT_FALLBACK_LANGUAGE ): RequestResultInterface => { + const organizationType: OrganizationType = useGetOrganizationType(); + + const tenantDomain: string = organizationType === OrganizationType.SUBORGANIZATION + ? store.getState()?.organization?.organization?.id + : name; const requestConfig: RequestConfigInterface = { headers: { @@ -49,7 +59,7 @@ const useGetBrandingPreferenceResolve = => { + const organizationType: OrganizationType = useGetOrganizationType(); + + const tenantDomain: string = organizationType === OrganizationType.SUBORGANIZATION + ? store.getState()?.organization?.organization?.id + : name; + const requestConfig: RequestConfigInterface = { headers: { Accept: "application/json", @@ -47,7 +58,7 @@ const useGetBrandingPreference = => { + const organizationType: OrganizationType = useGetOrganizationType(); + + const tenantDomain: string = organizationType === OrganizationType.SUBORGANIZATION + ? store.getState()?.organization?.organization?.id + : name; + const requestConfig: RequestConfigInterface = { headers: { Accept: "application/json", @@ -57,7 +65,7 @@ const useGetCustomTextPreference = < method: HttpMethods.GET, params: { locale, - name, + name: tenantDomain, screen, type }, diff --git a/apps/console/src/features/branding/pages/branding.tsx b/apps/console/src/features/branding/pages/branding.tsx index f96542a57ee..d301b5b44df 100644 --- a/apps/console/src/features/branding/pages/branding.tsx +++ b/apps/console/src/features/branding/pages/branding.tsx @@ -443,7 +443,7 @@ const BrandingPage: FunctionComponent = ( handleSubOrgAlerts(); } - + } }) .catch((error: IdentityAppsApiException) => { diff --git a/apps/console/src/features/core/configs/app.ts b/apps/console/src/features/core/configs/app.ts index c500cecde0d..adb91cbe172 100644 --- a/apps/console/src/features/core/configs/app.ts +++ b/apps/console/src/features/core/configs/app.ts @@ -81,7 +81,7 @@ export class Config { } if (skipAuthzRuntimePath) { - return window[ "AppUtils" ]?.getConfig()?.serverOriginWithTenant?.replace("/o/", ""); + return window[ "AppUtils" ]?.getConfig()?.serverOriginWithTenant?.replace("/o", ""); } return window[ "AppUtils" ]?.getConfig()?.serverOriginWithTenant; @@ -248,7 +248,7 @@ export class Config { CORSOrigins: `${ this.getDeploymentConfig()?.serverHost }/api/server/v1/cors/origins`, // TODO: Remove this endpoint and use ID token to get the details me: `${ this.getDeploymentConfig()?.serverHost }/scim2/Me`, - saml2Meta: `${ this.getDeploymentConfig()?.serverHost }/identity/metadata/saml2`, + saml2Meta: `${ this.resolveServerHost(false, true) }/identity/metadata/saml2`, wellKnown: `${ this.resolveServerHost(false, true) }/oauth2/token/.well-known/openid-configuration` }; } diff --git a/apps/console/src/features/core/constants/app-constants.ts b/apps/console/src/features/core/constants/app-constants.ts index 06ac5fd89c6..2ceeb63a109 100644 --- a/apps/console/src/features/core/constants/app-constants.ts +++ b/apps/console/src/features/core/constants/app-constants.ts @@ -18,6 +18,7 @@ import { AppThemeConfigInterface } from "@wso2is/core/models"; import { StringUtils } from "@wso2is/core/utils"; +import { MultitenantConstants } from "./multitenant-constants"; import { identityProviderConfig } from "../../../extensions/configs"; import { GovernanceCategoryForOrgsInterface, @@ -210,7 +211,7 @@ export class AppConstants { * @returns The super tenant domain. */ public static getSuperTenant(): string { - return window["AppUtils"]?.getConfig()?.superTenant; + return window["AppUtils"]?.getConfig()?.superTenant || MultitenantConstants.SUPER_TENANT_DISPLAY_NAME; } /** @@ -350,7 +351,7 @@ export class AppConstants { ], [ "SECRETS", `${AppConstants.getDeveloperViewBasePath()}/secrets` ], [ "SECRET_EDIT", `${AppConstants.getDeveloperViewBasePath()}/secrets/:type/:name` ], - [ + [ "ATTRIBUTE_MAPPINGS", `${AppConstants.getAdminViewBasePath()}/attribute-mappings/:type/:customAttributeMappingID?` ], diff --git a/apps/console/src/features/organizations/components/organization-list.tsx b/apps/console/src/features/organizations/components/organization-list.tsx index 6865c71a234..e4a9f0d7d63 100644 --- a/apps/console/src/features/organizations/components/organization-list.tsx +++ b/apps/console/src/features/organizations/components/organization-list.tsx @@ -329,7 +329,7 @@ export const OrganizationList: FunctionComponent try { response = await switchOrganization(organization.id); - await onSignIn(response, true, () => null, () => null, () => null, false); + await onSignIn(response, () => null, () => null, () => null); onListMutate(); mutateOrganizationBreadCrumbFetchRequest(); diff --git a/apps/console/src/features/organizations/components/organization-switch/organization-switch-breadcrumb.tsx b/apps/console/src/features/organizations/components/organization-switch/organization-switch-breadcrumb.tsx index 62f99fdc73e..317a48bddfb 100644 --- a/apps/console/src/features/organizations/components/organization-switch/organization-switch-breadcrumb.tsx +++ b/apps/console/src/features/organizations/components/organization-switch/organization-switch-breadcrumb.tsx @@ -106,7 +106,7 @@ export const OrganizationSwitchBreadcrumb: FunctionComponent null, () => { // If first level org, remove the `/o/` path from the location. @@ -181,8 +180,7 @@ export const OrganizationSwitchBreadcrumb: FunctionComponent null, - isFirstLevelOrganization + () => null ); mutateOrganizationBreadCrumbFetchRequest(); diff --git a/apps/console/src/features/organizations/hooks/use-organizations.ts b/apps/console/src/features/organizations/hooks/use-organizations.ts index 87f55aa18d5..4b190b739e4 100644 --- a/apps/console/src/features/organizations/hooks/use-organizations.ts +++ b/apps/console/src/features/organizations/hooks/use-organizations.ts @@ -17,12 +17,21 @@ */ import { useContext } from "react"; +import { MultitenantConstants } from "../../core/constants/multitenant-constants"; import OrganizationsContext, { OrganizationsContextProps } from "../context/organizations-context"; /** * Interface for the return type of the UseOrganizations hook. */ -export type UseOrganizationsInterface = OrganizationsContextProps; +export interface UseOrganizationsInterface extends OrganizationsContextProps { + /** + * Transforms the tenant domain to the correct format. + * + * @param tenantDomain - Tenant domain. + * @returns Transformed tenant domain. + */ + transformTenantDomain: (tenantDomain: string) => string; +} /** * Hook that provides access to the Organizations context. @@ -36,7 +45,25 @@ const useOrganizations = (): UseOrganizationsInterface => { throw new Error("useOrganizations must be used within a OrganizationsProvider"); } - return context; + /** + * Transforms the tenant domain to the correct format. + * + * @param tenantDomain - Tenant domain. + * @returns Transformed tenant domain. + */ + const transformTenantDomain = (tenantDomain: string): string => { + // With the latest Authz framework, `carbon.super` is resolved as `Super`. + if (tenantDomain === MultitenantConstants.SUPER_TENANT_DISPLAY_NAME) { + return MultitenantConstants.SUPER_TENANT_DOMAIN_NAME; + } + + return tenantDomain; + }; + + return { + ...context, + transformTenantDomain + }; }; export default useOrganizations; diff --git a/apps/console/src/index.jsp b/apps/console/src/index.jsp index 373cef6fbdd..11fe4d7e35a 100644 --- a/apps/console/src/index.jsp +++ b/apps/console/src/index.jsp @@ -248,12 +248,39 @@ : ""; }; + /** + * Construct the sign-in redirect URL. + * + * @returns {string} Contructed URL. + */ + function signInRedirectURL() { + if (getTenantName() === startupConfig.superTenant) { + return applicationDomain.replace(/\/+$/, '') + + "<%= htmlWebpackPlugin.options.basename ? '/' + htmlWebpackPlugin.options.basename : ''%>"; + } + + return applicationDomain.replace(/\/+$/, '') + getTenantPath() + + "<%= htmlWebpackPlugin.options.basename ? '/' + htmlWebpackPlugin.options.basename : ''%>"; + } + + /** + * Construct the sign-out redirect URL. + * + * @returns {string} Contructed URL. + */ + function getSignOutRedirectURL() { + if (getTenantName() === startupConfig.superTenant) { + return applicationDomain.replace(/\/+$/, ''); + } + + return applicationDomain.replace(/\/+$/, '') + getTenantPath(); + } + var auth = AsgardeoAuth.AsgardeoSPAClient.getInstance(); var authConfig = { - signInRedirectURL: applicationDomain.replace(/\/+$/, '') + getTenantPath() - + "<%= htmlWebpackPlugin.options.basename ? '/' + htmlWebpackPlugin.options.basename : ''%>", - signOutRedirectURL: applicationDomain.replace(/\/+$/, '') + getTenantPath(), + signInRedirectURL: signInRedirectURL(), + signOutRedirectURL: getSignOutRedirectURL(), clientID: "<%= htmlWebpackPlugin.options.clientID %>", baseUrl: getApiPath(), responseMode: "form_post", diff --git a/apps/console/src/protected-app.tsx b/apps/console/src/protected-app.tsx index 41a767266ef..d20c029542b 100644 --- a/apps/console/src/protected-app.tsx +++ b/apps/console/src/protected-app.tsx @@ -77,6 +77,7 @@ import { import { AppConstants } from "./features/core/constants"; import { history } from "./features/core/helpers"; import useRoutes from "./features/core/hooks/use-routes"; +import useOrganizationSwitch from "./features/organizations/hooks/use-organization-switch"; import { GovernanceCategoryForOrgsInterface, useGovernanceConnectorCategories @@ -102,6 +103,8 @@ export const ProtectedApp: FunctionComponent = (): ReactEleme const { onSignIn } = useSignIn(); + const { switchOrganization } = useOrganizationSwitch(); + const { filterRoutes } = useRoutes(); const { setUIConfig } = useUIConfig(); @@ -145,15 +148,37 @@ export const ProtectedApp: FunctionComponent = (): ReactEleme on(Hooks.HttpRequestSuccess, HttpUtils.onHttpRequestSuccess); on(Hooks.SignIn, async (signInResponse: BasicUserInfo) => { - const response: BasicUserInfo = { ...signInResponse }; - - await onSignIn( - response, - false, - () => null, - (idToken: DecodedIDTokenPayload) => loginSuccessRedirect(idToken), - () => setRenderApp(true) - ); + let response: BasicUserInfo = null; + + const getOrganizationName = () => { + const path: string = window.location.pathname; + const pathChunks: string[] = path.split("/"); + + const orgPrefixIndex: number = pathChunks.indexOf(window["AppUtils"].getConfig().organizationPrefix); + + if (orgPrefixIndex !== -1) { + return pathChunks[ orgPrefixIndex + 1 ]; + } + + return ""; + }; + + try { + if (getOrganizationName()) { + response = await switchOrganization(getOrganizationName()); + } else { + response = { ...signInResponse }; + } + + await onSignIn( + response, + () => null, + (idToken: DecodedIDTokenPayload) => loginSuccessRedirect(idToken), + () => setRenderApp(true) + ); + } catch(e) { + // TODO: Handle error + } }); }, []); diff --git a/apps/myaccount/CHANGELOG.md b/apps/myaccount/CHANGELOG.md index a112aaf50d5..ef48bc479c4 100644 --- a/apps/myaccount/CHANGELOG.md +++ b/apps/myaccount/CHANGELOG.md @@ -1,5 +1,11 @@ # @wso2is/myaccount +## 2.2.2 + +### Patch Changes + +- [#4430](https://github.com/wso2/identity-apps/pull/4430) [`261ac530b3`](https://github.com/wso2/identity-apps/commit/261ac530b3b815f7f55267cd3e4209e66ae37f2a) Thanks [@NipuniBhagya](https://github.com/NipuniBhagya)! - Fix issue with accessing carbon.super tenanted path + ## 2.2.1 ### Patch Changes diff --git a/apps/myaccount/java/org.wso2.identity.apps.myaccount.server.feature/pom.xml b/apps/myaccount/java/org.wso2.identity.apps.myaccount.server.feature/pom.xml index 602ea29979d..98785f15898 100644 --- a/apps/myaccount/java/org.wso2.identity.apps.myaccount.server.feature/pom.xml +++ b/apps/myaccount/java/org.wso2.identity.apps.myaccount.server.feature/pom.xml @@ -23,7 +23,7 @@ org.wso2.identity.apps identity-apps-myaccount - 2.2.2-SNAPSHOT + 2.2.3-SNAPSHOT ../pom.xml diff --git a/apps/myaccount/java/pom.xml b/apps/myaccount/java/pom.xml index 6f907110a3c..6dc90d29305 100644 --- a/apps/myaccount/java/pom.xml +++ b/apps/myaccount/java/pom.xml @@ -24,7 +24,7 @@ org.wso2.identity.apps identity-apps-myaccount pom - 2.2.2-SNAPSHOT + 2.2.3-SNAPSHOT WSO2 Identity Server MyAccount - Parent WSO2 Identity Server MyAccount Parent diff --git a/apps/myaccount/java/webapp/pom.xml b/apps/myaccount/java/webapp/pom.xml index fe3bbdc746c..f3c4c545512 100644 --- a/apps/myaccount/java/webapp/pom.xml +++ b/apps/myaccount/java/webapp/pom.xml @@ -23,7 +23,7 @@ org.wso2.identity.apps identity-apps-myaccount - 2.2.2-SNAPSHOT + 2.2.3-SNAPSHOT ../pom.xml diff --git a/apps/myaccount/package.json b/apps/myaccount/package.json index e6ba6aad3ce..0adae24be52 100644 --- a/apps/myaccount/package.json +++ b/apps/myaccount/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@wso2is/myaccount", - "version": "2.2.1", + "version": "2.2.2", "description": "WSO2 Identity Server My Account", "author": "WSO2", "license": "Apache-2.0", diff --git a/apps/myaccount/src/index.jsp b/apps/myaccount/src/index.jsp index 1b17f84f49a..78f14243f9a 100644 --- a/apps/myaccount/src/index.jsp +++ b/apps/myaccount/src/index.jsp @@ -221,12 +221,37 @@ : ""; }; + /** + * Construct the sign-in redirect URL. + * + * @returns {string} Contructed URL. + */ + function signInRedirectURL() { + if (getTenantName() === startupConfig.superTenant) { + return applicationDomain.replace(/\/+$/, '') + + "<%= htmlWebpackPlugin.options.basename ? '/' + htmlWebpackPlugin.options.basename : ''%>"; + } + return applicationDomain.replace(/\/+$/, '') + getTenantPath() + + "<%= htmlWebpackPlugin.options.basename ? '/' + htmlWebpackPlugin.options.basename : ''%>"; + } + + /** + * Construct the sign-out redirect URL. + * + * @returns {string} Contructed URL. + */ + function getSignOutRedirectURL() { + if (getTenantName() === startupConfig.superTenant) { + return applicationDomain.replace(/\/+$/, ''); + } + return applicationDomain.replace(/\/+$/, '') + getTenantPath(); + } + var auth = AsgardeoAuth.AsgardeoSPAClient.getInstance(); var authConfig = { - signInRedirectURL: applicationDomain.replace(/\/+$/, '') + getTenantPath() - + "<%= htmlWebpackPlugin.options.basename ? '/' + htmlWebpackPlugin.options.basename : ''%>", - signOutRedirectURL: applicationDomain.replace(/\/+$/, '') + getTenantPath(), + signInRedirectURL: signInRedirectURL(), + signOutRedirectURL: getSignOutRedirectURL(), clientID: "<%= htmlWebpackPlugin.options.clientID %>", baseUrl: getApiPath(), responseMode: "form_post",