@ParametersAreNonnullByDefault
See: Description
Interface | Description |
---|---|
AccountManagement | |
DataStorage | |
PersistenceCallback |
The Smartcrypt SDK persists user information across sessions.
|
SmartcryptKeyManagement | |
Smartkeys | |
Users |
Class | Description |
---|---|
SmartcryptKeyManagementImpl | |
SmartcryptKeyManagementImpl.Builder | |
SmartkeySpec | |
UserSpec |
The Key Management component is the starting point for all interactions with the Smartcrypt SDK. The Key Management component makes it easy to login as a Smartcrypt user and to create, retrieve, share, and use Smartkeys. Policies configured on the Smartcrypt manager are automatically enforced, and data stored locally are cryptographically tamper resistant.
MetaClient metaClient = new NativeMetaClient.Builder()
.appName("LoggingIn")
.appVersion("1.0.0")
.server("https://oh1.smartcrypt.com/mds")
.build();
SmartcryptKeyManagement smartcryptKeyManagement = new SmartcryptKeyManagementImpl.Builder()
.metaClient(metaClient)
.persistenceCallback(new InMemoryPersistenceCallback())
.build();
AccountManagement accountManagement = smartcryptKeyManagement.getAccountManagement();
// There are 3 types of login methods: managed, implicit, and unmanaged.
//
// Managed login is used for accounts that are managed by Active Directory. The credentials used are the
// same as those of the domain account.
//
// This login variant requires the developer to provide credentials, but does not require any system
// configuration.
//
accountManagement.loginManagedAccount("example@smartcrypt.com", "password");
// Implicit login uses the domain account of the computer user who owns the process running MetaClient.
// Typically, this is the user logged-in to Windows, Mac, etc, but may be a different user. On Windows,
// Integrated Windows Authentication is used for a seamless experience. On *nix systems, Kerberos is used,
// and the kinit program, or a similar utility, must be used to configure the account prior to login.
//
// This login variant does not require the developer to provide any credentials, but does require system
// configuration by the system administrator.
//
// Note that to use implicit login, the developer must supply a server URL to the MetaClient builder.
accountManagement.loginImplicitAccount();
/*
// Unmanaged login is used for accounts that are created in Smartcrypt Enterprise Manager. These do not live
// in Active Directory. The credentials are owned by Smartcrypt Enterprise Manager.
//
// This login variant requires the developer to provide credentials, but does not require any system
// configuration.
accountManagement.loginUnManagedAccount("unmanaged@smartcrypt.com", "password");
MetaClient metaClient = new NativeMetaClient.Builder()
.appName("CreatingAndUpdatingSmartkeys")
.appVersion("1.0.0")
.deviceName(UUID.randomUUID().toString())
.deviceUniqueId(UUID.randomUUID().toString())
.platform(Platform.LINUX)
.platformVersion("0")
.build();
SmartcryptKeyManagement smartcryptKeyManagement = new SmartcryptKeyManagementImpl.Builder()
.metaClient(metaClient)
.persistenceCallback(new InMemoryPersistenceCallback())
.build();
smartcryptKeyManagement.getAccountManagement().loginManagedAccount("<your username>", "<your password>");
Smartkeys smartkeys = smartcryptKeyManagement.getSmartkeys();
//
// To create a new Smartkey, prepare a SmartkeySpec with the information for the new key.
// Keys created using the SDK are always GenericSmartkeys.
//
SmartkeySpec createSmartkeySpec = new SmartkeySpec();
createSmartkeySpec.name = "Sample";
createSmartkeySpec.addAccess.add("john.doe@example.com");
// Key creation is synchronous, but you can be notified of updates to the key by listening to the Observable
Observable<Smartkey> keyObservable = smartkeys.create(createSmartkeySpec);
Smartkey smartkey = keyObservable
.doOnEach(genericSmartkeyNotification -> {
Smartkey key = genericSmartkeyNotification.getValue();
System.out.println("Got revision " + key.getRevision() + " for created Smartkey " + key.getName());
})
.blockingSingle();
//
// To update a key, once again prepare a SmartkeySpec. Most types of keys can be updated in some fashion
//
SmartkeySpec updateSmartkeySpec = new SmartkeySpec();
updateSmartkeySpec.name = "Updated Sample";
updateSmartkeySpec.removeAccess.add("john.doe@example.com");
// Key updates are synchronous, but once again, you can be notified of updates to the key by listening to
// the observable
Observable<Smartkey> updatedKeyObservable = smartkeys.update(smartkey, updateSmartkeySpec);
updatedKeyObservable
.subscribe(key -> System.out.println("Got updated Smartkey " + key.getName()));
MetaClient metaClient = new NativeMetaClient.Builder()
.appName("BackgroundProcessing")
.appVersion("1.0.0")
.deviceName(UUID.randomUUID().toString())
.deviceUniqueId(UUID.randomUUID().toString())
.platform(Platform.LINUX)
.platformVersion("0")
.build();
SmartcryptKeyManagement smartcryptKeyManagement = new SmartcryptKeyManagementImpl.Builder()
.metaClient(metaClient)
.persistenceCallback(new InMemoryPersistenceCallback())
.build();
// Background errors come out as Notifications and can easily be logged or monitored
smartcryptKeyManagement.getDataStorage().getNotifications()
.map(unfiltered -> {
Set<Notification> filtered = new LinkedHashSet<>(unfiltered.size());
for (Notification notification : unfiltered) {
if (notification instanceof SyncProblemNotification) {
filtered.add(notification);
}
}
return filtered;
})
.flatMap(Observable::fromIterable)
.subscribe(problem -> System.out.println(problem.message));
// Background processing can be paused. This may be necessary if your app goes into the a state where the
// process is alive, but the user does not expect it to be running, such as a backgrounded mobile app
smartcryptKeyManagement.pauseBackgroundProcessing();
// Background processing can also be resumed
smartcryptKeyManagement.resumeBackgroundProcessing();
MetaClient metaClient = new NativeMetaClient.Builder()
.appName("PersistingSmartkeys")
.appVersion("1.0.0")
.deviceName(UUID.randomUUID().toString())
.deviceUniqueId(UUID.randomUUID().toString())
.platform(Platform.LINUX)
.platformVersion("0")
.build();
SmartcryptKeyManagementImpl.Builder builder = new SmartcryptKeyManagementImpl.Builder()
.metaClient(metaClient);
// Persistence is done as part of sync. Sync happens on a worker thread, so the persistence happens on the
// same worker thread. Persistence is synchronous, and the next sync will wait until persistence has
// completed, but SDK consumers don't need to know that.
SmartcryptKeyManagement smartcryptKeyManagement = builder
.persistenceCallback(new InMemoryPersistenceCallback())
.build();
smartcryptKeyManagement.getAccountManagement().loginManagedAccount("<your username>", "<your password>");
Smartkeys smartkeys = smartcryptKeyManagement.getSmartkeys();
// For this example, any Smartkey will do. We'll just take the first one we get
Smartkey smartkey = smartkeys.listAll()
.blockingFirst()
.iterator().next();
// Smartkey serialization is straightforward. When serializing, the information of the provided Smartkey is
// used.
String serializedRepresentation = smartkeys.serialize(smartkey);
System.out.println("Serialized Smartkey " + smartkey.getName() + ": " + serializedRepresentation);
// Retrieving a Smartkey from its serialized form is also straightforward.
Smartkey deserializedSmartkey = smartkeys.deserialize(serializedRepresentation).blockingFirst();
System.out.println("Smartkey " + deserializedSmartkey.getName());
MetaClient metaClient = new NativeMetaClient.Builder()
.appName("PersistingMetadata")
.appVersion("1.0.0")
.deviceName(UUID.randomUUID().toString())
.deviceUniqueId(UUID.randomUUID().toString())
.platform(Platform.LINUX)
.platformVersion("0")
.build();
SmartcryptKeyManagementImpl.Builder builder = new SmartcryptKeyManagementImpl.Builder()
.metaClient(metaClient);
// Persistence is done as part of sync. Sync happens on a worker thread, so the persistence happens on the
// same worker thread. Persistence is synchronous, and the next sync will wait until persistence has
// completed, but SDK consumers don't need to know that.
SmartcryptKeyManagement smartcryptKeyManagement = builder
.persistenceCallback(new FilePersistenceCallback())
.build();
// Data restore, both threading and timing, is controlled by the developer
DataStorage dataStorage = smartcryptKeyManagement.getDataStorage();
dataStorage.restore();
// Be sure to define this class somewhere
class FilePersistenceCallback implements PersistenceCallback {
private final static String folder = "serializedMetadata";
public boolean onSaveData(Map<String, String> toSave, Set<String> toDelete) {
try {
Files.createDirectory(Paths.get(folder));
for (Map.Entry<String, String> datum : toSave.entrySet()) {
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(folder, datum.getKey()))) {
writer.write(datum.getValue());
}
}
for (String name : toDelete) {
Files.deleteIfExists(Paths.get(folder, name));
}
return true;
} catch (IOException e) {
return false;
}
}
public Map<String, String> onLoadData() {
try {
return Files.list(Paths.get(folder))
.collect(Collectors.toMap(
path -> path.getFileName().toString(), // Key
fileName -> { // Value
try {
return new String(Files.readAllBytes(fileName));
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
));
} catch (IOException e) {
return Collections.emptyMap();
}
}
}
// Observables emit a stream of events. This is a push model rather than a pull model.
Observable<Integer> observable = Observable.range(0, 5);
// Observables can be transformed
Observable<String> intsAsStrings = observable.map(Object::toString);
// Use common stream/observable operators
Observable<String> filteredInts = intsAsStrings.filter(number -> !"3".equals(number));
// Observables only process when subscribed to. All of the previous "work" is only setup - none of it has
// run yet. When we subscribe now, the work will happen.
Disposable subscription = filteredInts.subscribe(System.out::println);
// Subscriptions must be disposed when we're done with them, otherwise the stream will continue processing
// when we no longer need it
subscription.dispose();
//
// Observables can also be made blocking, effectively making them a single, synchronous call
//
Integer lastNumberBlocking = Observable.range(0, 4).blockingLast();
System.out.println("With a blocking call: " + lastNumberBlocking);