Thread: [PATCH] Support pg_ident mapping for LDAP

[PATCH] Support pg_ident mapping for LDAP

From
Jacob Champion
Date:
Hello,

There was a brief discussion [1] back in February on allowing user
mapping for LDAP, in order to open up some more complex authorization
logic (and slightly reduce the need for LDAP-to-Postgres user
synchronization). Attached is an implementation of this that separates
the LDAP authentication and authorization identities, and lets the
client control the former with an `ldapuser` connection option or its
associated PGLDAPUSER envvar.

This isn't as useful as, say, authorization based on LDAP attributes or
group membership, but it seems like a necessary step towards that
feature, since we'll need to separate authn and authz anyway. This
provides some feature parity with other auth methods like gss, and it
solves the "let anyone who can authenticate against LDAP connect as X
role" use case trivially.

There is precedent for allowing the DBA to choose whether to map a bare
username or the "full" identity expansion -- see for example
include_realm=1 for gss and clientname=DN for cert -- so I added an
ldap_map_dn=1 option which can be used to map the whole DN. (I'm not
entirely convinced that it's useful, but maybe there are some
deployments that put authorization information into the LDAP topology,
like "everyone in this particular subtree is an admin".) Unlike
include_realm, this is only allowed with an explicit map. I don't
anticipate people using a full DN as a database username, and I'm
worried that doing that without normalization could cause some major
confusion and/or security problems.

When using a newer client with an older server, the new `ldapuser`
option will cause a connection failure. For the case where PGUSER and
PGLDAPUSER are identical, that failure is technically unnecessary, and
I briefly considered stripping the `ldapuser` option from the
connection string in that case so that we could have wider
compatibility. I now think that's a bad idea, because suddenly
introducing a hard connection failure (or new success) just because
your PGLDAPUSER variable changed would be a major support hazard. The
TODO is still in the code to remind me to have the conversation.

WDYT?

--Jacob

[1] https://www.postgresql.org/message-id/94f6b945f9ca8cabe2b9d2a38ec19dca6f90a083.camel%40vmware.com

Attachment

Re: [PATCH] Support pg_ident mapping for LDAP

From
Jacob Champion
Date:
On Tue, 2021-08-31 at 19:39 +0000, Jacob Champion wrote:
> Hello,
> 
> There was a brief discussion [1] back in February on allowing user
> mapping for LDAP, in order to open up some more complex authorization
> logic (and slightly reduce the need for LDAP-to-Postgres user
> synchronization). Attached is an implementation of this that separates
> the LDAP authentication and authorization identities, and lets the
> client control the former with an `ldapuser` connection option or its
> associated PGLDAPUSER envvar.

The cfbot found a failure in postgres_fdw, which I completely neglected
in my design. I think the desired functionality should be to allow the
ldapuser connection option during CREATE USER MAPPING but not CREATE
SERVER. I'll have a v2 up today to fix that.

--Jacob

Re: [PATCH] Support pg_ident mapping for LDAP

From
Jacob Champion
Date:
On Wed, 2021-09-01 at 15:42 +0000, Jacob Champion wrote:
> The cfbot found a failure in postgres_fdw, which I completely neglected
> in my design. I think the desired functionality should be to allow the
> ldapuser connection option during CREATE USER MAPPING but not CREATE
> SERVER.

Fixed in v2, attached.

--Jacob

Attachment

Re: [PATCH] Support pg_ident mapping for LDAP

From
Zhihong Yu
Date:


On Wed, Sep 1, 2021 at 11:43 AM Jacob Champion <pchampion@vmware.com> wrote:
On Wed, 2021-09-01 at 15:42 +0000, Jacob Champion wrote:
> The cfbot found a failure in postgres_fdw, which I completely neglected
> in my design. I think the desired functionality should be to allow the
> ldapuser connection option during CREATE USER MAPPING but not CREATE
> SERVER.

Fixed in v2, attached.

--Jacob
Hi,

+       if (strcmp(val, "1") == 0)
+           hbaline->ldap_map_dn = true;
+       else
+           hbaline->ldap_map_dn = false;

The above can be shortened as:

  hbaline->ldap_map_dn = strcmp(val, "1") == 0;

Cheers

Re: [PATCH] Support pg_ident mapping for LDAP

From
Jacob Champion
Date:
On Wed, 2021-09-01 at 12:59 -0700, Zhihong Yu wrote:
> +       if (strcmp(val, "1") == 0)
> +           hbaline->ldap_map_dn = true;
> +       else
> +           hbaline->ldap_map_dn = false;
> 
> The above can be shortened as:
> 
>   hbaline->ldap_map_dn = strcmp(val, "1") == 0;

I usually prefer simplifying those conditionals, too, but in this case
I think it'd be a pretty big departure from the existing style. See for
example the handling of include_realm and compat_realm just after this
hunk.

--Jacob

Re: [PATCH] Support pg_ident mapping for LDAP

From
Zhihong Yu
Date:


On Wed, Sep 1, 2021 at 1:56 PM Jacob Champion <pchampion@vmware.com> wrote:
On Wed, 2021-09-01 at 12:59 -0700, Zhihong Yu wrote:
> +       if (strcmp(val, "1") == 0)
> +           hbaline->ldap_map_dn = true;
> +       else
> +           hbaline->ldap_map_dn = false;
>
> The above can be shortened as:
>
>   hbaline->ldap_map_dn = strcmp(val, "1") == 0;

I usually prefer simplifying those conditionals, too, but in this case
I think it'd be a pretty big departure from the existing style. See for
example the handling of include_realm and compat_realm just after this
hunk.

--Jacob
Hi,
I looked at v2-Allow-user-name-mapping-with-LDAP.patch and src/backend/postmaster/postmaster.c in master branch but didn't find what you mentioned.

I still think my recommendation is concise.

Cheers 

Re: [PATCH] Support pg_ident mapping for LDAP

From
Jacob Champion
Date:
On Wed, 2021-09-01 at 14:20 -0700, Zhihong Yu wrote:
> I looked at v2-Allow-user-name-mapping-with-LDAP.patch
> and src/backend/postmaster/postmaster.c in master branch but didn't
> find what you mentioned.

This hunk is in src/backend/libpq/hba.c, in the parse_hba_auth_opt()
function. The code there uses the less concise form throughout, as far
as I can see.

--Jacob

Re: [PATCH] Support pg_ident mapping for LDAP

From
Magnus Hagander
Date:
On Wed, Sep 1, 2021 at 8:43 PM Jacob Champion <pchampion@vmware.com> wrote:
>
> On Wed, 2021-09-01 at 15:42 +0000, Jacob Champion wrote:
> > The cfbot found a failure in postgres_fdw, which I completely neglected
> > in my design. I think the desired functionality should be to allow the
> > ldapuser connection option during CREATE USER MAPPING but not CREATE
> > SERVER.
>
> Fixed in v2, attached.

A couple of quick comments from a quick look-over:

I'm a bit hesitant about the ldapuser libpq parameter. Do we really
want to limit ourselves to just ldap, if we allow this? I mean, why
not allow say radius or pam to also specify a different username for
the external system? If we want to do that, now or in the future, we
should have a much more generic parameter name, something like
authuser?

Why do we actually need ldap_map_dn? Shouldn't this just be what
happens if you specify map= on an ldap connection?

-- 
 Magnus Hagander
 Me: https://www.hagander.net/
 Work: https://www.redpill-linpro.com/



Re: [PATCH] Support pg_ident mapping for LDAP

From
Jacob Champion
Date:
On Tue, 2021-09-28 at 15:38 +0200, Magnus Hagander wrote:
> I'm a bit hesitant about the ldapuser libpq parameter. Do we really
> want to limit ourselves to just ldap, if we allow this? I mean, why
> not allow say radius or pam to also specify a different username for
> the external system? If we want to do that, now or in the future, we
> should have a much more generic parameter name, something like
> authuser?

I'd be on board with a more general option name.

So from the perspective of a SASL exchange, PGUSER would be the
authorization identity, and PGAUTHUSER, say, would be the
authentication identity. Is "auth" a clear enough prefix that users and
devs will understand what the difference is between the two?

         | authn             authz
---------+-----------------------------------
  envvar | PGAUTHUSER        PGUSER
conninfo | authuser          user
frontend | conn->pgauthuser  conn->pguser backend | port->auth_user   port->user_name

> Why do we actually need ldap_map_dn? Shouldn't this just be what
> happens if you specify map= on an ldap connection?

For simple-bind setups, I think requiring users to match an entire DN
is probably unnecessary (and/or dangerous once you start getting into
regex mapping), so the map uses the bare username by default. My intent
was for that to have the same default behavior as cert maps.

Thanks,
--Jacob

Re: [PATCH] Support pg_ident mapping for LDAP

From
Jacob Champion
Date:
On Tue, 2021-09-28 at 18:02 +0000, Jacob Champion wrote:
> On Tue, 2021-09-28 at 15:38 +0200, Magnus Hagander wrote:
> > I'm a bit hesitant about the ldapuser libpq parameter. Do we really
> > want to limit ourselves to just ldap, if we allow this? I mean, why
> > not allow say radius or pam to also specify a different username for
> > the external system? If we want to do that, now or in the future, we
> > should have a much more generic parameter name, something like
> > authuser?
> 
> I'd be on board with a more general option name.
> 
> So from the perspective of a SASL exchange, PGUSER would be the
> authorization identity, and PGAUTHUSER, say, would be the
> authentication identity. Is "auth" a clear enough prefix that users and
> devs will understand what the difference is between the two?
> 
>          | authn             authz
> ---------+-----------------------------------
>   envvar | PGAUTHUSER        PGUSER
> conninfo | authuser          user
> frontend | conn->pgauthuser  conn->pguser backend | port->auth_user   port->user_name
> 
> > Why do we actually need ldap_map_dn? Shouldn't this just be what
> > happens if you specify map= on an ldap connection?
> 
> For simple-bind setups, I think requiring users to match an entire DN
> is probably unnecessary (and/or dangerous once you start getting into
> regex mapping), so the map uses the bare username by default. My intent
> was for that to have the same default behavior as cert maps.
> 
> Thanks,
> --Jacob


Re: [PATCH] Support pg_ident mapping for LDAP

From
Jacob Champion
Date:
On Tue, 2021-09-28 at 18:08 +0000, Jacob Champion wrote:
> >          | authn             authz
> > ---------+-----------------------------------
> >   envvar | PGAUTHUSER        PGUSER
> > conninfo | authuser          user
> > frontend | conn->pgauthuser  conn->pguser backend | port->auth_user   port->user_name

Ugh, PEBKAC problems today... apologies. This should have been

         | authn             authz
---------+-----------------------------------
  envvar | PGAUTHUSER        PGUSER
conninfo | authuser          user
frontend | conn->pgauthuser  conn->pguser
 backend | port->auth_user   port->user_name

--Jacob

Re: [PATCH] Support pg_ident mapping for LDAP

From
Jacob Champion
Date:
On Tue, 2021-09-28 at 18:15 +0000, Jacob Champion wrote:
>          | authn             authz
> ---------+-----------------------------------
>   envvar | PGAUTHUSER        PGUSER
> conninfo | authuser          user
> frontend | conn->pgauthuser  conn->pguser
>  backend | port->auth_user   port->user_name

v3 attached, which uses the above naming scheme and removes the stale
TODO. Changes in since-v2.

--Jacob

Attachment

Re: [PATCH] Support pg_ident mapping for LDAP

From
Jacob Champion
Date:
On Fri, 2021-10-29 at 17:38 +0000, Jacob Champion wrote:
> v3 attached, which uses the above naming scheme and removes the stale
> TODO. Changes in since-v2.

v4 rebases over the recent TAP changes.

--Jacob

Attachment