XMPPFramework - 在Openfire上通过SSL连接

时间:2014-06-19 04:41:35

标签: ios ssl xmpp openfire xmppframework

我尝试通过 SSL 将我的用户从我的iOS XMPP聊天客户端连接到Openfire服务器。

在我的 iOS 客户端中:

- (void)setupStream 
{
    ...
    // BOOL values for security settings
    customCertEvaluation = NO;
    allowSelfSignedCertificates = YES;
    allowSSLHostNameMismatch = NO;
}

在我的 Openfire 服务器安全设置>中客户端连接安全性,我已设置:

Required - Clients can only connect to the server using secured connections.

因此,将调用以下委托方法:

- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings 
{
    NSString *expectedCertName = [xmppStream.myJID domain];

    if (customCertEvaluation)
        [settings setObject:@(YES) forKey:GCDAsyncSocketManuallyEvaluateTrust];

    if (allowSelfSignedCertificates)
        [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];

    if (allowSSLHostNameMismatch)
        [settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLPeerName];

    else
        if (expectedCertName)
            [settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
}

我从这个帖子尝试了这个解决方案:XMPPFramework TLS/SSL connection with Openfire

但是,当我运行我的应用程序并尝试连接到服务器时,我收到此错误:

Security option unavailable - kCFStreamSSLAllowsAnyRoot - You must use manual trust evaluation

我查看了GCDAsyncSocket类,并认为kCFStreamSSLAllowsAnyRoot被声明为已弃用。实施NSAssert是故意抛出错误。

接下来,我决定改变我的BOOL值:

- (void)setupStream 
{
    ...
    // BOOL values for security settings
    // Manually evaluate trust
    customCertEvaluation = YES;
    allowSelfSignedCertificates = NO;
    allowSSLHostNameMismatch = NO;
}

这次,再一次,无法与服务器建立连接,但没有提示错误。

如果我将客户端连接安全性更改回原始设置>我可以很好地连接到Openfire。的可选即可。但是,我不会通过SSL连接,如客户端会话中每个用户的状态旁边的 lock 图标所示。

我的Android客户端(使用Smack API for XMPP)通过SSL连接到Openfire而没有任何问题。所以我想知道我是否需要使用XMPPFramework为我的iOS客户端实现解决方法。

我非常感谢任何建议。

4 个答案:

答案 0 :(得分:8)

说明

在最新版本的XMPP(after April 22)中,您可以不再使用allowSelfSignedCertificates = YES以下内容:

if (allowSelfSignedCertificates)
    [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];`

这是因为kCFStreamSSLAllowsAnyRoot& SSLSetAllowsAnyRoot已被弃用。

 /* 
  * ==== The following UNAVAILABLE KEYS are: (with throw an exception)
  * - kCFStreamSSLAllowsAnyRoot (UNAVAILABLE)
  *     You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).
  *     Corresponding deprecated method: SSLSetAllowsAnyRoot
  */

XMPPFramework/GCDAsyncSocket.h& Deprecated Secure Transport Functions


解决方案

  1. 转到Openfire服务器>安全设置>客户端连接安全性

    Check: Required - Clients can only connect to the server using secured connections.

  2. 在AppDelegate中定义变量

    BOOL customCertEvaluation;
    
  3. 在setupStream中设置变量

    - (void)setupStream 
    {
        ...
        customCertEvaluation = YES;
    }
    
  4. 在willSecureWithSettings

    中设置安全设置
    - (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
    {
        /*
         * Properly secure your connection by setting kCFStreamSSLPeerName 
         * to your server domain name
         */
        [settings setObject:xmppStream.myJID.domain forKey:(NSString *)kCFStreamSSLPeerName];
    
        /*
         * Use manual trust evaluation
         * as stated in the XMPPFramework/GCDAsyncSocket code documentation
         */
        if (customCertEvaluation)
            [settings setObject:@(YES) forKey:GCDAsyncSocketManuallyEvaluateTrust];
    }
    
  5. 手动验证对等

    /*
     * This is only called if the stream is secured with settings that include:
     * - GCDAsyncSocketManuallyEvaluateTrust == YES
     * That is, if a delegate implements xmppStream:willSecureWithSettings:, and plugs in that key/value pair.
     */
     - (void)xmppStream:(XMPPStream *)sender didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler
     {
         /* Custom validation for your certificate on server should be performed */
    
         completionHandler(YES); // After this line, SSL connection will be established
     }
    

答案 1 :(得分:1)

在我更新了我的XMPPFramework之后,我遇到了同样的问题。经过几天试图找出问题后,我遇到了这个问题,但解决方案对我来说并不适用。

这对我有用。问题似乎源自您的 xmppStream.startTLSPolicy 。设置startTLSPolicy明确地为我工作。

xmppStream.startTLSPolicy = XMPPStreamStartTLSPolicyPreferred; // or
xmppStream.startTLSPolicy = XMPPStreamStartTLSPolicyRequired;

以下是其工作原理的说明。

在XMPPStream的handleStreamFeatures方法中,事实证明了这一点。如果您的XMPP服务器没有按需要返回起始状态'并且您没有明确设置startTLSPolicy(默认值= XMPPStreamStartTLSPolicyAllowed)。客户端只会进行正常连接,而不是TLS连接。

以下是正在进行检查的XMPPStream中的代码部分(供参考)。

/**
 * This method is called anytime we receive the server's stream features.
 * This method looks at the stream features, and handles any requirements so communication can continue.
**/
- (void)handleStreamFeatures
{
    NSAssert(dispatch_get_specific(xmppQueueTag), @"Invoked on incorrect queue");

    XMPPLogTrace();

    // Extract the stream features
    NSXMLElement *features = [rootElement elementForName:@"stream:features"];

    // Check to see if TLS is required
    // Don't forget about that NSXMLElement bug you reported to apple (xmlns is required or element won't be found)
    NSXMLElement *f_starttls = [features elementForName:@"starttls" xmlns:@"urn:ietf:params:xml:ns:xmpp-tls"];

    if (f_starttls)
    {
        if ([f_starttls elementForName:@"required"] || [self startTLSPolicy] >= XMPPStreamStartTLSPolicyPreferred)
        {
            // TLS is required for this connection

            // Update state
            state = STATE_XMPP_STARTTLS_1;

            // Send the startTLS XML request
            [self sendStartTLSRequest];

            // We do not mark the stream as secure yet.
            // We're waiting to receive the <proceed/> response from the
            // server before we actually start the TLS handshake.

            // We're already listening for the response...
            return;
        }
    }
    else if (![self isSecure] && [self startTLSPolicy] == XMPPStreamStartTLSPolicyRequired)
    {
        // We must abort the connection as the server doesn't support our requirements.

        NSString *errMsg = @"The server does not support startTLS. And the startTLSPolicy is Required.";
        NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];

        otherError = [NSError errorWithDomain:XMPPStreamErrorDomain code:XMPPStreamUnsupportedAction userInfo:info];

        // Close the TCP connection.
        [self disconnect];

        // The socketDidDisconnect:withError: method will handle everything else
        return;
    }

    // Check to see if resource binding is required
    // Don't forget about that NSXMLElement bug you reported to apple (xmlns is required or element won't be found)
    NSXMLElement *f_bind = [features elementForName:@"bind" xmlns:@"urn:ietf:params:xml:ns:xmpp-bind"];

    if (f_bind)
    {
        // Start the binding process
        [self startBinding];

        // We're already listening for the response...
        return;
    }

    // It looks like all has gone well, and the connection should be ready to use now
    state = STATE_XMPP_CONNECTED;

    if (![self isAuthenticated])
    {
        [self setupKeepAliveTimer];

        // Notify delegates
        [multicastDelegate xmppStreamDidConnect:self];
    }
}

答案 2 :(得分:0)

您正在尝试使用过时的API,请检查新版本的iPhoneXMPP示例 - https://github.com/robbiehanson/XMPPFramework/commit/73f3c35a930b91d27e62bc19e91d9cdcc02c6e42

答案 3 :(得分:0)

customCertEvaluation = YES;
allowSelfSignedCertificates = YES;
allowSSLHostNameMismatch = NO;  

尝试这些可能会有所帮助