karaf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jean-Baptiste Onofré ...@nanthrax.net>
Subject Re: Some thoughts around adding security for Karaf Shell Commands
Date Thu, 22 Aug 2013 17:37:01 GMT
Hi David,

again it sounds good, and it's what I had in mind.

Before provide a more complete feedback, let me take a look on your github.

Thanks anyway !


On 08/22/2013 05:07 PM, David Bosschaert wrote:
> Hi all,
> As suggested by Christian, I started looking at adding role-based access to
> OSGi services in general (in Karaf) and applying this to the Karaf commands.
> At this point I have something that kinda works. It proxies services for
> service consumers using service registry hooks and on invocation checks
> that the Subject associated with the current Access Control Context has the
> right roles. If not it blocks the service invocation by throwing a
> SecurityException.
> Not all services are secured this way, there is a new property in
> etc/system.properties that selects what services are processed this way
> using a simple OSGi service filter. To apply it to the shell commands it is
> set to the following:
>    karaf.secured.services=(&(osgi.command.scope=*)(osgi.command.function=*))
> The actual ACLs for the secured services are defined using ConfigAdmin in a
> way that's pretty much identical to what I did for the JMX acls in
> KARAF-2435, except that the PID doesn't matter. The configuration is
> matched with a service on a 'service.guard' property. The other entries
> match method names of the service. They can also match values passed in (as
> you can do with JMX), so you can define different roles for doit("foo") and
> doit("bar"). An example configuration could look like this:
>    service.guard = (objectClass=org.acme.TestServiceAPI)
>    doit = admin, viewer
>    doit["foo"] = admin
> So the next thing I did was look at whether this could be applied to the
> shell commands. The problem was that every little command is a separate
> service so this would potentially be a lot of configuration files for the
> administrator to maintain. You really want to define the ACLs for a single
> scope in a single configuration file, something like this (for the bundle
> scope):
>    install = manager
>    start = manager
>    list = manager, viewer
>    stop = manager
>    stop[/.*0.*/] = admin # only admin can stop the framework
>    uninstall = admin
> To fit with the general service ACL model this would have to be 5 different
> configuration files (one for each command). I thought that that was not
> very user friendly. Therefore I came up with a mechanism that accepts
> ConfigAdmin configuration for commands in the same scope like the above and
> then generates additional ConfigAdmin configuration on the fly that
> conforms to the general service ACL form.
> With that, enabled... let's say I'm logged in as a 'manager', with the
> above example configuration for the bundle scope, the it has the following
> effect:
>    karaf@root()> stop 50
>    # works
>    karaf@root()> stop 0
>    Error executing command: Insufficient credentials.
> Which is pretty much what I wanted to achieve :)
> So basically what we have here is a combination of two things:
> 1. Modification of service registrations to add a roles property which is
> then used by the CommandProcessor to only show the commands that the user
> associated with the active console can potentially execute (it could still
> reject commands based on arguments passed in).
> 2. Proxying of services (including shell command services) that check that
> the Subject associated with the current AccessControlContext has the right
> roles to make this invocation.
> The role-checking is still done outside of the service implementations. The
> actual services being secured don't need to change their code.
> You can see my experimental implementation at my branch here:
> https://github.com/bosschaert/karaf/commit/2668b88a7ddfb1ba93e7e732884734ff7dc0d1a3
> That branch is not finished (cleanup, tests terribly lacking, no
> optimization) and some things could be made a little more user friendly,
> but it contains the general idea... If people are happy with the general
> idea I can focus a little on tiding it up...
> Thoughts anyone?
> David
> On 19 August 2013 10:56, David Bosschaert <david.bosschaert@gmail.com>wrote:
>> Hi Christian,
>> On 19 August 2013 10:29, Christian Schneider <chris@die-schneider.net>wrote:
>>> The idea was to use Shiro to establish a kind of security context in a
>>> thread local. Your approach of using Subject.doas might be the better
>>> alternative though.
>>>   In any case we should recommend one standard approach to establish the
>>> security context. Perhaps we could even allow both and have adapters to
>>> establish one context from another.
>> Yep, this needs to be standard.
>>>   On 08/15/2013 10:16 PM, Christian Schneider wrote:
>>>>>   I like the idea of adding permissions to the commands. I wonder though
>>>>>> if this is perhaps a more general problem that not only affects
>>>>>> commands.
>>>>>> So how about adding a generic permission check for services? For
>>>>>> example
>>>>>> I would like to use the @RolesAllowed annotation to couple roles
>>>>>> permissions with service methods.
>>>>>> A service registry hook could then check that the caller has the
>>>>>> permission before allowing the call. Of course there could be other
>>>>>> additional way of adding this information like the service properties
>>>>>> you mentioned.
>>>>>>   I'm not sure I like the annotation approach. One of the things
that I
>>>> would
>>>> like to enable is for customers to change the roles associated with
>>>> operations/service invocations afterwards, simply because the roles
>>>> chosen
>>>> by the developer may not match up with the roles mappings of all
>>>> organizations. With an annotation approach you'd have to modify the code
>>>> and recompile it when you want to change them. I prefer to use OSGi
>>>> ConfigAdmin for that since it completely decouples this information from
>>>> the code and can easily be modified later...
>>>> We should also provide a generic way to attach authentication
>>> I think there could be three levels of external configurability:
>>> 1. You could use annotations with roles like
>>> @RolesAllowed("admin")
>>> public void deleteUser(...);
>>> 2. You could use annotations to store permissions
>>> @RolesAllowed("Userservice.**deleteUser")
>>> public void deleteUser(...);
>>> Then the mapping to roles could be done by using groups in the simplest
>>> form. group UserService.deleteUser: admin, ...
>>> 3. You could completely externalize the decision. In this case a Policy
>>> Decision Point approach could make sense.
>>> You extract the meta information of a service call, give it to a pdp and
>>> get back an authorization decision.
>> I would favor having just option 3. I can see that option 2 provides some
>> form of indirection, but you still need to modify the service code to add
>> the annotation in the first place. That might be ok for services that have
>> their code in the Karaf codebase, but for outside services it would be
>> pretty much impossible.
>> I would rather have a clear single way of configuring this so that it's
>> very clear what the definition is - if a security guy wants to figure out
>> what roles are needed for options 1 & 2 (s)he needs to have access to the
>> source to read how the annotation was declared, or otherwise rely on
>> documentation, which you are never sure is actually in sync with the code.
>> If we'd opt for a combined annotation+external approach it's still quite
>> hard to get a full overview of what roles are required to invoke what if
>> you want to understand that... Hence I would simply go for having just
>> option 3 and keep everything in one place.
>>>   information to a thread that calls a service. I tought about using
>>>>>> apache shiro for this but I am not sure if it is universal enough.
>>>>>>   I don't understand why you need Shiro for this.
>>>> Isn't javax.security.auth.Subject.**doAs() the standard way to do this?
>>> Probably it is. How does this work internally? Does it also use a thread
>>> local? How  does it work if you spawn a new thread using an executor or
>>> similar?
>>> I think we should do some examples to see how it works in practice.
>> Re Subject.doAs(). The Subject would be configured via JAAS to contain the
>> appropriate roles for the current user, as we do today in Karaf (although
>> you should be able to configure Shiro to provide this info)...
>> Once you're inside a piece of code that is executed via Subject.doAs()
>> (which could be in a different thread) you can do:
>>    AccessControlContext acc = AccessController.getContext();
>>    Subject subject = Subject.getSubject(acc);
>> At this point you can get all the Principals from the subject, e.g. all
>> the roles:
>>    Set<RolePrincipal> roles = subject.getPrincipals(RolePrincipal.class);
>> This is all plain standard J2SE code, no library dependencies...
>> Cheers,
>> David

Jean-Baptiste Onofré
Talend - http://www.talend.com

View raw message