ClearspaceLockOutProvider.java 8.35 KB
Newer Older
1 2 3 4
/**
 * $Revision$
 * $Date$
 *
5
 * Copyright (C) 2005-2008 Jive Software. All rights reserved.
6 7
 *
 * This software is published under the terms of the GNU Public License (GPL),
8 9
 * a copy of which is included in this distribution, or a commercial license
 * agreement with Jive.
10 11 12
 */
package org.jivesoftware.openfire.clearspace;

13 14 15 16
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
17
import org.jivesoftware.openfire.XMPPServer;
18 19
import static org.jivesoftware.openfire.clearspace.ClearspaceManager.HttpType.GET;
import static org.jivesoftware.openfire.clearspace.ClearspaceManager.HttpType.PUT;
20 21 22
import org.jivesoftware.openfire.lockout.LockOutFlag;
import org.jivesoftware.openfire.lockout.LockOutProvider;
import org.jivesoftware.openfire.user.UserNotFoundException;
23
import org.jivesoftware.util.Log;
24
import org.xmpp.packet.JID;
25

26 27
import java.util.List;

28 29 30 31 32 33 34 35 36 37
/**
 * The ClearspaceLockOutProvider uses the UserService web service inside of Clearspace
 * to retrieve user properties from Clearspace.  One of these properties refers to whether
 * the user is disabled or not.  In the future we may implement this in a different manner
 * that will require less overall communication with Clearspace.
 *
 * @author Daniel Henninger
 */
public class ClearspaceLockOutProvider implements LockOutProvider {

38 39
    protected static final String USER_URL_PREFIX = "userService/";

40 41 42 43 44 45 46 47 48 49
    /**
     * Generate a ClearspaceLockOutProvider instance.
     */
    public ClearspaceLockOutProvider() {
    }

    /**
     * The ClearspaceLockOutProvider will retrieve lockout information from Clearspace's user properties.
     * @see org.jivesoftware.openfire.lockout.LockOutProvider#getDisabledStatus(String)
     */
50
    public LockOutFlag getDisabledStatus(String username) {
51 52 53 54 55 56
        try {
            // Retrieve the disabled status, translate it into a LockOutFlag, and return it.
            return checkUserDisabled(getUserByUsername(username));
        }
        catch (UserNotFoundException e) {
            // Not a valid user?  We will leave it up to the user provider to handle rejecting this user.
57
            Log.warn(e);
58 59
            return null;
        }
60 61 62 63 64 65 66
    }

    /**
     * The ClearspaceLockOutProvider will set lockouts in Clearspace itself.
     * @see org.jivesoftware.openfire.lockout.LockOutProvider#setDisabledStatus(org.jivesoftware.openfire.lockout.LockOutFlag)
     */
    public void setDisabledStatus(LockOutFlag flag) {
67
        setEnabledStatus(flag.getUsername(), false);
68 69 70 71 72 73 74
    }

    /**
     * The ClearspaceLockOutProvider will set lockouts in Clearspace itself.
     * @see org.jivesoftware.openfire.lockout.LockOutProvider#unsetDisabledStatus(String)
     */
    public void unsetDisabledStatus(String username) {
75
        setEnabledStatus(username, true);
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
    }

    /**
     * The ClearspaceLockOutProvider will set lockouts in Clearspace itself.
     * @see org.jivesoftware.openfire.lockout.LockOutProvider#isReadOnly()
     */
    public boolean isReadOnly() {
        return false;
    }

    /**
     * Clearspace only supports a strict "are you disabled or not".
     * @see org.jivesoftware.openfire.lockout.LockOutProvider#isDelayedStartSupported()
     */
    public boolean isDelayedStartSupported() {
        return false;
    }

    /**
     * Clearspace only supports a strict "are you disabled or not".
     * @see org.jivesoftware.openfire.lockout.LockOutProvider#isTimeoutSupported()
     */
    public boolean isTimeoutSupported() {
        return false;
    }

102 103 104 105 106 107 108 109
    /**
     * Clearspace needs to always be queried for disabled status.
     * @see org.jivesoftware.openfire.lockout.LockOutProvider#shouldNotBeCached()
     */
    public boolean shouldNotBeCached() {
        return true;
    }

110
    /**
111
     * Looks up and modifies a user's CS properties to indicate whether they are enabled or disabled.
112 113 114
     * It is important for this to incorporate the existing user data and only tweak the field
     * that we want to change.
     *
115
     * @param username Username of user to set status of.
116 117
     * @param enabled Whether the account should be enabled or disabled.
     */
118 119 120 121
    private void setEnabledStatus(String username, Boolean enabled) {
        try {
            Element user = getUserByUsername(username);
            Element modifiedUser = modifyUser(user.element("return"), "enabled", enabled ? "true" : "false");
122

123
            String path = USER_URL_PREFIX + "users";
124
            ClearspaceManager.getInstance().executeRequest(PUT, path, modifiedUser.asXML());
125 126 127 128 129 130 131 132 133
        }
        catch (UserNotFoundException e) {
            Log.error("User with name " + username + " not found.", e);
        }
        catch (Exception e) {
            // It is not supported exception, wrap it into an UnsupportedOperationException
            throw new UnsupportedOperationException("Unexpected error", e);
        }
    }
134

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
    /**
     * Modifies user properties XML by replacing a particular attribute setting to something new.
     *
     * @param user User data XML.
     * @param attributeName Name of attribute to replace.
     * @param newValue New value for attribute.
     * @return Modified element.
     */
    private Element modifyUser(Element user, String attributeName, String newValue) {
        Document groupDoc =  DocumentHelper.createDocument();
        Element rootE = groupDoc.addElement("updateUser");
        Element newUser = rootE.addElement("user");
        List userAttributes = user.elements();
        for (Object userAttributeObj : userAttributes) {
            Element userAttribute = (Element)userAttributeObj;
            if (userAttribute.getName().equals(attributeName)) {
                newUser.addElement(userAttribute.getName()).setText(newValue);
            } else {
                newUser.addElement(userAttribute.getName()).setText(userAttribute.getText());
            }
        }
        return rootE;
157 158 159
    }

    /**
160 161
     * Examines the XML returned about a user to find out if they are enabled or disabled. Returns
     * <tt>null</tt> when user can log in or a LockOutFlag if user cannot log in.
162 163
     *
     * @param responseNode Element returned from REST service. (@see #getUserByUsername)
164
     * @return Either a LockOutFlag indicating that the user is disabled, or null if everything is fine.
165
     */
166
    private LockOutFlag checkUserDisabled(Node responseNode) {
167 168 169 170 171 172 173 174 175 176
        try {
            Node userNode = responseNode.selectSingleNode("return");

            // Gets the username
            String username = userNode.selectSingleNode("username").getText();

            // Gets the enabled field
            boolean isEnabled = Boolean.valueOf(userNode.selectSingleNode("enabled").getText());
            if (isEnabled) {
                // We're good, indicate that they're not locked out.
177
                return null;
178 179 180 181 182
            }
            else {
                // Creates the lock out flag
                return new LockOutFlag(username, null, null);
            }
183
        }
184 185 186
        catch (Exception e) {
            // Hrm.  This is not good.  We have to opt on the side of positive.
            Log.error("Error while looking up user's disabled status from Clearspace: ", e);
187
            return null;
188 189 190 191 192 193 194 195
        }
    }

    /**
     * Retrieves user properties for a Clearspace user in XML format.
     *
     * @param username Username to look up.
     * @return XML Element including information about the user.
196
     * @throws UserNotFoundException The user was not found in the Clearspace database or there was an error.
197 198
     */
    private Element getUserByUsername(String username) throws UserNotFoundException {
199 200 201 202 203 204 205 206
        // Checks if the user is local
        if (username.contains("@")) {
            if (!XMPPServer.getInstance().isLocal(new JID(username))) {
                throw new UserNotFoundException("Cannot load user of remote server: " + username);
            }
            username = username.substring(0, username.lastIndexOf("@"));
        }
        
207 208 209 210
        try {
            // Requests the user
            String path = USER_URL_PREFIX + "users/" + username;
            // return the response
211
            return ClearspaceManager.getInstance().executeRequest(GET, path);
212
        }
213 214 215
        catch (UserNotFoundException e) {
            throw e;
        }
216 217
        catch (Exception e) {
            // It is not supported exception, wrap it into an UserNotFoundException
218
            throw new UserNotFoundException("Error loading the user from Clearspace: ", e);
219 220 221
        }
    }

222
}