POP3AuthProvider.java 9.09 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
 *
 * This software is published under the terms of the GNU Public License (GPL),
9 10
 * a copy of which is included in this distribution, or a commercial license
 * agreement with Jive.
11 12
 */

13
package org.jivesoftware.openfire.auth;
14 15

import org.jivesoftware.util.*;
16
import org.jivesoftware.util.cache.Cache;
17
import org.jivesoftware.util.cache.CacheFactory;
18
import org.jivesoftware.openfire.XMPPServer;
19 20 21
import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
22 23

import javax.mail.NoSuchProviderException;
24 25
import javax.mail.Session;
import javax.mail.Store;
26 27 28 29
import java.util.Properties;

/**
 * An AuthProvider that authenticates using a POP3 server. It will automatically create
30
 * local user accounts as needed. To enable this provider, set system properties as follows:
31
 *
32 33 34 35
 * <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>
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
 *
 * 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 {

    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() {
76 77 78 79 80 81 82 83 84 85
        // 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"))) {
86
            String cacheName = "POP3 Authentication";
87
            authCache = CacheFactory.createCache(cacheName);
88 89
        }

90 91
        useSSL = Boolean.valueOf(JiveGlobals.getProperty("pop3.ssl"));
        authRequiresDomain = Boolean.valueOf(JiveGlobals.getProperty("pop3.authRequiresDomain"));
92

93
        host = JiveGlobals.getProperty("pop3.host");
94 95 96 97
        if (host == null || host.length() < 1) {
            throw new IllegalArgumentException("pop3.host is null or empty");
        }

98
        debugEnabled = Boolean.valueOf(JiveGlobals.getProperty("pop3.debug"));
99

100
        domain = JiveGlobals.getProperty("pop3.domain");
101

102
        port = JiveGlobals.getIntProperty("pop3.port", useSSL ? 995 : 110);
103 104

        if (Log.isDebugEnabled()) {
105
            Log.debug("POP3AuthProvider: Created new POP3AuthProvider instance, fields:");
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
            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();
        }
123 124 125 126
        if (username.contains("@")) {
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
127
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
128 129 130 131 132 133
                username = username.substring(0, index);
            }
        } else {
            // Unknown domain. Return authentication failed.
            throw new UnauthorizedException();
        }
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

        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) {
            Log.error(e);
            throw new UnauthorizedException(e);
        }

        try {
            if (authRequiresDomain) {
                store.connect(host, port, username + "@" + domain, password);
            }
            else {
                store.connect(host, port, username, password);
            }
        }
        catch(Exception e) {
            Log.error(e);
            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 {
194
                Log.debug("POP3AuthProvider: Automatically creating new user account for " + username);
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
                // 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;
    }
220 221 222 223 224 225 226 227 228 229 230 231 232 233

    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;
    }
234
}