aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMagnus Hagander <magnus@hagander.net>2008-11-20 11:48:26 +0000
committerMagnus Hagander <magnus@hagander.net>2008-11-20 11:48:26 +0000
commitf179d5ea99b4598689e5aefed376874b68110978 (patch)
treef3af4e57ce35be33afe3839c9341f81c7c7367e3
parent3c486fbd1c8e8f79902a40ef929c4ed54f122561 (diff)
downloadpostgresql-f179d5ea99b4598689e5aefed376874b68110978.tar.gz
postgresql-f179d5ea99b4598689e5aefed376874b68110978.zip
Add support for using SSL client certificates to authenticate to the
database (only for SSL connections, obviously).
-rw-r--r--doc/src/sgml/client-auth.sgml31
-rw-r--r--doc/src/sgml/runtime.sgml10
-rw-r--r--src/backend/libpq/auth.c43
-rw-r--r--src/backend/libpq/hba.c43
-rw-r--r--src/backend/libpq/pg_hba.conf.sample2
-rw-r--r--src/include/libpq/hba.h5
6 files changed, 120 insertions, 14 deletions
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index de473f201c0..f10a93953e1 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -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>
@@ -388,6 +388,16 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
</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>
<para>
@@ -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>
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 1a862b5c4b2..f40899e0d60 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -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>
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index dfa3ff2e9a9..1d89e096820 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -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
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 64f67818c93..2464c5f6f94 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -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 $
*
*-------------------------------------------------------------------------
*/
@@ -859,6 +859,12 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
#else
unsupauth = "ldap";
#endif
+ else if (strcmp(token, "cert") == 0)
+#ifdef USE_SSL
+ parsedline->auth_method = uaCert;
+#else
+ unsupauth = "cert";
+#endif
else
{
ereport(LOG,
@@ -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;
}
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index c84d955e1b1..b50fa46c198 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -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
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index cf5942a2668..87d04640e4b 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -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