POP3AuthProvider.java 9.7 KB
Newer Older
1 2 3 4 5
/**
 * $RCSfile$
 * $Revision: 2654 $
 * $Date: 2005-08-14 14:40:32 -0300 (Sun, 14 Aug 2005) $
 *
6
 * Copyright (C) 2004-2008 Jive Software. All rights reserved.
7
 *
8 9 10 11 12 13 14 15 16 17 18
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
19 20
 */

21
package org.jivesoftware.openfire.auth;
22

23
import java.util.Properties;
24 25

import javax.mail.NoSuchProviderException;
26 27
import javax.mail.Session;
import javax.mail.Store;
28 29 30 31 32 33 34 35 36 37 38

import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
39 40 41

/**
 * An AuthProvider that authenticates using a POP3 server. It will automatically create
42
 * local user accounts as needed. To enable this provider, set system properties as follows:
43
 *
44 45 46 47
 * <ul>
 * <li><tt>provider.auth.className = org.jivesoftware.openfire.auth.POP3AuthProvider</tt></li>
 * <li><tt>provider.user.className = org.jivesoftware.openfire.user.POP3UserProvider</tt></li>
 * </ul>
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
 *
 * The properties to configure the provider are as follows:
 *
 * <ul>
 *      <li>pop3.host -- <i>(required)</i> the name (or IP) of the POP3 server.
 *      <li>pop.port -- the port of the POP3 server. The default value is 110 for standard
 *              connections and 995 for SSL connections.
 *      <li>pop3.domain -- the mail domain (e.g. gmail.com).
 *      <li>pop3.authRequiresDomain -- set this to true if the POP3 server requires a
 *              full email address for authentication (foo@example.com) rather than just
 *              a username (foo). The default value is false.
 *      <li>pop3.ssl -- true if an SSL connection to the POP3 server should be used. The default
 *              is false.
 *      <li>pop3.debug -- true if debugging output for the POP3 connection should be enabled. The
 *              default is false.
 *      <li>pop3.authCache.enabled -- true if authentication checks should be cached locally.
 *              This will decrease load on the POP3 server if users continually authenticate.
 *              The default value is false.
 *      <li>pop3.authCache.size -- the maximum size of the authentication cache (in bytes). The
 *              default value is 512 K.
 *      <li>pop3.authCache.maxLifetime -- the maximum lifetime of items in the authentication
 *              cache (in milliseconds). The default value is one hour.
 * </ul>
 *
 * @author Sean Meiners
 */
public class POP3AuthProvider implements AuthProvider {

76 77
	private static final Logger Log = LoggerFactory.getLogger(POP3AuthProvider.class);

78 79 80 81 82 83 84 85 86 87 88 89
    private Cache authCache = null;
    private String host = null;
    private String domain = null;
    private int port = -1;
    private boolean useSSL = false;
    private boolean authRequiresDomain = false;
    private boolean debugEnabled;

    /**
     * Initialiazes the POP3AuthProvider with values from the global config file.
     */
    public POP3AuthProvider() {
90 91 92 93 94 95 96 97 98 99
        // Convert XML based provider setup to Database based
        JiveGlobals.migrateProperty("pop3.authCache.enabled");
        JiveGlobals.migrateProperty("pop3.ssl");
        JiveGlobals.migrateProperty("pop3.authRequiresDomain");
        JiveGlobals.migrateProperty("pop3.host");
        JiveGlobals.migrateProperty("pop3.debug");
        JiveGlobals.migrateProperty("pop3.domain");
        JiveGlobals.migrateProperty("pop3.port");

        if (Boolean.valueOf(JiveGlobals.getProperty("pop3.authCache.enabled"))) {
100
            String cacheName = "POP3 Authentication";
101
            authCache = CacheFactory.createCache(cacheName);
102 103
        }

104 105
        useSSL = Boolean.valueOf(JiveGlobals.getProperty("pop3.ssl"));
        authRequiresDomain = Boolean.valueOf(JiveGlobals.getProperty("pop3.authRequiresDomain"));
106

107
        host = JiveGlobals.getProperty("pop3.host");
108 109 110 111
        if (host == null || host.length() < 1) {
            throw new IllegalArgumentException("pop3.host is null or empty");
        }

112
        debugEnabled = Boolean.valueOf(JiveGlobals.getProperty("pop3.debug"));
113

114
        domain = JiveGlobals.getProperty("pop3.domain");
115

116
        port = JiveGlobals.getIntProperty("pop3.port", useSSL ? 995 : 110);
117 118

        if (Log.isDebugEnabled()) {
119
            Log.debug("POP3AuthProvider: Created new POP3AuthProvider instance, fields:");
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
            Log.debug("\t host: " + host);
            Log.debug("\t port: " + port);
            Log.debug("\t domain: " + domain);
            Log.debug("\t useSSL: " + useSSL);
            Log.debug("\t authRequiresDomain: " + authRequiresDomain);
            Log.debug("\t authCacheEnabled: " + (authCache != null));
            if (authCache != null) {
                Log.debug("\t authCacheSize: " + authCache.getCacheSize());
                Log.debug("\t authCacheMaxLifetime: " + authCache.getMaxLifetime());
            }
        }
    }

    public void authenticate(String username, String password) throws UnauthorizedException {
        if (username == null || password == null) {
            throw new UnauthorizedException();
        }
137 138 139 140
        if (username.contains("@")) {
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
141
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
142 143 144 145 146 147
                username = username.substring(0, index);
            }
        } else {
            // Unknown domain. Return authentication failed.
            throw new UnauthorizedException();
        }
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

        Log.debug("POP3AuthProvider.authenticate("+username+", ******)");

            // If cache is enabled, see if the auth is in cache.
            if (authCache != null && authCache.containsKey(username)) {
                String hash = (String)authCache.get(username);
                if (StringUtils.hash(password).equals(hash)) {
                    return;
                }
            }

        Properties mailProps = new Properties();
        mailProps.setProperty("mail.debug", String.valueOf(debugEnabled));
        Session session = Session.getInstance(mailProps, null);
        Store store;
        try {
            store = session.getStore(useSSL ? "pop3s" : "pop3");
        }
        catch(NoSuchProviderException e) {
167
            Log.error(e.getMessage(), e);
168 169 170 171 172 173 174 175 176 177 178 179
            throw new UnauthorizedException(e);
        }

        try {
            if (authRequiresDomain) {
                store.connect(host, port, username + "@" + domain, password);
            }
            else {
                store.connect(host, port, username, password);
            }
        }
        catch(Exception e) {
180
            Log.error(e.getMessage(), e);
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
            throw new UnauthorizedException(e);
        }

        if (! store.isConnected()) {
            throw new UnauthorizedException("Could not authenticate user");
        }

        try {
            store.close();
        }
        catch (Exception e) {
            // Ignore.
        }

        // If cache is enabled, add the item to cache.
        if (authCache != null) {
            authCache.put(username, StringUtils.hash(password));
        }

        // See if the user exists in the database. If not, automatically create them.
        UserManager userManager = UserManager.getInstance();
        try {
            userManager.getUser(username);
        }
        catch (UserNotFoundException unfe) {
            String email = username + "@" + (domain!=null?domain:host);
            try {
208
                Log.debug("POP3AuthProvider: Automatically creating new user account for " + username);
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
                // Create user; use a random password for better safety in the future.
                // Note that we have to go to the user provider directly -- because the
                // provider is read-only, UserManager will usually deny access to createUser.
                UserManager.getUserProvider().createUser(username, StringUtils.randomString(8),
                        null, email);
            }
            catch (UserAlreadyExistsException uaee) {
                // Ignore.
            }
        }
    }

    public void authenticate(String username, String token, String digest)
            throws UnauthorizedException
    {
        throw new UnauthorizedException("Digest authentication not supported.");
    }

    public boolean isPlainSupported() {
        return true;
    }

    public boolean isDigestSupported() {
        return false;
    }
234 235 236 237 238 239 240 241 242 243 244 245 246 247

    public String getPassword(String username)
            throws UserNotFoundException, UnsupportedOperationException
    {
        throw new UnsupportedOperationException();
    }

     public void setPassword(String username, String password) throws UserNotFoundException {
        throw new UnsupportedOperationException();
    }

    public boolean supportsPasswordRetrieval() {
        return false;
    }
248
}