Skip to content

Commit

Permalink
Fix : Update Profile when synchronized profile property setting from …
Browse files Browse the repository at this point in the history
…AD - EXO-65023 - Meeds-io/meeds#1084 (#85)

Prior to this change, when we searched for synchronized people by their phone numbers, no results were displayed. This issue was due to the multi-valued synchronized property, which was saved as a map of string key-value pairs like "phones.home."

This change is going to prevent the profile property from being saved using the old user profile format and will instead be saved in the format of parent and child using a map of string and object key-value pairs.
It also adds the Mockito framework.
  • Loading branch information
sofyenne committed Sep 13, 2023
1 parent b5a441d commit 23a09eb
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 6 deletions.
5 changes: 5 additions & 0 deletions exo.core.component.organization.api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<testResources>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ private UserProfile importUserProfile(String username, boolean deleted) throws E
UserProfile externalUserProfile = externalStoreService.getEntity(IDMEntityType.USER_PROFILE, username);

if (externalUserProfile != null && externalUserProfile.getUserInfoMap() != null
&& !externalUserProfile.getUserInfoMap().isEmpty()) {
&& !externalUserProfile.getUserInfoMap().isEmpty()) {
Map<String, String> externalUserInfoMap = externalUserProfile.getUserInfoMap();
Map<String, String> internalUserInfoMap = (internalUserProfile == null
|| internalUserProfile.getUserInfoMap() == null) ? new HashMap<>() : internalUserProfile.getUserInfoMap();
Expand All @@ -798,11 +798,10 @@ private UserProfile importUserProfile(String username, boolean deleted) throws E
}

if (isModified) {
internalUserInfoMap.putAll(externalUserInfoMap);
UserProfile userProfile = organizationService.getUserProfileHandler().createUserProfileInstance(username);
userProfile.setUserInfoMap(internalUserInfoMap);
organizationService.getUserProfileHandler().saveUserProfile(userProfile, true);
return userProfile;
if (!externalUserInfoMap.containsKey("username")) {
externalUserInfoMap.put("username", username);
}
listenerService.broadcast(IDMExternalStoreService.USER_PROFILE_ADDED_FROM_EXTERNAL_STORE, this, externalUserInfoMap);
}
}
return internalUserProfile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public interface IDMExternalStoreService {

public static final String GROUP_MODIFIED_FROM_EXTERNAL_STORE = "exo.idm.externalStore.group.modified";

public static final String USER_PROFILE_ADDED_FROM_EXTERNAL_STORE = "exo.idm.externalStore.user.profile.new";

/**
* Authenticates user using external store only
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* This file is part of the Meeds project (https://meeds.io/).
*
* Copyright (C) 2023 Meeds Association [email protected]
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.exoplatform.services.organization.api;

import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.*;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import org.exoplatform.container.StandaloneContainer;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.services.listener.ListenerService;
import org.exoplatform.services.organization.BaseOrganizationService;
import org.exoplatform.services.organization.OrganizationService;
import org.exoplatform.services.organization.UserProfile;
import org.exoplatform.services.organization.UserProfileHandler;
import org.exoplatform.services.organization.externalstore.IDMExternalStoreImportService;
import org.exoplatform.services.organization.externalstore.IDMExternalStoreService;
import org.exoplatform.services.organization.externalstore.model.IDMEntityType;
import org.exoplatform.services.organization.impl.UserProfileImpl;

@RunWith(MockitoJUnitRunner.class)
public class IDMExternalStoreImportServiceTest {

@Mock
private InitParams initParams;

@Mock
private IDMExternalStoreService idmExternalStoreService;

@Mock
private ListenerService listenerService;

private IDMExternalStoreImportService idmExternalStoreImportService;

private OrganizationService organizationService;

private UserProfileHandler profileHandler;

@Before
public void setUp() throws Exception {
URL containerConfURL = TestUserHandler.class.getResource("/conf/standalone/test-configuration.xml");
assertNotNull(containerConfURL);

String containerConf = containerConfURL.toString();
StandaloneContainer.addConfigurationURL(containerConf);
StandaloneContainer container = StandaloneContainer.getInstance();

organizationService =
(BaseOrganizationService) container.getComponentInstance(org.exoplatform.services.organization.OrganizationService.class);
assertNotNull(organizationService);

profileHandler = organizationService.getUserProfileHandler();
this.idmExternalStoreImportService = new IDMExternalStoreImportService(container,
organizationService,
listenerService,
idmExternalStoreService,
null,
null,
initParams);
}

@Test
public void importUserProfileTest() throws Exception {
String userName = "john";
profileHandler.createUserProfileInstance();
UserProfile externalUserProfile = mock(UserProfile.class);
when(idmExternalStoreService.getEntity(IDMEntityType.USER_PROFILE, userName)).thenReturn(externalUserProfile);
when(externalUserProfile.getUserInfoMap()).thenReturn(new HashMap<>());
when(idmExternalStoreService.isEntityPresent(IDMEntityType.USER_PROFILE, userName)).thenReturn(true);
//
idmExternalStoreImportService.importEntityToInternalStore(IDMEntityType.USER_PROFILE, userName, false, false);
verify(listenerService, times(0)).broadcast(eq(IDMExternalStoreService.USER_PROFILE_ADDED_FROM_EXTERNAL_STORE),
anyObject(),
argThat(param -> param instanceof HashMap<?, ?>));

when(externalUserProfile.getUserInfoMap()).thenReturn(new HashMap<>());
//
idmExternalStoreImportService.importEntityToInternalStore(IDMEntityType.USER_PROFILE, userName, false, false);
verify(listenerService, times(0)).broadcast(eq(IDMExternalStoreService.USER_PROFILE_ADDED_FROM_EXTERNAL_STORE),
anyObject(),
argThat(param -> param instanceof HashMap<?, ?>));

Map<String, String> propertiesMap = new HashMap<>();
propertiesMap.put("propertyKey", "propertyValue");
when(externalUserProfile.getUserInfoMap()).thenReturn(propertiesMap);
//
idmExternalStoreImportService.importEntityToInternalStore(IDMEntityType.USER_PROFILE, userName, false, false);
verify(listenerService, times(1)).broadcast(eq(IDMExternalStoreService.USER_PROFILE_ADDED_FROM_EXTERNAL_STORE),
anyObject(),
argThat(param -> param instanceof HashMap<?, ?>));
UserProfile userProfile = new UserProfileImpl();
userProfile.setUserName(userName);
userProfile.setUserInfoMap(propertiesMap);
profileHandler.saveUserProfile(userProfile, false);
//
idmExternalStoreImportService.importEntityToInternalStore(IDMEntityType.USER_PROFILE, userName, false, false);
verify(listenerService, atLeast(0)).broadcast(eq(IDMExternalStoreService.USER_PROFILE_ADDED_FROM_EXTERNAL_STORE),
anyObject(),
argThat(param -> param instanceof HashMap<?, ?>));

Map<String, String> updatedPropertyMap = new HashMap<>();
updatedPropertyMap.put("propertyKey", "updatedPropertyValue");
when(externalUserProfile.getUserInfoMap()).thenReturn(updatedPropertyMap);
//
idmExternalStoreImportService.importEntityToInternalStore(IDMEntityType.USER_PROFILE, userName, false, false);
verify(listenerService, atLeast(1)).broadcast(eq(IDMExternalStoreService.USER_PROFILE_ADDED_FROM_EXTERNAL_STORE),
anyObject(),
argThat(param -> param instanceof HashMap<?, ?>));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ grant codeBase "@MAIN_CLASSES@-"{
};

grant codeBase "@TEST_CLASSES@-"{
permission java.lang.RuntimePermission "accessDeclaredMembers";
};

grant codeBase "@MAIN_CLASSES@../../../exo.core.component.security.core/-"{
Expand Down

0 comments on commit 23a09eb

Please sign in to comment.