There are a couple of ways to create a secured embedded Space (standalone or part of a Processing Unit). Access (to data) is granted only to users with sufficient privileges.
The secured Space URL property indicates that the Space being created should be secured.
UrlSpaceConfigurer urlSpaceConfigurer = new UrlSpaceConfigurer("/./space?secured");
GigaSpace gigaSpace = new GigaSpaceConfigurer(urlSpaceConfigurer).gigaSpace();
The secured URL property is also exposed as a convenient .secured(true) method call.
UrlSpaceConfigurer urlSpaceConfigurer = new UrlSpaceConfigurer("/./space").secured(true);
GigaSpace gigaSpace = new GigaSpaceConfigurer(urlSpaceConfigurer).gigaSpace();
The UserDetails can either be supplied as an object or in its simpler form of two Strings (username and password).
These will be used to implicitly create a secured Space, with security privileges being propagated to internal services (such as Filters).
UrlSpaceConfigurer urlSpaceConfigurer = new UrlSpaceConfigurer("/./space").userDetails("user", "password");
GigaSpace gigaSpace = new GigaSpaceConfigurer(urlSpaceConfigurer).gigaSpace();
To lookup a secured remote Space, the credentials (username and password) must be supplied for authentication. Once authenticated, the proxy can be used to carry out operations (on behalf of the user granted privileges).
UrlSpaceConfigurer urlSpaceConfigurer = new UrlSpaceConfigurer("jini://*/*/space").userDetails("user", "password");
GigaSpace gigaSpace = new GigaSpaceConfigurer(urlSpaceConfigurer).gigaSpace();
A processing unit by itself is not secured. It inherits its security from the managing GSM and GSC.
But, a processing unit may have an embedded Space which may be secured (if required), to protect access to data.
Processing Unit XML
The secured Space URL property indicates that the Space being created should be secured.
The UserDetails can be supplied in its simpler form of two Strings (username and password).
These will be used to implicitly create a secured Space, with security privileges being propagated to internal services (such as Filters).
Processing Units interacting with a secured remote Space, need to lookup the Space and supply credentials (username and password) which will be used for authentication. Once authenticated, the proxy can be used to carry out operations (on behalf of the user granted privileges).
The pu.properties file supplied during deployment may contain the username and password. If these are supplied, they will be used to implicitly create a secured Space, with security privileges being propagated to internal services.
Of course, having the username and password exposed (in pu.xml/pu.properties) isn't that "secure". A preferred usage would be to supply the credentials during deployment. The UI, CLI and Admin API provide a comprehensive support for deploying a secured processing unit.
The local cache is a read-only service on top of a remote Space. Thus, the local cache "creator" needs to have Read privileges.
Security is enforced by the remote Space, and the proxy should be acquired by supplying the username and password.
UrlSpaceConfigurer urlSpaceConfigurer = new UrlSpaceConfigurer("jini://*/*/space").userDetails("user", "password");
GigaSpace remoteSpace = new GigaSpaceConfigurer(urlSpaceConfigurer).gigaSpace();
LocalCacheSpaceConfigurer configurer = new LocalCacheSpaceConfigurer(remoteSpace.getSpace()).updateMode(UpdateMode.PULL);
GigaSpace localCache = new GigaSpaceConfigurer(configurer.localCache()).gigaSpace();
<os-core:space id="remoteSpace" url="jini://*/*/space" >
<os-core:security username="user" password="password"/>
</os-core:space>
<os-core:local-cache id="localCacheSpace" space="remoteSpace" update-mode="PULL"/>
<!--
OpenSpaces simplified Space API built on top of IJSpace/JavaSpace.
-->
<os-core:giga-space id="localCache" space="localCacheSpace"/>
Similar to a Local Cache, the Local View is a read-only service on top of a remote Space. Here, the cache is limited to Views. Thus, the local view "creator" needs to have Read privileges for the specific views. For example, needs to have Read privileges for both Trade and Stock classes, otherwise access will be denied.
UrlSpaceConfigurer urlSpaceConfigurer = new UrlSpaceConfigurer("jini://*/*/space").userDetails("user", "password");
GigaSpace remoteSpace = new GigaSpaceConfigurer(urlSpaceConfigurer).gigaSpace();
LocalViewSpaceConfigurer configurer = new LocalViewSpaceConfigurer(remoteSpace.getSpace())
.addView(new View(Trade.class, "quantity = 20"))
.addView(new View(Stock.class, "stockId => 10"));
GigaSpace localView = new GigaSpaceConfigurer(configurer.localView()).gigaSpace();
<os-core:space id="remoteSpace" url="jini://*/*/space" >
<os-core:security username="user" password="password"/>
</os-core:space>
<os-core:local-view id="localViewSpace" space="space">
<os-core:view-query where="quantity = 20" class="...Trade"/>
<os-core:view-query where="stockId => 10" class="...Stock"/>
</os-core:local-view>
<!--
OpenSpaces simplified Space API built on top of IJSpace/JavaSpace.
-->
<os-core:giga-space id="localView" space="localViewSpace"/>
Filters are interceptors inside the GigaSpaces Space which allow implementation of user-defined logic based on Space events. Some filters need to perform operations on the embedded Space. If secured, the filter needs to have sufficient privileges for its operations.
The username and password supplied when creating a Space, will be used to implicitly create a secured Space. The security privileges of the specified user will be propagated to the Filter. If the user has Read privileges, then the filter will be able to perform a space.read(..) on its embedded Space.
Before Authentication operation
A filter can be registered for before-authentication events. Before a client tries to authenticate, any filter with the before-authentication operation-code will be invoked. The SpaceContext supplied as part of the call holds a SecurityContext that has the UserDetails object.
The following Spring configuration registers this filter for before-authentication (6) operation:
Note that the annotated method must have the SpaceContext as a parameter.
//Delegate Filter
public class SimpleFilter {
@BeforeAuthentication
public void beforeAuthenticationMethod(SpaceContext context) {
SecurityContext securityContext = context.getSecurityContext();
UserDetails user = securityContext.getUserDetails();
AuditDetails audit = securityContext.getAuditDetails();
System.out.println("user: " + user.getUsername() + " connecting from host: " + audit.getHost());
}
...
}
The following Spring configuration XML shows how the filter can be configured, using explicit method listings. (In this case, annotations are not required.)
Note the before-authentication method adapter.
Implicitly create a secured Space, with security privileges being propagated to the filter.
These privileges need to be sufficient for operations being perform by the filter on the embedded Space.
The filter acquires a GigaSpaces reference on filter initialization. Now the filter can perform operations on the embedded secured Space.
public class SimpleFilter {
GigaSpace gigaSpace;
@OnFilterInit
void init(IJSpace space) {
gigaSpace= new GigaSpaceConfigurer(space).gigaSpace();
}
@BeforeWrite
public void beforeWrite(Data data) {
int seq = gigaSpace.count(new Data()); //Needs 'Read' privileges for 'count' operation
data.setSeq( seq++);
data.setTimestamp( new Date());
}
Custom Access Control
Custom Access Control is available from 7.0.2
Custom Access control using Space Filters allows for access decisions based on user/role/data relationships. The SpaceContext filter invocation parameter holds the SecurityContext of the current operation. This context provides you with UserDetails, the Authentication and AuditDetails. Based on these, you can enforce custom access decisions.
Note that the SpaceContext may be null in cases related to replication/recovery and filter operations such as "notify-trigger". In these cases, there is no user context.
The filter can be declared just like any other filter, but note that the priority plays a role in the order of filter execution. Default priority is zero.
public class CustomAccessControlFilter {
...
@BeforeRead
public void beforeRead(Account account, int operationCode, SpaceContext context) {
SecurityContext securityContext = context.getSecurityContext();
UserDetails user = securityContext.getUserDetails();
/*
* only owner of an account can have access to his/her record data
*/
if (!user.getUsername().equals(account.getOwner())) {
thrownew AccessDeniedException("you are not the account owner!");
}
}
...
}
public class CustomAccessControlFilter {
...
@BeforeWrite
public void beforeWrite(Account account, int operationCode, SpaceContext context) {
SecurityContext securityContext = context.getSecurityContext();
GrantedAuthorities authorities = securityContext.getAuthentication().getGrantedAuthorities();
/*
* "accountants" can only create an account with an initial balance of $500
*/
if (authorities.isUserInRole("accountants") && account.getBalance() > 500) {
thrownew AccessDeniedException("don't be greedy!");
}
}
...
}
Tasks can be executed in a collocated asynchronous manner within the Space (processing unit with an embedded Space). To execute a task, you must have Execute privileges. Execution can be restricted to certain tasks by applying the 'Class-Filter'. There is no need to define specific privileges for operations being performed by the task on the Space.
Here is a simple implementation of a task that performs a 'count' operation on the space.
Executor Remoting allows you to use remote invocations of POJO services, with the Space as the transport layer using OpenSpaces Executors. To invoke a service method, you must have Execute privileges for class org.openspaces.remoting.ExecutorRemotingTask.
Event Driven Remoting allows you to use remote invocations of POJO services, with the space as the transport layer using a polling container on the space side to process the invocations. Under the wires, event driven remoting uses the Space write and take capabilities. Thus, you must have Write and Take privileges (at both ends) for class org.openspaces.remoting.EventDrivenSpaceRemotingEntry.
GigaSpaces allows applications to connect using a JDBC driver. A GigaSpaces JDBC driver accepts SQL statements, translates them to Space operations, and returns standard result sets. To acquire a connection to a remote secured space, provide the credentials (username and password) as parameters to the connection.