Skip to content

Commit

Permalink
add scim system schema
Browse files Browse the repository at this point in the history
  • Loading branch information
amanda-ariyaratne committed Jan 22, 2025
1 parent 2b6a4a7 commit 3fc3493
Show file tree
Hide file tree
Showing 22 changed files with 138 additions and 82 deletions.
4 changes: 2 additions & 2 deletions apps/myaccount/src/api/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ export const getProfileInfo = (): Promise<BasicProfileInterface> => {
const profileResponse: BasicProfileInterface = {
emails: response.data.emails || "",
name: response.data.name || { familyName: "", givenName: "" },
pendingEmails: response.data[ProfileConstants.SCIM2_ENT_USER_SCHEMA]
? response.data[ProfileConstants.SCIM2_ENT_USER_SCHEMA].pendingEmails
pendingEmails: response.data[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA]
? response.data[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA].pendingEmails
: [],
phoneNumbers: response.data.phoneNumbers || [],
profileUrl: response.data.profileUrl || "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export const EmailRecovery: React.FunctionComponent<EmailRecoveryProps> = (
}
]
: [ emailAddress ],
[ProfileConstants.SCIM2_ENT_USER_SCHEMA]: {
[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA]: {
"verifyEmail": true
}
};
Expand Down
99 changes: 48 additions & 51 deletions apps/myaccount/src/components/profile/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -427,55 +427,46 @@ export const Profile: FunctionComponent<ProfileProps> = (props: ProfileProps): R
tempProfileInfo.set(schema.name, primaryEmail);
}
} else {
if (schema.extended
&& profileDetails?.profileInfo[ProfileConstants.SCIM2_ENT_USER_SCHEMA]
&& profileDetails?.profileInfo[ProfileConstants.SCIM2_ENT_USER_SCHEMA][schemaNames[0]]) {
tempProfileInfo.set(
schema.name,
profileDetails?.profileInfo[ProfileConstants.SCIM2_ENT_USER_SCHEMA]
? profileDetails?.profileInfo[
ProfileConstants.SCIM2_ENT_USER_SCHEMA][schemaNames[0]
]
: ""
);

return;
}

if (schema.extended
&& profileDetails?.profileInfo[userSchemaURI]
&& profileDetails?.profileInfo[userSchemaURI][schemaNames[0]]) {

const multiValuedAttributes: string[] = [
EMAIL_ADDRESSES_ATTRIBUTE,
MOBILE_NUMBERS_ATTRIBUTE,
VERIFIED_EMAIL_ADDRESSES_ATTRIBUTE,
VERIFIED_MOBILE_NUMBERS_ATTRIBUTE
if (schema.extended) {
const schemaURIs: string[] = [
ProfileConstants.SCIM2_ENT_USER_SCHEMA,
ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA,
userSchemaURI
];

if (multiValuedAttributes.includes(schemaNames[0])) {
for (const schemaURI of schemaURIs) {
if (profileDetails?.profileInfo[schemaURI]?.[schemaNames[0]]) {

const attributeValue: string | string[] =
profileDetails?.profileInfo[userSchemaURI]?.[schemaNames[0]];
const multiValuedAttributes: string[] = [
EMAIL_ADDRESSES_ATTRIBUTE,
MOBILE_NUMBERS_ATTRIBUTE,
VERIFIED_EMAIL_ADDRESSES_ATTRIBUTE,
VERIFIED_MOBILE_NUMBERS_ATTRIBUTE
];

const formattedValue: string = Array.isArray(attributeValue)
? attributeValue.join(",")
: "";
if (schemaURI === ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA
&& multiValuedAttributes.includes(schemaNames[0])) {
const attributeValue: string | string[] =
profileDetails?.profileInfo[schemaURI]?.[schemaNames[0]];

tempProfileInfo.set(schema.name, formattedValue);
const formattedValue: string = Array.isArray(attributeValue)
? attributeValue.join(",")
: "";

return;
}
tempProfileInfo.set(
schema.name,
profileDetails?.profileInfo[userSchemaURI]
? profileDetails?.profileInfo[userSchemaURI][schemaNames[0]]
: ""
);
tempProfileInfo.set(schema.name, formattedValue);

return;
}
return;
}

tempProfileInfo.set(
schema.name,
profileDetails?.profileInfo[schemaURI]?.[schemaNames[0]] ?? ""
);

return;
}
}
}
tempProfileInfo.set(schema.name, profileDetails.profileInfo[schemaNames[0]]);
}
} else {
Expand Down Expand Up @@ -505,14 +496,20 @@ export const Profile: FunctionComponent<ProfileProps> = (props: ProfileProps): R
}
}
} else {
if (schema.extended) {
tempProfileInfo.set(schema.name,
profileDetails?.profileInfo[ProfileConstants.SCIM2_ENT_USER_SCHEMA]?.[schemaNames[0]]
? profileDetails
?.profileInfo[
ProfileConstants.SCIM2_ENT_USER_SCHEMA
][schemaNames[0]][schemaNames[1]]
: "");
if (schema.extended
&& profileDetails?.profileInfo[ProfileConstants.SCIM2_ENT_USER_SCHEMA]?.[schemaNames[0]]) {
tempProfileInfo.set(
schema.name,
profileDetails.profileInfo[ProfileConstants.SCIM2_ENT_USER_SCHEMA][schemaNames[0]][
schemaNames[1]]
?? "");
} else if (schema.extended &&
profileDetails?.profileInfo[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA]?.[schemaNames[0]]) {
tempProfileInfo.set(
schema.name,
profileDetails.profileInfo[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA][schemaNames[0]][
schemaNames[1]]
?? "");
} else {
const subValue: BasicProfileInterface = profileDetails.profileInfo[schemaNames[0]]
&& profileDetails.profileInfo[schemaNames[0]].find(
Expand Down Expand Up @@ -698,7 +695,7 @@ export const Profile: FunctionComponent<ProfileProps> = (props: ProfileProps): R
if (values.get(formName)) {
value = {
...value,
[ProfileConstants.SCIM2_ENT_USER_SCHEMA]: {
[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA]: {
"verifyEmail": true
}
};
Expand Down Expand Up @@ -740,7 +737,7 @@ export const Profile: FunctionComponent<ProfileProps> = (props: ProfileProps): R
if (primaryValue) {
value = {
...value,
[ProfileConstants.SCIM2_ENT_USER_SCHEMA]: {
[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA]: {
"verifyEmail": true
}
};
Expand Down
8 changes: 4 additions & 4 deletions apps/myaccount/src/components/shared/mobile-update-wizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ export const MobileUpdateWizard: React.FunctionComponent<MobileUpdateWizardProps
const isMobileVerificationPending = (updatedMobileNumber: string, userData: Record<string, string>): boolean => {
const PENDING_MOBILE_CLAIM: string = "pendingMobileNumber";

return userData && userData[ProfileConstants.SCIM2_ENT_USER_SCHEMA] &&
userData[ProfileConstants.SCIM2_ENT_USER_SCHEMA][PENDING_MOBILE_CLAIM] &&
userData[ProfileConstants.SCIM2_ENT_USER_SCHEMA][PENDING_MOBILE_CLAIM] === updatedMobileNumber;
return userData && userData[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA] &&
userData[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA][PENDING_MOBILE_CLAIM] &&
userData[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA][PENDING_MOBILE_CLAIM] === updatedMobileNumber;

};

Expand Down Expand Up @@ -127,7 +127,7 @@ export const MobileUpdateWizard: React.FunctionComponent<MobileUpdateWizardProps
value: mobileNumber
}
],
[ProfileConstants.SCIM2_ENT_USER_SCHEMA]: { "verifyMobile": true }
[ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA]: { "verifyMobile": true }
};
updateProfileInfo(data).then((response: AxiosResponse) => {
if (response.status === 200) {
Expand Down
2 changes: 1 addition & 1 deletion apps/myaccount/src/configs/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class Config {
this.getDeploymentConfig()?.serverHost
}/api/server/v1/configs/home-realm-identifiers`,
isReadOnlyUser: `${this.getDeploymentConfig()?.serverHost}/scim2/Me?attributes=${
SCIMConfigs.scimEnterpriseUserClaimUri.isReadOnlyUser
SCIMConfigs.scimSystemUserClaimUri.isReadOnlyUser
}`,
issuer: `${this.getDeploymentConfig()?.serverHost}/oauth2/token`,
jwks: `${this.getDeploymentConfig()?.serverHost}/oauth2/jwks`,
Expand Down
2 changes: 1 addition & 1 deletion apps/myaccount/src/constants/user-management-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ export class UserManagementConstants {
/**
* Default scim2 custom user schema URI.
*/
public static readonly DEFAULT_SCIM2_CUSTOM_USER_SCHEMA_URI: string = "urn:scim:wso2:schema";
public static readonly DEFAULT_SCIM2_CUSTOM_USER_SCHEMA_URI: string = "urn:scim:schemas:extension:custom:User";
}
8 changes: 8 additions & 0 deletions apps/myaccount/src/extensions/configs/models/scim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,12 @@ export interface SCIMConfigInterface {
oneTimePassword: string,
profileUrl: string
};

scimSystemUserClaimUri: {
accountDisabled: string,
accountLocked: string,
askPassword: string,
isReadOnlyUser: string,
oneTimePassword: string
};
}
8 changes: 8 additions & 0 deletions apps/myaccount/src/extensions/configs/scim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,13 @@ export const SCIMConfigs: SCIMConfigInterface = {
isReadOnlyUser: "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.isReadOnlyUser",
oneTimePassword: "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.oneTimePassword",
profileUrl: "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.profileUrl"
},

scimSystemUserClaimUri: {
accountDisabled: "urn:scim:wso2:schema:accountDisabled",
accountLocked: "urn:scim:wso2:schema:accountLocked",
askPassword: "urn:scim:wso2:schema:askPassword",
isReadOnlyUser: "urn:scim:wso2:schema:isReadOnlyUser",
oneTimePassword: "urn:scim:wso2:schema:oneTimePassword"
}
};
2 changes: 1 addition & 1 deletion apps/myaccount/src/models/app-config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020-2024, WSO2 LLC. (https://www.wso2.com).
* Copyright (c) 2020-2025, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand Down
2 changes: 1 addition & 1 deletion features/admin.claims.v1/api/use-get-claim-dialects.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ export const EditBasicDetailsLocalClaims: FunctionComponent<EditBasicDetailsLoca
dialectID.push(ClaimManagementConstants.ATTRIBUTE_DIALECT_IDS.get("SCIM2_SCHEMAS_CORE"));
dialectID.push(ClaimManagementConstants.ATTRIBUTE_DIALECT_IDS.get("SCIM2_SCHEMAS_CORE_USER"));
dialectID.push(ClaimManagementConstants.ATTRIBUTE_DIALECT_IDS.get("SCIM2_SCHEMAS_EXT_ENT_USER"));
dialectID.push(ClaimManagementConstants.ATTRIBUTE_DIALECT_IDS.get("SCIM2_SCHEMAS_EXT_SYSTEM"));

if (customUserSchemaID) {
dialectID.push(customUserSchemaID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ export class ClaimManagementConstants {
name: "Enterprise Schema",
uri: "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
},
{
attributeButtonText: "claims:external.pageLayout.edit.attributeMappingPrimaryAction" ,
isAttributeButtonEnabled: true,
name: "System Schema",
uri: "urn:scim:wso2:schema"
},
{
attributeButtonText: "",
isAttributeButtonEnabled: true,
Expand Down Expand Up @@ -240,7 +246,7 @@ export class ClaimManagementConstants {
/**
* Default scim2 custom user schema URI.
*/
public static readonly DEFAULT_SCIM2_CUSTOM_USER_SCHEMA_URI: string = "urn:scim:wso2:schema";
public static readonly DEFAULT_SCIM2_CUSTOM_USER_SCHEMA_URI: string = "urn:scim:schemas:extension:custom:User";
}

/**
Expand Down
8 changes: 8 additions & 0 deletions features/admin.extensions.v1/configs/models/scim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,13 @@ export interface SCIMConfigInterface {
oneTimePassword: string,
profileUrl: string
};
scimSystemUserClaimUri: {
accountDisabled: string,
accountLocked: string,
askPassword: string,
forcePasswordReset: string,
isReadOnlyUser: string,
oneTimePassword: string
};
serverSupportedClaimsAvailable: string[];
}
8 changes: 8 additions & 0 deletions features/admin.extensions.v1/configs/scim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ export const SCIMConfigs: SCIMConfigInterface = {
oneTimePassword: "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.oneTimePassword",
profileUrl: "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.profileUrl"
},
scimSystemUserClaimUri: {
accountDisabled: "urn:scim:wso2:schema:accountDisabled",
accountLocked: "urn:scim:wso2:schema:accountLocked",
askPassword: "urn:scim:wso2:schema:askPassword",
forcePasswordReset: "urn:scim:wso2:schema:forcePasswordReset",
isReadOnlyUser: "urn:scim:wso2:schema:isReadOnlyUser",
oneTimePassword: "urn:scim:wso2:schema:oneTimePassword"
},
serverSupportedClaimsAvailable: [
"urn:scim:schemas:core:1.0",
"urn:ietf:params:scim:schemas:core:2.0",
Expand Down
2 changes: 1 addition & 1 deletion features/admin.extensions.v1/configs/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ export const userConfig: User = {
enableBulkImportSecondaryUserStore: true,
enableUsernameValidation: false,
hiddenItemsPerPageRemoteUserStoreDropdown: false,
userProfileSchema: ProfileConstants.SCIM2_ENT_USER_SCHEMA
userProfileSchema: ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA
};
5 changes: 3 additions & 2 deletions features/admin.users.v1/components/edit-user.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export const EditUser: FunctionComponent<EditUserPropsInterface> = (
const userRolesDisabledFeatures: string[] = useSelector((state: AppState) => {
return state.config.ui.features?.users?.disabledFeatures;
});
const userSchemaURI: string = useSelector((state: AppState) => state?.config?.ui?.userSchemaURI);

useEffect(() => {
const userStore: string = user?.userName?.split("/").length > 1
Expand All @@ -121,7 +122,7 @@ export const EditUser: FunctionComponent<EditUserPropsInterface> = (
|| readOnlyUserStores?.includes(userStore?.toString())
|| !hasUsersUpdatePermissions
|| user[ SCIMConfigs.scim.enterpriseSchema ]?.userSourceId
|| user[ UserManagementConstants.CUSTOMSCHEMA ]?.isReadOnlyUser === "true"
|| user[ userSchemaURI ]?.isReadOnlyUser === "true"
) {
setReadOnly(true);
}
Expand Down Expand Up @@ -218,7 +219,7 @@ export const EditUser: FunctionComponent<EditUserPropsInterface> = (
isUserManagedByParentOrg={ isUserManagedByParentOrg }
adminUserType={ AdminAccountTypes.INTERNAL }
allowDeleteOnly={
user[ UserManagementConstants.CUSTOMSCHEMA ]?.isReadOnlyUser === "true"
user[ userSchemaURI ]?.isReadOnlyUser === "true"
}
editUserDisclaimerMessage={ (
<Grid>
Expand Down
6 changes: 3 additions & 3 deletions features/admin.users.v1/components/user-change-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,9 @@ export const ChangePasswordComponent: FunctionComponent<ChangePasswordPropsInter
return;
}

const schemaURI: string = SCIMConfigs?.scimEnterpriseUserClaimUri?.forcePasswordReset?.
startsWith(ProfileConstants.SCIM2_ENT_USER_SCHEMA)
? ProfileConstants.SCIM2_ENT_USER_SCHEMA
const schemaURI: string = SCIMConfigs?.scimSystemUserClaimUri?.forcePasswordReset?.
startsWith(ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA)
? ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA
: userSchemaURI;

const data: PatchRoleDataInterface = {
Expand Down
10 changes: 5 additions & 5 deletions features/admin.users.v1/components/user-profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1244,12 +1244,12 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
};

if (adminUserType === "internal") {
const accountDisabledURI: string = SCIMConfigs?.scimEnterpriseUserClaimUri?.accountDisabled;
const accountLockedURI: string = SCIMConfigs?.scimEnterpriseUserClaimUri?.accountLocked;
const accountDisabledURI: string = SCIMConfigs?.scimSystemUserClaimUri?.accountDisabled;
const accountLockedURI: string = SCIMConfigs?.scimSystemUserClaimUri?.accountLocked;

const schemaURI: string = accountDisabledURI?.startsWith(ProfileConstants.SCIM2_ENT_USER_SCHEMA)
&& accountLockedURI?.startsWith(ProfileConstants.SCIM2_ENT_USER_SCHEMA)
? ProfileConstants.SCIM2_ENT_USER_SCHEMA
const schemaURI: string = accountDisabledURI?.startsWith(ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA)
&& accountLockedURI?.startsWith(ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA)
? ProfileConstants.SCIM2_SYSTEM_USER_SCHEMA
: userSchemaURI;

data = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1089,10 +1089,7 @@ export const BulkImportUserWizard: FunctionComponent<BulkImportUserInterface> =
selectedUserStore.toLowerCase() !== PRIMARY_USERSTORE.toLowerCase()
? `${selectedUserStore}/${email}`
: email,
[ !StringUtils.isEqualCaseInsensitive(userstore, primaryUserStoreDomainName)
? UserManagementConstants.CUSTOMSCHEMA
: UserManagementConstants.ENTERPRISESCHEMA
]: {
[ UserManagementConstants.SYSTEMSCHEMA ]: {
askPassword: "true"
}
};
Expand Down
Loading

0 comments on commit 3fc3493

Please sign in to comment.