From b28db2a88a732fa9faa49b666821e05b184a86a3 Mon Sep 17 00:00:00 2001
From: uhensler <urs.hensler@frentix.com>
Date: Fri, 17 May 2019 10:38:34 +0200
Subject: [PATCH] OO-3932: Send a globally unique user id to external editors

---
 .../doceditor/DocEditorIdentityService.java   | 51 +++++++++++++
 .../restapi/CollaboraWebService.java          | 10 +--
 .../manager/DocEditorIdentityServiceImpl.java | 73 +++++++++++++++++++
 .../manager/Office365ServiceImpl.java         |  2 +-
 .../restapi/Office365WebService.java          | 16 ++--
 .../manager/OnlyOfficeServiceImpl.java        | 25 ++-----
 .../manager/DocEditorIdentityServiceTest.java | 52 +++++++++++++
 .../java/org/olat/test/AllTestsJunit4.java    |  1 +
 8 files changed, 201 insertions(+), 29 deletions(-)
 create mode 100644 src/main/java/org/olat/core/commons/services/doceditor/DocEditorIdentityService.java
 create mode 100644 src/main/java/org/olat/core/commons/services/doceditor/manager/DocEditorIdentityServiceImpl.java
 create mode 100644 src/test/java/org/olat/core/commons/services/doceditor/manager/DocEditorIdentityServiceTest.java

diff --git a/src/main/java/org/olat/core/commons/services/doceditor/DocEditorIdentityService.java b/src/main/java/org/olat/core/commons/services/doceditor/DocEditorIdentityService.java
new file mode 100644
index 00000000000..73436de8f8c
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/doceditor/DocEditorIdentityService.java
@@ -0,0 +1,51 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.doceditor;
+
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 17 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public interface DocEditorIdentityService {
+	
+	/**
+	 * Get globally unique identity id.
+	 *
+	 * @param identity
+	 * @return
+	 */
+	public String getGlobalIdentityId(Identity identity);
+	
+	/**
+	 * Get identity by globally unique userId.
+	 * 
+	 *
+	 * @param globalIdentityId
+	 * @return
+	 */
+	public Identity getIdentity(String globalIdentityId);
+	
+	public String getUserDisplayName(Identity identity);
+
+}
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/collabora/restapi/CollaboraWebService.java b/src/main/java/org/olat/core/commons/services/doceditor/collabora/restapi/CollaboraWebService.java
index d930b01cafa..01bd52a336d 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/collabora/restapi/CollaboraWebService.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/collabora/restapi/CollaboraWebService.java
@@ -42,13 +42,13 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
 import org.apache.logging.log4j.Logger;
+import org.olat.core.commons.services.doceditor.DocEditorIdentityService;
 import org.olat.core.commons.services.doceditor.collabora.CollaboraModule;
 import org.olat.core.commons.services.doceditor.collabora.CollaboraService;
 import org.olat.core.commons.services.doceditor.wopi.Access;
 import org.olat.core.commons.services.vfs.VFSMetadata;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.vfs.VFSLeaf;
-import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -72,7 +72,7 @@ public class CollaboraWebService {
 	@Autowired 
 	private CollaboraService collaboraService;
 	@Autowired
-	private UserManager userManager;
+	private DocEditorIdentityService identityService;
 	
 	@GET
 	@Produces(MediaType.APPLICATION_JSON)
@@ -100,13 +100,13 @@ public class CollaboraWebService {
 		}
 		
 		VFSMetadata metadata = access.getMetadata();
-		String ownerId = metadata.getAuthor() != null? metadata.getAuthor().getKey().toString(): null;
+		String ownerId = metadata.getAuthor() != null? identityService.getGlobalIdentityId(metadata.getAuthor()): null;
 		CheckFileInfoVO checkFileInfoVO = CheckFileInfoVO.builder()
 				.withBaseFileName(metadata.getFilename()) // suffix is mandatory
 				.withOwnerId(ownerId)
 				.withSize(metadata.getFileSize())
-				.withUserId(access.getIdentity().getKey().toString())
-				.withUserFriendlyName(userManager.getUserDisplayName(access.getIdentity()))
+				.withUserId(identityService.getGlobalIdentityId(access.getIdentity()))
+				.withUserFriendlyName(identityService.getUserDisplayName(access.getIdentity()))
 				.withVersion(String.valueOf(metadata.getRevisionNr()))
 				.withLastModifiedTime(getAsIso8601(metadata.getLastModified()))
 				.withUserCanWrite(access.isCanEdit())
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/manager/DocEditorIdentityServiceImpl.java b/src/main/java/org/olat/core/commons/services/doceditor/manager/DocEditorIdentityServiceImpl.java
new file mode 100644
index 00000000000..5535c39e60d
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/doceditor/manager/DocEditorIdentityServiceImpl.java
@@ -0,0 +1,73 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.doceditor.manager;
+
+import org.apache.logging.log4j.Logger;
+import org.olat.basesecurity.BaseSecurityManager;
+import org.olat.core.commons.services.doceditor.DocEditorIdentityService;
+import org.olat.core.id.Identity;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.WebappHelper;
+import org.olat.user.UserManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 17 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class DocEditorIdentityServiceImpl implements DocEditorIdentityService {
+
+	private static final Logger log = Tracing.createLoggerFor(DocEditorIdentityServiceImpl.class);
+	
+	@Autowired
+	private BaseSecurityManager securityManager;
+	@Autowired
+	private UserManager userManager;
+
+	@Override
+	public String getGlobalIdentityId(Identity identity) {
+		return getGlobalUserIdPrefix() + identity.getName();
+	}
+
+	@Override
+	public Identity getIdentity(String globalIdenityId) {
+		try {
+			String username = globalIdenityId.substring(getGlobalUserIdPrefix().length());
+			return securityManager.findIdentityByNameCaseInsensitive(username);
+		} catch (NumberFormatException e) {
+			log.warn("Try to load identity with global unique id " + globalIdenityId, e);
+		}
+		return null;
+	}
+
+	private String getGlobalUserIdPrefix() {
+		return "openolat." + WebappHelper.getInstanceId() + ".";
+	}
+
+	@Override
+	public String getUserDisplayName(Identity identity) {
+		return userManager.getUserDisplayName(identity);
+	}
+
+}
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/office365/manager/Office365ServiceImpl.java b/src/main/java/org/olat/core/commons/services/doceditor/office365/manager/Office365ServiceImpl.java
index 79a869b6b01..aecbce7ae3b 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/office365/manager/Office365ServiceImpl.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/office365/manager/Office365ServiceImpl.java
@@ -31,6 +31,7 @@ import java.util.Set;
 
 import javax.annotation.PostConstruct;
 
+import org.apache.logging.log4j.Logger;
 import org.olat.core.commons.services.doceditor.DocEditor.Mode;
 import org.olat.core.commons.services.doceditor.DocEditorSecurityCallback;
 import org.olat.core.commons.services.doceditor.office365.Office365Module;
@@ -45,7 +46,6 @@ import org.olat.core.commons.services.vfs.VFSRepositoryService;
 import org.olat.core.gui.control.Event;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.StringHelper;
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/office365/restapi/Office365WebService.java b/src/main/java/org/olat/core/commons/services/doceditor/office365/restapi/Office365WebService.java
index af3ac8b23f2..21abe73313d 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/office365/restapi/Office365WebService.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/office365/restapi/Office365WebService.java
@@ -40,15 +40,15 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriInfo;
 
+import org.apache.logging.log4j.Logger;
+import org.olat.core.commons.services.doceditor.DocEditorIdentityService;
 import org.olat.core.commons.services.doceditor.office365.Office365Module;
 import org.olat.core.commons.services.doceditor.office365.Office365Service;
 import org.olat.core.commons.services.doceditor.wopi.Access;
 import org.olat.core.commons.services.vfs.VFSMetadata;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.vfs.VFSLeaf;
-import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -74,7 +74,7 @@ public class Office365WebService {
 	@Autowired 
 	private Office365Service office365Service;
 	@Autowired
-	private UserManager userManager;
+	private DocEditorIdentityService identityService;
 	
 	@GET
 	@Produces(MediaType.APPLICATION_JSON)
@@ -112,14 +112,18 @@ public class Office365WebService {
 			return Response.serverError().status(Status.NOT_FOUND).build();
 		}
 		
+		String userId = identityService.getGlobalIdentityId(access.getIdentity());
 		VFSMetadata metadata = access.getMetadata();
-		String ownerId = metadata.getAuthor() != null? metadata.getAuthor().getKey().toString(): null;
+		// ownerId is mandatory (this hack seens to work)
+		String ownerId = metadata.getAuthor() != null
+				? identityService.getGlobalIdentityId(metadata.getAuthor())
+				: userId;
 		CheckFileInfoVO checkFileInfoVO = CheckFileInfoVO.builder()
 				.withBaseFileName(metadata.getFilename()) // suffix is mandatory
 				.withOwnerId(ownerId)
 				.withSize(metadata.getFileSize())
-				.withUserId(access.getIdentity().getKey().toString())
-				.withUserFriendlyName(userManager.getUserDisplayName(access.getIdentity()))
+				.withUserId(userId)
+				.withUserFriendlyName(identityService.getUserDisplayName(access.getIdentity()))
 				.withVersion(String.valueOf(metadata.getRevisionNr()))
 				.withLastModifiedTime(getAsIso8601(metadata.getLastModified()))
 				.withSupportsGetLock(true)
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java
index e3eabd8f645..002cd7f7be8 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java
@@ -30,8 +30,9 @@ import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
-import org.olat.basesecurity.BaseSecurityManager;
+import org.apache.logging.log4j.Logger;
 import org.olat.core.commons.services.doceditor.DocEditor.Mode;
+import org.olat.core.commons.services.doceditor.DocEditorIdentityService;
 import org.olat.core.commons.services.doceditor.DocEditorSecurityCallback;
 import org.olat.core.commons.services.doceditor.onlyoffice.ApiConfig;
 import org.olat.core.commons.services.doceditor.onlyoffice.OnlyOfficeSecurityService;
@@ -46,7 +47,6 @@ import org.olat.core.commons.services.vfs.VFSMetadata;
 import org.olat.core.commons.services.vfs.VFSRepositoryService;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.vfs.VFSConstants;
@@ -58,7 +58,6 @@ import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.lock.LockInfo;
 import org.olat.core.util.vfs.lock.LockResult;
 import org.olat.restapi.security.RestSecurityHelper;
-import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -84,13 +83,11 @@ public class OnlyOfficeServiceImpl implements OnlyOfficeService {
 	@Autowired
 	private OnlyOfficeSecurityService onlyOfficeSecurityService;
 	@Autowired
+	private DocEditorIdentityService identityService;
+	@Autowired
 	private VFSRepositoryService vfsRepositoryService;
 	@Autowired
 	private VFSLockManager lockManager;
-	@Autowired
-	private BaseSecurityManager securityManager;
-	@Autowired
-	private UserManager userManager;
 
 	@Override
 	public boolean fileExists(String fileId) {
@@ -142,7 +139,7 @@ public class OnlyOfficeServiceImpl implements OnlyOfficeService {
 		
 		InfoImpl info = new InfoImpl();
 		String author = vfsMetadata.getAuthor() != null
-				? userManager.getUserDisplayName(vfsMetadata.getAuthor())
+				? identityService.getUserDisplayName(vfsMetadata.getAuthor())
 				: null;
 		info.setAuthor(author);
 		info.setCreated(null); // not in metadata
@@ -168,9 +165,9 @@ public class OnlyOfficeServiceImpl implements OnlyOfficeService {
 		apiConfig.setEditor(editorConfig);
 		
 		UserImpl user = new UserImpl();
-		String name = userManager.getUserDisplayName(identity);
+		String name = identityService.getUserDisplayName(identity);
 		user.setName(name);
-		user.setId(identity.getKey().toString());
+		user.setId(identityService.getGlobalIdentityId(identity));
 		editorConfig.setUser(user);
 		
 		String token = onlyOfficeSecurityService.getApiConfigToken(document, editorConfig);
@@ -304,13 +301,7 @@ public class OnlyOfficeServiceImpl implements OnlyOfficeService {
 
 	@Override
 	public Identity getIdentity(String identityId) {
-		try {
-			Long identityKey = Long.valueOf(identityId);
-			return securityManager.loadIdentityByKey(identityKey);
-		} catch (NumberFormatException e) {
-			log.warn("Try to load identity with key " + identityId, e);
-		}
-		return null;
+		return identityService.getIdentity(identityId);
 	}
 	
 }
diff --git a/src/test/java/org/olat/core/commons/services/doceditor/manager/DocEditorIdentityServiceTest.java b/src/test/java/org/olat/core/commons/services/doceditor/manager/DocEditorIdentityServiceTest.java
new file mode 100644
index 00000000000..4143720d0b1
--- /dev/null
+++ b/src/test/java/org/olat/core/commons/services/doceditor/manager/DocEditorIdentityServiceTest.java
@@ -0,0 +1,52 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.doceditor.manager;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+import org.olat.core.commons.services.doceditor.DocEditorIdentityService;
+import org.olat.core.id.Identity;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 17 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class DocEditorIdentityServiceTest extends OlatTestCase {
+	
+	@Autowired
+	private DocEditorIdentityService sut;
+	
+	@Test
+	public void shouldIdentifyIdentityBaGlobalId() {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("doc-editor-1");
+
+		String globalUserId = sut.getGlobalIdentityId(identity);
+		Identity reloadedIdentity = sut.getIdentity(globalUserId);
+		
+		assertThat(reloadedIdentity).isEqualTo(identity);
+	}
+
+}
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index 374388ab36a..da439120cb9 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -99,6 +99,7 @@ import org.junit.runners.Suite;
 	org.olat.commons.coordinate.cluster.lock.LockTest.class,
 	org.olat.commons.coordinate.CoordinatorTest.class,
 	org.olat.core.commons.services.csp.manager.CSPManagerTest.class,
+	org.olat.core.commons.services.doceditor.manager.DocEditorIdentityServiceTest.class,
 	org.olat.core.commons.services.doceditor.wopi.manager.AccessDAOTest.class,
 	org.olat.core.commons.services.doceditor.wopi.manager.WopiServiceTest.class,
 	org.olat.core.commons.services.vfs.manager.VFSXStreamTest.class,
-- 
GitLab