001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.security.pwd;
016    
017    import com.liferay.portal.exception.PwdEncryptorException;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.security.pwd.PasswordEncryptor;
021    import com.liferay.portal.kernel.util.CharPool;
022    import com.liferay.portal.kernel.util.PropsKeys;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.Validator;
026    import com.liferay.portal.util.PropsValues;
027    
028    /**
029     * @author Tomas Polesovsky
030     */
031    public class LegacyAlgorithmAwarePasswordEncryptor
032            extends BasePasswordEncryptor {
033    
034            @Override
035            public String[] getSupportedAlgorithmTypes() {
036                    return _parentPasswordEncryptor.getSupportedAlgorithmTypes();
037            }
038    
039            public void setParentPasswordEncryptor(
040                    PasswordEncryptor defaultPasswordEncryptor) {
041    
042                    _parentPasswordEncryptor = defaultPasswordEncryptor;
043            }
044    
045            @Override
046            protected String doEncrypt(
047                            String algorithm, String plainTextPassword,
048                            String encryptedPassword)
049                    throws PwdEncryptorException {
050    
051                    if (Validator.isNull(
052                                    PropsValues.PASSWORDS_ENCRYPTION_ALGORITHM_LEGACY)) {
053    
054                            if (_log.isDebugEnabled()) {
055                                    _log.debug(
056                                            "Skipping passwords upgrade scheme because " +
057                                                    PropsKeys.PASSWORDS_ENCRYPTION_ALGORITHM_LEGACY +
058                                                            " is blank");
059                            }
060    
061                            try {
062                                    return _parentPasswordEncryptor.encrypt(
063                                            algorithm, plainTextPassword, encryptedPassword);
064                            }
065                            catch (Exception e) {
066                                    StringBundler sb = new StringBundler(5);
067    
068                                    sb.append("Password upgrade was not successfully configured. ");
069                                    sb.append("Please set the property ");
070                                    sb.append("\"passwords.encryption.algorithm.legacy\" with ");
071                                    sb.append("the previous password encryption algorithm and ");
072                                    sb.append("restart.");
073    
074                                    throw new PwdEncryptorException(sb.toString(), e);
075                            }
076                    }
077    
078                    if (_log.isDebugEnabled()) {
079                            String message =
080                                    "Using legacy detection scheme for algorithm " + algorithm +
081                                            " with current password ";
082    
083                            if (Validator.isNull(encryptedPassword)) {
084                                    message += "empty";
085                            }
086                            else {
087                                    message += "provided";
088                            }
089    
090                            _log.debug(message);
091                    }
092    
093                    boolean prependAlgorithm = true;
094    
095                    if (Validator.isNotNull(encryptedPassword) &&
096                            (encryptedPassword.charAt(0) != CharPool.OPEN_CURLY_BRACE)) {
097    
098                            algorithm = PropsValues.PASSWORDS_ENCRYPTION_ALGORITHM_LEGACY;
099    
100                            prependAlgorithm = false;
101    
102                            if (_log.isDebugEnabled()) {
103                                    _log.debug("Using legacy algorithm " + algorithm);
104                            }
105                    }
106                    else if (Validator.isNotNull(encryptedPassword) &&
107                                     (encryptedPassword.charAt(0) == CharPool.OPEN_CURLY_BRACE)) {
108    
109                            int index = encryptedPassword.indexOf(CharPool.CLOSE_CURLY_BRACE);
110    
111                            if (index > 0) {
112                                    algorithm = encryptedPassword.substring(1, index);
113    
114                                    encryptedPassword = encryptedPassword.substring(index + 1);
115                            }
116    
117                            if (_log.isDebugEnabled()) {
118                                    _log.debug("Upgraded password to use algorithm " + algorithm);
119                            }
120                    }
121    
122                    String newEncryptedPassword = _parentPasswordEncryptor.encrypt(
123                            algorithm, plainTextPassword, encryptedPassword);
124    
125                    if (!prependAlgorithm) {
126                            if (_log.isDebugEnabled()) {
127                                    _log.debug(
128                                            "Generated password without algorithm prefix using " +
129                                                    algorithm);
130                            }
131    
132                            return newEncryptedPassword;
133                    }
134    
135                    if (_log.isDebugEnabled()) {
136                            _log.debug(
137                                    "Generated password with algorithm prefix using " + algorithm);
138                    }
139    
140                    StringBundler sb = new StringBundler(4);
141    
142                    sb.append(StringPool.OPEN_CURLY_BRACE);
143                    sb.append(getAlgorithmName(algorithm));
144                    sb.append(StringPool.CLOSE_CURLY_BRACE);
145                    sb.append(newEncryptedPassword);
146    
147                    return sb.toString();
148            }
149    
150            protected String getAlgorithmName(String algorithm) {
151                    int index = algorithm.indexOf(CharPool.SLASH);
152    
153                    if (index > 0) {
154                            return algorithm.substring(0, index);
155                    }
156    
157                    return algorithm;
158            }
159    
160            private static final Log _log = LogFactoryUtil.getLog(
161                    LegacyAlgorithmAwarePasswordEncryptor.class);
162    
163            private PasswordEncryptor _parentPasswordEncryptor;
164    
165    }