use of org.dom4j.Element in project Openfire by igniterealtime.
the class LocalMUCRole method updatePresence.
private void updatePresence() {
if (extendedInformation != null && presence != null) {
// Remove any previous extendedInformation, then re-add it.
Element mucUser = presence.getElement().element(QName.get("x", "http://jabber.org/protocol/muc#user"));
if (mucUser != null) {
// Remove any previous extendedInformation, then re-add it.
presence.getElement().remove(mucUser);
}
Element exi = extendedInformation.createCopy();
presence.getElement().add(exi);
}
}
use of org.dom4j.Element in project Openfire by igniterealtime.
the class LocalMUCRole method setPresence.
@Override
public void setPresence(Presence newPresence) {
// Try to remove the element whose namespace is "http://jabber.org/protocol/muc" since we
// don't need to include that element in future presence broadcasts
Element element = newPresence.getElement().element(QName.get("x", "http://jabber.org/protocol/muc"));
if (element != null) {
newPresence.getElement().remove(element);
}
this.presence = newPresence;
this.presence.setFrom(getRoleAddress());
updatePresence();
}
use of org.dom4j.Element in project Openfire by igniterealtime.
the class LocalOutgoingServerSession method secureAndAuthenticate.
private static LocalOutgoingServerSession secureAndAuthenticate(String remoteDomain, SocketConnection connection, XMPPPacketReader reader, StringBuilder openingStream, String localDomain) throws Exception {
final Logger log = LoggerFactory.getLogger(Log.getName() + "[Secure/Authenticate connection for: " + localDomain + " to: " + remoteDomain + "]");
Element features;
log.debug("Securing and authenticating connection ...");
log.debug("Indicating we want TLS and wait for response.");
connection.deliverRawText("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
MXParser xpp = reader.getXPPParser();
// Wait for the <proceed> response
Element proceed = reader.parseDocument().getRootElement();
if (proceed != null && proceed.getName().equals("proceed")) {
log.debug("Received 'proceed' from remote server. Negotiating TLS...");
try {
// boolean needed = JiveGlobals.getBooleanProperty(ConnectionSettings.Server.TLS_CERTIFICATE_VERIFY, true) &&
// JiveGlobals.getBooleanProperty(ConnectionSettings.Server.TLS_CERTIFICATE_CHAIN_VERIFY, true) &&
// !JiveGlobals.getBooleanProperty(ConnectionSettings.Server.TLS_ACCEPT_SELFSIGNED_CERTS, false);
connection.startTLS(true);
} catch (Exception e) {
log.debug("TLS negotiation failed: " + e.getMessage());
throw e;
}
log.debug("TLS negotiation was successful. Connection secured. Proceeding with authentication...");
if (!SASLAuthentication.verifyCertificates(connection.getPeerCertificates(), remoteDomain, true)) {
if (ServerDialback.isEnabled() || ServerDialback.isEnabledForSelfSigned()) {
log.debug("SASL authentication failed. Will continue with dialback.");
} else {
log.warn("Unable to authenticated the connection: SASL authentication failed (and dialback is not available).");
return null;
}
}
log.debug("TLS negotiation was successful so initiate a new stream.");
connection.deliverRawText(openingStream.toString());
// Reset the parser to use the new secured reader
xpp.setInput(new InputStreamReader(connection.getTLSStreamHandler().getInputStream(), StandardCharsets.UTF_8));
// Skip new stream element
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG; ) {
eventType = xpp.next();
}
// Get the stream ID
String id = xpp.getAttributeValue("", "id");
// Get new stream features
features = reader.parseDocument().getRootElement();
if (features != null) {
// Bookkeeping: determine what functionality the remote server offers.
boolean saslEXTERNALoffered = false;
if (features.element("mechanisms") != null) {
Iterator<Element> it = features.element("mechanisms").elementIterator();
while (it.hasNext()) {
Element mechanism = it.next();
if ("EXTERNAL".equals(mechanism.getTextTrim())) {
saslEXTERNALoffered = true;
break;
}
}
}
final boolean dialbackOffered = features.element("dialback") != null;
log.debug("Remote server is offering dialback: {}, EXTERNAL SASL:", dialbackOffered, saslEXTERNALoffered);
LocalOutgoingServerSession result = null;
// first, try SASL
if (saslEXTERNALoffered) {
log.debug("Trying to authenticate with EXTERNAL SASL.");
result = attemptSASLexternal(connection, xpp, reader, localDomain, remoteDomain, id, openingStream);
if (result == null) {
log.debug("Failed to authenticate with EXTERNAL SASL.");
} else {
log.debug("Successfully authenticated with EXTERNAL SASL.");
}
}
// SASL unavailable or failed, try dialback.
if (result == null) {
log.debug("Trying to authenticate with dialback.");
result = attemptDialbackOverTLS(connection, reader, localDomain, remoteDomain, id);
if (result == null) {
log.debug("Failed to authenticate with dialback.");
} else {
log.debug("Successfully authenticated with dialback.");
}
}
if (result != null) {
log.debug("Successfully secured and authenticated connection!");
return result;
} else {
log.warn("Unable to secure and authenticate connection: Exhausted all options.");
return null;
}
} else {
log.debug("Failed to secure and authenticate connection: neither SASL mechanisms nor SERVER DIALBACK were offered by the remote host.");
return null;
}
} else {
log.debug("Failed to secure and authenticate connection: <proceed> was not received!");
return null;
}
}
use of org.dom4j.Element in project Openfire by igniterealtime.
the class LocalOutgoingServerSession method createOutgoingSession.
/**
* Establishes a new outgoing session to a remote domain. If the remote domain supports TLS and SASL then the new
* outgoing connection will be secured with TLS and authenticated using SASL. However, if TLS or SASL is not
* supported by the remote domain or if an error occurred while securing or authenticating the connection using SASL
* then server dialback will be used.
*
* @param localDomain the local domain to authenticate with the remote domain.
* @param remoteDomain the remote domain.
* @param port default port to use to establish the connection.
* @return new outgoing session to a remote domain, or null.
*/
private static LocalOutgoingServerSession createOutgoingSession(String localDomain, String remoteDomain, int port) {
final Logger log = LoggerFactory.getLogger(Log.getName() + "[Create outgoing session for: " + localDomain + " to " + remoteDomain + "]");
log.debug("Creating new session...");
// Connect to remote server using XMPP 1.0 (TLS + SASL EXTERNAL or TLS + server dialback or server dialback)
log.debug("Creating plain socket connection to a host that belongs to the remote XMPP domain.");
final Socket socket = SocketUtil.createSocketToXmppDomain(remoteDomain, port);
if (socket == null) {
log.info("Unable to create new session: Cannot create a plain socket connection with any applicable remote host.");
return null;
}
SocketConnection connection = null;
try {
connection = new SocketConnection(XMPPServer.getInstance().getPacketDeliverer(), socket, false);
log.debug("Send the stream header and wait for response...");
StringBuilder openingStream = new StringBuilder();
openingStream.append("<stream:stream");
openingStream.append(" xmlns:db=\"jabber:server:dialback\"");
openingStream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
openingStream.append(" xmlns=\"jabber:server\"");
// OF-673
openingStream.append(" from=\"").append(localDomain).append("\"");
openingStream.append(" to=\"").append(remoteDomain).append("\"");
openingStream.append(" version=\"1.0\">");
connection.deliverRawText(openingStream.toString());
// Set a read timeout (of 5 seconds) so we don't keep waiting forever
int soTimeout = socket.getSoTimeout();
socket.setSoTimeout(5000);
XMPPPacketReader reader = new XMPPPacketReader();
reader.getXPPParser().setInput(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
// Get the answer from the Receiving Server
XmlPullParser xpp = reader.getXPPParser();
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG; ) {
eventType = xpp.next();
}
String serverVersion = xpp.getAttributeValue("", "version");
String id = xpp.getAttributeValue("", "id");
log.debug("Got a response (stream ID: {}, version: {}). Check if the remote server is XMPP 1.0 compliant...", id, serverVersion);
if (serverVersion != null && decodeVersion(serverVersion)[0] >= 1) {
log.debug("The remote server is XMPP 1.0 compliant (or at least reports to be).");
// Restore default timeout
socket.setSoTimeout(soTimeout);
log.debug("Processing stream features of the remote domain...");
Element features = reader.parseDocument().getRootElement();
if (features != null) {
log.debug("Check if both us as well as the remote server have enabled STARTTLS and/or dialback ...");
final boolean useTLS = JiveGlobals.getBooleanProperty(ConnectionSettings.Server.TLS_ENABLED, true);
if (useTLS && features.element("starttls") != null) {
log.debug("Both us and the remote server support the STARTTLS feature. Secure and authenticate the connection with TLS & SASL...");
LocalOutgoingServerSession answer = secureAndAuthenticate(remoteDomain, connection, reader, openingStream, localDomain);
if (answer != null) {
log.debug("Successfully secured/authenticated the connection with TLS/SASL)!");
// Everything went fine so return the secured and
// authenticated connection
log.debug("Successfully created new session!");
return answer;
}
log.debug("Unable to secure and authenticate the connection with TLS & SASL.");
} else if (connection.getTlsPolicy() == Connection.TLSPolicy.required) {
log.debug("I have no StartTLS yet I must TLS");
connection.close();
return null;
} else // Check if we are going to try server dialback (XMPP 1.0)
if (ServerDialback.isEnabled() && features.element("dialback") != null) {
log.debug("Both us and the remote server support the 'dialback' feature. Authenticate the connection with dialback...");
ServerDialback method = new ServerDialback(connection, localDomain);
OutgoingServerSocketReader newSocketReader = new OutgoingServerSocketReader(reader);
if (method.authenticateDomain(newSocketReader, localDomain, remoteDomain, id)) {
log.debug("Successfully authenticated the connection with dialback!");
StreamID streamID = new BasicStreamIDFactory().createStreamID(id);
LocalOutgoingServerSession session = new LocalOutgoingServerSession(localDomain, connection, newSocketReader, streamID);
connection.init(session);
// Set the hostname as the address of the session
session.setAddress(new JID(null, remoteDomain, null));
log.debug("Successfully created new session!");
return session;
} else {
log.debug("Unable to authenticate the connection with dialback.");
}
}
} else {
log.debug("Error! No data from the remote server (expected a 'feature' element).");
}
} else {
log.debug("The remote server is not XMPP 1.0 compliant.");
}
log.debug("Something went wrong so close the connection and try server dialback over a plain connection");
if (connection.getTlsPolicy() == Connection.TLSPolicy.required) {
log.debug("I have no StartTLS yet I must TLS");
connection.close();
return null;
}
connection.close();
} catch (SSLHandshakeException e) {
// This is a failure as described in RFC3620, section 5.4.3.2 "STARTTLS Failure".
log.info("STARTTLS negotiation failed. Closing connection (without sending any data such as <failure/> or </stream>).", e);
// It is probably (see OF-794) best if we, as the initiating entity, therefor don't send any data either.
if (connection != null) {
connection.forceClose();
}
} catch (Exception e) {
// This might be RFC3620, section 5.4.2.2 "Failure Case" or even an unrelated problem. Handle 'normally'.
log.warn("An exception occurred while creating an encrypted session. Closing connection.", e);
if (connection != null) {
connection.close();
}
}
if (ServerDialback.isEnabled()) {
log.debug("Unable to create a new session. Going to try connecting using server dialback as a fallback.");
// Use server dialback (pre XMPP 1.0) over a plain connection
final LocalOutgoingServerSession outgoingSession = new ServerDialback().createOutgoingSession(localDomain, remoteDomain, port);
if (outgoingSession != null) {
// TODO this success handler behaves differently from a similar success handler above. Shouldn't those be the same?
log.debug("Successfully created new session (using dialback as a fallback)!");
return outgoingSession;
} else {
log.warn("Unable to create a new session: Dialback (as a fallback) failed.");
return null;
}
} else {
log.warn("Unable to create a new session: exhausted all options (not trying dialback as a fallback, as server dialback is disabled by configuration.");
return null;
}
}
use of org.dom4j.Element in project Openfire by igniterealtime.
the class Workgroup method sendInvitation.
/**
* An agent has accepted the offer and was choosen to answer the user's requests. The workgroup
* will create a new room where the agent can answer the user's needs. Once the room has been
* created, the Agent and the user that made the request will receive invitiations to join the
* newly created room.<p>
* <p/>
* The workgroup will listen for all the packets sent to the room and generate a conversation
* transcript.
*
* @param agent the AgentSession that accepted and was choosen to respond the user's requests.
* @param request the request made by a user.
*/
public void sendInvitation(AgentSession agent, UserRequest request) {
// we need to destroy all MUC rooms created by workgroups
try {
RoomInterceptorManager interceptorManager = RoomInterceptorManager.getInstance();
WorkgroupManager workgroupManager = WorkgroupManager.getInstance();
String userJID = request.getUserJID().toString();
final Workgroup sessionWorkgroup = request.getWorkgroup();
final String sessionID = request.getSessionID();
String workgroupName = getJID().getNode();
final String serviceName = workgroupManager.getMUCServiceName();
final String roomName = sessionID + "@" + serviceName;
final String roomJID = roomName + "/" + workgroupName;
// Create the room by joining it. The workgroup will be the owner of the room and will
// invite the Agent and the user to join the room
JoinRoom joinRoom = new JoinRoom(getFullJID().toString(), roomJID);
interceptorManager.invokeInterceptors(getJID().toBareJID(), joinRoom, false, false);
send(joinRoom);
interceptorManager.invokeInterceptors(getJID().toBareJID(), joinRoom, false, true);
// Configure the newly created room
Map<String, Collection<String>> fields = new HashMap<String, Collection<String>>();
// Make a non-public room
List<String> values = new ArrayList<String>();
values.add("0");
fields.put("muc#roomconfig_publicroom", values);
// Set the room description
values = new ArrayList<String>();
values.add(roomName);
fields.put("muc#roomconfig_roomdesc", values);
// Set that anyone can change the room subject
values = new ArrayList<String>();
values.add("1");
fields.put("muc#roomconfig_changesubject", values);
// Make the room temporary
values = new ArrayList<String>();
values.add("0");
fields.put("muc#roomconfig_persistentroom", values);
// Set that only moderators can see the occupants' JID
values = new ArrayList<String>();
values.add("moderators");
fields.put("muc#roomconfig_whois", values);
// Set that we want packets to include the real JID
values = new ArrayList<String>();
values.add("0");
fields.put("anonymous", values);
// Only broadcast presences of participants and visitors
values = new ArrayList<String>();
values.add("participant");
values.add("visitor");
fields.put("muc#roomconfig_presencebroadcast", values);
RoomConfiguration conf = new RoomConfiguration(fields);
conf.setTo(roomName);
conf.setFrom(getFullJID());
interceptorManager.invokeInterceptors(getJID().toBareJID(), conf, false, false);
send(conf);
interceptorManager.invokeInterceptors(getJID().toBareJID(), conf, false, true);
// Create a new entry for the active session and the request made by the user
requests.put(sessionID, request);
// Invite the Agent to the new room
Invitation invitation = new Invitation(agent.getJID().toString(), sessionID);
invitation.setTo(roomName);
invitation.setFrom(getFullJID());
// Add workgroup extension that includes the JID of the user that made the request
Element element = invitation.addChildElement("offer", "http://jabber.org/protocol/workgroup");
element.addAttribute("jid", userJID);
// Add custom extension that includes the sessionID
element = invitation.addChildElement("session", "http://jivesoftware.com/protocol/workgroup");
element.addAttribute("workgroup", sessionWorkgroup.getJID().toString());
element.addAttribute("id", sessionID);
// anonymous user
if (request.isAnonymousUser()) {
element = invitation.addChildElement("user", "http://jivesoftware.com/protocol/workgroup");
element.addAttribute("id", request.getUserID());
}
interceptorManager.invokeInterceptors(getJID().toBareJID(), invitation, false, false);
send(invitation);
interceptorManager.invokeInterceptors(getJID().toBareJID(), invitation, false, true);
// Invite the user to the new room
sendUserInvitiation(request, roomName);
// Notify the request that invitations for support have been sent
request.invitationsSent(sessionID);
} catch (Exception e) {
Log.error(e.getMessage(), e);
}
}
Aggregations