Setting up Dovecot and Roundcube with Azure Active Directory B2C

This post explains how to configure Roundcube that connects to Dovecot to fetch mails letting the user authenticate against an Azure Active Directory B2C.

Nice diagram

Azure AD

App registration

First of all let's register a new app in AAD App registrations:
app registration

Change the domain of the redirect uri to the domain of your Roundcube installation.

Now let's create an OAuth client secret for Roundcube. Go to Certificates and secrets for the App we just registered, and create a new secret.
Certs and secrets

Save this secret for later, we will need it when configuring Roundcube.

Sign in/up flow

Now let's configure the Sign in/up flow, so users can log in. But first we need to add a custom attribute for our users, that will hold the Dovecot username for login.
Custom attr

How to populate this user attribute is left as exercise for the reader (use API connectors).

And now create a new flow. Call it something you like (mine is called B2C_1_SignUpIn), and add the attribute as claim for Roundcube:
Flow

We are done here. Next up is Roundcube.

Roundcube

Download and install it (at the time of writing the actual version is 1.6.0, and I tested everything with this version), and following this wiki page, we can configure OAuth.

We just have to add some parameters in roundcube/config/config.inc.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// ----------------------------------
// OAuth
// ----------------------------------

// Enable OAuth2 by defining a provider. Use 'generic' here
$config['oauth_provider'] = 'generic';

// Provider name to be displayed on the login button
$config['oauth_provider_name'] = 'Simons mail server';

// Mandatory: OAuth client ID for your Roundcube installation
$config['oauth_client_id'] = '<App registration client id>';

// Mandatory: OAuth client secret
$config['oauth_client_secret'] = '<client secret>';

// Mandatory: URI for OAuth user authentication (redirect)
$config['oauth_auth_uri'] = 'https://<yourB2Cdomain>.b2clogin.com/<yourB2Cdomain>.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_SignUpIn';

// Mandatory: Endpoint for OAuth authentication requests (server-to-server)
$config['oauth_token_uri'] = 'https://<yourB2Cdomain>.b2clogin.com/<yourB2Cdomain>.onmicrosoft.com/B2C_1_SignUpIn/oauth2/v2.0/token';

// Optional: Endpoint to query user identity if not provided in auth response
$config['oauth_identity_uri'] = null;

// Optional: disable SSL certificate check on HTTP requests to OAuth server
// See http://docs.guzzlephp.org/en/stable/request-options.html#verify for possible values
$config['oauth_verify_peer'] = true;

// Mandatory: OAuth scopes to request (space-separated string)
$config['oauth_scope'] = '<App registration client id> openid';

// Optional: additional query parameters to send with login request (hash array)
$config['oauth_auth_parameters'] = ['nonce' => mt_rand()];

// Optional: array of field names used to resolve the username within the identity information
$config['oauth_identity_fields'] = ['extension_PreferredLoginUsername'];

// Boolean: automatically redirect to Auth login when opening Roundcube without a valid session
$config['oauth_login_redirect'] = true;

That's it for Roundcube.

Dovecot

Dovecot docs are here. We need to configure conf.d/10-auth.conf like this:

1
2
3
4
5
6
7
auth_mechanisms = plain oauthbearer xoauth2

passdb {
driver = oauth2
mechanisms = xoauth2 oauthbearer
args = /etc/dovecot/dovecot-oauth2.conf.ext
}

and /etc/dovecot/dovecot-oauth2.conf.ext like this:

1
2
3
4
5
tokeninfo_url = https://<yourB2Cdomain>.b2clogin.com/<yourB2Cdomain>.onmicrosoft.com/b2c_1_signupin/oauth2/v2.0/token?token=
introspection_mode = local
openid_configuration_url = https://<yourB2Cdomain>.b2clogin.com/<yourB2Cdomain>.onmicrosoft.com/B2C_1_SignUpIn/v2.0/.well-known/openid-configuration
local_validation_key_dict = fs:posix:prefix=/etc/dovecot/keys/
username_attribute = extension_PreferredLoginUsername

Now we need to populate /etc/dovecot/keys/ with the keys from our OAuth provider (AAD). Go to https://<yourB2Cdomain>.b2clogin.com/<yourB2Cdomain>.onmicrosoft.com/b2c_1_signupin/discovery/v2.0/keys, and copy the keys key. It's something like this:

1
{"kid":"X5eXk4xyo...aNk","nbf":1493763266,"use":"sig","kty":"RSA","e":"AQAB","n":"tVKUtcx_...Xw"}

Create a file /etc/dovecot/keys/<App registration client id>/RS256/<kid> and put the key you copied above in that file.

The end

Restart Apache/Nginx, restard Dovecot, and try to log in. Everything should work.

Nice.

Bye.

avatar

Simons stuff