summaryrefslogtreecommitdiffstats
path: root/pki/base/common/src/com/netscape/cmscore/ldapconn/LdapAuthInfo.java
blob: b1af367b9d8ff20e06380b50927f6f753ca0019d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// (C) 2007 Red Hat, Inc.
// All rights reserved.
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmscore.ldapconn;

import java.util.Hashtable;

import netscape.ldap.LDAPConnection;
import netscape.ldap.LDAPException;

import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.base.EBaseException;
import com.netscape.certsrv.base.IConfigStore;
import com.netscape.certsrv.ldap.ILdapAuthInfo;
import com.netscape.cmsutil.password.IPasswordStore;

/**
 * class for reading ldap authentication info from config store
 */
public class LdapAuthInfo implements ILdapAuthInfo {

    protected int mType = -1;
    protected String[] mParms = null;

    private boolean mInited = false;

    private static Hashtable<String, String> passwords = new Hashtable<String, String>();

    /**
     * must call init(config) after this constructor.
     */
    public LdapAuthInfo() {
    }

    /**
     * constructs ldap auth info directly from config store.
     */
    public LdapAuthInfo(IConfigStore config) throws EBaseException {
        init(config);
    }

    /**
     * constructs ldap auth info directly from config store, and verifies
     * the password by attempting to connect to the server.
     */
    public LdapAuthInfo(IConfigStore config, String host, int port, boolean secure)
            throws EBaseException {
        init(config, host, port, secure);
    }

    public String getPasswordFromStore(String prompt) {
        String pwd = null;
        CMS.debug("LdapAuthInfo: getPasswordFromStore: try to get it from password store");

        // hey - should use password store interface to allow different implementations
        // but the problem is, other parts of the system just go directly to the file
        // so calling CMS.getPasswordStore() will give you an outdated one
        /*
                        IConfigStore mainConfig = CMS.getConfigStore();
                        String pwdFile = mainConfig.getString("passwordFile");
                        FileConfigStore pstore = new FileConfigStore(pwdFile);
        */
        IPasswordStore pwdStore = CMS.getPasswordStore();
        CMS.debug("LdapAuthInfo: getPasswordFromStore: about to get from passwored store: " + prompt);

        // support publishing dirsrv with different pwd than internaldb

        // Finally, interactively obtain the password from the user
        if (pwdStore != null) {
            CMS.debug("LdapAuthInfo: getPasswordFromStore: password store available");
            pwd = pwdStore.getPassword(prompt);
            //            pwd = pstore.getString(prompt);
            if (pwd == null) {
                CMS.debug("LdapAuthInfo: getPasswordFromStore: password for " + prompt +
                        " not found, trying internaldb");

                //               pwd = pstore.getString("internaldb");

                pwd = pwdStore.getPassword("internaldb"); // last resort
            } else
                CMS.debug("LdapAuthInfo: getPasswordFromStore: password found for prompt in password store");
        } else
            CMS.debug("LdapAuthInfo: getPasswordFromStore: password store not available: pwdStore is null");

        return pwd;
    }

    /**
     * initialize this class from the config store.
     */
    public void init(IConfigStore config) throws EBaseException {
        init(config, null, 0, true);
    }

    /**
     * initialize this class from the config store, and verify the password.
     * 
     * @param host The host that the directory server is running on.
     *            This will be used to verify the password by attempting to connect.
     *            If it is <code>null</code>, the password will not be verified.
     * @param port The port that the directory server is running on.
     */
    public void init(IConfigStore config, String host, int port, boolean secure)
            throws EBaseException {

        CMS.debug("LdapAuthInfo: init()");
        if (mInited) {
            CMS.debug("LdapAuthInfo: already initialized");
            return; // XXX throw exception here ?
        }
        CMS.debug("LdapAuthInfo: init begins");

        String authTypeStr = config.getString(PROP_LDAPAUTHTYPE);

        if (authTypeStr.equals(LDAP_BASICAUTH_STR)) {
            // is the password found in memory?
            boolean inMem = false;
            mType = LDAP_AUTHTYPE_BASICAUTH;
            mParms = new String[2];
            mParms[0] = config.getString(PROP_BINDDN);

            // Passwords should only be written to the file for testing,
            // never in production
            mParms[1] = config.getString(PROP_BINDPW, null);

            // Next, see if this password has been requested before
            String prompt = config.getString(PROP_BINDPW_PROMPT, null);

            if (prompt == null) {
                prompt = "LDAP Authentication";
                CMS.debug("LdapAuthInfo: init: prompt is null, change to " + prompt);
            } else
                CMS.debug("LdapAuthInfo: init: prompt is " + prompt);

            if (mParms[1] == null) {
                CMS.debug("LdapAuthInfo: init: try getting from memory cache");
                mParms[1] = passwords.get(prompt);
                if (mParms[1] != null) {
                    inMem = true;
                    CMS.debug("LdapAuthInfo: init: got password from memory");
                } else
                    CMS.debug("LdapAuthInfo: init: password not in memory");
            } else
                CMS.debug("LdapAuthInfo: init: found password from config");

            if (mParms[1] == null) {
                mParms[1] = getPasswordFromStore(prompt);
            } else {
                CMS.debug("LdapAuthInfo: init: password found for prompt.");
            }

            // verify the password
            if ((mParms[1] != null) && (!mParms[1].equals("")) && (host == null ||
                    authInfoOK(host, port, secure, mParms[0], mParms[1]))) {
                // The password is OK or uncheckable
                CMS.debug("LdapAuthInfo: password ok: store in memory cache");
                passwords.put(prompt, mParms[1]);
            } else {
                if (mParms[1] == null)
                    CMS.debug("LdapAuthInfo: password not found");
                else {
                    CMS.debug("LdapAuthInfo: password does not work");
                    /* what do you know?  Our IPasswordStore does not have a remove function.
                                    pstore.remove("internaldb");
                    */
                    if (inMem) {
                        // this is for the case when admin changes pwd
                        // from console
                        mParms[1] = getPasswordFromStore(prompt);
                        if (authInfoOK(host, port, secure, mParms[0], mParms[1])) {
                            CMS.debug("LdapAuthInfo: password ok: store in memory cache");
                            passwords.put(prompt, mParms[1]);
                        }
                    }
                }
            }

        } else if (authTypeStr.equals(LDAP_SSLCLIENTAUTH_STR)) {
            mType = LDAP_AUTHTYPE_SSLCLIENTAUTH;
            mParms = new String[1];
            mParms[0] = config.getString(PROP_CLIENTCERTNICKNAME, null);
        } else {
            throw new IllegalArgumentException(
                    "Unknown Ldap authentication type " + authTypeStr);
        }
        mInited = true;
        CMS.debug("LdapAuthInfo: init ends");
    }

    public void reset() {
        try {
            conn.disconnect();
        } catch (LDAPException e) {
        }
    }

    /**
     * Verifies the distinguished name and password by attempting to
     * authenticate to the server. If we connect to the server but cannot
     * authenticate, we conclude that the DN or password is invalid. If
     * we cannot connect at all, we don't know, so we return true
     * (there's no sense asking for the password again since we can't verify
     * it anyway). If we connect and authenticate successfully, we know
     * the DN and password are correct, so we return true.
     */
    private static LDAPConnection conn = new LDAPConnection();

    private static boolean
            authInfoOK(String host, int port, boolean secure, String dn, String pw) {

        // We dont perform auth checking if we are in SSL mode.
        if (secure)
            return true;

        boolean connected = false, authenticated = false;

        try {
            conn.connect(host, port);
            connected = true;
            conn.authenticate(dn, pw);
            authenticated = true;
        } catch (LDAPException e) {
        }

        /**
         * There is a bug in LDAP SDK. VM will crash on NT if
         * we connect and disconnect too many times.
         **/

        /**
         * if( connected ) {
         * try {
         * conn.disconnect();
         * } catch( LDAPException e ) { }
         * }
         **/

        if (connected && !authenticated) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * get authentication type.
     * 
     * @return one of: <br>
     *         LdapAuthInfo.LDAP_AUTHTYPE_BASICAUTH or
     *         LdapAuthInfo.LDAP_AUTHTYPE_SSLCLIENTAUTH
     */
    public int getAuthType() {
        return mType;
    }

    /**
     * get params for authentication
     * 
     * @return array of parameters for this authentication.
     */
    public String[] getParms() {
        return (String[]) mParms.clone();
    }

    /**
     * add password
     */
    public void addPassword(String prompt, String pw) {
        try {
            passwords.put(prompt, pw);
        } catch (Exception e) {
        }
    }

    /**
     * remove password
     */
    public void removePassword(String prompt) {
        try {
            passwords.remove(prompt);
        } catch (Exception e) {
        }
    }
}