Configuration
- Add the SDK to your project
- Instantiating the SDK
- Configuration model
- Certificate pinning
- Providing your own authentication request handlers and callbacks
- Other OneginiClient settings
- Sample initialization call
Add the SDK to your project
If you are using Gradle you can add the library with the following dependency.
Gradle dependency
compile 'com.onegini.mobile.sdk.android:onegini-sdk:VERSION@aar' {
transitive = true
}
Instantiating the SDK
All functions of the Onegini Android SDK are available from a single facade - the OneginiClient
. The OneginiClient
is a singleton which has to be set up
once with the OneginiClientBuilder
class. It can can be fetched via a OneginiClient.getInstance()
method afterwards.
Note: the Application (not Activity) context must be used to instantiate the OneginiClient
.
Code example OneginiClient instantiation
public class OneginiSDK {
public static OneginiClient getOneginiClient(final Context context) {
OneginiClient oneginiClient = OneginiClient.getInstance();
if (oneginiClient == null) {
oneginiClient = buildSDK(context);
}
return oneginiClient;
}
private static OneginiClient buildSDK(final Context context) {
final Context applicationContext = context.getApplicationContext();
final RegistrationRequestHandler registrationRequestHandler = new RegistrationRequestHandler(applicationContext);
final CreatePinRequestHandler createPinRequestHandler = new CreatePinRequestHandler(applicationContext);
final PinAuthenticationRequestHandler pinAuthenticationRequestHandler = new PinAuthenticationRequestHandler(applicationContext);
// will throw OneginiConfigNotFoundException if OneginiConfigModel class can't be found
return new OneginiClientBuilder(applicationContext, createPinRequestHandler, pinAuthenticationRequestHandler)
.setBrowserRegistrationRequestHandler(registrationRequestHandler)
.build();
}
}
First method that has to be called on OneginiClient
after app's startup is OneginiClient#start()
. This method is responsible for asynchronous initialization
of the SDK. During this process the SDK can return errors, for example if the device is using deprecated android version or when the app version is outdated.
Because of that the method expects a OneginiInitializationHandler
in order to return initialization results.
Code example OneginiClient initialization
// method called during app's startup
private void setupOneginiSDK() {
final OneginiClient oneginiClient = OneginiSDK.getOneginiClient(this);
oneginiClient.start(new OneginiInitializationHandler() {
@Override
public void onSuccess(final Set<UserProfile> removedUserProfiles) {
// remove UserProfiles that were removed on the server side and proceed with you application flow
}
@Override
public void onError(final OneginiInitializationError error) {
// handle different error types
}
});
}
Configuration model
Configuration properties should be provided to the SDK via an implementation of the OneginiClientConfigModel
interface. The implementation can be provided in
two ways:
- If the
SDK Configurator
script was used to apply configuration and certificate pinning to your app project, theOneginiClientConfigModel
implementation will be added to the app's main directory. In such case the SDK will use reflection and theContext#getPackageName()
method to search for a class called{your.application.package}.OneginiConfigModel
, that implements theOneginiClientConfigModel
interface. If the proper class can't be found, the SDK will throw anOneginiConfigNotFoundException
exception. - If you want to create the implementation manually, or when you want to move the generated implementation to a different (sub)package, then you can explicitly
provide the config using the
OneginiClientBuilder#setConfigModel()
method.
Code example OneginiClientConfigModel implementation
// ...
final OneginiClientConfigModel configModel = new OneginiClientConfigModel() {
/**
* Application identifier, as configured on the Token Server.
* Please note that once set, the id should not change. Otherwise the SDK will not be able to resolve internally stored data.
*/
@Override
public String getAppIdentifier() {
return "myAppId";
}
/**
* Application platform, as set within application version on the Token Server.
* Please note that once set, the platform should not change. Otherwise the SDK will not be able to resolve internally stored data.
*/
@Override
public String getAppPlatform() {
return "android";
}
/**
* Redirect uri used in the callback from the authentication process to the client
* @return the redirect uri used in the callback
*/
@Override
public String getRedirectUri() {
return "oneginisdk://loginsuccess";
}
/**
* Application version, as set within application version on the Token Server.
*/
@Override
public String getAppVersion() {
return "1.0";
}
/**
* Token Server's base url.
*/
@Override
public String getBaseUrl() {
return "https://acme.token-server.com";
}
/**
* Resource server base url.
*/
@Override
public String getResourceBaseUrl() {
return "https://acme.resource-gateway.com";
}
/**
* Resource containing certificate-to-pin identifier, by default it's `keystore.bks` located in `res/raw`.
*/
@Override
public int getCertificatePinningKeyStore() {
return R.raw.keystore;
}
/**
* Certificate-to-pin (`keystore.bks`) hash.
*/
@Override
public String getKeyStoreHash() {
return "52b7a8bb2a72356d271a6df6bdfc88f4d78e46913adca54da77a70f260e12af3";
}
/**
* Defice name. Will be used during client registration process, allows user to distinguish his devices more precisely.
* Please note that once set, the device name should not change. Otherwise the SDK will not be able to resolve internally stored data.
*/
@Override
public String getDeviceName() {
return android.os.Build.MODEL;
}
}
final OneginiClient oneginiClient = new OneginiClientBuilder(applicationContext, createPinRequestHandler, pinAuthenticationRequestHandler)
.setConfigModel(configModel)
.build();
// ...
It is up to the app developer to choose the storage method for the configuration parameters.
Certificate pinning
The SDK provides functionality to pin your servers certificate. Please note, if you pin the servers certificate itself you will need to deploy a new version of the application when you change the servers certificate. Best alternative is to use the intermediate certificate of the Certificate Authority used to get the server certificate (the second level in the certificate chain). This gives you the option to renew the server certificate without having to deploy a new version of the application.
Export the certificate
You can use Firefox to export the certificate. Click on the lock of the SSL website. Choose: more information. In the security tab press View certificate. Then go to the details tab. And there you can choose which certificate in the chain you wish to export.
Creating a keystore
In order to create a keystore you need a java jdk installed to get "keytool". And for android you need bouncy castle 1.46 (newer versions of bouncy castle create a keystore with a different header which is not accepted by android).
http://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on/1.46
Create keystore
keytool -import -alias MYALIAS -file /PATH/TO/CERTIFICATE/FROM/EXPORT -keystore /PATH/TO/keystore.bks -storepass PASSWORD -providerpath /PATH/TO/BOUNCYCASTLE/1.46/bcprov-ext-jdk15on-1.46.jar -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
Add the keystore to the project
The keystore has to be added to the "raw" directory of your android project. And your configuration needs to provide the keystore within the Configuration. For example:
Keystore configuration
@Override
public int getCertificatePinningKeyStore() {
return R.raw.keystore;
}
Keystore tampering protection
As the keystore is stored on the file system of the device, theoretically it is possible to tamper it. This is possible if the device is rooted an some malicious APP is installed. To prevent a tampered keystore, a SHA 256 hash of the keystore has to be provided by the APP. It is recommended to have the hash hardcoded and not in a separate property file or any other file on the file system. The keystore normally already is an element of the APPs binary and in that way hard coding the hash doesn't introduce any new inflexibilities.
Calculating the keystore hash
shasum -a 256 keystore.bks
Example code of hash in config model
@Override
public String getKeyStoreHash() {
return "7A8E3D2333A1324229712B288950E317CE5BE5F956C196CEF33B46993D371575";
}
Providing your own authentication request handlers and callbacks
When the Token Server returns oAuth 2.0 refresh tokens the user needs to provide a PIN or a fingerprint to store those credentials. For this you need to
provide your own authentication request handlers using OneginiClientBuilder
methods. The OneginiCreatePinRequestHandler
and
OneginiPinAuthenticationRequestHandler
are required in order to perform basic registration and authentication with PIN. Other handlers are optional and
should be provided only when the app uses functionalities like fingerprint or mobile authentication. Please read authentication request handlers
chapter for more details.
Other OneginiClient settings
OneginiClientBuilder
exposes additional methods to customize OneginiClient
behaviour:
shouldStoreCookies(final boolean shouldStoreCookies)
method can be used to specify if http client should store cookies between requests. The default value is TRUE.setHttpConnectTimeout(final int timeout)
method can be used to specify http client's connection timeout (in milliseconds). Default value is 60000 (60s).setHttpReadTimeout(final int timeout)
method can be used to specify http client's read timeout (in milliseconds). Default value is 60000 (60s).setDeviceConfigCacheDurationSeconds(final long cacheDurationSeconds)
method can be used to specify device configuration cache duration (in seconds). Default value is 300s (5 minutes). Passing 0 will disable the cache.
Sample initialization call
public static OneginiClient getOneginiClient(final Context context) {
OneginiClient oneginiClient = OneginiClient.getInstance();
if (oneginiClient == null) {
final Context applicationContext = context.getApplicationContext();
final RegistrationRequestHandler registrationRequestHandler = new RegistrationRequestHandler(applicationContext);
final OneginiCreatePinRequestHandler createPinRequestHandler = new CreatePinRequestHandler();
final OneginiPinAuthenticationRequestHandler pinAuthenticationRequestHandler = new PinAuthenticationRequestHandler();
final OneginiFingerprintAuthenticationRequestHandler fingerprintAuthenticationRequestHandler = new FingerprintAuthenticationRequesthandler();
// will throw OneginiConfigNotFoundException if OneginiConfigModel class can't be found
oneginiClient = new OneginiClientBuilder(applicationContext, createPinRequestHandler, pinAuthenticationRequestHandler)
.setBrowserRegistrationRequestHandler(registrationRequestHandler)
// optional settings
.setFingerprintAuthenticationRequestHandler(fingerprintAuthenticationRequestHandler)
.setConfigModel(new OneginiConfigModel())
.setHttpReadTimeout(30000)
.setDeviceConfigCacheDurationSeconds(600)
.build();
}
return oneginiClient;
}