001/* 002 * Copyright 2020 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.ametys.plugins.workspaces.documents.onlyoffice; 018 019import java.util.HashMap; 020import java.util.Map; 021import java.util.Set; 022 023import org.apache.avalon.framework.component.Component; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.avalon.framework.service.Serviceable; 027import org.apache.commons.lang3.StringUtils; 028 029import org.ametys.core.authentication.token.AuthenticationTokenManager; 030import org.ametys.core.ui.Callable; 031import org.ametys.core.user.CurrentUserProvider; 032import org.ametys.plugins.explorer.resources.Resource; 033import org.ametys.plugins.repository.AmetysObjectResolver; 034import org.ametys.runtime.config.Config; 035import org.ametys.runtime.plugin.component.AbstractLogEnabled; 036 037import com.auth0.jwt.JWT; 038import com.auth0.jwt.algorithms.Algorithm; 039 040/** 041 * Main helper for OnlyOffice edition 042 */ 043public class OnlyOfficeManager extends AbstractLogEnabled implements Component, Serviceable 044{ 045 /** The Avalon role */ 046 public static final String ROLE = OnlyOfficeManager.class.getName(); 047 048 /** The token manager */ 049 protected AuthenticationTokenManager _tokenManager; 050 /** The current user provider */ 051 protected CurrentUserProvider _currentUserProvider; 052 /** The Ametys object resolver */ 053 protected AmetysObjectResolver _resolver; 054 /** The Only Office key manager */ 055 protected OnlyOfficeKeyManager _onlyOfficeKeyManager; 056 057 @Override 058 public void service(ServiceManager manager) throws ServiceException 059 { 060 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 061 _tokenManager = (AuthenticationTokenManager) manager.lookup(AuthenticationTokenManager.ROLE); 062 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 063 _onlyOfficeKeyManager = (OnlyOfficeKeyManager) manager.lookup(OnlyOfficeKeyManager.ROLE); 064 } 065 066 /** 067 * Determines if OnlyOffice edition is available 068 * @return true if OnlyOffice edition is available 069 */ 070 @Callable 071 public boolean isOnlyOfficeEditionAvailable() 072 { 073 return Config.getInstance().getValue("workspaces.onlyoffice.enabled", false, false); 074 } 075 076 /** 077 * Get the needed information for Only Office edition 078 * @param resourceId the id of resource to edit 079 * @return the only office informations 080 */ 081 @Callable 082 public Map<String, Object> getOnlyOfficeInfo(String resourceId) 083 { 084 Map<String, Object> infos = new HashMap<>(); 085 086 Resource resource = _resolver.resolveById(resourceId); 087 088 String token = generateToken(resourceId); 089 String tokenCtx = StringUtils.substringAfter(resourceId, "://"); 090 091 Map<String, Object> fileInfo = new HashMap<>(); 092 fileInfo.put("title", resource.getName()); 093 fileInfo.put("fileExtension", StringUtils.substringAfterLast(resource.getName(), ".").toLowerCase()); 094 fileInfo.put("key", _onlyOfficeKeyManager.getKey(resourceId)); 095 096 String ooCMSUrl = Config.getInstance().getValue("workspaces.onlyoffice.bo.url"); 097 if (StringUtils.isEmpty(ooCMSUrl)) 098 { 099 ooCMSUrl = Config.getInstance().getValue("cms.url"); 100 } 101 102 String downloadUrl = ooCMSUrl 103 + "/_workspaces/only-office/download-resource?" 104 + "id=" + resourceId 105 + "&token=" + token 106 + "&tokenContext=" + tokenCtx; 107 108 fileInfo.put("urlDownload", downloadUrl); 109 110 infos.put("file", fileInfo); 111 112 String callbackUrl = ooCMSUrl 113 + "/_workspaces/only-office/response.json?" 114 + "id=" + resourceId 115 + "&token=" + token 116 + "&tokenContext=" + tokenCtx; 117 118 infos.put("callbackUrl", callbackUrl); 119 120 return infos; 121 } 122 /** 123 * Generate a token for OnlyOffice use 124 * @param fileId id of the resource that will be used by OnlyOffice 125 * @return the token 126 */ 127 @Callable 128 public String generateToken(String fileId) 129 { 130 Set<String> contexts = Set.of(StringUtils.substringAfter(fileId, "://")); 131 132 return _tokenManager.generateToken(_currentUserProvider.getUser(), 30000, true, null, contexts, "onlyOfficeResponse", null); 133 } 134 135 /** 136 * Sign a json configuration for OnlyOffice using a secret parametrized key 137 * @param toSign The json to sign 138 * @return The signed json 139 */ 140 @Callable 141 public Map<String, Object> signConfiguration(String toSign) 142 { 143 String secret = Config.getInstance().getValue("workspaces.onlyoffice.secret"); 144 145 Map<String, Object> result = new HashMap<>(); 146 147 if (StringUtils.isNotBlank(secret)) 148 { 149 Algorithm algorithm = Algorithm.HMAC256(secret); 150 String token = JWT.create() 151 .withIssuer(toSign) 152 .sign(algorithm); 153 result.put("signature", token); 154 } 155 156 result.put("success", "true"); 157 return result; 158 } 159}