On 8/10/24 12:09, Anton Hvornum wrote:
On 8/10/24 02:27, Anton Hvornum wrote:
On 8/9/24 22:59, Anton Hvornum ([email protected]) wrote:
I've attempted to get SAML login working using the following guide:
https://bluntlab.space/posts/sogo-saml-keycloak/
Currently I'm running apache, memcached, sogo and postgresql in a
docker compose environment while keycloak, postfix and dovecot are
running externally.
This is an excerpt from sogo.conf:
SOGoCacheCleanupInterval = 3600;
SOGoAuthenticationType = saml2;
NGImap4AuthMechanism = SAML;
SOGoSAML2IdpMetadataLocation = "/etc/sogo/idp-metadata.xml";
SOGoSAML2PrivateKeyLocation = "/etc/sogo/saml.privkey.pem";
SOGoSAML2CertificateLocation = "/etc/sogo/saml.cert.pem"; //
SOGoSAML2IdpPublicKeyLocation = "/etc/sogo/idp.key"; //
SOGoSAML2IdpCertificateLocation = "/etc/sogo/idp.crt";
SOGoSAML2LoginAttribute = "username"; SOGoSAML2LogoutEnabled = YES;
SOGoSAML2LogoutURL = "https://sogo.domain.com";
When visiting https://sogo.domain.com/SOGo i get redirected to the
keycloak realm SSO prompt, credentials are accepted and it
redirects me back to what I configured in KeyCloak to be "Assertion
Consumer Service POST Binding URL":
https://sogo.domain.com:443/SOGo/saml2-signon-post
But once there, I keep hitting:
```
sogod [11]: 192.168.0.10 "GET /SOGo HTTP/1.1" 302 0/0 0.002 - - 0 -
11 sogod [11]: |SOGo| starting method 'POST' on uri
'/SOGo/saml2-signon-post'
sogod [11]: |SOGo| traverse(acquire): SOGo => saml2-signon-post
sogod [11]: |SOGo| do traverse name: 'SOGo'
sogod [11]: |SOGo| do traverse name: 'saml2-signon-post'
sogod [11]: |SOGo| set clientObject: <SOGo[0x0x5a13bcaa3e80]:
name=SOGo>
sogod[11:11] EXCEPTION: <NSException: 0x5a13bcc7dd10>
NAME:NSInvalidArgumentException REASON:Tried to add nil value for
key 'login' to dictionary INFO:{}
```
Any idea why SOGo (or is it a library like lasso) would generate
"Tried to add nil value for key 'login' to dictionary INFO:{}"?
//Anton
From my limited ability to debug Objective-C, it appears that the
error is caused by:
https://github.com/Alinto/sogo/blob/b602b2b188ce6c331875450c6b1dbe48
240f4ff7/UI/MainUI/SOGoSAML2Actions.m#L176
```
newSession = [SOGoSAML2Session SAML2SessionInContext: context];
[newSession processAuthnResponse: [rq formValueForKey:
@"SAMLResponse"]];
login = [newSession login];
```
Where `[newSession login]` is `nil`?
My next obsession is going to be guessing what could be missing in
the SAML response from keycloak. Here's the post-back data from
keycloak: https://0x0.st/XWZs.txt
//Anton
I also keep getting:
```
(process:907): Lasso-CRITICAL **: 11:28:20.078: 2024-08-10 11:28:20
(profile.c/:913) Trying to unref a non GObject pointer
file=profile.c:913 pointerbybname=profile->identity
pointer=0x5f5b99c00e40 (process:907): Lasso-CRITICAL **:
11:28:20.078: 2024-08-10 11:28:20 (profile.c/:916) Trying to unref a
non GObject pointer file=profile.c:916
pointerbybname=profile->session pointer=0x5f5b99cb6ae0 ```
And in a production container I get coredump:ed:
```
2024-08-10 12:05:10.867 sogod[34:34] PG0x0x5e19c98edae0 SQL: COMMIT
TRANSACTION
(process:34): Lasso-CRITICAL **: 12:05:10.886: 2024-08-10 12:05:10
(profile.c/:913) Trying to unref a non GObject pointer
file=profile.c:913 pointerbybname=profile->identity
pointer=0x5e19ca0f5d90
2024-08-10 12:05:11.077 sogod[28:28] INFO(-[NGActiveSocket isAlive])
poll(): fd=7 revents=0x0011)
Aug 10 12:05:11 sogod [28]: <0x0x5e19c9ccd250[WOWatchDogChild]> child
34 exited
Aug 10 12:05:11 sogod [28]: <0x0x5e19c9ccd250[WOWatchDogChild]>
(terminated due to signal 11, coredump) ```
Which according to some bug reports should already be handled:
- https://bugs.sogo.nu//view.php?id=5153
- https://bugs.sogo.nu/view.php?id=5270
- https://bugs.sogo.nu/view.php?id=5153
The exception appears to happen only to the two keys in `lassoLogin`
that has been "dumped" or loaded by a string:
https://github.com/Alinto/sogo/blob/b602b2b188ce6c331875450c6b1dbe482
40f4ff7/SoObjects/SOGo/SOGoSAML2Session.m#L354-L362
And while debugging, with my limited knowledge, it looks like I get a
segfault right after the response is being sent.
```
gdb \
-ex 'set breakpoint pending on' \
-ex 'break SOGoSAML2Actions.m:174' \
-ex 'run' \
--args /usr/bin/sogod -WOUseWatchDog NO -SOGoDebugRequests YES
-WONoDetach YES -WOPort 0.0.0.0:20000 -WOWorkersCount 1 -WOLogFile -
-WOPidFile /tmp/sogo.pid ```
Generates:
```
Aug 10 11:57:30 sogod [271]: |SOGo| WOHttpAdaptor listening on
address 0.0.0.0:20000 Aug 10 11:57:31 sogod [271]: |SOGo| starting
method 'POST' on uri '/SOGo/saml2-signon-post'
Aug 10 11:57:31 sogod [271]: <0x0x582dab9c4650[SOGoCache]> Cache
cleanup interval set every 3600.000000 seconds Aug 10 11:57:31 sogod
[271]: <0x0x582dab9c4650[SOGoCache]> Using
host(s) 'memcached:11211' as server(s) Aug 10 11:57:31 sogod [271]:
|SOGo| traverse(acquire): SOGo => saml2-signon-post Aug 10 11:57:31
sogod [271]: |SOGo| do traverse name: 'SOGo'
Aug 10 11:57:31 sogod [271]: |SOGo| do traverse name:
'saml2-signon-post'
Aug 10 11:57:31 sogod [271]: |SOGo| set clientObject:
<SOGo[0x0x582dab9cb550]: name=SOGo>
Breakpoint 1, -[SOGoSAML2Actions saml2SignOnPOSTAction]
(self=0x582dabbea890, _cmd=0x582dabb12e90) at
/usr/src/debug/sogo/SOGo-5.10.0/UI/MainUI/SOGoSAML2Actions.m:174
174 newSession = [SOGoSAML2Session SAML2SessionInContext:
context];
(gdb) next
175 [newSession processAuthnResponse: [rq formValueForKey:
@"SAMLResponse"]];
176 login = [newSession login];
178 application = [SoApplication application];
179 auth = [application authenticatorInContext: context];
182 inContext: context];
181 andPassword: [newSession
identifier]
182 inContext: context];
2024-08-10 11:57:42.261 sogod[271:271] PostgreSQL72 connection
established: <0x0x582dabcc6000[PGConnection]:
connection=0x0x582dabcb4c30>
2024-08-10 11:57:42.261 sogod[271:271] PostgreSQL72 channel
0x0x582dabcb8840 opened (connection=<0x0x582dabcc6000[PGConnection]:
connection=0x0x582dabcb4c30>, count=2)
2024-08-10 11:57:42.262 sogod[271:271] PG0x0x582dabcb8840 SQL: BEGIN
TRANSACTION
2024-08-10 11:57:42.262 sogod[271:271] PG0x0x582dabcb8840 SQL: SELECT
t1.c_creationdate, t1.c_id, t1.c_lastseen, t1.c_value FROM
sogo_sessions_folder t1 WHERE t1.c_id='Gq...+62v'
2024-08-10 11:57:42.263 sogod[271:271] PG0x0x582dabcb8840 SQL:
ROLLBACK TRANSACTION
2024-08-10 11:57:42.263 sogod[271:271] PG0x0x582dab5d4ae0 SQL: BEGIN
TRANSACTION
2024-08-10 11:57:42.263 sogod[271:271] PG0x0x582dab5d4ae0 SQL: INSERT
INTO sogo_sessions_folder (c_lastseen, c_creationdate, c_value, c_id)
VALUES (1723283862, 1723283862, '91R...EmI', 'Gq...+62v')
2024-08-10 11:57:42.264 sogod[271:271] PG0x0x582dab5d4ae0 SQL: COMMIT
TRANSACTION
185 creds = [auth parseCredentials: [authCookie value]];
187 value: [[SOGoSession
valueForSessionKey: [creds lastObject]] asSHA1String]];
188 [xsrfCookie setPath: [NSString stringWithFormat:
@"/%@/", [[context request] applicationName]]];
189 [response addCookie: xsrfCookie];
191 oldLocation = [[context clientObject] baseURLInContext:
context];
193 oldLocation, [login
stringByEscapingURL]];
195 [response setStatus: 302];
196 [response setHeader: newLocation forKey: @"location"];
197 [response addCookie: authCookie];
205 return response;
206 }
-[SoActionInvocation
callOnObject:withPositionalParametersWhenNotNil:inContext:]
(self=<optimized out>, _cmd=<optimized out>, _client=<optimized out>,
_positionalArgs=0x0, _ctx=0x582dab9d1b90)
at SoObjects/SoActionInvocation.m:310
310 result = [result retain];
311 [method release]; method = nil;
312 return [result autorelease];
0x00007e26c476bb40 in ?? () from /usr/lib/libgnustep-base.so.1.29
Cannot find bounds of current function Cannot find bounds of current
function Cannot find bounds of current function
(gdb) c
Continuing.
(process:271): Lasso-CRITICAL **: 11:57:50.259: 2024-08-10 11:57:50
(profile.c/:913) Trying to unref a non GObject pointer
file=profile.c:913 pointerbybname=profile->identity
pointer=0x582dabcb4de0
Program received signal SIGSEGV, Segmentation fault.
0x00007e26c3fb1f81 in g_type_check_instance_is_fundamentally_a ()
from /usr/lib/libgobject-2.0.so.0 ```
Any guidance or assistance here would be greatly appreciated as I'm
way out in deep water.
My two main concerns are:
- What's missing from KeyCloak or what fields/data are wrong in the
SAML2 response that could cause this
- How do I patch the lassoLogin data to not cause coredump/critical
errors
//Anton
Continuing on to debug this, it appears that:
On a good run (before auth is done), de-allocation in lasso looks like:
```
912 lasso_mem_debug("LassoProfile", "Identity",
profile->identity);
(gdb) print profile->identity
$2 = (LassoIdentity *) 0x0
freeing LassoProfile/Identity (at (nil))
913 lasso_release_gobject(profile->identity);
```
On a bad run, it looks like this:
```
912 lasso_mem_debug("LassoProfile", "Identity",
profile->identity);
(gdb) print profile->identity
$4 = (LassoIdentity *) 0x614290dbbc10
freeing LassoProfile/Identity (at 0x614290dbbc10)
913 lasso_release_gobject(profile->identity);
Program received signal SIGSEGV, Segmentation fault.
```
Either way, it appears to hit after the request is sent to the user so
it shouldn't matter for debugging what's missing between SOGo and
KeyCloak SAML2 response.
But it appears that SOGo treats my SAML2 user as anonymous or
non-existant:
```
if (!user || [[user login] isEqualToString: @"anonymous"]) ```
However when adding in authentication using SQL:
https://www.sogo.nu/files/docs/SOGoInstallationGuide.html#Authenticati
on-using-SQL I got a bit further but had to manually manipulate the
url from https://sogo.domain.com//anton to
https://sogo.domain.com/so/anton
As if it didn't really get that it should redirect to `/so/anton`.
Which got me thinking, that something was wrong with an attribute
somewhere.
It looks like changing mapper type from "User Attribute" to "User
Property" for email and username gets me further.
So I tried removing SQL Auth source, which caused the user to not be
able to login again.
But adding back in SQL authentication causes the `/so/<user>` URL to
present a HTTP status code causing a plain HTTP login window:
```
SOGoUserSources =
(
{
type = sql;
id = vmail_mailbox;
viewURL = "postgresql://sogo:sogo@sogo_db:5432/sogo/users";
canAuthenticate = YES;
isAddressBook = YES;
userPasswordAlgorithm = md5;
prependPasswordScheme = YES;
displayName = "Global Address Book";
}
);
```
psql -U sogo sogo -c "CREATE TABLE IF NOT EXISTS users (c_uid
VARCHAR(255), c_name VARCHAR(255), c_password VARCHAR(255), c_cn
VARCHAR(255), mail VARCHAR(255))"
psql -U sogo sogo -c "INSERT INTO users (c_uid, c_name, c_password,
c_cn, mail) VALUES ('anton', 'anton',
'098f6bcd4621d373cade4e832627b4f6', 'anton', '[email protected]')"
Resetting everything to make sure I didn't do more mistakes while
debugging, I now hit: LASSO_DS_ERROR_CA_CERT_CHAIN_LOAD_FAILED
Sorry for the noise but the SAML2 docs are slightly limited and I have
no idea how to properly interpret these debug messages.
//Anton