XMPPCallbackHandler.java 5.83 KB
Newer Older
1
/**
Matt Tucker's avatar
Matt Tucker committed
2 3
 * $Revision$
 * $Date$
4 5 6 7 8 9 10
 *
 * Copyright (C) 2005 Jive Software. All rights reserved.
 *
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution.
 */

11
package org.jivesoftware.openfire.net;
12

13
import org.jivesoftware.openfire.auth.AuthFactory;
14
import org.jivesoftware.openfire.auth.AuthToken;
15
import org.jivesoftware.openfire.auth.AuthorizationManager;
16 17
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.sasl.VerifyPasswordCallback;
18 19
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.Log;
20 21 22 23 24 25 26

import javax.security.auth.callback.*;
import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.RealmCallback;
import java.io.IOException;

/**
Matt Tucker's avatar
Matt Tucker committed
27
 * Callback handler that may be used when doing SASL authentication. A CallbackHandler
28
 * may be required depending on the SASL mechanism being used.<p>
29
 *
Matt Tucker's avatar
Matt Tucker committed
30 31 32 33 34
 * Mechanisms that use a digest don't include a password so the server needs to use the
 * stored password of the user to compare it (somehow) with the specified digest. This
 * operation requires that the UserProvider being used supports passwords retrival.
 * {@link SASLAuthentication} should not offer these kind of SASL mechanisms if the user
 * provider being in use does not support passwords retrieval.
35 36 37 38 39
 *
 * @author Hao Chen
 */
public class XMPPCallbackHandler implements CallbackHandler {

Matt Tucker's avatar
Matt Tucker committed
40 41
    public XMPPCallbackHandler() {
    }
42

Matt Tucker's avatar
Matt Tucker committed
43 44
    public void handle(final Callback[] callbacks)
            throws IOException, UnsupportedCallbackException {
45

46

47
        String realm;
Matt Tucker's avatar
Matt Tucker committed
48
        String name = null;
49

50 51 52
        for (Callback callback : callbacks) {
            if (callback instanceof RealmCallback) {
                realm = ((RealmCallback) callback).getText();
Matt Tucker's avatar
Matt Tucker committed
53
                if (realm == null) {
54
                    realm = ((RealmCallback) callback).getDefaultText();
Matt Tucker's avatar
Matt Tucker committed
55
                }
56
                //Log.debug("XMPPCallbackHandler: RealmCallback: " + realm);
Matt Tucker's avatar
Matt Tucker committed
57
            }
58 59
            else if (callback instanceof NameCallback) {
                name = ((NameCallback) callback).getName();
Matt Tucker's avatar
Matt Tucker committed
60
                if (name == null) {
61
                    name = ((NameCallback) callback).getDefaultName();
Matt Tucker's avatar
Matt Tucker committed
62
                }
63
                //Log.debug("XMPPCallbackHandler: NameCallback: " + name);
Matt Tucker's avatar
Matt Tucker committed
64
            }
65
            else if (callback instanceof PasswordCallback) {
Matt Tucker's avatar
Matt Tucker committed
66
                try {
67 68
                    // Get the password from the UserProvider. Some UserProviders may not support
                    // this operation
69
                    ((PasswordCallback) callback)
70 71
                            .setPassword(AuthFactory.getPassword(name).toCharArray());

72
                    //Log.debug("XMPPCallbackHandler: PasswordCallback");
Matt Tucker's avatar
Matt Tucker committed
73 74 75 76
                }
                catch (UserNotFoundException e) {
                    throw new IOException(e.toString());
                }
77 78 79 80 81
                catch (UnsupportedOperationException uoe) {
                    throw new IOException(uoe.toString());
                }

            }
82
            else if (callback instanceof VerifyPasswordCallback) {
83
                //Log.debug("XMPPCallbackHandler: VerifyPasswordCallback");
84
                VerifyPasswordCallback vpcb = (VerifyPasswordCallback) callback;
85
                try {
86 87
                    AuthToken at = AuthFactory.authenticate(name, new String(vpcb.getPassword()));
                    vpcb.setVerified((at != null));
88 89 90 91
                }
                catch (UnauthorizedException e) {
                    vpcb.setVerified(false);
                }
Matt Tucker's avatar
Matt Tucker committed
92
            }
93
            else if (callback instanceof AuthorizeCallback) {
94
                //Log.debug("XMPPCallbackHandler: AuthorizeCallback");
95 96 97 98 99 100 101 102 103 104 105
                AuthorizeCallback authCallback = ((AuthorizeCallback) callback);
                // Principal that authenticated
                String principal = authCallback.getAuthenticationID();
                // Username requested (not full JID)
                String username = authCallback.getAuthorizationID();
                // Remove any REALM from the username. This is optional in the spec and it may cause
                // a lot of users to fail to log in if their clients is sending an incorrect value
                if (username != null && username.contains("@")) {
                    username = username.substring(0, username.lastIndexOf("@"));
                }
                if (principal.equals(username)) {
106 107
                    //client perhaps made no request, get default username
                    username = AuthorizationManager.map(principal);
108
                    if (Log.isDebugEnabled()) {
109
                        //Log.debug("XMPPCallbackHandler: no username requested, using " + username);
110
                    }
111 112
                }
                if (AuthorizationManager.authorize(username, principal)) {
113
                    if (Log.isDebugEnabled()) {
114
                        //Log.debug("XMPPCallbackHandler: " + principal + " authorized to " + username);
115
                    }
Matt Tucker's avatar
Matt Tucker committed
116
                    authCallback.setAuthorized(true);
117
                    authCallback.setAuthorizedID(username);
118 119
                }
                else {
120
                    if (Log.isDebugEnabled()) {
121
                        //Log.debug("XMPPCallbackHandler: " + principal + " not authorized to " + username);
122
                    }
123
                    authCallback.setAuthorized(false);
Matt Tucker's avatar
Matt Tucker committed
124 125 126
                }
            }
            else {
127
                if (Log.isDebugEnabled()) {
128
                    //Log.debug("XMPPCallbackHandler: Callback: " + callback.getClass().getSimpleName());
129 130
                }
                throw new UnsupportedCallbackException(callback, "Unrecognized Callback");
Matt Tucker's avatar
Matt Tucker committed
131 132 133 134
            }
        }
    }
}