I preface this blog post with a warning. None of this is production ready. Purely a proof of concept that works using bad practices to work around some limitations of SAML for a webmail client

With Microsoft's impending EOL date for Microsoft Exchange 2019 and frankly no effort being put into Windows 11 my goals have shifted for 2024. Migrating to linux both on servers and workstations.

Not an easy task. Linux enterprise deployments are not well documented at times. But so far I have successfully setup

I fully expect some future blog posts maybe even videos about more of these topics. But for now I want to focus on the email. How do we replicate Microsoft Exchange functionality?

Why SOGo?

One of the best features of Microsoft Exchange. the thing that kept me using it from version 2010 all the way until 2019 was ActiveSync. It's makes email setup on mobile devices very simple. Without exposing IMAP to the world. Personally I feel that makes it more secure. But if I need to expose a web service for calendar/contact sync I might as well do the email itself.

As far as I am aware SOGo is the only up to date implementation of ActiveSync on linux. It's also just a very nice modern webmail client even if its full of odd choices. Like being forced to use the (domain)/SOGo/ URL because that is hard coded in many files... Would of preferred to not have that messy URL but whatever.

What do we need first?

I am not going to talk you through setting up SOGo or an email server from scratch here. This is merely info to help others out as SOGo is honestly borderline undocumented for many aspects. Especially SAML

I will assume the following though

Part 1: Keycloak setup

Before we even go near SOGo we need to configure a Keycloak client for SOGo

So simply make a new SAML client. Important The client ID has to be quite exact for me its http://sogo.bluntlab.int/SOGo/saml2-metadata

Notice the http I assume that for some reason SOGo is not seeing my proxy setup as being SSL so its SAML client ID is also http If your proxy setup is correct this might be https. You will quickly find out if your client ID is wrong when you never even get a login prompt.

Keycloak client ID

On the next page we simply set the Valid Redirect URI's to https://sogo.bluntlab.int/SOGo/* You can probably make this a bit more precise but for our example a lovely little wildcard will suffice.

The default settings however will not work. SOGo is fussy and expects signed assertions so enable that next

Keycloak assertion signing

I personally disabled client signing under the keys tab. Purely because I had enough issues setting this up. Keycloak likes to generate its own client keys that I struggled to get working with SOGo. I made my own keys with OpenSSL but could not import them into Keycloak because my private key was not password protected :| Keycloak makes this way harder than it needs to be. It does not need the private key oh well Maybe this is me being dumb.

Do not do this in production. While probably not a high risk it does mean that anyone can pretend to be your SAML client as long as they can get a valid SSL certificate

Keycloak client signing

Next step go to the client scopes tab. The is a default entry named after the client ID. click through to that and then simply add a basic mapper for email and username. SOGo will use LDAP to look up other user attributes like full name.

Keycloak attribute mapping

Final step on the advanced tab simply fill out the binding URL's For me this was https://sogo.bluntlab.int/SOGo/saml2-signon-post and https://sogo.bluntlab.int/SOGo/saml2-sls

Keycloak binding URL's

SOGo Configuration

SOGo is great. Unfortunately its not well documented in some large areas. Hope you enjoy reading variables and trying to decipher what that does.

SOGo Documentation at its finest

Yes the entire section on SAML literaly just says look at the config variables and figure it out yourself. No examples. No explanation given.

SOGo Variables we care about

The are multiple problems here. And the issue is made worse if you google SOGo SAML configuration. Multiple forum threads with examples that simply will never work. First of all you do not need to configure all of these. and some of them have super vague names

For example SOGoSAML2IdpCertificateLocation is not for setting the public key of your IDP but actually to set the CA certificate to verify the actual public key... Yet the documentation does not explain this. I spent ages on this struggling with CA validation errors.

Here's my valid config

  SOGoSAML2PrivateKeyLocation = /etc/sogo/saml.key;
  SOGoSAML2CertificateLocation = /etc/sogo/saml.crt;
  SOGoSAML2IdpMetadataLocation = /etc/sogo/idp.xml;
  SOGoSAML2LoginAttribute = "username";
  //SOGoSAML2IdpPublicKeyLocation = /etc/sogo/idp.crt; Not using as we specify the metadata above
  //SOGoSAML2IdpCertificateLocation = /etc/sogo/idp.crt; This is actually CA cert and in 99% of cases will not be used
  SOGoSAML2LogoutEnabled = YES;
  SOGoSAML2LogoutURL = https://sogo.bluntlab.int;
  SOGoAuthenticationType = saml2;

Of course you should generate a self signed certificate for the client with the following command

openssl req -x509 -nodes -sha256 -days 3650 -newkey rsa:2048 -keyout saml.key -out saml.crt

ideally the public key should be imported to Keycloak too so you can enable client signing verification.

And there we go SSO configured. Try and login. with any luck you will get a login prompt. But logging in will likely get an infinite redirect loop. Why is this you ask?

SOGo redirecting forever

The solution was quite simple actually. in the SOGo logs it mentions memcached being down... Well its a dependency of SOGo but funny enough most install guides do not mention this. It is installed but the service is not started. systemctl enable --now memcached sorts this one out. Funny enough SOGo seems to work fine without memcached until you enable SAML hence so many guides lacking this setup step.

Another problem solved. should be a slam dunk now. lets try logging in again. No redirects this time... but its taking a while to load.

SOGo with no mailboxes

And yet another problem. It worked pre SAML but now we dont get any mailboxes. Why is this. The SOGo logs actually help for the first time since starting this.

sogod [6468]: [ERROR] <0x0x564fafb27910[NGImap4ConnectionManager]> IMAP4 login failed:
  host=localhost, user=char, pwd=yes

This makes perfect sense. Our IMAP service (dovecot) is using LDAP and wants a plain text password. Well now SOGo no longer has the plain text password. It has SAML tokens that dovecot simply cant do anything with. How the feck do we fix this then?

As far as I know the are 3 solutions

At this point after many hours just getting here and the discovering this I was not super happy. CrudeSAML seems fine but its also not compiled in a repo that I could find. The second the build tools are mentioned I start finding the shortcuts.

It's not that I did not try though. But when you have ZERO documentation on some SAML plugin that I had to figure out how to compile myself it is no wonder that it failed to work. SOGo devs should be ashamed that they have not put ANY effort into documentation even if this is a 3rd party thing. Plus Dovecots hatred of SASL means the only module that would work is PAM and PAM is junk. I wasted hours here.

I also tried pam-script-saml but its PHP... and hates Keycloak. and also has no documentation or debugging. Last updated 4 years ago. Yeah I think I will pass

This is the 2nd dodgy thing I have done. Please figure out SAML authentication in a production setup as this is super dodgy. Ultimately if this server is only serving mail/SOGo its not super bad as anyone that can be "localhost" likely has a command line and file access so "passwords" mean nothing. But this is a warning

To do this you need an entry like this in your dovecot config

passdb {
        driver = static
        args = allow_real_nets=127.0.0.1/32,::1 nopassword=n
}

This adds a password check for localhosts... that simply ignores the password and goes yep your who you say you are.

SOGo devs please add more detail on setting up SAML with something like dovecot so we can actually have proper security. I should not have to disable authentication for localhost even if it's dovecot that the issue here.

With this bodge lets try again.

SOGo logged in

Now some of you are screaming. Yes this is working but it is only half the email stack. We cant send emails with dovecot. We need to involve a MTA like postfix or sendmail.

Thankfully the is a simple solution for this problem. Simply disable auth. SOGo allows this. just comment out SOGoSMTPAuthenticationType in sogo.conf. Then configure your MTA of choice like above. for postfix this is setting up mynetworks. I wont go into detail on this really.

Or you can just use sendmail with sogo. but I chose postfix as I was using it already and had DKIM configured.

Remember that this can allow localhost to send as anyone as reject_sender_login_mismatch only works if your actually authenticated. But this is fairly common. And SOGo seems to limit it anyway. I can select from all the addresses setup in LDAP. Not sure how this works if you use other LDAP variables besides "mail" but good enough for my needs.

SOGo logged in

You reached the end, well done :D

Comments