Hello, Yes, with saml2 or cas, sogo still need a user source as the sso will only be used to validate and fetch the mail of the user but for all the rest, like the cn, it needs a ldap or sql user source.
So, everything is working now, or you still have issues? May I ask how you configured your imap server? Quentin -----Original Message----- From: [email protected] <[email protected]> On Behalf Of Anton Hvornum Sent: samedi 10 août 2024 20:38 To: [email protected] Subject: Re: [SOGo] SOGo with SAML2 against KeyCloak 23+ causes "Tried to add nil value for key 'login' to dictionary INFO" On 8/10/24 18:20, Anton Hvornum wrote: > 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 > So the LASSO_DS_ERROR_CA_CERT_CHAIN_LOAD_FAILED appears to happen because the extracted certificate and public key from KeyCloak does not contain: -----BEGIN PRIVATE KEY----- and not -----BEGIN PUBLIC KEY----- And the HTTP authentication appears to be a faulty apache configuration taken from the example conf. But SOGo will not function without a SOGoUserSources alongside the SAML2 login for (to me) unknown reasons. Apologies for the noise, but debugging the SAML stuff was not easy and I was hoping someone else had bumped into similar issues. Thanks for Jeroen in a previous mail thread: https://www.mail-archive.com/[email protected]/msg29861.html It really helped out with the mappers as well as where to get the RSA keys from. //Anton
