Primitive implementation of CertificateService.

A primitive implementation of CertificateService. Also includes a
modified version of irc-api that supports getting a custom SSL context
from the server parameters.
I have been able to confirm its workings by connecting to
'swiftco.dal.net' (certificate has a different CN.)
fix-message-formatting
Danny van Heumen 12 years ago
parent b1f4dd6490
commit 1178b51255

@ -8,6 +8,7 @@
import java.util.*; import java.util.*;
import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*; import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.*;
@ -37,10 +38,15 @@ public class IrcActivator
/** /**
* The currently valid bundle context. * The currently valid bundle context.
*/ */
public static BundleContext bundleContext = null; private static BundleContext bundleContext = null;
private static ResourceManagementService resourceService; private static ResourceManagementService resourceService;
/**
* Certificate Service instance.
*/
private static CertificateService certiticateService;
/** /**
* Called when this bundle is started. In here we'll export the * Called when this bundle is started. In here we'll export the
* IRC ProtocolProviderFactory implementation so that it could be * IRC ProtocolProviderFactory implementation so that it could be
@ -112,4 +118,33 @@ public static ResourceManagementService getResources()
= ResourceManagementServiceUtils.getService(bundleContext); = ResourceManagementServiceUtils.getService(bundleContext);
return resourceService; return resourceService;
} }
/**
* Bundle Context
*
* @return returns bundle context
*/
public static BundleContext getBundleContext()
{
return bundleContext;
}
/**
* Return the certificate verification service impl.
*
* @return the CertificateVerification service.
*/
public static CertificateService getCertificateVerificationService()
{
if(certiticateService == null)
{
ServiceReference guiVerifyReference
= IrcActivator.getBundleContext().getServiceReference(
CertificateService.class.getName());
if(guiVerifyReference != null)
certiticateService = (CertificateService)
IrcActivator.getBundleContext().getService(
guiVerifyReference);
}
return certiticateService;
}
} }

@ -7,9 +7,13 @@
package net.java.sip.communicator.impl.protocol.irc; package net.java.sip.communicator.impl.protocol.irc;
import java.io.*; import java.io.*;
import java.security.*;
import java.util.*; import java.util.*;
import javax.net.ssl.*;
import net.java.sip.communicator.impl.protocol.irc.ModeParser.ModeEntry; import net.java.sip.communicator.impl.protocol.irc.ModeParser.ModeEntry;
import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.*;
@ -61,7 +65,7 @@ public class IrcStack
* Connection state of a successful IRC connection. * Connection state of a successful IRC connection.
*/ */
private IIRCState connectionState; private IIRCState connectionState;
/** /**
* The cached channel list. * The cached channel list.
* *
@ -133,20 +137,16 @@ public void connect(String host, int port, String password,
this.joined.clear(); this.joined.clear();
this.irc = new IRCApiImpl(true); this.irc = new IRCApiImpl(true);
// FIXME Currently, the secure connection is created by
// explicitly creating an SSLContext for 'SSL'. According
// to Ingo (in a mailing list conversation) it is better to
// use the CertificateService for this. This should be
// implemented in the irc-api library, though.
this.params.setServer(new IRCServer(host, port, password,
secureConnection));
synchronized (this.irc) synchronized (this.irc)
{ {
this.params.setServer(new IRCServer(host, port, password,
secureConnection));
this.params.setCustomContext(getCustomSSLContext(host));
this.irc.addListener(new ServerListener()); this.irc.addListener(new ServerListener());
connectSynchronized(); connectSynchronized();
} }
} }
/** /**
* Perform synchronized connect operation. * Perform synchronized connect operation.
* *
@ -195,7 +195,7 @@ public void onFailure(Exception e)
.trace("Waiting for the connection to be established ..."); .trace("Waiting for the connection to be established ...");
result.wait(); result.wait();
} }
this.connectionState = result.getValue(); this.connectionState = result.getValue();
// TODO Implement connection timeout and a way to recognize that // TODO Implement connection timeout and a way to recognize that
// the timeout occurred. // the timeout occurred.
@ -232,6 +232,30 @@ public void onFailure(Exception e)
} }
} }
/**
* Create a custom SSL context for this particular server.
*
* @return returns a customized SSL context or <tt>null</tt> if one cannot
* be created.
*/
private SSLContext getCustomSSLContext(String hostname)
{
SSLContext context = null;
try
{
CertificateService cs =
IrcActivator.getCertificateVerificationService();
X509TrustManager tm =
cs.getTrustManager(hostname);
context = cs.getSSLContext(tm);
}
catch (GeneralSecurityException e)
{
LOGGER.error("failed to create custom SSL context", e);
}
return context;
}
/** /**
* Disconnect from the IRC server * Disconnect from the IRC server
*/ */
@ -239,8 +263,8 @@ public void disconnect()
{ {
if (this.connectionState == null && this.irc == null) if (this.connectionState == null && this.irc == null)
return; return;
synchronized(this.joined) synchronized (this.joined)
{ {
// Leave all joined channels. // Leave all joined channels.
for (ChatRoomIrcImpl channel : this.joined.values()) for (ChatRoomIrcImpl channel : this.joined.values())
@ -248,7 +272,7 @@ public void disconnect()
leave(channel); leave(channel);
} }
} }
synchronized(this.irc) synchronized (this.irc)
{ {
// Disconnect and clean up // Disconnect and clean up
this.irc.disconnect(); this.irc.disconnect();
@ -575,7 +599,7 @@ public void onFailure(Exception e)
.trace("Finished waiting for join operation for channel '" .trace("Finished waiting for join operation for channel '"
+ chatroom.getIdentifier() + "' to complete."); + chatroom.getIdentifier() + "' to complete.");
// TODO How to handle 480 (+j): Channel throttle exceeded? // TODO How to handle 480 (+j): Channel throttle exceeded?
Exception e = joinSignal.getException(); Exception e = joinSignal.getException();
if (e != null) if (e != null)
{ {
@ -666,10 +690,12 @@ public void command(ChatRoomIrcImpl chatroom, String command)
int endOfNick = command.indexOf(' '); int endOfNick = command.indexOf(' ');
if (endOfNick == -1) if (endOfNick == -1)
{ {
throw new IllegalArgumentException("Invalid private message format. Message was not sent."); throw new IllegalArgumentException(
"Invalid private message format. "
+ "Message was not sent.");
} }
target = command.substring(0, endOfNick); target = command.substring(0, endOfNick);
command = command.substring(endOfNick+1); command = command.substring(endOfNick + 1);
} }
else else
{ {
@ -703,12 +729,12 @@ private static ChatRoomMemberRole convertMemberMode(char modeSymbol)
} }
/** /**
* A listener for server-level messages (any messages that are related to the * A listener for server-level messages (any messages that are related to
* server, the connection, that are not related to any chatroom in * the server, the connection, that are not related to any chatroom in
* particular) or that are personal message from user to local user. * particular) or that are personal message from user to local user.
*/ */
private class ServerListener private class ServerListener
extends VariousMessageListenerAdapter extends VariousMessageListenerAdapter
{ {
/** /**
* Print out server notices for debugging purposes and for simply * Print out server notices for debugging purposes and for simply
@ -744,10 +770,9 @@ public void onServerNumericMessage(ServerNumericMessage msg)
@Override @Override
public void onError(ErrorMessage msg) public void onError(ErrorMessage msg)
{ {
LOGGER.debug("ERROR: " + msg.getSource() + ": " LOGGER.debug("ERROR: " + msg.getSource() + ": " + msg.getText());
+ msg.getText());
} }
/** /**
* Upon receiving a private message from a user, deliver that to a * Upon receiving a private message from a user, deliver that to a
* private chat room and create one if it does not exist. We can ignore * private chat room and create one if it does not exist. We can ignore
@ -780,8 +805,8 @@ public void onUserPrivMessage(UserPrivMsg msg)
* @param user the source user * @param user the source user
* @param text the message * @param text the message
*/ */
private void deliverReceivedMessageToPrivateChat(ChatRoomIrcImpl chatroom, private void deliverReceivedMessageToPrivateChat(
String user, String text) ChatRoomIrcImpl chatroom, String user, String text)
{ {
ChatRoomMember member = chatroom.getChatRoomMember(user); ChatRoomMember member = chatroom.getChatRoomMember(user);
MessageIrcImpl message = MessageIrcImpl message =
@ -813,7 +838,7 @@ private ChatRoomIrcImpl initiatePrivateChatRoom(String user)
return chatroom; return chatroom;
} }
} }
/** /**
* A chat room listener. * A chat room listener.
* *
@ -924,9 +949,10 @@ public void onChannelPart(ChanPartMessage msg)
} }
catch (NullPointerException e) catch (NullPointerException e)
{ {
System.err LOGGER
.println("This should not have happened. Please report this as it is a bug."); .warn(
e.printStackTrace(); "This should not have happened. Please report this as it is a bug.",
e);
} }
} }
} }
@ -959,8 +985,7 @@ public void onChannelKick(ChannelKick msg)
{ {
ChatRoomMember kicker = ChatRoomMember kicker =
this.chatroom.getChatRoomMember(user); this.chatroom.getChatRoomMember(user);
this.chatroom.fireMemberPresenceEvent(kickedMember, this.chatroom.fireMemberPresenceEvent(kickedMember, kicker,
kicker,
ChatRoomMemberPresenceChangeEvent.MEMBER_KICKED, ChatRoomMemberPresenceChangeEvent.MEMBER_KICKED,
msg.getText()); msg.getText());
} }
@ -1214,9 +1239,9 @@ sourceMember, new Date(),
ChatRoomMessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED); ChatRoomMessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED);
break; break;
case UNKNOWN: case UNKNOWN:
LOGGER.info("Unknown mode: " LOGGER.info("Unknown mode: " + (mode.isAdded() ? "+" : "-")
+ (mode.isAdded() ? "+" : "-") + mode.getParams()[0] + mode.getParams()[0] + ". Original mode string: '"
+ ". Original mode string: '" + msg.getModeStr() + "'"); + msg.getModeStr() + "'");
break; break;
default: default:
LOGGER.info("Unsupported mode '" LOGGER.info("Unsupported mode '"
@ -1395,16 +1420,43 @@ private static class ServerParameters
implements IServerParameters implements IServerParameters
{ {
/**
* Nick name.
*/
private String nick; private String nick;
/**
* Alternative nick names.
*/
private List<String> alternativeNicks = new ArrayList<String>(); private List<String> alternativeNicks = new ArrayList<String>();
/**
* Real name.
*/
private String real; private String real;
/**
* Ident.
*/
private String ident; private String ident;
/**
* IRC server.
*/
private IRCServer server; private IRCServer server;
/**
* Custom SSL Context.
*/
private SSLContext sslContext = null;
/**
* Construct ServerParameters instance.
* @param nickName nick name
* @param realName real name
* @param ident ident
* @param server IRC server instance
*/
private ServerParameters(String nickName, String realName, private ServerParameters(String nickName, String realName,
String ident, IRCServer server) String ident, IRCServer server)
{ {
@ -1415,54 +1467,128 @@ private ServerParameters(String nickName, String realName,
this.server = server; this.server = server;
} }
/**
* Get nick name.
*
* @return returns nick name
*/
@Override @Override
public String getNickname() public String getNickname()
{ {
return this.nick; return this.nick;
} }
/**
* Set new nick name.
*
* @param nick nick name
*/
public void setNickname(String nick) public void setNickname(String nick)
{ {
this.nick = checkNick(nick); this.nick = checkNick(nick);
} }
/**
* Verify nick name.
*
* @param nick nick name
* @return returns nick name
* @throws IllegalArgumentException throws
* <tt>IllegalArgumentException</tt> if an invalid nick name
* is provided.
*/
private String checkNick(String nick) private String checkNick(String nick)
{ {
if (nick == null) if (nick == null)
throw new IllegalArgumentException("a nick name must be provided"); throw new IllegalArgumentException(
if (nick.startsWith("#")) "a nick name must be provided");
throw new IllegalArgumentException("the nick name must not start with '#' since this is reserved for IRC channels"); if (nick.startsWith("#"))
throw new IllegalArgumentException(
"the nick name must not start with '#' "
+ "since this is reserved for IRC channels");
return nick; return nick;
} }
/**
* Get alternative nick names.
*
* @return returns list of alternatives
*/
@Override @Override
public List<String> getAlternativeNicknames() public List<String> getAlternativeNicknames()
{ {
return this.alternativeNicks; return this.alternativeNicks;
} }
/**
* Get ident string.
*
* @return returns ident
*/
@Override @Override
public String getIdent() public String getIdent()
{ {
return this.ident; return this.ident;
} }
/**
* Get real name
*
* @return returns real name
*/
@Override @Override
public String getRealname() public String getRealname()
{ {
return this.real; return this.real;
} }
/**
* Get server
*
* @return returns server instance
*/
@Override @Override
public IRCServer getServer() public IRCServer getServer()
{ {
return this.server; return this.server;
} }
/**
* Set server instance.
*
* @param server IRC server instance
*/
public void setServer(IRCServer server) public void setServer(IRCServer server)
{ {
if (server == null)
throw new IllegalArgumentException("server cannot be null");
this.server = server; this.server = server;
} }
/**
* Get the SSL Context.
*
* Returns the custom SSLContext or null in case there is no
* custom implementation.
*
* @return returns the SSLContext or null
*/
@Override
public SSLContext getCustomContext()
{
return this.sslContext;
}
/**
* Set custom SSLContext.
*
* @param context the custom SSLContext
*/
public void setCustomContext(SSLContext context)
{
this.sslContext = context;
}
} }
/** /**

@ -24,7 +24,7 @@ public class ProtocolProviderFactoryIrcImpl
{ {
public ProtocolProviderFactoryIrcImpl() public ProtocolProviderFactoryIrcImpl()
{ {
super(IrcActivator.bundleContext, ProtocolNames.IRC); super(IrcActivator.getBundleContext(), ProtocolNames.IRC);
} }
/** /**
@ -42,7 +42,7 @@ public ProtocolProviderFactoryIrcImpl()
public AccountID installAccount( String userIDStr, public AccountID installAccount( String userIDStr,
Map<String, String> accountProperties) Map<String, String> accountProperties)
{ {
BundleContext context = IrcActivator.bundleContext; BundleContext context = IrcActivator.getBundleContext();
if (context == null) if (context == null)
throw new NullPointerException( throw new NullPointerException(

@ -6,6 +6,7 @@
*/ */
package net.java.sip.communicator.impl.protocol.irc; package net.java.sip.communicator.impl.protocol.irc;
import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.*;
@ -25,7 +26,7 @@ public class ProtocolProviderServiceIrcImpl
/** /**
* The irc server. * The irc server.
*/ */
private IrcStack ircStack; private IrcStack ircStack = null;
/** /**
* The id of the account that this protocol provider represents. * The id of the account that this protocol provider represents.
@ -150,6 +151,7 @@ public RegistrationState getRegistrationState()
{ {
return currentRegistrationState; return currentRegistrationState;
} }
/** /**
* Starts the registration process. * Starts the registration process.

@ -9,6 +9,7 @@ Import-Package: org.osgi.framework,
org.jitsi.service.resources, org.jitsi.service.resources,
net.java.sip.communicator.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util, net.java.sip.communicator.util,
net.java.sip.communicator.service.certificate,
net.java.sip.communicator.service.protocol, net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.event, net.java.sip.communicator.service.protocol.event,
org.slf4j, org.slf4j,

Loading…
Cancel
Save