]> granicus.if.org Git - postgresql/commitdiff
Add support for using SSL client certificates to authenticate to the
authorMagnus Hagander <magnus@hagander.net>
Thu, 20 Nov 2008 11:48:26 +0000 (11:48 +0000)
committerMagnus Hagander <magnus@hagander.net>
Thu, 20 Nov 2008 11:48:26 +0000 (11:48 +0000)
database (only for SSL connections, obviously).

doc/src/sgml/client-auth.sgml
doc/src/sgml/runtime.sgml
src/backend/libpq/auth.c
src/backend/libpq/hba.c
src/backend/libpq/pg_hba.conf.sample
src/include/libpq/hba.h

index de473f201c011c3361541ff6c4615ba273449526..f10a93953e1d63511fe26c5ab38b161972efd8d9 100644 (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>
 
index 1a862b5c4b24590407b2afe1876db1330541d7aa..f40899e0d60e5fb6959abe46d6a4a2f4ceaaac27 100644 (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>
 
index dfa3ff2e9a993c1a197a6a4376dcdec54f9a5e0d..1d89e096820f1c96d9ee9798ee7e2293c939bed9 100644 (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
index 64f67818c93349501d77bbffa4e379aa8eadbac3..2464c5f6f94c1126a6258bfe931beafe0294267d 100644 (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;
 }
index c84d955e1b1374f1f6a01cddca0b76584a33c3b6..b50fa46c1982c98092e4c274a6246060ab882973 100644 (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
index cf5942a2668e607b9ec196fb5aee7715dec9f7da..87d04640e4b410701d8be533d6247c1a42682934 100644 (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