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
- FreeIPA Domain
- Keycloak SSO
- A postfix & dovecot email server that uses LDAP with the FreeIPA
- Semaphore UI with Ansible
- Some test clients being deployed with Ansilble
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
- You are using Postfix and Dovecot with LDAP auth setup
- You have managed to get SOGo working with LDAP auth against your Postfix/Dovecot setup
- You have Keycloak setup on a SSL domain and have some knowledge of configuring SAML
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.
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
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.
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.
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
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.
Yes the entire section on SAML literaly just says look at the config variables and figure it out yourself. No examples. No explanation given.
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?
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.
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
- Configure dovecot with the CrudeSAML SASL plugin
- Configure PAM with the CrudeSAML PAM plugin
- Yolo it and disable password auth for localhost
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
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.
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.