@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);