CloudTran Home

 
  
 
Contents  >   4.  Concepts
 


4.6 Concepts - Security

By default the security use in CloudTran is Spring's security model - specifically Spring Security 3.0.5. By default security is on.

You can configure security as you wish but by default in CloudTran there is the standard JDBC authentication-provider - i.e. database backed authentication This means that the needs to be a dataSource containing the tables as defined in Springs documentation, and shown below.

  CREATE TABLE users (
    username VARCHAR(50) NOT NULL PRIMARY KEY,
    password VARCHAR(50) NOT NULL,
    enabled BIT NOT NULL
  );
    
  CREATE TABLE authorities (
    username VARCHAR(50) NOT NULL,
    authority VARCHAR(50) NOT NULL
  );
    
  ALTER TABLE authorities 
        ADD CONSTRAINT fk_authorities_users foreign key(username) 
        REFERENCES users(username);
The following example shows how to configure the JDBC authentication-provider. Note This is the datasource that needs to contain the 'user' and 'authorities' tables.
<beans:bean id="propertiesConfigurer" 
               class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
               >
    <beans:property name="properties">
        <beans:props>
            <beans:prop key="authentication.datasourceUrl">jdbc:mysql://localhost:3306/saas
            </beans:prop>
            <beans:prop key="authentication.username">jeewiz</beans:prop>
            <beans:prop key="authentication.password">jeewiz</beans:prop>
        </beans:props>
    </beans:property>
</beans:bean>

<authentication-manager alias="authenticationManager">
    <authentication-provider>
        <jdbc-user-service data-source-ref="securityDataSource" />
    </authentication-provider>
</authentication-manager>

<beans:bean id="securityDataSource" destroy-method="close"
    class="org.apache.commons.dbcp.BasicDataSource">
    <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <beans:property name="url" value="${authentication.datasourceUrl}" />
    <beans:property name="username" value="${authentication.username}" />
    <beans:property name="password" value="${authentication.password}" />
</beans:bean>

 4.6.1  Service Boundaries
 4.6.2  Software as a Service

4.6.1  Service Boundaries
At the service boundary the security context needs to be passed to the remote service. This is achieved by adding to the service an additional parameter of type OBJECT. For example a modelled service may be:
public interface IMyService
{
    public String doSomething( String str, Integer i );
}

This would be the interface presented to the user of the service. However under the covers the service would actually become:

public interface IMyServiceGS
{
    public String doSomething( String str, Integer i, Object additionalDetails );
}

So the service defined at the GigaSpaces level would be IMyServiceGS.

At the client side the CtProxies class remains and provides the user's proxy to the service.

public static class MyService 
{
    private static IMyService proxy = null;
    private static IMyService broadcastProxy = null;
    public  static IMyService localServiceObject = null; // is set by service constructor 
    private static int IMyServiceModuloNumberForLocalSpace = -1;
    private static AtomicBoolean IMyServiceGetProxyInUse          = new AtomicBoolean( false );
    private static AtomicBoolean IMyServiceGetBroadcastProxyInUse = new AtomicBoolean( false );
    
    /**
     * The getProxy( int modulo ) attempts to optimise the proxy using the given modulo value.
     * If the cohort in which this getProxy() call is initiated is also the destination cohort
     * then this method simply returns the localServiceObject.
     *
     * The localServiceObject in this class is initialised when the service is instantiated 
     * and the IMyServiceModuloNumberForLocalSpace is initialised in the initMethod() 
     */
    public static IMyService getProxy( int modulo ) 
    {
        if( IMyServiceModuloNumberForLocalSpace == modulo ) 
        {
            return localServiceObject;
        }
        return getProxy();
    }
    
    public static IMyService getProxy() 
    {
        .....
        proxy = new MyServiceFacade();
        .....
        return proxy;
    }
    
    public static IMyService getBroadcastProxy() 
    {
        .....
        broadcastProxy = new MyServiceFacade( true );
        .....
        return broadcastProxy;
    }
}

A new class - 'MyServiceFacade' - is used to interface to the underlying service. This facade implements IMyService and contains a proxy to the GigaSpaces proxy

public class MyServiceFacade implements IMyService 
{
    public MyServiceFacade() 
    {
        this( false );
    }
    public MyServiceFacade( boolean broadcast ) 
    {
        this.broadcast = broadcast;
        if( broadcast ) 
        {
            proxy = GSProxies.MyService.getBroadcastProxy();
        }
        else 
        {
            proxy = GSProxies.MyService.getProxy();
        }
    }
    
    public String doSomething( String str, Integer i ) 
    {
        // get the security context and pass it into the gigaspaces proxy
        Object additions = SecurityUtils.getSecurityContext();
        return proxy.doSomething(  str, i, additions  );
    }
    public Future doSomething( String str, Integer i ) 
    {
        // get the security context and pass it into the gigaspaces proxy
        Object additions = SecurityUtils.getSecurityContext();
        return proxy.asyncDoSomthing(  puName ,  additions  );
    }
    private IMyServiceGS proxy = null;
    private boolean broadcast;
}

NOTE As you can see the 'additionalDetails' object is used at present to carry the Security Context. In future it may be used to carry additional information such as the distributed transaction details.

The GigaSpace proxy can be obtained directly from the GSProxies class.

At the server side the Service class 'MyService' implements both the IMyService and IMyServiceGS intefaces



public class MyService implements IMyServiceGS, IMyService 
{
    
    /******************************************************************************************
     **  Re-generated Methods
     **
     **  The following methods will be re-generated.
     **  Any changes made in this section will be lost when the application is re-generated.
     **
     **  Add any extra (i.e. un-modeled) code at the end of this file
     ******************************************************************************************/
    
    /**
     * The async implementation of doSomething
     */
    public Future asyncDoSomething( String str, Integer i ) 
    {
        return null;	// server-side implementation of async method returns null
    }
    public Future asyncDoSomething( String str, Integer i, Object additionalDetails ) 
    {
        if( additionalDetails != null ) 
        {
            SecurityUtils.setSecurityContext( additionalDetails );
        }
        return asyncDoSomething( str, i );
    }
    public String doSomething( String str, Integer i, Object additionalDetails )
    {
        if( additionalDetails != null ) 
        {
            SecurityUtils.setSecurityContext( additionalDetails );
        }
        return doSomething( str, i );
    }
    
    .....
    .....
    
    /******************************************************************************************
     **  Implementation Methods
     **
     **  The following methods hold the implementations of methods defined in the model.
     **  The bodies of these methods will not be regenerated - you create these.
     **  However, you should only change the body of the method - between the comments.
     **  The generator takes care of ...
     **  This process will not work if you edit the 'uid' or 'end' comments.
     **
     ******************************************************************************************/
    public String doSomething( String str, Integer i )
    {
       .... - implementation goes here
    }

The implementation method can be filled by the developer as per normal.


4.6.2  Software as a Service
There is a slight variation in the Security model for SAAS. This is because the tenantId needs to be passed around along with the security context. This is described in more detail in the section on SaaS Security, but essentially the logged-on user's username includes the tenantId. This is achieved by storing the login names as a concatination of the username and the tenantId.

For example the user 'johnsmith' who belongs to tenant T1 would have a username of 'johnsmith:T1'. The user's login would still be 'johnsmith' but the username stored in the 'users' table would be username 'johnsmith:T1'.

To achieve this requires an extension to Springs 'UsernamePasswordAuthenticationFilter'. The CloudTran extension is called 'CTUsernamePasswordAuthenticationFilter' and is included in the classpath by default. It can be included in the Spring configuration as follows

<beans:bean id="customUsernamePasswordAuthenticationFilter" 
            class="com.cloudtran.web.CTUsernamePasswordAuthenticationFilter"
            >
    <beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>


Copyright (c) 2001-2011 CloudTran Inc.