outgoingserversession.java
来自「基于Jabber协议的即时消息服务器」· Java 代码 · 共 679 行 · 第 1/3 页
JAVA
679 行
// Skip the opening stream sent by the server
for (int eventType = xpp.getEventType();
eventType != XmlPullParser.START_TAG;) {
eventType = xpp.next();
}
// SASL authentication was successful so create new
// OutgoingServerSession
String id = xpp.getAttributeValue("", "id");
StreamID streamID = new BasicStreamIDFactory().createStreamID(id);
OutgoingServerSession session = new OutgoingServerSession(domain,
connection, new OutgoingServerSocketReader(reader), streamID);
connection.init(session);
// Set the hostname as the address of the session
session.setAddress(new JID(null, hostname, null));
// Set that the session was created using TLS+SASL (no server dialback)
session.usingServerDialback = false;
return session;
}
else {
Log.debug("OS - Error, EXTERNAL SASL authentication with " + hostname +
" failed");
return null;
}
}
}
Log.debug("OS - Error, EXTERNAL SASL was not offered by " + hostname);
}
else {
Log.debug("OS - Error, no SASL mechanisms were offered by " + hostname);
}
}
else {
Log.debug("OS - Error, <proceed> was not received");
}
return null;
}
private static boolean doExternalAuthentication(String domain, SocketConnection connection,
XMPPPacketReader reader) throws DocumentException, IOException, XmlPullParserException {
StringBuilder sb = new StringBuilder();
sb.append("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"EXTERNAL\">");
sb.append(StringUtils.encodeBase64(domain));
sb.append("</auth>");
connection.deliverRawText(sb.toString());
Element response = reader.parseDocument().getRootElement();
if (response != null && "success".equals(response.getName())) {
return true;
}
return false;
}
OutgoingServerSession(String serverName, Connection connection,
OutgoingServerSocketReader socketReader, StreamID streamID) {
super(serverName, connection, streamID);
this.socketReader = socketReader;
socketReader.setSession(this);
}
public void process(Packet packet) throws UnauthorizedException, PacketException {
try {
String senderDomain = packet.getFrom().getDomain();
if (!getAuthenticatedDomains().contains(senderDomain)) {
synchronized (senderDomain.intern()) {
if (!getAuthenticatedDomains().contains(senderDomain) &&
!authenticateSubdomain(senderDomain, packet.getTo().getDomain())) {
// Return error since sender domain was not validated by remote server
returnErrorToSender(packet);
return;
}
}
}
if (conn != null && !conn.isClosed()) {
conn.deliver(packet);
}
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
/**
* Authenticates a subdomain of this server with the specified remote server over an exsiting
* outgoing connection. If the existing session was using server dialback then a new db:result
* is going to be sent to the remote server. But if the existing session was TLS+SASL based
* then just assume that the subdomain was authenticated by the remote server.
*
* @param domain the local subdomain to authenticate with the remote server.
* @param hostname the hostname of the remote server.
* @return True if the subdomain was authenticated by the remote server.
*/
private boolean authenticateSubdomain(String domain, String hostname) {
if (!usingServerDialback) {
// Using SASL so just assume that the domain was validated
// (note: this may not be correct)
addAuthenticatedDomain(domain);
return true;
}
ServerDialback method = new ServerDialback(getConnection(), domain);
if (method.authenticateDomain(socketReader, domain, hostname, getStreamID().getID())) {
// Add the validated domain as an authenticated domain
addAuthenticatedDomain(domain);
return true;
}
return false;
}
private void returnErrorToSender(Packet packet) {
RoutingTable routingTable = XMPPServer.getInstance().getRoutingTable();
try {
if (packet instanceof IQ) {
IQ reply = new IQ();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setChildElement(((IQ) packet).getChildElement().createCopy());
reply.setError(PacketError.Condition.remote_server_not_found);
ChannelHandler route = routingTable.getRoute(reply.getTo());
if (route != null) {
route.process(reply);
}
}
else if (packet instanceof Presence) {
Presence reply = new Presence();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setError(PacketError.Condition.remote_server_not_found);
ChannelHandler route = routingTable.getRoute(reply.getTo());
if (route != null) {
route.process(reply);
}
}
else if (packet instanceof Message) {
Message reply = new Message();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setType(((Message)packet).getType());
reply.setThread(((Message)packet).getThread());
reply.setError(PacketError.Condition.remote_server_not_found);
ChannelHandler route = routingTable.getRoute(reply.getTo());
if (route != null) {
route.process(reply);
}
}
}
catch (UnauthorizedException e) {
// Do nothing
}
catch (Exception e) {
Log.warn("Error returning error to sender. Original packet: " + packet, e);
}
}
/**
* Returns a collection with all the domains, subdomains and virtual hosts that where
* authenticated. The remote server will accept packets sent from any of these domains,
* subdomains and virtual hosts.
*
* @return domains, subdomains and virtual hosts that where validated.
*/
public Collection<String> getAuthenticatedDomains() {
return Collections.unmodifiableCollection(authenticatedDomains);
}
/**
* Adds a new authenticated domain, subdomain or virtual host to the list of
* authenticated domains for the remote server. The remote server will accept packets
* sent from this new authenticated domain.
*
* @param domain the new authenticated domain, subdomain or virtual host to add.
*/
public void addAuthenticatedDomain(String domain) {
authenticatedDomains.add(domain);
}
/**
* Removes an authenticated domain from the list of authenticated domains. The remote
* server will no longer be able to accept packets sent from the removed domain, subdomain or
* virtual host.
*
* @param domain the domain, subdomain or virtual host to remove from the list of
* authenticated domains.
*/
public void removeAuthenticatedDomain(String domain) {
authenticatedDomains.remove(domain);
}
/**
* Returns the list of hostnames related to the remote server. This tracking is useful for
* reusing the same session for the same remote server even if the server has many names.
*
* @return the list of hostnames related to the remote server.
*/
public Collection<String> getHostnames() {
return Collections.unmodifiableCollection(hostnames);
}
/**
* Adds a new hostname to the list of known hostnames of the remote server. This tracking is
* useful for reusing the same session for the same remote server even if the server has
* many names.
*
* @param hostname the new known name of the remote server
*/
private void addHostname(String hostname) {
if (hostnames.add(hostname)) {
// Register the outgoing session in the SessionManager. If the session
// was already registered nothing happens
sessionManager.registerOutgoingServerSession(hostname, this);
// Add a new route for this new session
XMPPServer.getInstance().getRoutingTable().addRoute(new JID(hostname), this);
}
}
public String getAvailableStreamFeatures() {
// Nothing special to add
return null;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?