001/* 002 * (C) Copyright 2006-2016 Nuxeo SA (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 * Bogdan Stefanescu 018 * Florent Guillaume 019 */ 020package org.nuxeo.ecm.core.api; 021 022import static org.nuxeo.ecm.core.api.security.SecurityConstants.SYSTEM_USERNAME; 023 024import java.io.Serializable; 025import java.security.Principal; 026import java.util.ArrayList; 027import java.util.Collection; 028import java.util.Map; 029import java.util.function.Consumer; 030import java.util.function.Function; 031 032import org.apache.commons.lang3.mutable.MutableObject; 033import org.nuxeo.ecm.core.api.CoreSessionService.CoreSessionRegistrationInfo; 034import org.nuxeo.ecm.core.api.impl.UserPrincipal; 035import org.nuxeo.ecm.core.api.local.ClientLoginModule; 036import org.nuxeo.ecm.core.api.local.LoginStack; 037import org.nuxeo.ecm.core.api.repository.RepositoryManager; 038import org.nuxeo.ecm.core.api.security.SecurityConstants; 039import org.nuxeo.runtime.api.Framework; 040import org.nuxeo.runtime.api.login.LoginComponent; 041 042/** 043 * The CoreInstance is the main access point to a CoreSession. 044 */ 045public class CoreInstance { 046 047 private static final CoreInstance INSTANCE = new CoreInstance(); 048 049 private CoreInstance() { 050 } 051 052 /** 053 * Gets the CoreInstance singleton. 054 * 055 * @deprecated since 8.4, use {@link CoreSessionService} directly. 056 */ 057 public static CoreInstance getInstance() { 058 return INSTANCE; 059 } 060 061 /** 062 * Opens a {@link CoreSession} for the currently logged-in user. 063 * <p> 064 * The session must be closed using {@link CoreSession#close}. 065 * 066 * @param repositoryName the repository name, or {@code null} for the default repository 067 * @return the session 068 * @since 5.9.3 069 */ 070 public static CoreSession openCoreSession(String repositoryName) { 071 return openCoreSession(repositoryName, getPrincipal((String) null)); 072 } 073 074 /** 075 * MUST ONLY BE USED IN UNIT TESTS to open a {@link CoreSession} for the given user. 076 * <p> 077 * The session must be closed using {@link CoreSession#close}. 078 * 079 * @param repositoryName the repository name, or {@code null} for the default repository 080 * @param username the user name 081 * @return the session 082 * @since 5.9.3 083 */ 084 public static CoreSession openCoreSession(String repositoryName, String username) { 085 return openCoreSession(repositoryName, getPrincipal(username)); 086 } 087 088 /** 089 * Opens a {@link CoreSession} for a system user. 090 * <p> 091 * The session must be closed using {@link CoreSession#close}. 092 * 093 * @param repositoryName the repository name, or {@code null} for the default repository 094 * @return the session 095 * @since 5.9.3 096 */ 097 public static CoreSession openCoreSessionSystem(String repositoryName) { 098 return openCoreSession(repositoryName, getPrincipal((SecurityConstants.SYSTEM_USERNAME))); 099 } 100 101 /** 102 * Opens a {@link CoreSession} for a system user with an optional originating username. 103 * <p> 104 * The session must be closed using {@link CoreSession#close}. 105 * 106 * @param repositoryName the repository name, or {@code null} for the default repository 107 * @param originatingUsername the originating username to set on the SystemPrincipal 108 * @return the session 109 * @since 8.1 110 */ 111 public static CoreSession openCoreSessionSystem(String repositoryName, String originatingUsername) { 112 NuxeoPrincipal principal = getPrincipal((SecurityConstants.SYSTEM_USERNAME)); 113 principal.setOriginatingUser(originatingUsername); 114 return openCoreSession(repositoryName, principal); 115 } 116 117 /** 118 * NOT PUBLIC, DO NOT CALL. Kept public for compatibility with old code. 119 * <p> 120 * Opens a {@link CoreSession} for the given context. 121 * 122 * @param repositoryName the repository name, or {@code null} for the default repository 123 * @param context the session open context 124 * @return the session 125 */ 126 public static CoreSession openCoreSession(String repositoryName, Map<String, Serializable> context) { 127 return openCoreSession(repositoryName, getPrincipal(context)); 128 } 129 130 /** 131 * MUST ONLY BE USED IN UNIT TESTS to open a {@link CoreSession} for the given principal. 132 * <p> 133 * The session must be closed using {@link CoreSession#close}. 134 * 135 * @param repositoryName the repository name, or {@code null} for the default repository 136 * @param principal the principal 137 * @return the session 138 * @since 5.9.3 139 */ 140 public static CoreSession openCoreSession(String repositoryName, Principal principal) { 141 if (principal instanceof NuxeoPrincipal) { 142 return openCoreSession(repositoryName, (NuxeoPrincipal) principal); 143 } else { 144 return openCoreSession(repositoryName, getPrincipal(principal.getName())); 145 } 146 } 147 148 /** 149 * MUST ONLY BE USED IN UNIT TESTS to open a {@link CoreSession} for the given principal. 150 * <p> 151 * The session must be closed using {@link CoreSession#close}. 152 * 153 * @param repositoryName the repository name, or {@code null} for the default repository 154 * @param principal the principal 155 * @return the session 156 * @since 5.9.3 157 */ 158 public static CoreSession openCoreSession(String repositoryName, NuxeoPrincipal principal) { 159 if (repositoryName == null) { 160 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 161 repositoryName = repositoryManager.getDefaultRepository().getName(); 162 } 163 return Framework.getService(CoreSessionService.class).createCoreSession(repositoryName, principal); 164 } 165 166 /** 167 * Gets an existing open session for the given session id. 168 * <p> 169 * The returned CoreSession must not be closed, as it is owned by someone else. 170 * 171 * @param sessionId the session id 172 * @return the session, which must not be closed 173 */ 174 public CoreSession getSession(String sessionId) { 175 return Framework.getService(CoreSessionService.class).getCoreSession(sessionId); 176 } 177 178 /** 179 * Use {@link CoreSession#close} instead. 180 * 181 * @since 5.9.3 182 */ 183 public static void closeCoreSession(CoreSession session) { 184 Framework.getService(CoreSessionService.class).releaseCoreSession(session); 185 } 186 187 protected static NuxeoPrincipal getPrincipal(Map<String, Serializable> map) { 188 if (map == null) { 189 return getPrincipal((String) null); // logged-in principal 190 } 191 NuxeoPrincipal principal = (NuxeoPrincipal) map.get("principal"); 192 if (principal == null) { 193 principal = getPrincipal((String) map.get("username")); 194 } 195 return principal; 196 } 197 198 protected static NuxeoPrincipal getPrincipal(String username) { 199 if (username != null) { 200 if (SYSTEM_USERNAME.equals(username)) { 201 return new SystemPrincipal(null); 202 } else { 203 return new UserPrincipal(username, new ArrayList<>(), false, false); 204 } 205 } else { 206 LoginStack.Entry entry = ClientLoginModule.getCurrentLogin(); 207 if (entry != null) { 208 Principal p = entry.getPrincipal(); 209 if (p instanceof NuxeoPrincipal) { 210 return (NuxeoPrincipal) p; 211 } else if (LoginComponent.isSystemLogin(p)) { 212 return new SystemPrincipal(p.getName()); 213 } else { 214 throw new RuntimeException("Unsupported principal: " + p.getClass()); 215 } 216 } else { 217 if (Framework.isTestModeSet()) { 218 return new SystemPrincipal(null); 219 } else { 220 throw new NuxeoException( 221 "Cannot create a CoreSession outside a security context, " + " login() missing."); 222 } 223 } 224 } 225 } 226 227 /** 228 * Gets the number of open sessions. 229 * 230 * @since 5.4.2 231 * @deprecated since 8.4, use {@link CoreSessionService#getNumberOfOpenCoreSessions()} directly 232 */ 233 @Deprecated 234 public int getNumberOfSessions() { 235 return Framework.getService(CoreSessionService.class).getNumberOfOpenCoreSessions(); 236 } 237 238 /** 239 * Gets the number of open sessions. 240 * 241 * @since 5.4.2 242 * @deprecated since 8.4, use {@link CoreSessionService#getCoreSessionRegistrationInfos()} directly 243 */ 244 @Deprecated 245 public Collection<CoreSessionRegistrationInfo> getRegistrationInfos() { 246 return Framework.getService(CoreSessionService.class).getCoreSessionRegistrationInfos(); 247 } 248 249 /** 250 * Gets the name of the currently logged-in principal. 251 * 252 * @return the principal name, or {@code null} if there was no login 253 * @since 8.4 254 */ 255 protected static String getCurrentPrincipalName() { 256 Principal p = ClientLoginModule.getCurrentPrincipal(); 257 return p == null ? null : p.getName(); 258 } 259 260 /** 261 * Runs the given {@link Function} with a system {@link CoreSession} while logged in as a system user. 262 * 263 * @param repositoryName the repository name for the {@link CoreSession} 264 * @param function the function taking a system {@link CoreSession} and returning a result of type {@code <R>} 265 * @param <R> the function return type 266 * @return the result of the function 267 * @since 8.4 268 */ 269 public static <R> R doPrivileged(String repositoryName, Function<CoreSession, R> function) { 270 MutableObject<R> result = new MutableObject<>(); 271 new UnrestrictedSessionRunner(repositoryName, getCurrentPrincipalName()) { 272 @Override 273 public void run() { 274 result.setValue(function.apply(session)); 275 } 276 }.runUnrestricted(); 277 return result.getValue(); 278 } 279 280 /** 281 * Runs the given {@link Function} with a system {@link CoreSession} while logged in as a system user. 282 * 283 * @param session an existing session 284 * @param function the function taking a system {@link CoreSession} and returning a result of type {@code <R>} 285 * @param <R> the function return type 286 * @return the result of the function 287 * @since 8.4 288 */ 289 public static <R> R doPrivileged(CoreSession session, Function<CoreSession, R> function) { 290 MutableObject<R> result = new MutableObject<>(); 291 new UnrestrictedSessionRunner(session) { 292 @Override 293 public void run() { 294 result.setValue(function.apply(session)); 295 } 296 }.runUnrestricted(); 297 return result.getValue(); 298 } 299 300 /** 301 * Runs the given {@link Consumer} with a system {@link CoreSession} while logged in as a system user. 302 * 303 * @param repositoryName the repository name for the {@link CoreSession} 304 * @param consumer the consumer taking a system {@link CoreSession} 305 * @since 8.4 306 */ 307 public static void doPrivileged(String repositoryName, Consumer<CoreSession> consumer) { 308 new UnrestrictedSessionRunner(repositoryName, getCurrentPrincipalName()) { 309 @Override 310 public void run() { 311 consumer.accept(session); 312 } 313 }.runUnrestricted(); 314 } 315 316 /** 317 * Runs the given {@link Consumer} with a system {@link CoreSession} while logged in as a system user. 318 * 319 * @param session an existing session 320 * @param consumer the consumer taking a system {@link CoreSession} 321 * @since 8.4 322 */ 323 public static void doPrivileged(CoreSession session, Consumer<CoreSession> consumer) { 324 new UnrestrictedSessionRunner(session) { 325 @Override 326 public void run() { 327 consumer.accept(session); 328 } 329 }.runUnrestricted(); 330 } 331 332}