feat(core): Allow disabling tls validation for localhost (#286)

pull/273/head
Nicolas Höft 2020-08-05 19:52:18 +02:00 committed by GitHub
parent 223b27b89b
commit 1f9888254a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 195 additions and 49 deletions

View File

@ -1832,6 +1832,9 @@ Supported formats are: `smtp://domain:port`, `smtps://domain`,
`tls=YES` will enforce using STARTTLS smtp connections. Thus,
`smtp://localhost:587/?tls=YES` would use the default MUA port
on localhost with STARTTLS enforced.
To disable TLS verification for localhost domains, passing
`tlsVerifyMode=allowInsecureLocalhost` will such connections:
`smtp://localhost:587/?tls=YES&tlsVerifyMode=allowInsecureLocalhost`.
|D |SOGoSMTPAuthenticationType
|Activate SMTP authentication and specifies which type is in use.
@ -1919,6 +1922,7 @@ URL with a fully qualified domain name, such as:
[options="compact"]
* `imaps://mail.acme.com:993`
* `imap://mail.acme.com:143/?tls=YES`
* `imap://127.0.0.1:143/?tls=YES&tlsVerifyMode=allowInsecureLocalhost`
|D |SOGoSieveServer
|Parameter used to set the DNS name or IP address of the Sieve
@ -1933,6 +1937,7 @@ qualified domain name, such as:
[options="compact"]
* `sieve://mail.acme.com:4190/?tls=YES`
* `sieve://127.0.0.14190/?tls=YES&tlsVerifyMode=allowInsecureLocalhost`
Note that TLS is supported but SSL is not.

View File

@ -28,7 +28,7 @@
SOGoMailAccount
Parent object: SOGoMailAccounts
Child objects: SOGoMailFolder
The SOGoMailAccount represents a single IMAP4 mail account (host, login,
password, etc)
*/
@ -91,6 +91,7 @@ typedef enum {
- (NSDictionary *) identityForEmail: (NSString *) email;
- (NSString *) signature;
- (NSString *) encryption;
- (NSString *) tlsVerifyMode;
/* folder pathes */
- (NSArray *) toManyRelationshipKeysWithNamespaces: (BOOL) withNSs;

View File

@ -92,7 +92,7 @@ static NSString *inboxFolderName = @"INBOX";
[otherUsersFolderName release];
[sharedFoldersName release];
[subscribedFolders release];
[super dealloc];
[super dealloc];
}
- (BOOL) isInDraftsFolder
@ -135,7 +135,7 @@ static NSString *inboxFolderName = @"INBOX";
if (namespace)
{
[self _appendNamespace: namespace toFolders: folders];
ASSIGN(otherUsersFolderName, [folders lastObject]);
ASSIGN(otherUsersFolderName, [folders lastObject]);
}
namespace = [namespaceDict objectForKey: @"shared"];
@ -275,7 +275,7 @@ static NSString *inboxFolderName = @"INBOX";
SOGoDomainDefaults *dd;
id inboxQuota, infos;
float quota;
inboxQuota = nil;
if ([self supportsQuotas])
{
@ -744,6 +744,17 @@ static NSString *inboxFolderName = @"INBOX";
return encryption;
}
- (NSString *) tlsVerifyMode
{
NSString *verifyMode;
verifyMode = [[self _mailAccount] objectForKey: @"tlsVerifyMode"];
if (!verifyMode || ![verifyMode length])
verifyMode = @"default";
return verifyMode;
}
- (NSMutableString *) imap4URLString
{
NSMutableString *imap4URLString;
@ -829,7 +840,7 @@ static NSString *inboxFolderName = @"INBOX";
NSEnumerator *e;
NSString *guid;
id currentFolder;
BOOL hasAnnotatemore;
ud = [[context activeUser] userDefaults];
@ -854,7 +865,7 @@ static NSString *inboxFolderName = @"INBOX";
result = [client annotation: @"*" entryName: @"/comment" attributeName: @"value.priv"];
else
result = [client lstatus: @"*" flags: [NSArray arrayWithObjects: @"x-guid", nil]];
e = [folderList objectEnumerator];
while ((currentFolder = [[e nextObject] substringFromIndex: 1]))
@ -863,7 +874,7 @@ static NSString *inboxFolderName = @"INBOX";
guid = [[[[result objectForKey: @"FolderList"] objectForKey: currentFolder] objectForKey: @"/comment"] objectForKey: @"value.priv"];
else
guid = [[[result objectForKey: @"status"] objectForKey: currentFolder] objectForKey: @"x-guid"];
if (!guid || ![guid isNotNull])
{
// Don't generate a GUID for "Other users" and "Shared" namespace folders - user foldername instead
@ -881,7 +892,7 @@ static NSString *inboxFolderName = @"INBOX";
guid = [NSString stringWithFormat: @"%@", currentFolder];
else
{
// If folder doesn't exists - ignore it.
// If folder doesn't exists - ignore it.
nresult = [client status: currentFolder
flags: [NSArray arrayWithObject: @"UIDVALIDITY"]];
if (![[nresult valueForKey: @"result"] boolValue])
@ -897,10 +908,10 @@ static NSString *inboxFolderName = @"INBOX";
guid = [NSString stringWithFormat: @"%@", currentFolder];
}
}
[folders setObject: [NSString stringWithFormat: @"folder%@", guid] forKey: [NSString stringWithFormat: @"folder%@", currentFolder]];
}
return folders;
}
@ -964,7 +975,7 @@ static NSString *inboxFolderName = @"INBOX";
}
else
obj = [super lookupName: _key inContext: _ctx acquire: NO];
/* return 404 to stop acquisition */
if (!obj)
obj = [NSException exceptionWithHTTPStatus: 404 /* Not Found */];
@ -1224,7 +1235,7 @@ static NSString *inboxFolderName = @"INBOX";
if (delegateUser)
[delegateUser removeMailDelegator: owner];
}
[self _setDelegates: delegates];
}
}

View File

@ -93,7 +93,7 @@
container];
folder = nil;
}
return folder;
}
@ -211,7 +211,7 @@
// use the container's one.
//
login = [[[self context] activeUser] login];
if (!login)
login = [[[[self container] context] activeUser] login];
@ -265,7 +265,7 @@
[self warnWithFormat:@"container does not implement -imap4URL!"];
url = nil;
}
return url;
}
@ -285,6 +285,7 @@
{
SOGoMailAccount *account;
NSString *urlString;
NSString *useTls = @"NO";
/* this could probably be handled better from NSURL but it's buggy in
GNUstep */
@ -292,10 +293,11 @@
{
account = [self mailAccountFolder];
if ([[account encryption] isEqualToString: @"tls"])
urlString = [NSString stringWithFormat: @"%@?tls=YES",
[self imap4URLString]];
else
urlString = [self imap4URLString];
{
useTls = @"YES";
}
urlString = [NSString stringWithFormat: @"%@?tls=%@&tlsVerifyMode=%@",
[self imap4URLString], useTls, [account tlsVerifyMode]];
imap4URL = [[NSURL alloc] initWithString: urlString];
}

View File

@ -23,6 +23,7 @@
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WORequest.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSURL+misc.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
@ -136,7 +137,7 @@
_defaults = nil;
_settings = nil;
uid = nil;
realUID = nil;
domain = nil;
@ -166,7 +167,7 @@
domain = nil;
}
}
newLogin = [newLogin stringByReplacingString: @"%40"
withString: @"@"];
if (b)
@ -312,7 +313,7 @@
return allEmails;
}
//
//
// We always return the last object among our list of email addresses. This value
// is always added in SOGoUserManager: -_fillContactMailRecords:
//
@ -396,7 +397,7 @@
format = [ud timeFormat];
if (format)
[dateFormatter setTimeFormat: format];
return dateFormatter;
}
@ -475,7 +476,7 @@
- (SOGoUserSettings *) userSettings
{
if (!_settings)
if (!_settings)
{
_settings = [SOGoUserSettings settingsForUser: login];
[_settings retain];
@ -643,8 +644,9 @@
- (void) _appendSystemMailAccountWithDelegatedIdentities: (BOOL) appendDeletegatedIdentities
{
NSString *fullName, *imapLogin, *imapServer, *cImapServer,
*encryption, *scheme, *action, *query, *customEmail, *sieveServer;
*encryption, *scheme, *action, *queryTls, *customEmail, *sieveServer, *tlsVerifyMode;
NSMutableDictionary *mailAccount, *identity, *mailboxes, *receipts, *security, *mailSettings;
NSDictionary *queryComponents;
NSNumber *port;
NSMutableArray *identities, *mails;
NSArray *delegators, *delegates;
@ -692,36 +694,43 @@
// 3. port & encryption
scheme = [cUrl scheme] ? [cUrl scheme] : [url scheme];
query = [cUrl query] ? [cUrl query] : [url query];
queryComponents = [cUrl query] ? [cUrl queryComponents] : [url queryComponents];
queryTls = [queryComponents valueForKey: @"tls"];
tlsVerifyMode = [queryComponents valueForKey: @"tlsVerifyMode"];
if (!tlsVerifyMode)
tlsVerifyMode = @"default";
if (scheme
&& [scheme caseInsensitiveCompare: @"imaps"] == NSOrderedSame)
{
if (query && [query caseInsensitiveCompare: @"tls=YES"] == NSOrderedSame)
{
defaultPort = 143;
encryption = @"tls";
}
if (queryTls && [queryTls caseInsensitiveCompare: @"YES"] == NSOrderedSame)
{
defaultPort = 143;
encryption = @"tls";
}
else
{
encryption = @"ssl";
defaultPort = 993;
}
{
encryption = @"ssl";
defaultPort = 993;
}
}
else
{
if (query && [query caseInsensitiveCompare: @"tls=YES"] == NSOrderedSame)
if (queryTls && [queryTls caseInsensitiveCompare: @"YES"] == NSOrderedSame)
encryption = @"tls";
else
encryption = @"none";
defaultPort = 143;
}
port = [cUrl port] ? [cUrl port] : [url port];
if ([port intValue] == 0) /* port is nil or intValue == 0 */
port = [NSNumber numberWithInt: defaultPort];
[mailAccount setObject: port forKey: @"port"];
[mailAccount setObject: encryption forKey: @"encryption"];
[mailAccount setObject: tlsVerifyMode forKey: @"tlsVerifyMode"];
// 4. Sieve server
sieveServer = [self _fetchFieldForUser: @"c_sievehostname"];
@ -730,7 +739,7 @@
{
[mailAccount setObject: sieveServer forKey: @"sieveServerName"];
}
// 5. Identities
identities = [NSMutableArray new];
[identities addObjectsFromArray: [_defaults mailIdentities]];
@ -1048,11 +1057,11 @@
- (SOGoContactFolder *) personalContactsFolderInContext: (WOContext *) context
{
SOGoContactFolders *folders;
folders = [[self homeFolderInContext: context] lookupName: @"Contacts"
inContext: context
acquire: NO];
return [folders lookupPersonalFolder: @"personal"
ignoringRights: YES];
}
@ -1113,7 +1122,7 @@
id authValue;
authValue = [self _fetchFieldForUser: @"canAuthenticate"];
return [authValue boolValue];
}
@ -1158,9 +1167,9 @@
- (int) numberOfSimultaneousBookings
{
NSNumber *v;
v = [self _fetchFieldForUser: @"numberOfSimultaneousBookings"];
if (v)
return [v intValue];

View File

@ -30,7 +30,9 @@ $(TEST_TOOL)_OBJC_FILES += \
TestNSString+Crypto.m \
TestNSString+URLEscaping.m \
TestNSString+Utilities.m \
TestNSURL+misc.m \
TestNGMailAddressParser.m \
TestNGInternetSocketAddress.m \
\
# I don't know how to link against -l:SOGoBackend \
undefined reference to `__objc_class_name_SOGoMailFolder'
@ -42,7 +44,7 @@ $(TEST_TOOL)_CPPFLAGS += \
ADDITIONAL_LIB_DIRS += \
-L../../SoObjects/SOGo/SOGo.framework/Versions/Current/sogo -L../../SOPE/NGCards/obj -L../../SOPE/GDLContentStore/obj -lSOGo -lNGMime -lNGCards -lGDLContentStore -lNGExtensions -lSBJson -lobjc \
-L/usr/local/lib -lSaxObjC \
-L/usr/local/lib -lSaxObjC -lNGStreams \
-Wl,-rpath,../../SoObjects/SOGo/SOGo.framework/Versions/Current/sogo -Wl,-rpath,../../SOPE/NGCards/obj -Wl,-rpath,../../SOPE/GDLContentStore/obj
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed

View File

@ -0,0 +1,56 @@
/* TestNGInternetSocketAddress.m - this file is part of SOGo
*
* Copyright (C) 2020 Nicolas Höft
*
* Author: Nicolas Höft <nicolas@hoeft.de>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <NGStreams/NGInternetSocketAddress.h>
#import "SOGoTest.h"
@interface TestNGInternetSocketAddress : SOGoTest
@end
@implementation TestNGInternetSocketAddress
- (void) test_isLocalhost
{
// @"localhost6",
NSString *addrStr[] = { @"127.0.0.1", @"127.1.2.3", @"localhost", @"something.localhost", @"localhost.", nil };
NSString **curHost;
BOOL is_localhost;
NSString *error;
curHost = addrStr;
while (*curHost)
{
NGInternetSocketAddress *addr;
addr = [NGInternetSocketAddress addressWithPort: 1234
onHost: *curHost];
is_localhost = [addr isLocalhost];
error = [NSString stringWithFormat:
@"expected '%@' to be a localhost address", *curHost];
testWithMessage(is_localhost, error);
curHost++;
}
}
@end

View File

@ -61,10 +61,6 @@
[NSNumber numberWithInt: NSISOLatin1StringEncoding],
[NSNumber numberWithInt: 0],
@"nil",
[NSNumber numberWithInt: [NSString defaultCStringEncoding]],
[NSNumber numberWithInt: 0],
@"",
[NSNumber numberWithInt: [NSString defaultCStringEncoding]],
[NSNumber numberWithInt: 0],

View File

@ -0,0 +1,64 @@
/* TestNSURL+miscm - this file is part of SOGo
*
* Copyright (C) 2020 Nicolas Höft
*
* Author: Nicolas Höft <nicolas@hoeft.de>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSDictionary.h>
#import <NGStreams/NGInternetSocketAddress.h>
#import <NGExtensions/NSURL+misc.h>
#import "SOGoTest.h"
@interface TestNSURL_plusmisc : SOGoTest
@end
@implementation TestNSURL_plusmisc
- (void) test_queryComponents
{
NSString *urlStr;
NSString *error;
NSURL *url;
NSDictionary *queryComp;
urlStr = @"http://domain/path?key=value";
url = [NSURL URLWithString: urlStr];
queryComp = [url queryComponents];
error = [NSString stringWithFormat:
@"expected '%@' to have 1 entry", urlStr];
testWithMessage([queryComp count] == 1, error);
test([[queryComp valueForKey: @"key"] isEqualToString: @"value"]);
urlStr = @"http://domain/path?key1=value123&key2=val2&";
url = [NSURL URLWithString: urlStr];
queryComp = [url queryComponents];
error = [NSString stringWithFormat:
@"expected '%@' to have 2 entries, got %d", urlStr, [queryComp count]];
testWithMessage([queryComp count] == 2, error);
test([[queryComp valueForKey: @"key1"] isEqualToString: @"value123"]);
test([[queryComp valueForKey: @"key2"] isEqualToString: @"val2"]);
}
@end