[Freeipa-devel] [RFC] Creating a new plugin to make it simpler to add users via LDAP

Simo Sorce simo at redhat.com
Wed Feb 13 16:27:10 UTC 2013


On Wed, 2013-02-13 at 16:33 +0100, Petr Viktorin wrote:
> On 02/13/2013 04:15 PM, Petr Spacek wrote:
> > On 13.2.2013 15:53, Simo Sorce wrote:
> >> Hello list,
> >>
> >> with recently seen a few requests to add FreeIPA users via LDAP
> >> directly. This is a common method supported by many meta-directory/HR
> >> systems, however so far we cannot really recommend it because we add
> >> quite a number of attributes automatically in our framework code when we
> >> create users, and those functions can change in future versions.
> >>
> >> However these external tools are usually not very flexible and
> >> supporting them as they are would make for a much better experience for
> >> integrators.
> >>
> >> I had a brief discussion with Rob on IRC on how to address this
> >> situation.
> >>
> >> If we limit ourselves to users we could probably resolve this problem
> >> with a relatively simple 389ds plugin that intercept add operations that
> >> try to add a user.
> >>
> >> The idea is that the remote system would be allowed to set a minimum of
> >> attributes (even incomplete according to our schema). But as long as a
> >> specific set of objectclasses is set (say person and posixaccount) the
> >> operation would be recognized as an attempt to create a user account.
> >>
> >> In this case the plugin would take over the operation and perform a call
> >> against our framework using json. The call would send a reformatted
> >> request using the data we got in input so that any custom
> >> objectclass /attribute can be preserved. The call would also add a
> >> special flag so the framework knows this is coming from 389ds itself.
> >>
> >> The framework would treat this requests in a slightly special way, it
> >> would use all the common code currently used to properly format a user
> >> entry adding all the ancillary data we need, but instead of trying to
> >> ldapadd the entry, it would instead return it back to the caller.
> >>
> >> 389ds at this point gets back a json reply, convert it into an ldap add
> >> operation and proceeds with this new 'augmented' operation instead of
> >> the original one.
> >>
> >> What do people think about this option ?
> >> I think it would be extremely valuable for admins, as it would allow
> >> them to drive user 'synchronization' in a very simple way.
> >> It could also be used to properly augment winsync users so we can allow
> >> full creation when syncing from AD with all the proper attributes
> >> created through the json request. So I see a lot of optential here.
> >>
> >> The only doubt is the json back and forth communication.
> >>
> >> What do people on the framework side think ? Is there going to be any
> >> big problem in adapting the framework so we can use common code to
> >> prepare the object but then change the last stp and return a json reply
> >> instead of perfroming an ldap add operation ?
> >
> > Personally, I don't like the idea of JSON requests & response parsing
> > *inside* 389. I see a lot of opportunities for crash or security hole.

Petr, p[lease substantiate what is your worry, how is using json in
389ds a security issue ? It is well confined, and the only server you
contact is the http server on localhost, not any random external server,
so what makes you think of security holes ? What would cause crashes ?
Please be precise and substantiate a threat model, I currently see
nothing special in this scenario.

> It seems Petr is reading my mind here. I was thinking about these 
> solutions too; they seem cleaner but I don't know if they're feasible.

I am sorry, but 'cleaner' is really the last word I'd use, 'hack' is
what comes to mind here to be honest.

> > What about small (optional) separate daemon?

One more moving part one additional process, that does very little, it
looks to me as a big hammer to yield.

> > A) Variant with separate sub-tree
> >
> > 1. create some new subtree, e.g. cn=useradd-playground,dc=example,dc=com

This has more consequences than you may think.
I do not like the separate field idea because you need to treat it in a
special way. We would probably need special ACIs to anoty allow any
other client to see this subtree otherwise they may see incomplete
objects. Yet we need to allow some user to write to it.
We need to decide case by case which plugins to enable, not all DS
plugins can use filters or exclude subtrees so we may have issues with
some plugins if we do not want them to operate on these special entries
and so on. 

> > 2. watch this sub-tree with persistent search

Persistent search are scarce, and user creation is rare, it would be
over blown, plus it would be a race condition if the daemon dies for
whatever reason.

> > 3. catch new objects and run IPA commands as necessary

With what user identity ?
Keep in mind that one of the reasons we use delegation is to make sure
that ACIs are meaningful *and* auditing reflects the actual user that
did operations.

With an external daemon you have to cases:
1) you use a fixed identity for the external daemon to create these
users, that means the daemon now have to do additional checks to see if
the user used to create the entry is authorized or not and what
attributes it is authorized to create. This is a nightmare, as you do
not want to start parsing ACIs in the external deamons, also prone to
race conditions if ACIs are being changed.
I *really* don't like this.

2) make the daemon all powerful so it can do s4u2self and s4u2proxy for
any user in the system. This way the daemon can connect to LDAP as the
original user and ACIs are applied as usual. This means the daemon is
*all powerful* as it can impersonate any users.
I *really* don't like this either.


Also keep in mind that this 2 step method means you cannot easily relay
back errors to the original client.

So you can end up with the original system believing all is fine, but
the actual real user object creation failed.

This in turn requires additional monitoring by admins they will need to
monitor the playground area to see if some objects are 'stranded' there.

They need some way to find out what went wrong in the 2 step procedure
which is obscure to them.

Then they need to find a way to re-trigger the original system to
re-create the user, even though the original system was told the
creation as ok, so this may be difficult depending on the system.

It quickly becomes a nightmare handling errors with this 2 step system.

> > 4. replace "old" objects with referrals to IPA objects (or do something
> > different)

uh ?

> > I'm not sure that various meta-directory systems can handle situation
> > where user disappeared/object is moved/object is morphed to referal.
> > That can be a problem.

Yes and not the only one.

> A separate tree would mean we're not committed to supporting this 
> particular kind of magic forever. We could have different "compatibility 
> hacks" in the future, each with its own semantics.

Yes a separate tree would really be much more work, sorry but I do not
like this 'solution; one bit for the above reasons.

> > B) More crazy variant with LDAP "proxy"
> > (Now I'm on very thin ice, I don't know how complex it would be. I only
> > found some examples like [1].)
> > Prepare "fake" (non-IPA) LDAP server with same LDAP "structure" and let
> > separate daemon watch server's content and run IPA commands as
> > necessary. It would be best if the small daemon can pretend to be LDAP
> > server and catch LDAP operations directly, as shown in [1].
> 
> An adaptor would certainly be the proper solution when we need to 
> interop with an inflexible foreign interface. The question is if 
> building one is worth it.

It has all the same issues as the above daemon, *plus* all the
complexity of a full LDAP server, because you do not know what checking
operations the remote system may be doing, so you can't just fake up
some parts, you need a full staging proxy.
So now we go from a simple plugin that does some json, to a full blown
mapping proxy. With delayed operations.

The complexity scale is 1:100 or more if you ask me (where 1 is the
plugin I described and 100 is plan B).

> In both cases rather than core IPA functionality this would be something 
> external, something the users have to explicitly install and use, 
> something that doesn't necessarily have to work right with user-supplied 
> plugins, something limited (say, to  users only), and something that'd 
> always use existing code paths.
> I'm really worried about scope creep here; after a few years of adding 
> features like this IPA would become unmaintainable. Better to have a 
> focused core and add on top.

This is why I proposed a plugin that is limited to users and calls the
framework so we can use common code.
The *simpler* way would be to simply replicate the core framework login
in the 389ds plugin or even *move* it there.

But we want to keep the logic in the framework as it is more flexible
and easier to work with and extend, so I proposed a 389ds plugin that
just *asks* the framwrok for the data. This keeps the busienss loginc in
the python framewrok, yet it allows an LDAP driver to add users properly
in IPA just using LDAP calls.

I do not see this as a slippery slope, as it would be limited to user
creation by definition.

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York




More information about the Freeipa-devel mailing list