RFC Feature Planning: Add Permission Grant list to User Profile and UserGroup details

Scott Seago sseago at redhat.com
Wed Apr 4 20:01:49 UTC 2012


On 04/04/2012 03:18 PM, Matt Wagner wrote:
> On Tue, Apr 03, 2012 at 02:08:53PM +0200, Jan Provaznik wrote:
>> -1 for this (+1 for doing this on background), I experienced many
>> situations when customer's LDAP server was responding too slow.
>> Typical real-life situation is: LDAP is used for SMTP auth, SMTP
>> server is overloaded ->  LDAP responses are slow. IOW slow LDAP is
>> much more common then it would be expected.
> I think I actually agree with Jan, but just to play devil's advocate...
>
> I don't believe it's ever safe to cache LDAP data, because we have no
> way of knowing when it changes. We could cache things for the duration
> of a method call (like Rails does with SQL in controllers), but I think
> anything beyond that is technically unsafe. And it's not like we're
> concerned about possibly serving a blog post a couple of seconds after
> it's deleted -- we're talking about caching security information with
> having no way of knowing when what we've cached becomes out of date.
>
You're acting as devil's advocate for a proposal  that wasn't one of the 
two options I'd proposed :-)

Both of my suggestions involved caching the results, to be considered 
valid for some period of time. The only difference was whether we do it 
on a set polling interval or if we cache it "on demand" -- i.e. on the 
first demand for it, then use it for a bit until it's considered "stale" 
again.

If we don't cache LDAP data, the whole proposal for denormalizing 
permission design becomes invalid, since the idea is to have a direct 
"grantee" list per object to filter on for list_for_user, etc.


> Continuing as devil's advocate for a moment, I would contend that if
> someone's LDAP server is slow, it's not our fault, and is in fact
> unavoidable, that our application will be slow during permission checks.
> And building on the SMTP auth example -- this implies that the
> mailserver is not caching LDAP information, because they deemed it
> unacceptable for spam to go to a user once their account is turned off,
> or for a new user to not receive mail for a few minutes. So surely, we
> shouldn't allow user to spin up (or terminate!) cloud instances after
> they were fired.
>
Hmm. Again my proposal (that Jan was objecting to) still cached -- but 
we cached "on demand" -- so every so often we'd potentially slow down on 
a permissions check, then we'd be fast for a while until things were 
considering stale.
> At a previous employer, the practice was to move employees who left the
> company to the "Exited Users" Active Directory group, so even caching
> group membership is unsafe.
>
Well if you're caching for 30 seconds (or something similarly small) you 
could argue that it's not unsafe -- would it really have mattered if the 
admin had been 30 seconds later in moving the user to te "exited users" 
group?
> Poking around a bit, I'm seeing other projects where their "cache" was
> per-pageload -- along the lines of what I was saying with the Rails SQL
> cache, which only lives as long as the controller action. The next
> pageload will do the same queries.
>
> I started this off mostly playing devil's advocate, and being a big fan
> of caching. But in the course of doing so, I think I actually changed my
> mind, and come to the opinion that we really shouldn't be caching user
> authentication data. I think we need to re-query on every permission
> check, even if this is going to slow things down considerably. In
> practice this information changes relatively infrequently, but since we
> have no way of knowing WHEN it changes, I think that caching it in our
> database is unsafe and improper.
>
So we're not talking about authentication data here -- that's all in the 
session still. But for group membership, with a short enough 
timeout/refresh interval we're _probably_ safe -- we're talking about 
"propagation time" rather than erroneous permission results, really.

That said, we could do it in another way that avoid caching group 
membership entirely (but it does complicate the permission checks, 
preventing us from gaining the full benefit of the denormalization). 
Essentially we could do the following:
1) denormalize _inherited_ permission relations as planned (i.e. 
explicit records on the instance for users and groups with access from 
whatever level in the hierarchy
2) do _not_ denormalize group members in the above -- i.e. if "Joe" is 
in the "Engineering Management" group, and "Engineering Management" has 
the "Pool Administrator" role in the Engineering pool, and we have a 
"Redmine" deployment in that pool then we would not have a denormalized 
permission record for "(Joe, Pool Administrator, Redmine)" -- we would 
only have one for "(Engineering Management Group, Pool Administrator, 
Redmine)"
3) for permissions checks, instead of simply doing a lookup on the 
denormalized table for Joe, we'd have to look for both Group and 
invididual grants, after pulling the current group assignments for the 
current user

i.e. my proposal would leave just this for base permission checks:
   return true obj.derived_permissions.find(:first, :include => [:role 
=> :privileges],
                 :conditions => ["derived_permissions.user_id=:user and
                                 privileges.target_type=:target_type and
                                  privileges.action=:action",
                                 { :user => user.id,
                                    :target_type => target_type.name,
                                              :action => action}])

Instead we'd first need to pull the user's LDAP group list, and then 
join _twice_ with permissions, once verifying user => user.id, and again 
verifying group in user.groups

Scott




More information about the aeolus-devel mailing list