001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (C) Alkacon Software (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, 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.jlan;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsUser;
032import org.opencms.main.CmsException;
033import org.opencms.main.CmsLog;
034import org.opencms.main.OpenCms;
035
036import java.security.InvalidKeyException;
037import java.security.NoSuchAlgorithmException;
038
039import org.apache.commons.logging.Log;
040
041import org.alfresco.jlan.server.auth.PasswordEncryptor;
042import org.alfresco.jlan.server.auth.UserAccount;
043import org.alfresco.jlan.server.auth.UsersInterface;
044import org.alfresco.jlan.server.config.ServerConfiguration;
045import org.springframework.extensions.config.ConfigElement;
046
047/**
048 * This class is used for authenticating OpenCms users to JLAN.<p>
049 *
050 * Since JLAN requires MD4 password hashes for authentication, which are not by default stored in the database,
051 * users who want to use the JLAN functionality should log in at least once into OpenCms normally so that the MD4
052 * hash of their password can be computed and stored.<p>
053 *
054 */
055public class CmsJlanUsers implements UsersInterface {
056
057    /** The default OU separator to use if none is configured. */
058    public static final String DEFAULT_OU_SEPARATOR = "___";
059
060    /** The additional info key for the MD4 password hash. */
061    public static final String JLAN_HASH = "jlan_hash";
062
063    /** Name of the runtime property used to configure the OU separator for CIFS login. */
064    public static final String PARAM_JLAN_OU_SEPARATOR = "jlan.ou.separator";
065
066    /** The logger instance for this class. */
067    private static final Log LOG = CmsLog.getLog(CmsJlanUsers.class);
068
069    /** The CMS context. */
070    private static CmsObject m_adminCms;
071
072    /**
073     * Computes an MD4 hash for the password.
074     *
075     * @param password the password for which to compute the hash
076     * @throws NoSuchAlgorithmException
077     * @throws InvalidKeyException
078     *
079     * @return the password hash
080     **/
081    public static byte[] hashPassword(String password) throws InvalidKeyException, NoSuchAlgorithmException {
082
083        PasswordEncryptor encryptor = new PasswordEncryptor();
084        return encryptor.generateEncryptedPassword(password, null, PasswordEncryptor.MD4, null, null);
085    }
086
087    /**
088     * Sets the CMS context.<p>
089     *
090     * @param cms the context to set
091     */
092    public static void setAdminCms(CmsObject cms) {
093
094        if (m_adminCms == null) {
095            m_adminCms = cms;
096        } else {
097            LOG.warn("Can't set admin CmsObject twice!");
098        }
099    }
100
101    /**
102     * Translates user names by replacing a custom OU separator with the standard OU separator '/'.
103     *
104     * This is needed because either JLAN or the client cuts off the part before the slash during authentication,
105     * so OpenCms never gets to see it. So if we want CIFS authentication for users from non-root OUs, we need to use
106     * a different separator.<p>
107     *
108     * @param name the user name to translate
109     *
110     * @return the translated user name
111     */
112    public static final String translateUser(String name) {
113
114        String ouSeparator = (String)(OpenCms.getRuntimeProperty(PARAM_JLAN_OU_SEPARATOR));
115        if (ouSeparator == null) {
116            ouSeparator = DEFAULT_OU_SEPARATOR;
117        }
118        String result = name;
119        result = result.replace(ouSeparator, "/");
120        return result;
121    }
122
123    /**
124     * @see org.alfresco.jlan.server.auth.UsersInterface#getUserAccount(java.lang.String)
125     */
126    public UserAccount getUserAccount(String userName) {
127
128        try {
129            userName = translateUser(userName);
130            CmsUser user = m_adminCms.readUser(userName);
131            UserAccount account = new UserAccount(userName, "");
132            Object jlanHash = user.getAdditionalInfo(JLAN_HASH);
133            if (OpenCms.getTwoFactorAuthenticationHandler().needsTwoFactorAuthentication(user)) {
134                LOG.warn("JLAN: Users for who two-factor authentication is enabled cannot access the network share.");
135            }
136            if (jlanHash != null) {
137                account.setMD4Password((byte[])jlanHash);
138            } else {
139                LOG.warn("JLAN: Could not log in user " + userName + " because of missing hash");
140                return null;
141            }
142            return account;
143        } catch (CmsException e) {
144            return null;
145        }
146    }
147
148    /**
149     * @see org.alfresco.jlan.server.auth.UsersInterface#initializeUsers(org.alfresco.jlan.server.config.ServerConfiguration, org.springframework.extensions.config.ConfigElement)
150     */
151    public void initializeUsers(ServerConfiguration config, ConfigElement params) {
152
153        // do nothing
154    }
155}