diff options
author | Andrew Dunstan <andrew@dunslane.net> | 2021-03-29 15:31:22 -0400 |
---|---|---|
committer | Andrew Dunstan <andrew@dunslane.net> | 2021-03-29 15:49:39 -0400 |
commit | 6d7a6feac48b1970c4cd127ee65d4c487acbb5e9 (patch) | |
tree | 8728162431269b3ae654eddb1d3a8e1c99972ec3 /src/backend/libpq/auth.c | |
parent | efcc7572f532ea564fedc6359c2df43045ee7908 (diff) | |
download | postgresql-6d7a6feac48b1970c4cd127ee65d4c487acbb5e9.tar.gz postgresql-6d7a6feac48b1970c4cd127ee65d4c487acbb5e9.zip |
Allow matching the DN of a client certificate for authentication
Currently we only recognize the Common Name (CN) of a certificate's
subject to be matched against the user name. Thus certificates with
subjects '/OU=eng/CN=fred' and '/OU=sales/CN=fred' will have the same
connection rights. This patch provides an option to match the whole
Distinguished Name (DN) instead of just the CN. On any hba line using
client certificate identity, there is an option 'clientname' which can
have values of 'DN' or 'CN'. The default is 'CN', the current procedure.
The DN is matched against the RFC2253 formatted DN, which looks like
'CN=fred,OU=eng'.
This facility of probably best used in conjunction with an ident map.
Discussion: https://postgr.es/m/92e70110-9273-d93c-5913-0bccb6562740@dunslane.net
Reviewed-By: Michael Paquier, Daniel Gustafsson, Jacob Champion
Diffstat (limited to 'src/backend/libpq/auth.c')
-rw-r--r-- | src/backend/libpq/auth.c | 34 |
1 files changed, 27 insertions, 7 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 994251e7d9d..9dc28e19aaf 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -2800,12 +2800,23 @@ static int CheckCertAuth(Port *port) { int status_check_usermap = STATUS_ERROR; + char *peer_username = NULL; Assert(port->ssl); + /* select the correct field to compare */ + switch (port->hba->clientcertname) + { + case clientCertDN: + peer_username = port->peer_dn; + break; + case clientCertCN: + peer_username = port->peer_cn; + } + /* Make sure we have received a username in the certificate */ - if (port->peer_cn == NULL || - strlen(port->peer_cn) <= 0) + if (peer_username == NULL || + strlen(peer_username) <= 0) { ereport(LOG, (errmsg("certificate authentication failed for user \"%s\": client certificate contains no user name", @@ -2813,8 +2824,8 @@ CheckCertAuth(Port *port) return STATUS_ERROR; } - /* Just pass the certificate cn to the usermap check */ - status_check_usermap = check_usermap(port->hba->usermap, port->user_name, port->peer_cn, false); + /* Just pass the certificate cn/dn to the usermap check */ + status_check_usermap = check_usermap(port->hba->usermap, port->user_name, peer_username, false); if (status_check_usermap != STATUS_OK) { /* @@ -2824,9 +2835,18 @@ CheckCertAuth(Port *port) */ if (port->hba->clientcert == clientCertFull && port->hba->auth_method != uaCert) { - ereport(LOG, - (errmsg("certificate validation (clientcert=verify-full) failed for user \"%s\": CN mismatch", - port->user_name))); + switch (port->hba->clientcertname) + { + case clientCertDN: + ereport(LOG, + (errmsg("certificate validation (clientcert=verify-full) failed for user \"%s\": DN mismatch", + port->user_name))); + break; + case clientCertCN: + ereport(LOG, + (errmsg("certificate validation (clientcert=verify-full) failed for user \"%s\": CN mismatch", + port->user_name))); + } } } return status_check_usermap; |