001/* 002 * (C) Copyright 2018 Nuxeo (http://nuxeo.com/) and others. 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 * Contributors: 017 * Thomas Roger 018 */ 019 020package org.nuxeo.wopi; 021 022import static java.nio.charset.StandardCharsets.UTF_8; 023import static org.nuxeo.wopi.Constants.ACCESS_TOKEN_PARAMETER; 024import static org.nuxeo.wopi.Constants.JWT_TOKEN_TTL; 025import static org.nuxeo.wopi.Constants.WOPI_SERVLET_PATH; 026 027import java.nio.charset.Charset; 028import java.util.List; 029import java.util.Map; 030 031import javax.servlet.http.HttpServletRequest; 032import javax.ws.rs.core.HttpHeaders; 033 034import org.apache.commons.lang3.StringUtils; 035import org.apache.logging.log4j.LogManager; 036import org.apache.logging.log4j.Logger; 037import org.nuxeo.ecm.core.api.Blob; 038import org.nuxeo.ecm.core.api.DocumentModel; 039import org.nuxeo.ecm.core.api.NuxeoPrincipal; 040import org.nuxeo.ecm.core.api.PropertyException; 041import org.nuxeo.ecm.core.blob.BlobManager; 042import org.nuxeo.ecm.core.blob.BlobProvider; 043import org.nuxeo.ecm.jwt.JWTClaims; 044import org.nuxeo.ecm.jwt.JWTService; 045import org.nuxeo.runtime.api.Framework; 046import org.nuxeo.wopi.exception.UnauthorizedException; 047 048/** 049 * @since 10.3 050 */ 051public class Helpers { 052 053 private static final Logger log = LogManager.getLogger(Helpers.class); 054 055 public static final Charset UTF_7 = new com.beetstra.jutf7.CharsetProvider().charsetForName("UTF-7"); 056 057 private Helpers() { 058 // helper class 059 } 060 061 public static String readUTF7String(String s) { 062 byte[] bytes = s.getBytes(UTF_8); 063 return new String(bytes, UTF_7); 064 } 065 066 public static String createJWTToken() { 067 return Framework.getService(JWTService.class).newBuilder().withTTL(JWT_TOKEN_TTL).build(); 068 } 069 070 public static String getJWTToken(HttpServletRequest request) { 071 String token = request.getParameter(ACCESS_TOKEN_PARAMETER); 072 if (token == null || Framework.getService(JWTService.class).verifyToken(token) == null) { 073 throw new UnauthorizedException(); 074 } 075 return token; 076 } 077 078 public static long getJWTTokenExp(String token) { 079 Map<String, Object> claims = Framework.getService(JWTService.class).verifyToken(token); 080 long expireAt = (long) claims.get(JWTClaims.CLAIM_EXPIRES_AT); 081 return expireAt * 1000; // milliseconds 082 } 083 084 // copied from org.nuxeo.ecm.platform.ui.web.tag.fn.Functions which lives in nuxeo-platform-ui-web 085 public static String principalFullName(NuxeoPrincipal principal) { 086 String first = principal.getFirstName(); 087 String last = principal.getLastName(); 088 return userDisplayName(principal.getName(), first, last); 089 } 090 091 public static Blob getEditableBlob(DocumentModel doc, String xpath) { 092 Blob blob = null; 093 try { 094 blob = (Blob) doc.getPropertyValue(xpath); 095 } catch (PropertyException e) { 096 // prevent server error 097 } 098 if (blob == null) { 099 log.debug("Blobs: repository={} docId={} xpath={} Cannot find blob", doc::getRepositoryName, doc::getId, 100 () -> xpath); 101 return null; 102 } 103 // ignore blob providers that don't support sync 104 if (!supportsSync(blob)) { 105 log.debug( 106 "Blobs: repository={} docId={} xpath={} Ignoring blob as it is backed by a BlobProvider preventing sync", 107 doc::getRepositoryName, doc::getId, () -> xpath); 108 return null; 109 } 110 return blob; 111 } 112 113 /** 114 * @deprecated since 11.1, use {@link #supportsSync} (with opposite semantics) instead 115 */ 116 @Deprecated 117 protected static boolean isExternalBlobProvider(Blob blob) { 118 BlobManager blobManager = Framework.getService(BlobManager.class); 119 BlobProvider blobProvider = blobManager.getBlobProvider(blob); 120 return blobProvider != null && (!blobProvider.supportsUserUpdate() || blobProvider.getBinaryManager() == null); 121 } 122 123 protected static boolean supportsSync(Blob blob) { 124 BlobManager blobManager = Framework.getService(BlobManager.class); 125 BlobProvider blobProvider = blobManager.getBlobProvider(blob); 126 return blobProvider != null && blobProvider.supportsSync(); 127 } 128 129 public static String getWOPIURL(String baseURL, String action, DocumentModel doc, String xpath) { 130 return String.format("%s%s/%s/%s/%s/%s", baseURL, WOPI_SERVLET_PATH, action, doc.getRepositoryName(), 131 doc.getId(), xpath); 132 } 133 134 protected static String userDisplayName(String id, String first, String last) { 135 if (StringUtils.isEmpty(first)) { 136 if (StringUtils.isEmpty(last)) { 137 return id; 138 } else { 139 return last; 140 } 141 } else { 142 if (StringUtils.isEmpty(last)) { 143 return first; 144 } else { 145 return first + ' ' + last; 146 } 147 } 148 } 149 150 public static String getHeader(HttpHeaders httpHeaders, String headerName) { 151 List<String> headers = httpHeaders.getRequestHeader(headerName); 152 return headers == null || headers.isEmpty() ? null : headers.get(0); 153 } 154 155}