Add support for using SSL client certificates to authenticate to the

database (only for SSL connections, obviously).
This commit is contained in:
Magnus Hagander 2008-11-20 11:48:26 +00:00
parent 3c486fbd1c
commit f179d5ea99
6 changed files with 120 additions and 14 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.111 2008/11/18 13:10:20 petere Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.112 2008/11/20 11:48:26 mha Exp $ -->
<chapter id="client-authentication">
<title>Client Authentication</title>
@ -387,6 +387,16 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>cert</></term>
<listitem>
<para>
Authenticate using SSL client certificates. See
<xref linkend="auth-cert"> for details.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>pam</></term>
<listitem>
@ -1114,6 +1124,25 @@ ldapserver=ldap.example.net prefix="cn=" suffix="dc=example, dc=net"
</sect2>
<sect2 id="auth-cert">
<title>Certificate authentication</title>
<indexterm zone="auth-cert">
<primary>Certificate</primary>
</indexterm>
<para>
This authentication method uses SSL client certificates to perform
authentication. It is therefore only available for SSL connections.
When using this authentication method, the server will require that
the client provide a certificate. No password prompt will be sent
to the client. The <literal>cn</literal> attribute of the certificate
will be matched with the username the user is trying to log in as,
and if they match the login will be allowed. Username mapping can be
used if the usernames don't match.
</para>
</sect2>
<sect2 id="auth-pam">
<title>PAM authentication</title>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.421 2008/11/20 09:29:35 mha Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.422 2008/11/20 11:48:26 mha Exp $ -->
<chapter Id="runtime">
<title>Operating System Environment</title>
@ -1674,11 +1674,9 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput
</para>
<para>
<productname>PostgreSQL</> currently does not support authentication
using client certificates, since it cannot differentiate between
different users. As long as the user holds any certificate issued
by a trusted CA it will be accepted, regardless of what account the
user is trying to connect with.
You can use the authentication method <literal>cert</> to use the
client certificate for authenticating users. See
<xref linkend="auth-cert"> for details.
</para>
</sect2>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.172 2008/11/20 09:29:36 mha Exp $
* $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.173 2008/11/20 11:48:26 mha Exp $
*
*-------------------------------------------------------------------------
*/
@ -113,6 +113,14 @@ ULONG(*__ldap_start_tls_sA) (
static int CheckLDAPAuth(Port *port);
#endif /* USE_LDAP */
/*----------------------------------------------------------------
* Cert authentication
*----------------------------------------------------------------
*/
#ifdef USE_SSL
static int CheckCertAuth(Port *port);
#endif
/*----------------------------------------------------------------
* Kerberos and GSSAPI GUCs
@ -431,6 +439,14 @@ ClientAuthentication(Port *port)
#endif
break;
case uaCert:
#ifdef USE_SSL
status = CheckCertAuth(port);
#else
Assert(false);
#endif
break;
case uaTrust:
status = STATUS_OK;
break;
@ -2120,3 +2136,28 @@ CheckLDAPAuth(Port *port)
}
#endif /* USE_LDAP */
/*----------------------------------------------------------------
* SSL client certificate authentication
*----------------------------------------------------------------
*/
#ifdef USE_SSL
static int
CheckCertAuth(Port *port)
{
Assert(port->ssl);
/* Make sure we have received a username in the certificate */
if (port->peer_cn == NULL ||
strlen(port->peer_cn) <= 0)
{
ereport(LOG,
(errmsg("Certificate login failed for user \"%s\": client certificate contains no username",
port->user_name)));
return STATUS_ERROR;
}
/* Just pass the certificate CN to the usermap check */
return check_usermap(port->hba->usermap, port->user_name, port->peer_cn, false);
}
#endif

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.173 2008/11/20 09:29:36 mha Exp $
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.174 2008/11/20 11:48:26 mha Exp $
*
*-------------------------------------------------------------------------
*/
@ -858,6 +858,12 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
parsedline->auth_method = uaLDAP;
#else
unsupauth = "ldap";
#endif
else if (strcmp(token, "cert") == 0)
#ifdef USE_SSL
parsedline->auth_method = uaCert;
#else
unsupauth = "cert";
#endif
else
{
@ -893,6 +899,17 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
return false;
}
if (parsedline->conntype != ctHostSSL &&
parsedline->auth_method == uaCert)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("cert authentication is only supported on hostssl connections"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
/* Parse remaining arguments */
while ((line_item = lnext(line_item)) != NULL)
{
@ -923,8 +940,9 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
if (parsedline->auth_method != uaIdent &&
parsedline->auth_method != uaKrb5 &&
parsedline->auth_method != uaGSS &&
parsedline->auth_method != uaSSPI)
INVALID_AUTH_OPTION("map", "ident, krb5, gssapi and sspi");
parsedline->auth_method != uaSSPI &&
parsedline->auth_method != uaCert)
INVALID_AUTH_OPTION("map", "ident, krb5, gssapi, sspi and cert");
parsedline->usermap = pstrdup(c);
}
else if (strcmp(token, "clientcert") == 0)
@ -957,7 +975,18 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
parsedline->clientcert = true;
}
else
{
if (parsedline->auth_method == uaCert)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
parsedline->clientcert = false;
}
}
else if (strcmp(token, "pamservice") == 0)
{
@ -1021,6 +1050,14 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
{
MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
}
/*
* Enforce any parameters implied by other settings.
*/
if (parsedline->auth_method == uaCert)
{
parsedline->clientcert = true;
}
return true;
}

View File

@ -35,7 +35,7 @@
# an IP address and netmask in separate columns to specify the set of hosts.
#
# METHOD can be "trust", "reject", "md5", "crypt", "password", "gss", "sspi",
# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords
# "krb5", "ident", "pam", "ldap" or "cert". Note that "password" sends passwords
# in clear text; "md5" is preferred since it sends encrypted passwords.
#
# OPTIONS are a set of options for the authentication in the format

View File

@ -4,7 +4,7 @@
* Interface to hba.c
*
*
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.52 2008/11/20 09:29:36 mha Exp $
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.53 2008/11/20 11:48:26 mha Exp $
*
*-------------------------------------------------------------------------
*/
@ -26,7 +26,8 @@ typedef enum UserAuth
uaGSS,
uaSSPI,
uaPAM,
uaLDAP
uaLDAP,
uaCert
} UserAuth;
typedef enum ConnType