001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.repository;
029
030import org.opencms.configuration.CmsConfigurationException;
031import org.opencms.configuration.CmsParameterConfiguration;
032import org.opencms.db.CmsUserSettings;
033import org.opencms.file.CmsObject;
034import org.opencms.file.wrapper.CmsObjectWrapper;
035import org.opencms.file.wrapper.I_CmsResourceWrapper;
036import org.opencms.main.CmsException;
037import org.opencms.main.CmsLog;
038import org.opencms.main.OpenCms;
039import org.opencms.security.CmsRole;
040import org.opencms.workplace.CmsWorkplace;
041
042import java.security.MessageDigest;
043import java.util.ArrayList;
044import java.util.Collections;
045import java.util.List;
046import java.util.Map;
047import java.util.concurrent.TimeUnit;
048
049import org.apache.commons.codec.binary.Hex;
050import org.apache.commons.lang3.RandomStringUtils;
051import org.apache.commons.logging.Log;
052
053import com.google.common.cache.CacheBuilder;
054
055/**
056 * Creates a repository session to access OpenCms.<p>
057 *
058 * The configuration of the used {@link I_CmsResourceWrapper} is done here.
059 * This is the main class to get access to the resources in the VFS of
060 * OpenCms. The method {@link #login(String, String)} logs in to OpenCms
061 * and returns a {@link CmsRepositorySession} to use for basic file and
062 * folder operations.<p>
063 *
064 * The project and the site to use for the access to OpenCms is read out
065 * of the user settings.<p>
066 *
067 * @see CmsObjectWrapper
068 *
069 * @since 6.5.6
070 */
071public class CmsRepository extends A_CmsRepository {
072
073    /** The log object for this class. */
074    private static final Log LOG = CmsLog.getLog(CmsRepository.class);
075
076    /** Random value used for hashing login credentials for the CmsObject cache. */
077    private static String m_passwordSalt = RandomStringUtils.randomAlphanumeric(10);
078
079    /** The name of the parameter of the configuration. */
080    private static final String PARAM_WRAPPER = "wrapper";
081
082    /** Timed cache for CmsObjects. */
083    private Map<String, CmsObject> m_cmsObjectCache;
084
085    /** The list of configured wrappers of the repository. */
086    private List<I_CmsResourceWrapper> m_wrappers;
087
088    /**
089     * Empty default constructor.<p>
090     */
091    public CmsRepository() {
092
093        super();
094        m_wrappers = new ArrayList<I_CmsResourceWrapper>();
095        CacheBuilder<?, ?> builder = CacheBuilder.newBuilder().concurrencyLevel(4).expireAfterWrite(
096            30,
097            TimeUnit.SECONDS);
098        m_cmsObjectCache = (Map<String, CmsObject>)(builder.build().asMap());
099    }
100
101    /**
102     * Gets the cache key for a username/password pair.
103     *
104     * @param user the user name
105     * @param password the password
106     * @return the cache key to use
107     */
108    private static String getLoginKey(String user, String password) {
109
110        try {
111            MessageDigest md5 = MessageDigest.getInstance("MD5");
112            md5.update(user.getBytes("UTF-8"));
113            md5.update(new byte[] {0});
114            md5.update(password.getBytes("UTF-8"));
115            md5.update(new byte[] {0});
116            md5.update(m_passwordSalt.getBytes("UTF-8"));
117            return Hex.encodeHexString(md5.digest());
118        } catch (Exception e) {
119            return null;
120        }
121
122    }
123
124    /**
125     * @see org.opencms.repository.A_CmsRepository#initConfiguration()
126     */
127    @Override
128    public void initConfiguration() throws CmsConfigurationException {
129
130        CmsParameterConfiguration config = getConfiguration();
131        List<I_CmsResourceWrapper> wrapperObjects = CmsRepositoryManager.createResourceWrappersFromConfiguration(
132            config,
133            PARAM_WRAPPER,
134            LOG);
135        m_wrappers = Collections.unmodifiableList(wrapperObjects);
136        super.initConfiguration();
137    }
138
139    /**
140     * @see org.opencms.repository.I_CmsRepository#initializeCms(org.opencms.file.CmsObject)
141     */
142    public void initializeCms(CmsObject cms) {
143
144        // do nothing
145    }
146
147    /**
148     * @see org.opencms.repository.A_CmsRepository#login(java.lang.String, java.lang.String)
149     */
150    @Override
151    public I_CmsRepositorySession login(String userName, String password) throws CmsException {
152
153        CmsObject cms;
154        // Cache CmsObjects for 30 seconds to avoid expensive password checks
155        // (We always copy the cached values, so it's safe for multithreading)
156        String cacheKey = getLoginKey(userName, password);
157        CmsObject origCms = m_cmsObjectCache.get(cacheKey);
158        String configuredProject = getConfiguration().getString("project", null);
159        String configuredSite = getConfiguration().getString("root", null);
160        String roleStr = getConfiguration().getString("role", CmsRole.WORKPLACE_USER.getRoleName());
161        CmsRole requiredRole = null;
162        if (!"any".equals(roleStr)) {
163            if (roleStr.indexOf("/") == -1) {
164                requiredRole = CmsRole.valueOfRoleName(roleStr).forOrgUnit(null);
165            } else {
166                requiredRole = CmsRole.valueOfRoleName(roleStr);
167            }
168        }
169        String project = configuredProject;
170        String site = configuredSite;
171        if (origCms != null) {
172            cms = OpenCms.initCmsObject(origCms);
173        } else {
174            cms = OpenCms.initCmsObject(OpenCms.getDefaultUsers().getUserGuest());
175            cms.loginUser(userName, password);
176            if (requiredRole != null) {
177                OpenCms.getRoleManager().checkRole(cms, requiredRole);
178            }
179            if ((site == null) || (project == null)) {
180                CmsUserSettings settings = new CmsUserSettings(cms);
181                if (site == null) {
182                    site = CmsWorkplace.getStartSiteRoot(cms, settings);
183                }
184                if (project == null) {
185                    project = settings.getStartProject();
186                }
187            }
188            cms.getRequestContext().setSiteRoot(site);
189            cms.getRequestContext().setCurrentProject(cms.readProject(project));
190            m_cmsObjectCache.put(cacheKey, OpenCms.initCmsObject(cms));
191        }
192
193        // set the object wrapper as an attribute in the request context, so that it can be
194        // used everywhere a CmsObject is accessible.
195        CmsObjectWrapper objWrapper = new CmsObjectWrapper(cms, m_wrappers);
196        boolean addBOM = getConfiguration().getBoolean("addBOM", true);
197        objWrapper.setAddByteOrderMark(addBOM);
198        cms.getRequestContext().setAttribute(CmsObjectWrapper.ATTRIBUTE_NAME, objWrapper);
199
200        return new CmsRepositorySession(objWrapper, getFilter(), isTranslationEnabled() ? getTranslation() : null);
201    }
202
203}