diff --git a/Documentation/SOGoInstallationGuide.asciidoc b/Documentation/SOGoInstallationGuide.asciidoc index 78073b76a..9e582aab8 100644 --- a/Documentation/SOGoInstallationGuide.asciidoc +++ b/Documentation/SOGoInstallationGuide.asciidoc @@ -2628,6 +2628,14 @@ from the SOGo Webmail interface. Defaults to `NO` when unset. +|D |SOGoMailAuxiliaryUserAccountsReadOnly +|Only useful if `SOGoMailAuxiliaryUserAccountsEnabled = YES;`. Tell that auxiliiary +accounts are read-only and can only be set by admin with sogo-tool. User cannot +add external account nor modify them. Any previous external account not set by admin +will be removed. + +Defaults to `NO` when unset. + |U |SOGoDefaultCalendar |Parameter used to specify which calendar is used when creating an event or a task. Possible values are: diff --git a/SoObjects/Mailer/SOGoMailAccount.m b/SoObjects/Mailer/SOGoMailAccount.m index 2b4e2a34a..3a6ca86fb 100644 --- a/SoObjects/Mailer/SOGoMailAccount.m +++ b/SoObjects/Mailer/SOGoMailAccount.m @@ -956,9 +956,27 @@ static NSString *inboxFolderName = @"INBOX"; } else { + password = [[self _mailAccount] objectForKey: @"password"]; if (!password) - password = @""; + { + SOGoDomainDefaults *dd; + dd = [[context activeUser] domainDefaults]; + if([dd mailAuxiliaryUserAccountsReadOnly] && [[self _mailAccount] objectForKey: @"readOnly"]) + { + //If we use aux account in read only, to not have a password means to use the current user one + imapURL = [self imap4URL]; + + password = [[self authenticatorInContext: context] + imapPasswordInContext: context + forURL: imapURL + forceRenew: renewed]; + if (!password) + [self errorWithFormat: @"no IMAP4 password available"]; + } + else + password = @""; + } } return password; diff --git a/SoObjects/SOGo/SOGoDomainDefaults.h b/SoObjects/SOGo/SOGoDomainDefaults.h index 82fb7d0db..91f28718a 100644 --- a/SoObjects/SOGo/SOGoDomainDefaults.h +++ b/SoObjects/SOGo/SOGoDomainDefaults.h @@ -37,7 +37,7 @@ - (BOOL) mailCustomFromEnabled; - (BOOL) mailAuxiliaryUserAccountsEnabled; - +- (BOOL) mailAuxiliaryUserAccountsReadOnly; - (BOOL) mailDisableXForward; - (NSString *) mailDomain; - (NSString *) imapServer; diff --git a/SoObjects/SOGo/SOGoDomainDefaults.m b/SoObjects/SOGo/SOGoDomainDefaults.m index d1d4be6c9..8745fd251 100644 --- a/SoObjects/SOGo/SOGoDomainDefaults.m +++ b/SoObjects/SOGo/SOGoDomainDefaults.m @@ -106,6 +106,11 @@ return [self boolForKey: @"SOGoMailAuxiliaryUserAccountsEnabled"]; } +- (BOOL) mailAuxiliaryUserAccountsReadOnly +{ + return [self boolForKey: @"SOGoMailAuxiliaryUserAccountsReadOnly"]; +} + - (BOOL) mailDisableXForward { return [self boolForKey: @"SOGoMailDisableXForward"]; diff --git a/SoObjects/SOGo/SOGoMailer.m b/SoObjects/SOGo/SOGoMailer.m index 021d4faa2..3c7fabc46 100644 --- a/SoObjects/SOGo/SOGoMailer.m +++ b/SoObjects/SOGo/SOGoMailer.m @@ -276,6 +276,7 @@ NSURL * smtpUrl; SOGoUser* user; SOGoSystemDefaults *sd; + SOGoDomainDefaults *domainDefaults; BOOL doSmtpAuth; result = nil; @@ -325,6 +326,16 @@ { login = [currentAcount objectForKey: @"userName"]; password = [currentAcount objectForKey: @"password"]; + domainDefaults = [[woContext activeUser] domainDefaults]; + if(!password && [domainDefaults mailAuxiliaryUserAccountsReadOnly] && [currentAcount objectForKey: @"readOnly"]) + { + //If aux account is read only with no password, user the current user one instead + protocol = @"imap"; + if ([encryption isEqualToString: @"ssl"] || [encryption isEqualToString: @"tls"]) + protocol = @"imaps"; + server = [NSString stringWithFormat: @"%@://%@", protocol, [currentAcount objectForKey: @"serverName"]]; + password = [authenticator smtpPasswordInContext: woContext forURL: server]; + } smtpAuthMethod = @"plain"; //Only support plain for auxiliary account } else diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m index 14ad6b6cd..a246e8d24 100644 --- a/SoObjects/SOGo/SOGoUser.m +++ b/SoObjects/SOGo/SOGoUser.m @@ -1068,6 +1068,8 @@ [self _appendSystemMailAccountWithDelegatedIdentities: appendDeletegatedIdentities]; if ([[self domainDefaults] mailAuxiliaryUserAccountsEnabled]) { + + //If we are in read-only, only add account with this param auxAccounts = [[self userDefaults] auxiliaryMailAccounts]; if (auxAccounts) { @@ -1085,7 +1087,8 @@ account = [auxAccounts objectAtIndex: i]; if (![[account objectForKey: @"password"] isKindOfClass: [NSDictionary class]]) { - [self errorWithFormat:@"Can't decrypt the password for auxiliary account %@, is not a dictionnary", + if(![account objectForKey: @"readOnly"]) //Read only account can have no password + [self errorWithFormat:@"Can't decrypt the password for auxiliary account %@, is not a dictionnary", [account objectForKey: @"name"]]; continue; } diff --git a/UI/PreferencesUI/UIxJSONPreferences.m b/UI/PreferencesUI/UIxJSONPreferences.m index 7434ba3a7..0bf4b6779 100644 --- a/UI/PreferencesUI/UIxJSONPreferences.m +++ b/UI/PreferencesUI/UIxJSONPreferences.m @@ -506,31 +506,7 @@ static SoProduct *preferencesProduct = nil; // Add timezone offset [values setObject: [NSNumber numberWithInt: [[defaults timeZone] secondsFromGMT]] forKey: @"UserTimeZoneSecondsFromGMT"]; - accounts = [NSMutableArray arrayWithArray: [values objectForKey: @"AuxiliaryMailAccounts"]]; - if ([accounts count]) - { - int i; - NSDictionary *security, *accountPassword; - NSMutableDictionary *auxAccount, *limitedSecurity; - NSString *password, *encryptedPassword, *sogoSecret, *iv, *tag; - NSException* exception = nil; - - for (i = 0; i < [accounts count]; i++) - { - auxAccount = [accounts objectAtIndex: i]; - security = [auxAccount objectForKey: @"security"]; - if (security && [domainDefaults mailCertificateEnabled]) - { - limitedSecurity = [NSMutableDictionary dictionaryWithDictionary: security]; - if ([limitedSecurity objectForKey: @"certificate"]) - { - [limitedSecurity setObject: [NSNumber numberWithBool: YES] forKey: @"hasCertificate"]; - [limitedSecurity removeObjectForKey: @"certificate"]; - } - [auxAccount setObject: limitedSecurity forKey: @"security"]; - } - } - } + NSMutableArray *clean_accounts = [NSMutableArray array]; // We inject our default mail account account = [[[context activeUser] mailAccountsNoRawHtmlSignature] objectAtIndex: 0]; if (![account objectForKey: @"receipts"]) @@ -542,8 +518,44 @@ static SoProduct *preferencesProduct = nil; forKey: @"receipts"]; } if (account) - [accounts insertObject: account atIndex: 0]; - [values setObject: accounts forKey: @"AuxiliaryMailAccounts"]; + [clean_accounts addObject: account]; + + //Now check external account + if (![domainDefaults mailAuxiliaryUserAccountsReadOnly] && [domainDefaults mailAuxiliaryUserAccountsEnabled]) + { + accounts = [NSMutableArray arrayWithArray: [values objectForKey: @"AuxiliaryMailAccounts"]]; + if ([accounts count]) + { + int i; + NSDictionary *security, *accountPassword; + NSMutableDictionary *auxAccount, *limitedSecurity; + NSString *password, *encryptedPassword, *sogoSecret, *iv, *tag; + NSException* exception = nil; + + BOOL isReadOnly = [domainDefaults mailAuxiliaryUserAccountsReadOnly]; + for (i = 0; i < [accounts count]; i++) + { + auxAccount = [accounts objectAtIndex: i]; + if(isReadOnly && [auxAccount objectForKey: @"readOnly"]) + continue; + security = [auxAccount objectForKey: @"security"]; + if (security && [domainDefaults mailCertificateEnabled]) + { + limitedSecurity = [NSMutableDictionary dictionaryWithDictionary: security]; + if ([limitedSecurity objectForKey: @"certificate"]) + { + [limitedSecurity setObject: [NSNumber numberWithBool: YES] forKey: @"hasCertificate"]; + [limitedSecurity removeObjectForKey: @"certificate"]; + } + [auxAccount setObject: limitedSecurity forKey: @"security"]; + } + [clean_accounts addObject: auxAccount]; + } + } + } + + + [values setObject: clean_accounts forKey: @"AuxiliaryMailAccounts"]; // Ignore parameters as they are injected in the system mail account ([SOGoUser mailAccounts]) [values removeObjectForKey: @"SOGoMailIdentities"]; diff --git a/UI/PreferencesUI/UIxPreferences.m b/UI/PreferencesUI/UIxPreferences.m index d6a4b5b5f..47c73c0af 100644 --- a/UI/PreferencesUI/UIxPreferences.m +++ b/UI/PreferencesUI/UIxPreferences.m @@ -1230,6 +1230,11 @@ static NSArray *reminderValues = nil; return [[user domainDefaults] mailAuxiliaryUserAccountsEnabled]; } +- (BOOL) mailAuxiliaryUserAccountsReadOnly +{ + return [[user domainDefaults] mailAuxiliaryUserAccountsReadOnly]; +} + // // Used internally // @@ -1534,15 +1539,30 @@ static NSArray *reminderValues = nil; // - (NSArray *) _extractAuxiliaryAccounts: (NSArray *) accounts { - int count, max; + int count, i; + id isReadOnly; NSMutableArray *auxAccounts; NSMutableDictionary *account; + NSDictionary *currentAux, *auxAccount; NSString *sogoSecret, *password; - max = [accounts count]; - auxAccounts = [NSMutableArray arrayWithCapacity: max]; + auxAccounts = [NSMutableArray array]; - for (count = 1; count < max; count++) + if ([self mailAuxiliaryUserAccountsReadOnly]) { + //External account are read only. Meaning we don't accept any data from accounts + //Instead we fetch the current ones to not lost them + currentAux = [[[user userDefaults] source] objectForKey: @"AuxiliaryMailAccounts"]; + for (i = 0; i < [currentAux count]; i++) + { + auxAccount = [currentAux objectAtIndex: i]; + isReadOnly = [auxAccount objectForKey: @"readOnly"]; + if(isReadOnly) + [auxAccounts addObject: auxAccount]; + } + } + else + { + for (count = 1; count < [accounts count]; count++) { account = [accounts objectAtIndex: count]; if ([self _validateAccount: account]) @@ -1569,6 +1589,7 @@ static NSArray *reminderValues = nil; [auxAccounts addObject: account]; } } + } return auxAccounts; } @@ -1863,7 +1884,7 @@ static NSArray *reminderValues = nil; accounts = [v objectForKey: @"AuxiliaryMailAccounts"]; if (accounts && [accounts isKindOfClass: [NSArray class]]) { - if ([accounts count] > 0) + if ([accounts count] > 0 || [self mailAuxiliaryUserAccountsReadOnly]) //in the second case it's expected to have only the main account { // The first account is the main system account. The following mapping is required: // - forceDefaultIdentity => SOGoMailForceDefaultIdentity diff --git a/UI/WebServerResources/js/Mailer/Account.service.js b/UI/WebServerResources/js/Mailer/Account.service.js index 159050f9e..58e130d71 100644 --- a/UI/WebServerResources/js/Mailer/Account.service.js +++ b/UI/WebServerResources/js/Mailer/Account.service.js @@ -490,11 +490,13 @@ // Fetch draft initial data return Account.$$resource.fetch(message.$absolutePath({asDraft: true}), 'edit').then(function(data) { var accountDefaults = Account.$Preferences.defaults.AuxiliaryMailAccounts[_this.id]; - if (accountDefaults.security) { - if (accountDefaults.security.alwaysSign) - data.sign = true; - if (accountDefaults.security.alwaysEncrypt) - data.encrypt = true; + if(accountDefaults) { + if (accountDefaults.security) { + if (accountDefaults.security.alwaysSign) + data.sign = true; + if (accountDefaults.security.alwaysEncrypt) + data.encrypt = true; + } } Account.$log.debug('New message (edit): ' + JSON.stringify(data, undefined, 2)); angular.extend(message.editable, data);