avalon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Niclas Hedhman <nic...@hedhman.org>
Subject [RT] Security Protection Mechanism in Merlin
Date Sun, 14 Dec 2003 15:53:50 GMT

Gang,
Maybe this has been discussed before, but I haven't seen it for quite a while, 
so I start with a blank piece of paper.

Security Protection Mechanism is about a simplified way for all components to 
protect objects, methods, resources and so on. The Protection Mechanism 
should support both "trusted system components" as well as "non-trusted 
users" and everything in between.

I have been thinking a little bit about this recently, and would like to get 
it going;

My very short Wish-list
1. Codebase security a la standard Java security policies, to fulfill the 
"trusted system components" vs "untrusted system components" difference.

2. Subject level security, leveraging the JAAS, for User based authorization 
at any granularity.

3. Ease-of-Use for both Component Author and Component User. Very little code 
should be required by each of these groups.

4. Pluggable architecture for the management of users, roles and rights, to 
allow for simple authorization systems or all the way to DB driven ones. 
Neither the component author nor the component user should need to worry 
about what authorization system that is in place.


I have been drawing on a piece of paper for quite a while now, and the 
"cleanest" (IMHO) way I see it happening is to introduce support for it in 
Framework. The strong argument would be that security is (or should be for 
all non-M$ apps) a very central piece of concern;

public interface SecureServiceManager extends ServiceManager
{
    Object lookup( String role, Object securityContext );

    // returns a securityContext, i.e. an javax.security.auth.Subject
    // instance. Not sure if it is a security risk to return the Subject
    // to the caller. Need to be investigated.
    Object login( CallbackHandler callback );

    void logout( Object securityContext );
}

and the corresponding

public interface SecureServiceable
{
    void service( SecureServiceManager manager );
}

BUT, one could harness the Context as well, so that the "User Code" would be 
something like;

public void contextualize( Context context )
{
    SecureServiceManager secman = (SecureServiceManager) context.get( 
"avalon.security.servicemanager" );
    // and so on...
}

It doesn't look as neat, and I suggest we keep that debate separately. Below 
is showacse of the use with the introduction of SecureServiceManager.


Let's look at "use-case" part;

The service that contains the protected operations should be fairly simple to 
write. 

public interface MyService
{
    void doSomeOperation();
}

public class MyComponent extends AbstractLogEnabled
    implements MyProtectedService
{
    private Permission m_RequiredPermission;

    public MyComponent()
    {
        m_RequiredPermission = new WhatEverPermission( "ForInstanceAName" );
    }

    public void doSomeOperation()
    {
        AccessController.checkPermission( m_RequiredPermission ); 
        //  :
        //  :
    }
}

Now let's say a web service component want to use the service above, BUT where 
doSomeOperation() is granted only to some people.
First of all we need to provide some authentication, and secondly the 
authorization and interceptor for the above component.


public interface MyWebService
{
    Object login( CallbackHandler callback );

    void logout( Object securityContext );

    void serveTheRequest();
}


public class MyComponent extends AbstractLogEnabled
    implements SecureServiceable
{
    private SecureServiceManager m_Manager;

    public void service( SecureServiceManager man )
    {
        m_Manager = man;
    }

    // The CallbackHandler is from javax.security.auth.callback
    public Object login( CallbackHandler callback )
    {
        // Returns, if successful, a security context to be used
        // in protected calls.
        return m_Manager.login( callback );
    }

    public void logout( Object securityContext )
    {
        m_Manager.logout( securityContext );
    }

    void someWebRequest( Object securityContext )
    {
        MySecureService mss = m_Manager.lookup( MySecureService.ROLE, 
securityContext );

        mss.serveTheRequest();
        m_Manager.release();  // Not going to argue if this is required now...
    }
}


IMHO, the above use-case is "really clean" :o)
Minimal amount of work for both the component author and the component user.

The above scenario is nice, BUT doesn't it only covers part of the problem, 
i.e. protecting a particular method?
What about I need to protect individual objects or resources, based on users??

The establishment of the AccessControlContext in Merlin, will provide full 
protection to everything, so by creating sophisticated Permission classes, I 
can practically protect according to any strategy, for instance;

Let's say I want to protected a persisted database object.

public class MyValueObject
{
    private String m_PrimaryKey;
    private String m_Name;
    private String m_Description;
    private Collection m_Widgets;

    public MyValueObject()
    {}

    public String getPrimaryKey()
    {
        return m_PrimaryKey;
    }

    public String getName()
    {
        DatabasePermission perm = 
            new DatabasePermission( m_PrimaryKey + ".name", "read" );
        AccessController.checkPermission( perm );
        return m_Name;
    }    

    public void setName( String name )
    {
        DatabasePermission perm = 
            new DatabasePermission( m_PrimaryKey + ".name", "write" );
        AccessController.checkPermission( perm );
        m_Name = name;
    }

    public String getDescription()
    {
        DatabasePermission perm = 
            new DatabasePermission( m_PrimaryKey + ".description", "read" );
        AccessController.checkPermission( perm );
        return m_Description;
    }

    public void setDescription( String descr )
    {
        DatabasePermission perm = 
            new DatabasePermission( m_PrimaryKey + ".description", "write" );
        AccessController.checkPermission( perm );
        m_Description = descr;
    }

    public Collection getWidgets()
    {
        DatabasePermission perm = 
            new DatabasePermission( m_PrimaryKey + ".widgets", "read" );
        AccessController.checkPermission( perm );
        ArrayList clone = new ArrayList( m_Widgets );
        return clone;
    }

    public void addWidget( Widget widget )
    {
        DatabasePermission perm = 
            new DatabasePermission( m_PrimaryKey + ".widgets", "add" );
        AccessController.checkPermission( perm );
        m_Widgets.add( widget );
    }

    public void removeWidget( Widget widget )
    {
        DatabasePermission perm = 
            new DatabasePermission( m_PrimaryKey + ".widgets", "remove" );
        AccessController.checkPermission( perm );
        m_Widgets.remove( widget );
    }
}


But then you would need to create some fairly fancy DatabasePermission class, 
which understand how permissions granted would imply access or not according 
to the permissions required. This is bringing us over to the Authorization 
Management, which is outside the scope of this RT (see below). However, it is 
important to notice that the DatabasePermission above, is therefor NOT a good 
solution, since it ties the compont to tightly to a particular Authorization 
Management system (DB).


Now, back to Merlin and how to implement this;

Each lookup in the SecureServiceManager, needs to make sure that the security 
context is the same, otherwise instantiate a new Proxy (!), but not 
necessarily a new component.

The ApplianceInvocationHandler would need to wrap the whole call with 
something like this (Exception handling left out);

public Object invoke( final Object proxy,
                final Method method,
                final Object[] args )
                throws Throwable
{
    MyAction action = new MyAction( m_Instance, method, args );
    return Subject.doAs( m_Subject, action );
}

private class MyAction
    implements PrivilegedAction
{
    private Method m_Method;
    private Object m_Instance;
    private Object[] m_Args;

    PrivilegedAction( Object instance, Method method, Object[] args)
    {
        m_Instance = instance;
        m_Args = args;
        m_Method = method;
    }

    public Object run()
    {
        return m_Method.invoke( m_Instance, m_Args );
    }
}


And then we would need a new SecureSecurityManager and understand the 
SecureServiceable interface signature...

Believe it or not, but I have only cover ONE out THREE issues with user based 
authorization, namely the Protection Mechanism.

We need to work out 
1. Security Configuration, i.e. the pluggable system of components making up 
the complete security system.
2. Standardized Authorization Management, i.e. standardized way to manage "Who 
can do What", how to add/remove/edit/audit users, roles and rights.
 

Ok, that's about it for now... How do you all feel about this subject?? I hope 
you are not in M$ mood ;o)

Cheers,
Niclas

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Mime
View raw message