001/*
002 * (C) Copyright 2006-2011 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 *     Florent Guillaume
018 */
019
020package org.nuxeo.ecm.core.api;
021
022import org.nuxeo.runtime.api.Framework;
023import org.nuxeo.runtime.api.login.NuxeoLoginContext;
024
025/**
026 * Helper class to run code with an unrestricted session.
027 * <p>
028 * The caller must implement the {@link #run} method, and call {@link #runUnrestricted}.
029 *
030 * @author Florent Guillaume
031 */
032public abstract class UnrestrictedSessionRunner {
033
034    protected String originatingUsername;
035
036    protected CoreSession session;
037
038    protected final boolean sessionIsAlreadyUnrestricted;
039
040    protected final String repositoryName;
041
042    /** True if a call to {@link #runUnrestricted} is in progress. */
043    protected boolean isUnrestricted;
044
045    /**
046     * Constructs a {@link UnrestrictedSessionRunner} given an existing session (which may or may not be already
047     * unrestricted).
048     * <p>
049     * Originating user is taken on given session.
050     *
051     * @param session the available session
052     */
053    protected UnrestrictedSessionRunner(CoreSession session) {
054        this.session = session;
055        sessionIsAlreadyUnrestricted = checkUnrestricted(session);
056        if (sessionIsAlreadyUnrestricted) {
057            repositoryName = null;
058        } else {
059            repositoryName = session.getRepositoryName();
060        }
061        NuxeoPrincipal pal = session.getPrincipal();
062        if (pal != null) {
063            originatingUsername = pal.getName();
064        }
065    }
066
067    /**
068     * Constructs a {@link UnrestrictedSessionRunner} given a repository name.
069     *
070     * @param repositoryName the repository name
071     */
072    protected UnrestrictedSessionRunner(String repositoryName) {
073        session = null;
074        sessionIsAlreadyUnrestricted = false;
075        this.repositoryName = repositoryName;
076    }
077
078    /**
079     * Constructs a {@link UnrestrictedSessionRunner} given a repository name and an originating user name.
080     *
081     * @param repositoryName the repository name
082     * @param originatingUser the user name behind the system user
083     */
084    protected UnrestrictedSessionRunner(String repositoryName, String originatingUser) {
085        session = null;
086        sessionIsAlreadyUnrestricted = false;
087        this.repositoryName = repositoryName;
088        originatingUsername = originatingUser;
089    }
090
091    public String getOriginatingUsername() {
092        return originatingUsername;
093    }
094
095    public void setOriginatingUsername(String originatingUsername) {
096        this.originatingUsername = originatingUsername;
097    }
098
099    protected boolean checkUnrestricted(CoreSession session) {
100        return session.getPrincipal().isAdministrator();
101    }
102
103    /**
104     * Calls the {@link #run()} method with an unrestricted {@link #session}. During this call, {@link #isUnrestricted}
105     * is set to {@code true}.
106     */
107    public void runUnrestricted() {
108        isUnrestricted = true;
109        try {
110            if (sessionIsAlreadyUnrestricted) {
111                if (NuxeoPrincipal.isCurrentAdministrator()) {
112                    run();
113                } else {
114                    // should be removed when login and session will be synchronized / NXP-27399
115                    Framework.doPrivileged(this::run);
116                }
117                return;
118            }
119
120            CoreSession baseSession = session;
121            try (NuxeoLoginContext loginContext = Framework.loginSystem(originatingUsername)) {
122                session = CoreInstance.getCoreSession(repositoryName);
123                run();
124            } finally {
125                session = baseSession;
126            }
127        } finally {
128            isUnrestricted = false;
129        }
130    }
131
132    /**
133     * This method will be called by {@link #runUnrestricted()} with {@link #session} available as an unrestricted
134     * session.
135     * <p>
136     * It can also be called directly in which case the {@link #session} available will be the one passed to
137     * {@code #UnrestrictedSessionRunner(CoreSession)}.
138     */
139    public abstract void run();
140
141}