View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0002060 | SOGo | Backend General | public | 2012-10-23 09:02 | 2012-11-15 17:18 |
Reporter | sim | Assigned To | |||
Priority | normal | Severity | major | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Product Version | 2.0.1 | ||||
Target Version | 2.0.2a | Fixed in Version | 2.0.2a | ||
Summary | 0002060: userPasswordAlgorithm = ssh.b64 creates {sha.b64}(null) for any password | ||||
Description | When updating a user password from the WebUI (SOGoPasswordChangeEnabled=YES), passwords are inserted into the LDAP database as "{sha.b64}(null)" | ||||
Additional Information | SOGo defaults sha to sha.hex, which is different than dovecot. Dovecot defaults sha to sha.b64. For completeness I've tried the following variants: All of them result in a password like {prefix}(null) | ||||
Tags | No tags attached. | ||||
AZctually, when this occurs, you should see this message in your log: "Unsupported user-password algorithm: blablal" |
|
"ssh" is not a real password scheme. This is maybe just a typo. SHA (plus optionally ".b64", as well as the other variants) should work. |
|
Yes, it's supposed to be sha. And no it does not work. I more recently tried sha256 and sha512 and neither of them work - base64 or hex. There is no error in any log files pertaining to "Unsupported user-password algorithm". "grep -R algorithm /var/log" shows nothing |
|
I see the problem now. |
|
Fantastic! Thank you. |
|
2012-10-31 12:38
|
0001-NString-Crypto-fix-encryption-with-schemes-having-an.patch (7,752 bytes)
From 5a30265baeb364823219cec5ae9a7bb6e807dfa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20H=C3=B6ft?= <Nicolas.Hoeft@gmail.com> Date: Wed, 31 Oct 2012 13:33:42 +0100 Subject: [PATCH 1/2] NString+Crypto: fix encryption with schemes having an encoding asCryptedPassUsingScheme was not removing the encoding from a scheme (e.g. 'sha.b64' was not split up in sha and 'b64'). getDefaultEncodingForScheme now detects the encoding from such schemes and returns both the encoding and the true scheme name. --- SoObjects/SOGo/NSString+Crypto.h | 2 +- SoObjects/SOGo/NSString+Crypto.m | 102 +++++++++++++++++++++++---------------- 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/SoObjects/SOGo/NSString+Crypto.h b/SoObjects/SOGo/NSString+Crypto.h index cc35a89..100bfac 100644 --- a/SoObjects/SOGo/NSString+Crypto.h +++ b/SoObjects/SOGo/NSString+Crypto.h @@ -56,7 +56,7 @@ typedef enum { - (NSString *) asSHA1String; - (NSString *) asMD5String; -+ (keyEncoding) getDefaultEncodingForScheme: (NSString *) passwordScheme; ++ (NSArray *) getDefaultEncodingForScheme: (NSString *) passwordScheme; @end diff --git a/SoObjects/SOGo/NSString+Crypto.m b/SoObjects/SOGo/NSString+Crypto.m index f3370b8..7a720d4 100644 --- a/SoObjects/SOGo/NSString+Crypto.m +++ b/SoObjects/SOGo/NSString+Crypto.m @@ -71,8 +71,7 @@ { NSString *scheme; NSString *pass; - NSArray *schemeComps; - keyEncoding encoding; + NSArray *encodingAndScheme; NSRange range; int selflen, len; @@ -88,32 +87,11 @@ if (len == 0) scheme = defaultScheme; - encoding = [NSString getDefaultEncodingForScheme: scheme]; - - // get the encoding which may be part of the scheme - // e.g. ssha.hex forces a hex encoded ssha scheme - // possible is "b64" or "hex" - schemeComps = [scheme componentsSeparatedByString: @"."]; - if ([schemeComps count] == 2) - { - NSString *stringEncoding; - // scheme without encoding string is the first item - scheme = [schemeComps objectAtIndex: 0]; - // encoding string is second item - stringEncoding = [schemeComps objectAtIndex: 1]; - if ([stringEncoding caseInsensitiveCompare: @"hex"] == NSOrderedSame) - { - encoding = encHex; - } - else if ([stringEncoding caseInsensitiveCompare: @"b64"] == NSOrderedSame || - [stringEncoding caseInsensitiveCompare: @"base64"] == NSOrderedSame) - { - encoding = encBase64; - } - } + encodingAndScheme = [NSString getDefaultEncodingForScheme: scheme]; pass = [self substringWithRange: range]; - return [NSArray arrayWithObjects: scheme, pass, [NSNumber numberWithInt: encoding], nil]; + // return array with [scheme, password, encoding] + return [NSArray arrayWithObjects: [encodingAndScheme objectAtIndex: 1], pass, [encodingAndScheme objectAtIndex: 0], nil]; } /** @@ -147,7 +125,7 @@ if (encoding == encHex) { decodedData = [NSData decodeDataFromHexString: pass]; - + if(decodedData == nil) { decodedData = [NSData data]; @@ -208,8 +186,10 @@ * * @param passwordScheme The scheme to use * @param theSalt The binary data of the salt - * @param userEncoding The encoding (plain, hex, base64) to be used - * @return If successful, the encrypted and encoded NSString of the format {scheme}pass, or nil if the scheme did not exists or an error occured + * @param userEncoding The encoding (plain, hex, base64) to be used. If set to + * encDefault, the encoding will be detected from scheme name. + * @return If successful, the encrypted and encoded NSString of the format {scheme}pass, + * or nil if the scheme did not exists or an error occured. */ - (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme withSalt: (NSData *) theSalt @@ -217,6 +197,22 @@ { keyEncoding dataEncoding; NSData* cryptedData; + + // use default encoding scheme, when set to default + if (userEncoding == encDefault) + { + // the encoding needs to be detected before crypting, + // to get the plain scheme (without encoding identifier) + NSArray* encodingAndScheme; + encodingAndScheme = [NSString getDefaultEncodingForScheme: passwordScheme]; + dataEncoding = [[encodingAndScheme objectAtIndex: 0] intValue]; + passwordScheme = [encodingAndScheme objectAtIndex: 1]; + } + else + { + dataEncoding = userEncoding; + } + // convert NSString to NSData and apply encryption scheme cryptedData = [self dataUsingEncoding: NSUTF8StringEncoding]; cryptedData = [cryptedData asCryptedPassUsingScheme: passwordScheme withSalt: theSalt]; @@ -224,12 +220,6 @@ if (cryptedData == nil) return nil; - // use default encoding scheme, when set to default - if (userEncoding == encDefault) - dataEncoding = [NSString getDefaultEncodingForScheme: passwordScheme]; - else - dataEncoding = userEncoding; - if (dataEncoding == encHex) { // hex encoding @@ -250,19 +240,49 @@ /** * Returns the encoding for a specified scheme * - * @param passwordScheme The scheme for which to get the encoding. + * @param passwordScheme The scheme for which to get the encoding. Can be "scheme.encoding" in which case the encoding is returned * @see keyEncoding - * @return returns the encoding, if unknown returns encPlain + * @return returns NSArray with elements {NSNumber encoding, NSString* scheme} where scheme is the 'real' scheme without the ".encoding" part. + * 'encoding' is stored as NSNumber in the array. If the encoding was not detected, encPlain is used for encoding. */ -+ (keyEncoding) getDefaultEncodingForScheme: (NSString *) passwordScheme ++ (NSArray *) getDefaultEncodingForScheme: (NSString *) passwordScheme { + NSArray *schemeComps; + NSString *trueScheme; + keyEncoding encoding = encPlain; + + // get the encoding which may be part of the scheme + // e.g. ssha.hex forces a hex encoded ssha scheme + // possible is "b64" or "hex" + schemeComps = [passwordScheme componentsSeparatedByString: @"."]; + if ([schemeComps count] == 2) + { + trueScheme = [schemeComps objectAtIndex: 0]; + NSString *stringEncoding; + // encoding string is second item + stringEncoding = [schemeComps objectAtIndex: 1]; + if ([stringEncoding caseInsensitiveCompare: @"hex"] == NSOrderedSame) + { + encoding = encHex; + } + else if ([stringEncoding caseInsensitiveCompare: @"b64"] == NSOrderedSame || + [stringEncoding caseInsensitiveCompare: @"base64"] == NSOrderedSame) + { + encoding = encBase64; + } + } + else + { + trueScheme = passwordScheme; + } + // in order to keep backwards-compatibility, hex encoding is used for sha1 here if ([passwordScheme caseInsensitiveCompare: @"md5"] == NSOrderedSame || [passwordScheme caseInsensitiveCompare: @"plain-md5"] == NSOrderedSame || [passwordScheme caseInsensitiveCompare: @"sha"] == NSOrderedSame || [passwordScheme caseInsensitiveCompare: @"cram-md5"] == NSOrderedSame) { - return encHex; + encoding = encHex; } else if ([passwordScheme caseInsensitiveCompare: @"smd5"] == NSOrderedSame || [passwordScheme caseInsensitiveCompare: @"ldap-md5"] == NSOrderedSame || @@ -272,9 +292,9 @@ [passwordScheme caseInsensitiveCompare: @"sha512"] == NSOrderedSame || [passwordScheme caseInsensitiveCompare: @"ssha512"] == NSOrderedSame) { - return encBase64; + encoding = encBase64; } - return encPlain; + return [NSArray arrayWithObjects: [NSNumber numberWithInt: encoding], trueScheme, nil]; } /** -- 1.8.0 |
2012-10-31 12:38
|
0002-SQLSource-LDAPSource-do-not-write-a-password-when-th.patch (4,432 bytes)
From cd2f1b28875694787b718b45e201cd49d685ed78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20H=C3=B6ft?= <Nicolas.Hoeft@gmail.com> Date: Wed, 31 Oct 2012 13:34:10 +0100 Subject: [PATCH 2/2] SQLSource,LDAPSource: do not write a password when the scheme is unknown _encryptPassword did not return nil when the password generated from NSString+Crypto returned an error. This patch changes this behaviour and also does not write the password to the SQL or LDAP database when _encryptPassword returns nil. --- SoObjects/SOGo/LDAPSource.m | 45 +++++++++++++++++++++++++++++---------------- SoObjects/SOGo/SQLSource.m | 15 ++++++++++----- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/SoObjects/SOGo/LDAPSource.m b/SoObjects/SOGo/LDAPSource.m index 81024a2..96a98ef 100644 --- a/SoObjects/SOGo/LDAPSource.m +++ b/SoObjects/SOGo/LDAPSource.m @@ -586,7 +586,10 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm]; if (pass == nil) - [self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm]; + { + [self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm]; + return nil; + } return [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass]; } @@ -629,24 +632,34 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField NGLdapModification *mod; NGLdapAttribute *attr; NSArray *changes; + NSString* encryptedPass; attr = [[NGLdapAttribute alloc] initWithAttributeName: @"userPassword"]; if ([_userPasswordAlgorithm isEqualToString: @"none"]) - [attr addStringValue: newPassword]; - else - [attr addStringValue: [self _encryptPassword: newPassword]]; - - mod = [NGLdapModification replaceModification: attr]; - changes = [NSArray arrayWithObject: mod]; - *perr = PolicyNoError; - - if ([bindConnection bindWithMethod: @"simple" - binddn: userDN - credentials: oldPassword]) - didChange = [bindConnection modifyEntryWithDN: userDN - changes: changes]; - else - didChange = NO; + { + encryptedPass = newPassword; + } + else + { + encryptedPass = [self _encryptPassword: newPassword]; + } + if(encryptedPass != nil) + { + [attr addStringValue: encryptedPass]; + mod = [NGLdapModification replaceModification: attr]; + changes = [NSArray arrayWithObject: mod]; + *perr = PolicyNoError; + + if ([bindConnection bindWithMethod: @"simple" + binddn: userDN + credentials: oldPassword]) + { + didChange = [bindConnection modifyEntryWithDN: userDN + changes: changes]; + } + else + didChange = NO; + } } else didChange = [bindConnection changePasswordAtDn: userDN diff --git a/SoObjects/SOGo/SQLSource.m b/SoObjects/SOGo/SQLSource.m index 2c50913..d3ceeca 100644 --- a/SoObjects/SOGo/SQLSource.m +++ b/SoObjects/SOGo/SQLSource.m @@ -187,7 +187,10 @@ pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm]; if (pass == nil) - [self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm]; + { + [self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm]; + return nil; + } if (_prependPasswordScheme) result = [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass]; @@ -308,18 +311,20 @@ NSString *sqlstr; BOOL didChange; BOOL isOldPwdOk; - + isOldPwdOk = NO; didChange = NO; - + // Verify current password isOldPwdOk = [self checkLogin:login password:oldPassword perr:perr expire:0 grace:0]; - + if (isOldPwdOk) { // Encrypt new password NSString *encryptedPassword = [self _encryptPassword: newPassword]; - + if(encryptedPassword == nil) + return NO; + // Save new password login = [login stringByReplacingString: @"'" withString: @"''"]; cm = [GCSChannelManager defaultChannelManager]; -- 1.8.0 |
These are the patches. The first fixes the problem with valid schemes as "sha.b64" and the second will prevent the SQL and LDAP parts to write passwords as "(null)" to the database @inverse: Please apply them with |
|
Patches applied: https://github.com/inverse-inc/sogo/commit/6ad59a8481972be77b1af56b93ec24dd6482aaf6 |
|
Date Modified | Username | Field | Change |
---|---|---|---|
2012-10-23 09:02 | sim | New Issue | |
2012-10-26 18:02 |
|
Note Added: 0004719 | |
2012-10-27 13:26 | the_nic | Note Added: 0004727 | |
2012-10-29 05:40 | sim | Note Added: 0004731 | |
2012-10-30 16:27 | the_nic | Note Added: 0004750 | |
2012-10-31 00:37 | sim | Note Added: 0004759 | |
2012-10-31 12:38 | the_nic | File Added: 0001-NString-Crypto-fix-encryption-with-schemes-having-an.patch | |
2012-10-31 12:38 | the_nic | File Added: 0002-SQLSource-LDAPSource-do-not-write-a-password-when-th.patch | |
2012-10-31 12:40 | the_nic | Note Added: 0004762 | |
2012-10-31 12:43 | the_nic | Note Edited: 0004762 | |
2012-10-31 12:46 | ludovic | Target Version | => 2.0.3 |
2012-11-06 14:05 | ludovic | Note Added: 0004781 | |
2012-11-06 14:05 | ludovic | Status | new => closed |
2012-11-06 14:05 | ludovic | Resolution | open => fixed |
2012-11-06 14:05 | ludovic | Fixed in Version | => 2.0.3 |
2012-11-15 17:18 | francis | Fixed in Version | 2.0.3 => 2.0.2a |
2012-11-15 17:18 | francis | Target Version | 2.0.3 => 2.0.2a |