/*
* Copyright (C) 2005-2008 Jive Software. All rights reserved.
*
* 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.
*/
package org.jivesoftware.openfire.plugin;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.jivesoftware.openfire.SharedGroupException;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.group.Group;
import org.jivesoftware.openfire.group.GroupAlreadyExistsException;
import org.jivesoftware.openfire.group.GroupManager;
import org.jivesoftware.openfire.group.GroupNotFoundException;
import org.jivesoftware.openfire.lockout.LockOutManager;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.user.User;
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.PropertyEventDispatcher;
import org.jivesoftware.util.PropertyEventListener;
import org.jivesoftware.util.StringUtils;
import org.xmpp.packet.JID;
/**
* Plugin that allows the administration of users via HTTP requests.
*
* @author Justin Hunt
*/
public class UserServicePlugin implements Plugin, PropertyEventListener {
private UserManager userManager;
private RosterManager rosterManager;
private XMPPServer server;
private String secret;
private boolean enabled;
private boolean httpBasicAuth;
private Collection<String> allowedIPs;
public void initializePlugin(PluginManager manager, File pluginDirectory) {
server = XMPPServer.getInstance();
userManager = server.getUserManager();
rosterManager = server.getRosterManager();
secret = JiveGlobals.getProperty("plugin.userservice.secret", "");
// If no secret key has been assigned to the user service yet, assign a
// random one.
if (secret.equals("")) {
secret = StringUtils.randomString(8);
setSecret(secret);
}
// See if the service is enabled or not.
enabled = JiveGlobals.getBooleanProperty("plugin.userservice.enabled", false);
// See if the HTTP Basic Auth is enabled or not.
httpBasicAuth = JiveGlobals.getBooleanProperty("plugin.userservice.httpAuth.enabled", false);
// Get the list of IP addresses that can use this service. An empty list
// means that this filter is disabled.
allowedIPs = StringUtils.stringToCollection(JiveGlobals.getProperty("plugin.userservice.allowedIPs", ""));
// Listen to system property events
PropertyEventDispatcher.addListener(this);
}
public void destroyPlugin() {
userManager = null;
// Stop listening to system property events
PropertyEventDispatcher.removeListener(this);
}
public void createUser(String username, String password, String name, String email, String groupNames)
throws UserAlreadyExistsException, GroupAlreadyExistsException, UserNotFoundException,
GroupNotFoundException {
userManager.createUser(username, password, name, email);
userManager.getUser(username);
if (groupNames != null) {
Collection<Group> groups = new ArrayList<Group>();
StringTokenizer tkn = new StringTokenizer(groupNames, ",");
while (tkn.hasMoreTokens()) {
String groupName = tkn.nextToken();
Group group = null;
try {
group = GroupManager.getInstance().getGroup(groupName);
} catch (GroupNotFoundException e) {
// Create this group ;
group = GroupManager.getInstance().createGroup(groupName);
group.getProperties().put("sharedRoster.showInRoster", "onlyGroup");
group.getProperties().put("sharedRoster.displayName", groupName);
group.getProperties().put("sharedRoster.groupList", "");
}
groups.add(group);
}
for (Group group : groups) {
group.getMembers().add(server.createJID(username, null));
}
}
}
public void deleteUser(String username) throws UserNotFoundException, SharedGroupException {
User user = getUser(username);
userManager.deleteUser(user);
rosterManager.deleteRoster(server.createJID(username, null));
}
/**
* Lock Out on a given username
*
* @param username
* the username of the local user to disable.
* @throws UserNotFoundException
* if the requested user does not exist in the local server.
*/
public void disableUser(String username) throws UserNotFoundException {
getUser(username);
LockOutManager.getInstance().disableAccount(username, null, null);
}
/**
* Remove the lockout on a given username
*
* @param username
* the username of the local user to enable.
* @throws UserNotFoundException
* if the requested user does not exist in the local server.
*/
public void enableUser(String username) throws UserNotFoundException {
getUser(username);
LockOutManager.getInstance().enableAccount(username);
}
public void updateUser(String username, String password, String name, String email, String groupNames)
throws UserNotFoundException, GroupAlreadyExistsException {
User user = getUser(username);
if (password != null)
user.setPassword(password);
if (name != null)
user.setName(name);
if (email != null)
user.setEmail(email);
if (groupNames != null) {
Collection<Group> newGroups = new ArrayList<Group>();
StringTokenizer tkn = new StringTokenizer(groupNames, ",");
while (tkn.hasMoreTokens()) {
String groupName = tkn.nextToken();
Group group = null;
try {
group = GroupManager.getInstance().getGroup(groupName);
} catch (GroupNotFoundException e) {
// Create this group ;
group = GroupManager.getInstance().createGroup(groupName);
group.getProperties().put("sharedRoster.showInRoster", "onlyGroup");
group.getProperties().put("sharedRoster.displayName", groupName);
group.getProperties().put("sharedRoster.groupList", "");
}
newGroups.add(group);
}
Collection<Group> existingGroups = GroupManager.getInstance().getGroups(user);
// Get the list of groups to add to the user
Collection<Group> groupsToAdd = new ArrayList<Group>(newGroups);
groupsToAdd.removeAll(existingGroups);
// Get the list of groups to remove from the user
Collection<Group> groupsToDelete = new ArrayList<Group>(existingGroups);
groupsToDelete.removeAll(newGroups);
// Add the user to the new groups
for (Group group : groupsToAdd) {
group.getMembers().add(server.createJID(username, null));
}
// Remove the user from the old groups
for (Group group : groupsToDelete) {
group.getMembers().remove(server.createJID(username, null));
}
}
}
/**
* Add new roster item for specified user
*
* @param username
* the username of the local user to add roster item to.
* @param itemJID
* the JID of the roster item to be added.
* @param itemName
* the nickname of the roster item.
* @param subscription
* the type of subscription of the roster item. Possible values
* are: -1(remove), 0(none), 1(to), 2(from), 3(both).
* @param groupNames
* the name of a group to place contact into.
* @throws UserNotFoundException
* if the user does not exist in the local server.
* @throws UserAlreadyExistsException
* if roster item with the same JID already exists.
* @throws SharedGroupException
* if roster item cannot be added to a shared group.
*/
public void addRosterItem(String username, String itemJID, String itemName, String subscription, String groupNames)
throws UserNotFoundException, UserAlreadyExistsException, SharedGroupException {
getUser(username);
Roster r = rosterManager.getRoster(username);
JID j = new JID(itemJID);
try {
r.getRosterItem(j);
throw new UserAlreadyExistsException(j.toBareJID());
} catch (UserNotFoundException e) {
// Roster item does not exist. Try to add it.
}
if (r != null) {
List<String> groups = new ArrayList<String>();
if (groupNames != null) {
StringTokenizer tkn = new StringTokenizer(groupNames, ",");
while (tkn.hasMoreTokens()) {
groups.add(tkn.nextToken());
}
}
RosterItem ri = r.createRosterItem(j, itemName, groups, false, true);
if (subscription == null) {
subscription = "0";
}
ri.setSubStatus(RosterItem.SubType.getTypeFromInt(Integer.parseInt(subscription)));
r.updateRosterItem(ri);
}
}
/**
* Update roster item for specified user
*
* @param username
* the username of the local user to update roster item for.
* @param itemJID
* the JID of the roster item to be updated.
* @param itemName
* the nickname of the roster item.
* @param subscription
* the type of subscription of the roster item. Possible values
* are: -1(remove), 0(none), 1(to), 2(from), 3(both).
* @param groupNames
* the name of a group.
* @throws UserNotFoundException
* if the user does not exist in the local server or roster item
* does not exist.
* @throws SharedGroupException
* if roster item cannot be added to a shared group.
*/
public void updateRosterItem(String username, String itemJID, String itemName, String subscription,
String groupNames) throws UserNotFoundException, SharedGroupException {
getUser(username);
Roster r = rosterManager.getRoster(username);
JID j = new JID(itemJID);
RosterItem ri = r.getRosterItem(j);
List<String> groups = new ArrayList<String>();
if (groupNames != null) {
StringTokenizer tkn = new StringTokenizer(groupNames, ",");
while (tkn.hasMoreTokens()) {
groups.add(tkn.nextToken());
}
}
ri.setGroups(groups);
ri.setNickname(itemName);
if (subscription == null) {
subscription = "0";
}
ri.setSubStatus(RosterItem.SubType.getTypeFromInt(Integer.parseInt(subscription)));
r.updateRosterItem(ri);
}
/**
* Delete roster item for specified user. No error returns if nothing to
* delete.
*
* @param username
* the username of the local user to add roster item to.
* @param itemJID
* the JID of the roster item to be deleted.
* @throws UserNotFoundException
* if the user does not exist in the local server.
* @throws SharedGroupException
* if roster item cannot be deleted from a shared group.
*/
public void deleteRosterItem(String username, String itemJID) throws UserNotFoundException, SharedGroupException {
getUser(username);
Roster r = rosterManager.getRoster(username);
JID j = new JID(itemJID);
// No roster item is found. Uncomment the following line to throw
// UserNotFoundException.
// r.getRosterItem(j);
r.deleteRosterItem(j, true);
}
/**
* Returns the the requested user or <tt>null</tt> if there are any problems
* that don't throw an error.
*
* @param username
* the username of the local user to retrieve.
* @return the requested user.
* @throws UserNotFoundException
* if the requested user does not exist in the local server.
*/
private User getUser(String username) throws UserNotFoundException {
JID targetJID = server.createJID(username, null);
// Check that the sender is not requesting information of a remote
// server entity
if (targetJID.getNode() == null) {
// Sender is requesting presence information of an anonymous user
throw new UserNotFoundException("Username is null");
}
return userManager.getUser(targetJID.getNode());
}
/**
* Returns all group names or an empty collection.
*
*/
public Collection<String> getAllGroups() {
Collection<Group> groups = GroupManager.getInstance().getGroups();
Collection<String> groupNames = new ArrayList<String>();
for (Group group : groups) {
groupNames.add(group.getName());
}
return groupNames;
}
/**
* Returns all group names or an empty collection for specific user
*
*/
public Collection<String> getUserGroups(String username) throws UserNotFoundException {
User user = getUser(username);
Collection<Group> groups = GroupManager.getInstance().getGroups(user);
Collection<String> groupNames = new ArrayList<String>();
for (Group group : groups) {
groupNames.add(group.getName());
}
return groupNames;
}
/**
* Returns the secret key that only valid requests should know.
*
* @return the secret key.
*/
public String getSecret() {
return secret;
}
/**
* Sets the secret key that grants permission to use the userservice.
*
* @param secret
* the secret key.
*/
public void setSecret(String secret) {
JiveGlobals.setProperty("plugin.userservice.secret", secret);
this.secret = secret;
}
public Collection<String> getAllowedIPs() {
return allowedIPs;
}
public void setAllowedIPs(Collection<String> allowedIPs) {
JiveGlobals.setProperty("plugin.userservice.allowedIPs", StringUtils.collectionToString(allowedIPs));
this.allowedIPs = allowedIPs;
}
/**
* Returns true if the user service is enabled. If not enabled, it will not
* accept requests to create new accounts.
*
* @return true if the user service is enabled.
*/
public boolean isEnabled() {
return enabled;
}
/**
* Enables or disables the user service. If not enabled, it will not accept
* requests to create new accounts.
*
* @param enabled
* true if the user service should be enabled.
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
JiveGlobals.setProperty("plugin.userservice.enabled", enabled ? "true" : "false");
}
public boolean isHttpBasicAuth() {
return httpBasicAuth;
}
public void setHttpBasicAuth(boolean httpBasicAuth) {
this.httpBasicAuth = httpBasicAuth;
JiveGlobals.setProperty("plugin.userservice.httpAuth.enabled", httpBasicAuth ? "true" : "false");
}
public void propertySet(String property, Map<String, Object> params) {
if (property.equals("plugin.userservice.secret")) {
this.secret = (String) params.get("value");
} else if (property.equals("plugin.userservice.enabled")) {
this.enabled = Boolean.parseBoolean((String) params.get("value"));
} else if (property.equals("plugin.userservice.allowedIPs")) {
this.allowedIPs = StringUtils.stringToCollection((String) params.get("value"));
} else if (property.equals("plugin.userservice.httpAuth.enabled")) {
this.httpBasicAuth = Boolean.parseBoolean((String) params.get("value"));
}
}
public void propertyDeleted(String property, Map<String, Object> params) {
if (property.equals("plugin.userservice.secret")) {
this.secret = "";
} else if (property.equals("plugin.userservice.enabled")) {
this.enabled = false;
} else if (property.equals("plugin.userservice.allowedIPs")) {
this.allowedIPs = Collections.emptyList();
} else if (property.equals("plugin.userservice.httpAuth.enabled")) {
this.httpBasicAuth = false;
}
}
public void xmlPropertySet(String property, Map<String, Object> params) {
// Do nothing
}
public void xmlPropertyDeleted(String property, Map<String, Object> params) {
// Do nothing
}
}