The clientServerConfigs example uses the cacheRunner example to demonstrate the common recommended cache server and client configurations for client/server caching. The example configurations are located under the GemFire installation in examples/dist/clientServerConfigs. For information on client/server
caching, see the GemFire Enterprise Developer's Guide and
the online Java API documentation.
The examples/dist/clientServerConfigs
directory contains the XML cache configuration files for the cache server and client. There are two cache server configuration files. The first is server_notify_all.xml, which configures the server for the notify-all client entry update behavior. The second is server_notify_by_subscription.xml, which configures the server for notify-by-subscription behavior. There is one client file, client.xml.
In these files:
/root/cs_region. The client
creates the region with local scope, which ensures region isolation. The
server creates it with distributed-ack scope and replicate data policy so multiple server instances have identical data. The server also creates a
very simple loader on the region.You may need to change the cache server communication port to avoid conflicting with processes already running on your system. If you do, just make sure to change to
the same setting for cache-server port in both of the server_notify*.xml files.
You may also need to change the locator communication port to avoid conflicting with processes already running on your system. If you do, just make sure to change 4111 to your new port number in the following files: server/gemfire.properties, and client.xml.
clientServerConfigs directory also contains subdirectories with gemfire.properties files in them. These provide the distributed system configurations for the various client/server
caching models. They specify the server and client mcast-port settings that
define the distributed systems the VMs belong to. For the standalone client, they specify that the VM does not belong to any distributed system.
mcast-port settings to
avoid conflicting with ports that are already in use on your system. If you do, make sure
the setting in client_separate_dist_sys/gemfire.properties
is still different from the setting in server/gemfire.properties.
Do not change any of the settings in client_standalone/gemfire.properties.You will need at least two terminal sessions: one to run a cache server VM and one to run a client VM. These examples show one server and one client running at a time, but you can increase the number of either. However many you run, you need a separate terminal session for each.
examples/dist/clientServerConfigs.
The rest of the example instructions are relative to this directory.Follow these steps to start a locator, start the cache server, and add some entries to the server's cache.
server directory.
gemfire start-locator -port=41111
server_notify_by_subscription.xml file or the server_notify_all.xml file:
java cacheRunner.CacheRunner ../server_notify_by_subscription.xml
-- or --
java cacheRunner.CacheRunner ../server_notify_all.xml
This starts the cacheRunner program with the server's XML file and the current working directory's gemfire.properties file settings. The XML file defines a region named /root/cs_region and gives it a loader and a listener. The different configuration files determine how the server updates the client for server-side entry modifications. We'll see more about this at the end of the example.
When the server starts you see this prompt:
/root
value1, for the first entry, entry1, and you cause a loader
invocation by getting an entry, entry2, that doesn't exist in the cache.
The loader is programmed to return a value that is the string equivalent of the key. The listener reports on all entry creations, and specifies whether the value came from a load operation.
/root> chrgn cs_region /root/cs_region> put entry1 value1 CacheListener.afterCreate EntryEvent on region /root/cs_region [distributed, not expiration, local origin] [not load] Key: entry1 Old value: null New value: value1 /root/cs_region> get entry2 CacheListener.afterCreate EntryEvent on region /root/cs_region [distributed, not expiration, local origin] [local load] Key: entry2 Old value: null New value: entry2 entry2 -> String: "entry2" /root/cs_region> ls Region Entries: entry1 -> byte[]: "value1" entry2 -> String: "entry2" Subregions: /root/cs_region>Leave this running. The listener will report when there are modifications to the server's cs_region.
Follow these instructions for either of the client subdirectories to see the client/server cache working.
client_standalone or the client_separate_dist_sys directory and run the following:
java cacheRunner.CacheRunner ../client.xml
registerInterest step if you are running the server with the server_notify_all.xml file.
/root> chrgn cs_region
/root/cs_region> registerInterest entry1
Interest registered in entry1
/root/cs_region> get entry1
entry1 -> byte[]: "value1"
/root/cs_region> get entry2
entry2 -> String: "entry2"
/root/cs_region> des entry2
/root/cs_region> get entry3
entry3 -> String: "entry3"
/root/cs_region> put entry1 valueFromClient
/root/cs_region>
As you run the commands, note the output in the server VM.
When you ask for an entry that exists on the server, like entry1, it is passed directly
from the server cache. When you ask for an entry that the
server does not have, like entry3, it invokes its loader, updates the server cache,
and returns the result. When you put an entry on the client side, the new value is passed up to the server.
ls on both the server and client to verify the cache contents. Both sides should report the same thing:
/root/cs_region> ls
Region Entries:
entry1 -> byte[]: "valueFromClient"
entry3 -> String: "entry3"
With notify-by-subscription, the server automatically sends entry update notification, with values, for the entries the client has registered interest in. For entries that are not registered, the client can get values explicitly, but receives no updates for server-side update operations. With notify-all, the server automatically sends entry update notifications to the client as invalidations for all entries, with no values passed. Then, if the client needs the value, the get operation retrieves it from the server.
entry1 and entry2 in the server session.
/root/cs_region> put entry1 serverValue1
...
/root/cs_region> put entry2 serverValue2
...
notify-by-subscription, the client side entry1 has the new server value. This is because the client registered interest in entry1 at the beginning of this session. The other entry, entry3, is not changed, so at this point it does not match the server cache. Since the client did not register interest in entry3, the server does not propagate any information on the server-side modification.
To see the results, run ls on the client side.
/root/cs_region> ls
entry1 -> byte[]: "serverValue1"
entry3 -> String: "entry3"
notify-all, entry1 is invalidated on the client.
To see this, run ls on the client side:
/root/cs_region> ls
entry1 -> No value in cache.
entry3 -> String: "entry3"
You need to stop the running server and client sessions so you can configure them for the following authentication/authorization example. Follow these instructions:
quit in the server session, but leave the session open.quit in the client session and leave the session open.GemFire can be configured so that a client attempting to connect to a server must first submit credentials to the server for authentication. Credentials are typically submitted as a username and a password. Client operations on the server can be authorized or denied based on the client's credentials.
Authentication and authorization in this example is configured in the gemfire.properties files for the server and client. Descriptions of the configuration properties are listed below.
Do not enter these values. These are descriptions of security properties for the server.
# The sample implementation of LDAP server-based authentication. security-client-authenticator=templates.security.LdapUserAuthenticator.create # Point to a valid LDAP server. security-ldap-server=ldap # The baseDN details (top level directory tree) of the LDAP server mentioned above. security-ldap-basedn=ou=ldapTesting,dc=pune,dc=gemstone,dc=com # The sample implementation of Xml-based authorization. security-client-accessor=templates.security.XmlAuthorization.create # The xml configuration file for XmlAuthorization accessor mentioned above. # Modify the usernames in the provided XML to match those recognized by the # LDAP server mentioned above. security-authz-xml-uri=authz-ldap.xmlDo not enter these values. These are descriptions of security properties for the client.
# The username/password-based sample implementation of AuthInitialize. security-client-auth-init=templates.security.UserPasswordAuthInit.create # The authentication credentials, such as a username and password. # These should be valid combinations recognized by the LDAP server mentioned # on the server side. security-username=gemfire security-password=gemfire
Follow these steps to configure the cache server for authentication and authorization, then start the server.
server directory if the server session is not already in that directory.gemfire.properties file so the file can be restored to its original, unedited state. gemfire.properties file.
security-ldap-server=ldap security-ldap-basedn=ou=ldapTesting,dc=pune,dc=gemstone,dc=com security-client-authenticator=templates.security.LdapUserAuthenticator.create security-client-accessor=templates.security.XmlAuthorization.create security-authz-xml-uri=authz-ldap.xml
Refer to the Sample GemFire Security Implementations section for other options for configuring and launching the server with cacheRunner.
server_notify_by_subscription.xml file:
java cacheRunner.CacheRunner ../server_notify_by_subscription.xml
This starts the cacheRunner program with the server's XML file and the current working directory's gemfire.properties file settings. The xml file defines a region named /root/cs_region and gives it a loader and a listener.
Once the server has started, this prompt appears:
/root>
/root> chrgn cs_region
/root/cs_region> put entry1 value1
CacheListener.afterCreate EntryEvent on region /root/cs_region
[distributed, not expiration, local origin]
[not load]
Key: entry1
Old value: null
New value: value1
/root/cs_region> ls
Region Entries:
entry1 -> byte[]: "value1"
Subregions:
/root/cs_region
Leave this running. The listener will report when there are modifications to the server's cs_region. To see the client/server cache working with authentication and authorization, you will modify the configuration in the client_standalone subdirectory. Make a copy of the gemfire.properties file in that directory so the file can be restored to its original, unedited state.
With Valid Credentials:
client_standalone directory if it's not already in that directory.gemfire.properties file (be sure to remove # from the security- properties):
security-client-auth-init=templates.security.UserPasswordAuthInit.create
security-username=gemfire3
security-password=gemfire3
java cacheRunner.CacheRunner ../client.xml
/root> chrgn cs_regionThe
/root/cs_region> ls
Region Entries: Subregions: /root/cs_region> get entry1 entry1 -> byte[]: "value1"
/root/cs_region> ls Region Entries: entry1 -> byte[]: "value1" Subregions: /root/cs_region> put key2 value2
put operation results in this error message:
com.gemstone.gemfire.cache.client.ServerOperationException: com.gemstone.gemfire
.security.NotAuthorizedException: Not authorized to perform PUT operation on region
[/root/cs_region]
The error message reports that the put operation is not authorized.
Note that authorization is granted for the get operation. Review the roles and privileges table in LDAP Authentication to see that the gemfire3 credentials authorize the client to perform reader operations, which includes get, but not writer operations, which includes put.
With Invalid Credentials:
quit in the client session to stop the running client.
security-username and security-password properties in gemfire.properties to start the client with invalid credentials:
security-username=invalidUsr security-password=invalidUsr
AuthenticationFailedException occurs:java cacheRunner.CacheRunner ../client.xml
Exception in thread "main" com.gemstone.gemfire.security.AuthenticationFailedException:
LdapUserAuthenticator: Failure with provided username, password combination for user name: invalidUsr
With No Credentials:
security-client-auth-init, security-username and security-password properties from gemfire.properties to start the client without any credentials.AuthenticationRequiredException exception occurs.
java cacheRunner.CacheRunner ../client.xml
Exception in thread "main" com.gemstone.gemfire.security.AuthenticationRequiredException:
No security-* properties are provided
quit to stop the running server.
gemfire stop-locator -port=41111
exit to close the server session.
exit to close the session.
There are two aspects to GemFire security:
Authentication can be either Dummy, LDAP server-based, or PKCS-based, whereas authorization is XML-based only. For different authentication schemes, the corresponding authorization XML configuration file should be provided to the Sample Authorization module.
This authentication scheme is based on a simple username and password. The server side authenticator is in package templates.security.DummyAuthenticator.create. The client side initializer for it is in templates.security.UserPasswordAuthInit.create.
| Authentication User Name | Authorization Roles | Permission to the Roles | |||
|---|---|---|---|---|---|
| root, admin, administrator | reader, writer, cacheOps |
|
|||
| reader0, reader1, reader2 | reader |
|
|||
| writer0, writer1, writer2 | writer |
|
|||
| reader3, reader4 | queryRegions |
|
This scheme is based on the usernames and password configured in a LDAP server. Refer to the Security chapter in the GemFire Enterprise System Administrator's Guide for more details. The server side authenticator is in package templates.security.LdapUserAuthenticator.create The client side initializer for it is in templates.security.UserPasswordAuthInit.create.
| Authentication User Name | Authorization Roles | Permission to the Roles | |||
|---|---|---|---|---|---|
| gemfire1, gemfire2 | reader, writer, cacheOps |
|
|||
| gemfire3, gemfire4, gemfire5 | reader |
|
|||
| gemfire6, gemfire7, gemfire8 | writer |
|
|||
| gemfire9, gemfire10 | queryRegions |
|
This scheme is based on public/private key-based encryption and decryption. Refer to the Security chapter in the GemFire Enterprise System Administrator's Guide for keystore configurations. The server-side authenticator is in package templates.security.PKCSAuthenticator.create. The client-side initializer is in templates.security.PKCSAuthInit.create.
PKCS configuration details:
gemfire.properties for client-side configuration.
% security-keystorepath=<absolute filepath to keystore where keys are generated>
% security-alias=<alias name given while generating Public & Private key pair for the Client>
% security-keystorepass=<password entered while generating Private key while Self-signing>
gemfire.properties for server side configuration.
% security-publickey-filepath=<absolute filepath to keystore where public keys are generated>
% security-publickey-pass=<password entered while generating key to TrustStore>
| Authentication KeyStore Aliases | Authorization Roles | Permission to the Roles | |||
|---|---|---|---|---|---|
| gemfire1, gemfire2 | reader, writer, cacheOps |
|
|||
| gemfire3, gemfire4, gemfire5 | reader |
|
|||
| gemfire6, gemfire7, gemfire8 | writer |
|
|||
| gemfire9, gemfire10 | queryRegions |
|
This authorization scheme is based on the prior mapping of authentication credentials to roles and privileges. Permissions in XML files are supplied corresponding to the authentication scheme. Refer to the Security chapter in the GemFire Enterprise System Administrator's Guide for more information. The server-side security-accessor is in package templates.security.XmlAuthorization.create, and security-authz-xml-uri should point to either authz-dummy.xml or authz-ldap.xml, depending on the security-authenticator provided.
There are a number of scenarios you can explore with this basic setup. You might add
other clients and see the effect on client peers when a client updates an entry. You could see how the behavior changes when subscriptions are disabled
(in the client's XML configuration file, change the true value
to false for the "subscription-enabled" attribute).