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 java.security.Principal;
023import java.util.ArrayList;
024import java.util.function.Consumer;
025import java.util.function.Function;
026
027import org.apache.commons.lang3.mutable.MutableObject;
028import org.nuxeo.ecm.core.api.impl.UserPrincipal;
029import org.nuxeo.ecm.core.api.local.ClientLoginModule;
030import org.nuxeo.ecm.core.api.local.LoginStack;
031import org.nuxeo.ecm.core.api.repository.RepositoryManager;
032import org.nuxeo.runtime.api.Framework;
033import org.nuxeo.runtime.api.login.LoginComponent;
034
035/**
036 * The CoreInstance is the main access point to a CoreSession.
037 */
038public class CoreInstance {
039
040    private CoreInstance() {
041    }
042
043    /**
044     * Opens a {@link CoreSession} for the currently logged-in user.
045     * <p>
046     * The session must be closed using {@link CloseableCoreSession#close}.
047     *
048     * @param repositoryName the repository name, or {@code null} for the default repository
049     * @return the session
050     * @since 5.9.3
051     */
052    public static CloseableCoreSession openCoreSession(String repositoryName) {
053        return openCoreSession(repositoryName, getPrincipal(null));
054    }
055
056    /**
057     * MUST ONLY BE USED IN UNIT TESTS to open a {@link CoreSession} for the given user.
058     * <p>
059     * The session must be closed using {@link CloseableCoreSession#close}.
060     *
061     * @param repositoryName the repository name, or {@code null} for the default repository
062     * @param username the user name
063     * @return the session
064     * @since 5.9.3
065     */
066    public static CloseableCoreSession openCoreSession(String repositoryName, String username) {
067        return openCoreSession(repositoryName, getPrincipal(username));
068    }
069
070    /**
071     * Opens a {@link CoreSession} for a system user.
072     * <p>
073     * The session must be closed using {@link CloseableCoreSession#close}.
074     *
075     * @param repositoryName the repository name, or {@code null} for the default repository
076     * @return the session
077     * @since 5.9.3
078     */
079    public static CloseableCoreSession openCoreSessionSystem(String repositoryName) {
080        return openCoreSession(repositoryName, new SystemPrincipal(null));
081    }
082
083    /**
084     * Opens a {@link CoreSession} for a system user with an optional originating username.
085     * <p>
086     * The session must be closed using {@link CloseableCoreSession#close}.
087     *
088     * @param repositoryName the repository name, or {@code null} for the default repository
089     * @param originatingUsername the originating username to set on the SystemPrincipal
090     * @return the session
091     * @since 8.1
092     */
093    public static CloseableCoreSession openCoreSessionSystem(String repositoryName, String originatingUsername) {
094        return openCoreSession(repositoryName, new SystemPrincipal(originatingUsername));
095    }
096
097    /**
098     * Opens a {@link CoreSession} for the given principal.
099     * <p>
100     * The session must be closed using {@link CloseableCoreSession#close}.
101     *
102     * @param repositoryName the repository name, or {@code null} for the default repository
103     * @param principal the principal
104     * @return the session
105     * @since 5.9.3
106     */
107    public static CloseableCoreSession openCoreSession(String repositoryName, NuxeoPrincipal principal) {
108        if (repositoryName == null) {
109            RepositoryManager repositoryManager = Framework.getService(RepositoryManager.class);
110            repositoryName = repositoryManager.getDefaultRepositoryName();
111        }
112        return Framework.getService(CoreSessionService.class).createCoreSession(repositoryName, principal);
113    }
114
115    /**
116     * Gets an existing open session for the given session id.
117     * <p>
118     * The returned CoreSession must not be closed, as it is owned by someone else.
119     *
120     * @param sessionId the session id
121     * @return the session, which must not be closed
122     */
123    public CoreSession getSession(String sessionId) {
124        return Framework.getService(CoreSessionService.class).getCoreSession(sessionId);
125    }
126
127    /**
128     * Use {@link CloseableCoreSession#close} instead.
129     *
130     * @since 5.9.3
131     */
132    public static void closeCoreSession(CloseableCoreSession session) {
133        Framework.getService(CoreSessionService.class).releaseCoreSession(session);
134    }
135
136    protected static NuxeoPrincipal getPrincipal(String username) {
137        if (username != null) {
138            return new UserPrincipal(username, new ArrayList<>(), false, false);
139        } else {
140            LoginStack.Entry entry = ClientLoginModule.getCurrentLogin();
141            if (entry != null) {
142                Principal p = entry.getPrincipal();
143                if (p instanceof NuxeoPrincipal) {
144                    return (NuxeoPrincipal) p;
145                } else if (LoginComponent.isSystemLogin(p)) {
146                    return new SystemPrincipal(p.getName());
147                } else {
148                    throw new RuntimeException("Unsupported principal: " + p.getClass());
149                }
150            } else {
151                if (Framework.isTestModeSet()) {
152                    return new SystemPrincipal(null);
153                } else {
154                    throw new NuxeoException(
155                            "Cannot create a CoreSession outside a security context, " + " login() missing.");
156                }
157            }
158        }
159    }
160
161    /**
162     * Gets the name of the currently logged-in principal.
163     *
164     * @return the principal name, or {@code null} if there was no login
165     * @since 8.4
166     */
167    protected static String getCurrentPrincipalName() {
168        NuxeoPrincipal p = ClientLoginModule.getCurrentPrincipal();
169        return p == null ? null : p.getName();
170    }
171
172    /**
173     * Runs the given {@link Function} with a system {@link CoreSession} while logged in as a system user.
174     *
175     * @param repositoryName the repository name for the {@link CoreSession}
176     * @param function the function taking a system {@link CoreSession} and returning a result of type {@code <R>}
177     * @param <R> the function return type
178     * @return the result of the function
179     * @since 8.4
180     */
181    public static <R> R doPrivileged(String repositoryName, Function<CoreSession, R> function) {
182        MutableObject<R> result = new MutableObject<>();
183        new UnrestrictedSessionRunner(repositoryName, getCurrentPrincipalName()) {
184            @Override
185            public void run() {
186                result.setValue(function.apply(session));
187            }
188        }.runUnrestricted();
189        return result.getValue();
190    }
191
192    /**
193     * Runs the given {@link Function} with a system {@link CoreSession} while logged in as a system user.
194     *
195     * @param session an existing session
196     * @param function the function taking a system {@link CoreSession} and returning a result of type {@code <R>}
197     * @param <R> the function return type
198     * @return the result of the function
199     * @since 8.4
200     */
201    public static <R> R doPrivileged(CoreSession session, Function<CoreSession, R> function) {
202        MutableObject<R> result = new MutableObject<>();
203        new UnrestrictedSessionRunner(session) {
204            @Override
205            public void run() {
206                result.setValue(function.apply(session));
207            }
208        }.runUnrestricted();
209        return result.getValue();
210    }
211
212    /**
213     * Runs the given {@link Consumer} with a system {@link CoreSession} while logged in as a system user.
214     *
215     * @param repositoryName the repository name for the {@link CoreSession}
216     * @param consumer the consumer taking a system {@link CoreSession}
217     * @since 8.4
218     */
219    public static void doPrivileged(String repositoryName, Consumer<CoreSession> consumer) {
220        new UnrestrictedSessionRunner(repositoryName, getCurrentPrincipalName()) {
221            @Override
222            public void run() {
223                consumer.accept(session);
224            }
225        }.runUnrestricted();
226    }
227
228    /**
229     * Runs the given {@link Consumer} with a system {@link CoreSession} while logged in as a system user.
230     *
231     * @param session an existing session
232     * @param consumer the consumer taking a system {@link CoreSession}
233     * @since 8.4
234     */
235    public static void doPrivileged(CoreSession session, Consumer<CoreSession> consumer) {
236        new UnrestrictedSessionRunner(session) {
237            @Override
238            public void run() {
239                consumer.accept(session);
240            }
241        }.runUnrestricted();
242    }
243
244}