/*
* (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Bogdan Stefanescu
* Florent Guillaume
*/
package org.nuxeo.ecm.core.api;
import static org.nuxeo.ecm.core.api.security.SecurityConstants.SYSTEM_USERNAME;
import java.io.Serializable;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import org.apache.commons.lang3.mutable.MutableObject;
import org.nuxeo.ecm.core.api.CoreSessionService.CoreSessionRegistrationInfo;
import org.nuxeo.ecm.core.api.impl.UserPrincipal;
import org.nuxeo.ecm.core.api.local.ClientLoginModule;
import org.nuxeo.ecm.core.api.local.LoginStack;
import org.nuxeo.ecm.core.api.repository.RepositoryManager;
import org.nuxeo.ecm.core.api.security.SecurityConstants;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.api.login.LoginComponent;
/**
* The CoreInstance is the main access point to a CoreSession.
*/
public class CoreInstance {
private static final CoreInstance INSTANCE = new CoreInstance();
private CoreInstance() {
}
/**
* Gets the CoreInstance singleton.
*
* @deprecated since 8.4, use {@link CoreSessionService} directly.
*/
public static CoreInstance getInstance() {
return INSTANCE;
}
/**
* Opens a {@link CoreSession} for the currently logged-in user.
* <p>
* The session must be closed using {@link CoreSession#close}.
*
* @param repositoryName the repository name, or {@code null} for the default repository
* @return the session
* @since 5.9.3
*/
public static CoreSession openCoreSession(String repositoryName) {
return openCoreSession(repositoryName, getPrincipal((String) null));
}
/**
* MUST ONLY BE USED IN UNIT TESTS to open a {@link CoreSession} for the given user.
* <p>
* The session must be closed using {@link CoreSession#close}.
*
* @param repositoryName the repository name, or {@code null} for the default repository
* @param username the user name
* @return the session
* @since 5.9.3
*/
public static CoreSession openCoreSession(String repositoryName, String username) {
return openCoreSession(repositoryName, getPrincipal(username));
}
/**
* Opens a {@link CoreSession} for a system user.
* <p>
* The session must be closed using {@link CoreSession#close}.
*
* @param repositoryName the repository name, or {@code null} for the default repository
* @return the session
* @since 5.9.3
*/
public static CoreSession openCoreSessionSystem(String repositoryName) {
return openCoreSession(repositoryName, getPrincipal((SecurityConstants.SYSTEM_USERNAME)));
}
/**
* Opens a {@link CoreSession} for a system user with an optional originating username.
* <p>
* The session must be closed using {@link CoreSession#close}.
*
* @param repositoryName the repository name, or {@code null} for the default repository
* @param originatingUsername the originating username to set on the SystemPrincipal
* @return the session
* @since 8.1
*/
public static CoreSession openCoreSessionSystem(String repositoryName, String originatingUsername) {
NuxeoPrincipal principal = getPrincipal((SecurityConstants.SYSTEM_USERNAME));
principal.setOriginatingUser(originatingUsername);
return openCoreSession(repositoryName, principal);
}
/**
* NOT PUBLIC, DO NOT CALL. Kept public for compatibility with old code.
* <p>
* Opens a {@link CoreSession} for the given context.
*
* @param repositoryName the repository name, or {@code null} for the default repository
* @param context the session open context
* @return the session
*/
public static CoreSession openCoreSession(String repositoryName, Map<String, Serializable> context) {
return openCoreSession(repositoryName, getPrincipal(context));
}
/**
* MUST ONLY BE USED IN UNIT TESTS to open a {@link CoreSession} for the given principal.
* <p>
* The session must be closed using {@link CoreSession#close}.
*
* @param repositoryName the repository name, or {@code null} for the default repository
* @param principal the principal
* @return the session
* @since 5.9.3
*/
public static CoreSession openCoreSession(String repositoryName, Principal principal) {
if (principal instanceof NuxeoPrincipal) {
return openCoreSession(repositoryName, (NuxeoPrincipal) principal);
} else {
return openCoreSession(repositoryName, getPrincipal(principal.getName()));
}
}
/**
* MUST ONLY BE USED IN UNIT TESTS to open a {@link CoreSession} for the given principal.
* <p>
* The session must be closed using {@link CoreSession#close}.
*
* @param repositoryName the repository name, or {@code null} for the default repository
* @param principal the principal
* @return the session
* @since 5.9.3
*/
public static CoreSession openCoreSession(String repositoryName, NuxeoPrincipal principal) {
if (repositoryName == null) {
RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class);
repositoryName = repositoryManager.getDefaultRepository().getName();
}
return Framework.getService(CoreSessionService.class).createCoreSession(repositoryName, principal);
}
/**
* Gets an existing open session for the given session id.
* <p>
* The returned CoreSession must not be closed, as it is owned by someone else.
*
* @param sessionId the session id
* @return the session, which must not be closed
*/
public CoreSession getSession(String sessionId) {
return Framework.getService(CoreSessionService.class).getCoreSession(sessionId);
}
/**
* Use {@link CoreSession#close} instead.
*
* @since 5.9.3
*/
public static void closeCoreSession(CoreSession session) {
Framework.getService(CoreSessionService.class).releaseCoreSession(session);
}
protected static NuxeoPrincipal getPrincipal(Map<String, Serializable> map) {
if (map == null) {
return getPrincipal((String) null); // logged-in principal
}
NuxeoPrincipal principal = (NuxeoPrincipal) map.get("principal");
if (principal == null) {
principal = getPrincipal((String) map.get("username"));
}
return principal;
}
protected static NuxeoPrincipal getPrincipal(String username) {
if (username != null) {
if (SYSTEM_USERNAME.equals(username)) {
return new SystemPrincipal(null);
} else {
return new UserPrincipal(username, new ArrayList<>(), false, false);
}
} else {
LoginStack.Entry entry = ClientLoginModule.getCurrentLogin();
if (entry != null) {
Principal p = entry.getPrincipal();
if (p instanceof NuxeoPrincipal) {
return (NuxeoPrincipal) p;
} else if (LoginComponent.isSystemLogin(p)) {
return new SystemPrincipal(p.getName());
} else {
throw new RuntimeException("Unsupported principal: " + p.getClass());
}
} else {
if (Framework.isTestModeSet()) {
return new SystemPrincipal(null);
} else {
throw new NuxeoException(
"Cannot create a CoreSession outside a security context, " + " login() missing.");
}
}
}
}
/**
* Gets the number of open sessions.
*
* @since 5.4.2
* @deprecated since 8.4, use {@link CoreSessionService#getNumberOfOpenCoreSessions()} directly
*/
@Deprecated
public int getNumberOfSessions() {
return Framework.getService(CoreSessionService.class).getNumberOfOpenCoreSessions();
}
/**
* Gets the number of open sessions.
*
* @since 5.4.2
* @deprecated since 8.4, use {@link CoreSessionService#getCoreSessionRegistrationInfos()} directly
*/
@Deprecated
public Collection<CoreSessionRegistrationInfo> getRegistrationInfos() {
return Framework.getService(CoreSessionService.class).getCoreSessionRegistrationInfos();
}
/**
* Gets the name of the currently logged-in principal.
*
* @return the principal name, or {@code null} if there was no login
* @since 8.4
*/
protected static String getCurrentPrincipalName() {
Principal p = ClientLoginModule.getCurrentPrincipal();
return p == null ? null : p.getName();
}
/**
* Runs the given {@link Function} with a system {@link CoreSession} while logged in as a system user.
*
* @param repositoryName the repository name for the {@link CoreSession}
* @param function the function taking a system {@link CoreSession} and returning a result of type {@code <R>}
* @param <R> the function return type
* @return the result of the function
* @since 8.4
*/
public static <R> R doPrivileged(String repositoryName, Function<CoreSession, R> function) {
MutableObject<R> result = new MutableObject<>();
new UnrestrictedSessionRunner(repositoryName, getCurrentPrincipalName()) {
@Override
public void run() {
result.setValue(function.apply(session));
}
}.runUnrestricted();
return result.getValue();
}
/**
* Runs the given {@link Function} with a system {@link CoreSession} while logged in as a system user.
*
* @param session an existing session
* @param function the function taking a system {@link CoreSession} and returning a result of type {@code <R>}
* @param <R> the function return type
* @return the result of the function
* @since 8.4
*/
public static <R> R doPrivileged(CoreSession session, Function<CoreSession, R> function) {
MutableObject<R> result = new MutableObject<>();
new UnrestrictedSessionRunner(session) {
@Override
public void run() {
result.setValue(function.apply(session));
}
}.runUnrestricted();
return result.getValue();
}
/**
* Runs the given {@link Consumer} with a system {@link CoreSession} while logged in as a system user.
*
* @param repositoryName the repository name for the {@link CoreSession}
* @param consumer the consumer taking a system {@link CoreSession}
* @since 8.4
*/
public static void doPrivileged(String repositoryName, Consumer<CoreSession> consumer) {
new UnrestrictedSessionRunner(repositoryName, getCurrentPrincipalName()) {
@Override
public void run() {
consumer.accept(session);
}
}.runUnrestricted();
}
/**
* Runs the given {@link Consumer} with a system {@link CoreSession} while logged in as a system user.
*
* @param session an existing session
* @param consumer the consumer taking a system {@link CoreSession}
* @since 8.4
*/
public static void doPrivileged(CoreSession session, Consumer<CoreSession> consumer) {
new UnrestrictedSessionRunner(session) {
@Override
public void run() {
consumer.accept(session);
}
}.runUnrestricted();
}
}