Getting Started with Glacier2

9 min read

9 min read

9 min read

9 min read

9 min read

9 min read

9 min read

9 min read

9 min read

Using Glacier2 in a minimal configuration involves the following tasks:

  1. Write a configuration file for the router.
  2. Write a password file for the router. (Glacier2 also supports other ways to authenticate users.)
  3. Decide whether to use the router's internal session manager, or supply your own session manager.
  4. Start the router on a host with access to the public and private networks.
  5. Modify the client configuration to use the router.
  6. Modify the client to create a router session.

The following router configuration property establish the necessary endpoint:

Properties
Glacier2.Client.Endpoints=tcp -h 5.6.7.8 -p 4063

The endpoint defined by Glacier2.Client.Endpoints is used by the Ice runtime in a client to interact directly with the router. It is also the endpoint where requests from routed proxies are sent. This endpoint is defined on the public network interface because it must be accessible to clients. Furthermore, the endpoint uses a fixed port because clients may be statically configured with a proxy for this endpoint. The port numbers 4063 (for TCP) and 4064 (for SSL) are reserved for Glacier2 by the Internet Assigned Numbers Authority (IANA).

Note that this configuration enables the router to forward requests from clients to servers. Additional configuration is necessary to support callbacks from servers to clients.

You must also decide which authentication scheme (or schemes) to use. A file-based mechanism is available, as are more sophisticated strategies.

If clients access a location service via the router, additional router configuration is typically necessary.

The router's simplest authentication mechanism uses an access control list in a text file containing user names and password hashes. The supported hash formats depend on the platform.

Hashes in the modular crypt format (MCF) have the structure $identifier$content, where identifier denotes the hashing scheme and content contains the scheme's parameters and hash.

On Windows and macOS:

  • PBKDF2 using SHA-1, SHA-256, or SHA-512 as the digest algorithm.

On Linux:

  • Any password hash format supported by the system's crypt library, including SHA-256 and SHA-512 crypt.

The property Glacier2.CryptPasswords specifies the name of the password file:

Properties
Glacier2.CryptPasswords=passwords

Each non-blank line contains exactly two whitespace-separated fields, a user name and a password hash, and each user name appears only once.

For example, the following password file contains an entry for the user name test on Linux:

test $6$rounds=656000$PFLqAztdBNhCjPeZ$GeZ3rLbMu4FObT78zAqQ15qJu0M/DSAZVBoNJCm95AaTflH.c06IcgFNbm8fOnl1ynGcEBqa.Ftgw3lJ0jPRm0

The same entry on Windows and macOS:

test $pbkdf2-sha256$29000$O4dQinGOcY7RWktJyXlvbQ$D0BZnA1kTw4Jl4xGUzdMOSxKO/vODiMCHEE9ZRLF4Gg

You can use the icehashpassword helper script to generate these password hashes. This script requires Python and pip to be installed. To install this script run:

Shell
pip install zeroc-icehashpassword

icehashpassword generates PBKDF2 hashes on Windows and macOS, and crypt hashes on Linux. It reads the password and prints the hash. On Linux:

Shell
icehashpassword
Password:
$6$rounds=656000$PFLqAztdBNhCjPeZ$GeZ3rLbMu4FObT78zAqQ15qJu0M/DSAZVBoNJCm95AaTflH.c06IcgFNbm8fOnl1ynGcEBqa.Ftgw3lJ0jPRm0

On Windows and macOS:

Shell
icehashpassword
Password:
$pbkdf2-sha256$29000$O4dQinGOcY7RWktJyXlvbQ$D0BZnA1kTw4Jl4xGUzdMOSxKO/vODiMCHEE9ZRLF4Gg

You may also specify several optional parameters:

  • -d MESSAGE_DIGEST_ALGORITHM, --digest=MESSAGE_DIGEST_ALGORITHM: sha1, sha256 (the default), or sha512 on Windows and macOS; sha256 or sha512 (the default) on Linux.
  • -s SALT_SIZE, --salt=SALT_SIZE (Windows and macOS only)
  • -r ROUNDS, --rounds=ROUNDS

For example:

Shell
icehashpassword -r 25000 -d sha256
Password:
...

Assuming our configuration properties are stored in a file named config, you can start the router with the following command:

Shell
glacier2router --Ice.Config=config

The following property configures a client to use a Glacier2 router:

Properties
Ice.Default.Router=Glacier2/router:tcp -h 5.6.7.8 -p 4063

The Ice.Default.Router property defines the router proxy. Its endpoints must match those in Glacier2.Client.Endpoints.

A Glacier2 router hosts one well-known object. The default identity of this object is Glacier2/router, corresponding to the Glacier2::Router interface. If an application requires the use of multiple different (that is, not replicated) routers, it is a good idea to assign a unique identity to this object by configuring the routers with different values of the Glacier2.InstanceName property, as shown in the following example:

Properties
Glacier2.InstanceName=PublicRouter

This property changes the category of the object identity, which becomes PublicRouter/router. The client's configuration must also be changed to reflect the new identity:

Properties
Ice.Default.Router=PublicRouter/router:tcp -h 5.6.7.8 -p 4063

One exception to this rule is if you deploy multiple Glacier2 routers as replicas, for example, to gain redundancy or to distribute the message-forwarding load over a number of machines. In that case, all the routers must use the same instance name, and the router clients can use proxies with multiple endpoints, such as:

Properties
Ice.Default.Router=PublicRouter/router:tcp -h 5.6.7.8 -p 4063:tcp -h 6.10.7.8 -p 4063

Session management is provided by the Glacier2::Router interface:

Slice
module Glacier2
{
exception PermissionDeniedException
{
string reason;
}
interface Router extends Ice::Router
{
Session* createSession(string userId, string password)
throws PermissionDeniedException, CannotCreateSessionException;
Session* createSessionFromSecureConnection()
throws PermissionDeniedException,CannotCreateSessionException;
idempotent string getCategoryForClient();
void destroySession()
throws SessionNotExistException;
}
}

The interface defines two operations for creating sessions: createSession and createSessionFromSecureConnection. The router requires each client to create a session using one of these operations; only after the session is created will the router forward requests on behalf of the client.

The createSession operation expects a user name and password and, depending on the router's configuration, returns either a Session proxy or nil. When using the default authentication scheme, the given user name and password must match an entry in the router's password file in order to successfully create a session.

The createSessionFromSecureConnection operation does not require a user name and password because it authenticates the client using the credentials associated with the client's SSL connection to the router.

To create a session, the client typically creates the router proxy from the communicator and then calls one of the create operations. For example:

C++
Glacier2::RouterPrx router{
communicator,
"Glacier2/router:tcp -h 5.6.7.8 -p 4063"};
optional<Glacier2::SessionPrx> session =
router->createSession(Env::getUsername(), "password");
C#
Glacier2.RouterPrx router = Glacier2.RouterPrxHelper.createProxy(
communicator,
"Glacier2/router:tcp -h 5.6.7.8 -p 4063");
Glacier2.SessionPrx? session =
await router.createSessionAsync(Environment.UserName, "password");
Java
RouterPrx router = RouterPrx.createProxy(
communicator, "Glacier2/router:tcp -h 5.6.7.8 -p 4063");
SessionPrx session;
try {
session = router.createSession(System.getProperty("user.name"), "password");
} catch (PermissionDeniedException | CannotCreateSessionException e) {
System.out.println("Could not create session: " + e.getMessage());
return;
}
JavaScript
const router = new Glacier2.RouterPrx(
communicator,
"Glacier2/router:tcp -h 5.6.7.8 -p 4063");
const session = await router.createSession(name, "password");
MATLAB
router = Glacier2.RouterPrx(communicator, ...
'Glacier2/router:tcp -h 5.6.7.8 -p 4063');
username = char(java.lang.System.getProperty('user.name'));
session = router.createSession(username, 'password');
PHP
$router = Glacier2\RouterPrxHelper::createProxy(
$communicator, 'Glacier2/router:tcp -h 5.6.7.8 -p 4063');
$username = get_current_user();
$session = $router->createSession($username, 'password');
Python
router = Glacier2.RouterPrx(
communicator,
"Glacier2/router:tcp -h 5.6.7.8 -p 4063")
session = await router.createSessionAsync(getpass.getuser(), "password")
Ruby
router = Glacier2::RouterPrx.new(
communicator,
"Glacier2/router:tcp -h 5.6.7.8 -p 4063")
username = Etc.getlogin
session = router.createSession(username, "password")
Swift
let router = try makeProxy(
communicator: communicator,
proxyString: "Glacier2/router:tcp -h 5.6.7.8 -p 4063",
type: Glacier2.RouterPrx.self)
let session = try await router.createSession(
userId: NSUserName(),
password: "password")

If the router is configured with a session manager, the createSession and createSessionFromSecureConnection operations may return a proxy for an object implementing the Glacier2::Session interface (or an application-specific derived interface). The client receives a null proxy if no session manager is configured.

A non-null session proxy returned by a create operation must be configured with the router that created it because the session object is only accessible via the router. If the router is configured as the client's default router at the time createSession or createSessionFromSecureConnection is invoked, then the session proxy is already properly configured and nothing else is required. Otherwise, the client must explicitly configure the session proxy with a router using the ice_router proxy method.

A Glacier2 session ends when the connection between the client and the router closes or when the client calls destroySession on the router. The server-side application can also end a session by calling destroy on the SessionControl object that the router passes to the session manager's create operation.