/* * Copyright 2016 Anno van Vliet * * 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.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.DOMReader; import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.auth.AuthFactory; import org.jivesoftware.openfire.roster.RosterItem; import org.jivesoftware.openfire.roster.RosterItemProvider; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xmpp.packet.JID; import gnu.inet.encoding.Stringprep; import gnu.inet.encoding.StringprepException; /** * Export and import Users in the Openfire XML format. * * @author Anno van Vliet * */ public class OpenfireExporter implements InExporter { private static final Logger Log = LoggerFactory.getLogger(OpenfireExporter.class); private final String serverName; private final UserManager userManager; private final RosterItemProvider rosterItemProvider; /** */ public OpenfireExporter() { serverName = XMPPServer.getInstance().getServerInfo().getXMPPDomain(); userManager = UserManager.getInstance(); rosterItemProvider = RosterManager.getRosterItemProvider(); } /** * @param serverName * @param userManager * @param rosterItemProvider */ public OpenfireExporter(String serverName, UserManager userManager, RosterItemProvider rosterItemProvider) { super(); this.serverName = serverName; this.userManager = userManager; this.rosterItemProvider = rosterItemProvider; } /* (non-Javadoc) * @see org.jivesoftware.openfire.plugin.Exporter#exportUsers() */ @Override public Document exportUsers() { Log.debug("exportUsers"); Document document = DocumentHelper.createDocument(); Element root = document.addElement("Openfire"); Collection<User> users = userManager.getUsers(); for (User user : users) { Element userElement = root.addElement("User"); String userName = user.getUsername(); userElement.addElement("Username").addText(userName); try { String pw = AuthFactory.getPassword(user.getUsername()); userElement.addElement("Password").addText(pw); } catch (UserNotFoundException e) { Log.info("User " + userName + " not found, setting their password to their username"); userElement.addElement("Password").addText(userName); } catch (UnsupportedOperationException e) { Log.info("Unable to retrieve " + userName + " password, setting their password to their username"); userElement.addElement("Password").addText(userName); } userElement.addElement("Email").addText(user.getEmail() == null ? "" : user.getEmail()); String name = user.getName(); userElement.addElement("Name").addText(name == null ? "" : name); //creation and modified date are not used as part of the import process but are exported //for historical purposes, should they be formatted differently? userElement.addElement("CreationDate").addText(String.valueOf(user.getCreationDate().getTime())); userElement.addElement("ModifiedDate").addText(String.valueOf(user.getModificationDate().getTime())); Element rosterElement = userElement.addElement("Roster"); Collection<RosterItem> roster = user.getRoster().getRosterItems(); for (RosterItem ri : roster) { Element itemElement = rosterElement.addElement("Item"); itemElement.addAttribute("jid", ri.getJid().toBareJID()); itemElement.addAttribute("askstatus", String.valueOf(ri.getAskStatus().getValue())); itemElement.addAttribute("recvstatus", String.valueOf(ri.getRecvStatus().getValue())); itemElement.addAttribute("substatus", String.valueOf(ri.getSubStatus().getValue())); itemElement.addAttribute("name", ri.getNickname()); List<String> groups = ri.getGroups(); for (String group : groups) { if (group != null && group.trim().length() > 0) { itemElement.addElement("Group").addText(group); } } } } return document; } /* (non-Javadoc) * @see org.jivesoftware.openfire.plugin.InExporter#validate() */ @Override public boolean validate(InputStream file) { Log.debug("validate"); org.w3c.dom.Document doc = new UserSchemaValidator(file, "wildfire-user-schema.xsd.xml").validateAndParse(); return ( doc != null); } /* (non-Javadoc) * @see org.jivesoftware.openfire.plugin.InExporter#importUsers(java.io.InputStream, java.lang.String, boolean) */ @Override public List<String> importUsers(InputStream inputStream, String previousDomain, boolean isUserProviderReadOnly) { Log.debug("importUsers"); DOMReader xmlReader = new DOMReader(); Document doc = xmlReader.read(new UserSchemaValidator(inputStream).validateAndParse()); return importUsers(doc, previousDomain, isUserProviderReadOnly); } /* * (non-Javadoc) * * @see * org.jivesoftware.openfire.plugin.InExporter#importUsers(org.dom4j.Document, * java.lang.String) */ @SuppressWarnings("unchecked") private List<String> importUsers(Document document, String previousDomain, boolean isUserProviderReadOnly) { Log.debug("importUsers"); List<String> invalidUsers = new ArrayList<String>(); Element users = document.getRootElement(); Iterator<Element> usersIter = users.elementIterator("User"); while (usersIter.hasNext()) { Element user = usersIter.next(); String userName = null; String password = null; String email = null; String name = null; List<RosterItem> rosterItems = new ArrayList<RosterItem>(); Iterator<Element> userElements = user.elementIterator(); while (userElements.hasNext()) { Element userElement = userElements.next(); String nameElement = userElement.getName(); if ("Username".equals(nameElement)) { userName = userElement.getText(); } else if ("Password".equals(nameElement)) { password = userElement.getText(); } else if ("Name".equals(nameElement)) { name = userElement.getText(); } else if ("Email".equals(nameElement)) { email = userElement.getText(); } else if ("Roster".equals(nameElement)) { Iterator<Element> rosterIter = userElement.elementIterator("Item"); while (rosterIter.hasNext()) { Element rosterElement = rosterIter.next(); String jid = rosterElement.attributeValue("jid"); String askstatus = rosterElement.attributeValue("askstatus"); String recvstatus = rosterElement.attributeValue("recvstatus"); String substatus = rosterElement.attributeValue("substatus"); String nickname = rosterElement.attributeValue("name"); List<String> groups = new ArrayList<String>(); Iterator<Element> groupIter = rosterElement.elementIterator("Group"); while (groupIter.hasNext()) { Element group = groupIter.next(); String groupName = group.getText(); if (groupName != null && groupName.trim().length() > 0) { groups.add(groupName); } } // used for migration if (previousDomain != null) { jid = jid.replace(previousDomain, serverName); } rosterItems.add(new RosterItem(new JID(jid), RosterItem.SubType.getTypeFromInt(Integer.parseInt(substatus)), RosterItem.AskType.getTypeFromInt(Integer.parseInt(askstatus)), RosterItem.RecvType.getTypeFromInt(Integer.parseInt(recvstatus)), nickname, groups)); } } } if ((userName != null) && (password != null)) { try { userName = Stringprep.nodeprep(userName); if (isUserProviderReadOnly) { userManager.createUser(userName, password, name, email); } // Check to see user exists before adding their roster, this is for // read-only user providers. userManager.getUser(userName); for (RosterItem ri : rosterItems) { rosterItemProvider.createItem(userName, ri); } } catch (StringprepException se) { Log.info("Invalid username " + userName); invalidUsers.add(userName); } catch (UserAlreadyExistsException e) { Log.info("User already exists " + userName); invalidUsers.add(userName); } catch (UserNotFoundException e) { Log.info("User not found " + userName); invalidUsers.add(userName); } } } return invalidUsers; } }