OpenPMF ClientSDK

Version 1.1 - February 2019 - © ObjectSecurity LLC - all rights reserved - questions? contact us

Overview

The OpenPMF ClientSDK is a library used by applications to use OpenPMF for fine-grained authorization management against a specified set of application feature attributes, e.g. menus, buttons, IP address. Applications provide “application feature attributes” to OpenPMF for which they need access control, e.g. menus, buttons, IP address. OpenPMF ingests this “application feature specification”, and policy administrators work through OpenPMF’s security policy automation roundtrip, potentially tapping into an external identity management system that provides requestor attributes (e.g. identities, groups etc.). OpenPMF’s policy automation roundtrip results in a ClientSDK permission file that assigns the fine-grained application feature attributes (permissions) to requestor attributes (e.g. user identities, user groups).



ClientSDK Architecture Overview


The SDK is provided to application creators for linking into their client applications that utilize OpenPMF’s fine-grained authorization management services. The library encapsulates all necessary integrations with OpenPMF’s REST APIs in support of rights management for that application.

All calls made by the SDK to OpenPMF are encrypted over HTTPS. An API key is set in every request header so the sender may be verified, and the JSON payload is signed with the client’s private key so that the integrity of the passed data may be verified. The client’s public key must be imported into OpenPMF manually.

The SDK is available as a Java language jar file. This web page documents its API.

Definitions

Application Specification - The application provided features and properties to be rights managed. Specified as JSON. Also called the feature matrix.

Feature Matrix - Same as the application specification.

IAM - Identity and Access Management.

Rights Matrix - The OpenPMF policy generated feature rights by user and/or group.

Access Management

In order for any API call to be permitted by OpenPMF, both the client and the payload signature must verified using the SDK-generated calling client’s public key.

When the OpenPMF ClientSDK is accessed for the first time a private-public key pair is generated, unique to the particular client application. The public key is written out to disk to the default directory of the client application. The name is opmf_client_sdk.pub. This key must be copied to the OpenPMF data folder of the user’s workspace. Your ObjectSecurity administrator can assist with this.

The SDK adds an API key to each API call’s request header, based on the client’s public key. On the API end, this key is verified using the public key from the data folder of the user’s workspace. If the API key is not verified, the call returns a security exception error.

Further, the API call payload (content) is signed using the calling client’s private security key. On the API side, the signature is verified using the public key from the user’s data directory. If the payload signature cannot be verified, the API call terminates with a security exception error.

In order to synchronize the SDK calls to the correct OpenPMF user, associated with the calling client application, the HTTPS port accessed after login to OpenPMF must be set in the ClientSDK using the method setHost() from the calling application, see below. If the incorrect port is used by the ClientSDK, client verification will fail.

The API

public static SDK getInstance( );

Returns the singleton SDK instance using any prior persisted state. This method calls getInstance( true ).

Prior persisted state includes the prior generated key pair for payload signing, the last application specification set by the client, and the last received application rights matrix.


public static SDK getInstance( boolean useCachedState );

Returns the singleton SDK instance. If this is the first instantiation at application startup, the instance will utilized cached state from its last running if useCachedState is true.

In either case, this method uses the private user store of the current user for cached SDK state. To enable this for the first time on Windows systems, the following must be done to make the store available.

This is a known issue with Java on Windows, and may be solved by following the procedure (suggested by MKorsch on StackOverflow: http://stackoverflow.com/questions/16428098/groovy-shell-warning-could-not-open-create-prefs-root-node):

  1. Go into the Start Menu and type regedit into the search field.
  2. Navigate to path HKEY_LOCAL_MACHINE\Software\JavaSoft (Windows 10 seems to now have this here: HKEY_LOCAL_MACHINE\Software\WOW6432Node\JavaSoft)
  3. Right click on the JavaSoft folder and click on New -> Key
  4. Name the new key ‘Prefs’ and everything should work.

public static void setHost( String domain, int port );

Sets the host information for the OpenPMF server.

domain is the host name or IP address, and port is the HTTPS port of the service. Consult the OpenPMF server’s properties for this information.


public static void setKeys( KeyPair appKeypair ) throws GeneralSecurityException;

Passes in the client’s public and private key pair to be used for payload signing. Keys should be generated using “DSA” algorithm. Key provider used must be “SUN”.

If a key pair is not passed in, the ClientSDK will generate a pair on behalf of the client.

The key pair is persisted in user store between runs. OpenPMF will require the public key for verification of received API calls.


public boolean setSpecification( String jsonAppImportSpec );

Provide the application's import specification, or feature matrix, to the SDK. This is provided every time the application feature set or other related configuration changes. The SDK will pass the specification on to OpenPMF when pushSpecification( ) is called.

String jsonAppImportSpec - The app's import specification file in json format.

Returns true if successfully received and cached a valid specification.


public boolean pushSpecification( );

Push the application specification to OpenPMF via an import API call. OpenPMF will then import the specification into the current project. Once imported, the specification may be executed against the application security policy and imported Gluu roles and identities. See generateRights( ) below.

Returns true if the import completed successfully. If not use getLastError( ) to determine what error occurred.


public boolean generateRights( boolean returnRights );

Instruct OpenPMF to generate the rights matrix from the application client data sets. These are the application specification, the app's OpenPMF-based security policy, and the imported IAM data (ldap directory).

boolean returnRights - If true, the generated rights matrix is returned directly from the underlying API call, in JSON format, and cached by the SDK. In this case pullRights( ), below, need not be called.

Returns true if rights matrix was generated correctly. If not use getLastError( ) to determine what error occurred.


public void refreshRights( double minutes );

Initiates a rights matrix generation cycle every number of minutes specified. minutes may be set to a fraction of a minute. Any running refresh cycle initiated with previous call to this method is terminated.

double minutes - If >0, rights will be re-generated repeatedly every number of minutes. If ==0, any previously initiated refresh cycle is terminated, and the call returns immediately.


public boolean pullRights( );

Retrieves the last generated rights matrix from OpenPMF for the client application. The node id of the last set application specification is used to identify the matrix to return.

Returns true if the rights matrix was successfully returned.


public String fullRightsMatrix( );

Returns the last pulled and cached rights matrix as a JSON formatted string.


public String featureRightsForAttribute( String type );

Return the feature rights keyed by attribute values for the specified attribute type, e.g. “identity” or “role”, as a JSON formatted String.


public String featureRightsForAttributeValue( String type, String value );

Return the feature rights for the attribute type and value specified, e.g. “identity” for “user1”, as a JSON formatted String.


[deprecated] public String featureRightsByIdentity( );

Return the feature rights keyed by user identity, as a JSON formatted String


[deprecated] public String featureRightsByGroup( );

Return the feature rights keyed by group or role, as a JSON formatted String.


public boolean available( );

Returns true if rights results are available from (cached in) the SDK. This may be stale information. Use updated( ) to see if a rights update is needed.


public boolean updated( );

Returns true if updated rights are available since the last setSpecification( ), pushSpecification( ) or generateRights( false ) call. A successful call to any of those API methods will set updated false.

A successful call to generateRights( true ) or pullRights( ) will set updated true.


public String getResponseProperty( String propertyKey );

Returns the property value for the specified key of the response JSON of the last API call, if it exists.


public String getLastError( );

Returns a readable error String for the last error that occurred within the SDK.

Examples

Usage

	import com.objectsecurity.openpmf.appclient.SDK;

	...

	SDK sdk= SDK.getInstance( true );

	String appSpecJson= readAppSpec(); // not part of SDK
	// send our specification to SDK
	sdk.setSpecification( appSpecJson );

	// send spec to OpenPMF, i.e. as an 'import'
	boolean success= sdk.pushSpecification();
	if( !success )
		System.out.println( sdk.getLastError() );

	// have OpenPMF generate the app's rights matrix, optionally return the result
	success= sdk.generateRights( true );
	if( !success )
		System.out.println( sdk.getLastError() );

	// specifically request the application's rights matrix from OpenPMF
	success= sdk.pullRights();
	if( success ) {
		String
		rights= sdk.featureRightsByGroup();
		System.out.println( "Features by Role:\n\t"+rights );
		rights= sdk.featureRightsByIdentity();
		System.out.println( "Features by Identity:\n\t"+rights );
	}

Application Specification:

{
"id": "OpenPMF Application Data Import",
"version": "1.0",
"node": {
	"name": "DEMO_APPLICATION app system",
	"id": "4587908fdghjGHJ",
	"parts": [{
		"name": "DEMO_APPLICATION Application",
		"type": "application",
		"id": "4dfghghfjklHJ",
		"features": {
			"buttons": [{
				"name": "DEMO_APPLICATION Search Button",
				"type": "application_button",
				"values": [
					"btn_search",
					"btn_report",
					"btn_dashboard",
					"btn_myaccount",
					"btn_vendor",
					"btn_product_parent",
					"btn_contract",
					"btn_product_name",
					"btn_product_category",
					"btn_product_oem",
					"btn_product_price",
					"btn_product_shipping",
					"btn_product_parts",
					"btn_SubAssembly",
					"btn_purchaseOrder",
					"txt_vendor",
					"txt_contract"
				]
			}],
			"menus": [{
				"name": "DEMO_APPLICATION Menu",
				"type": "application_menu",
				"values": [
					"Saved",
					"Risks",
					"Print",
					"Admin",
					"News",
					"Account",
					"About",
					"Logout"
				]
			}]
		}
	},{
		"name": "DEMO_APPLICATION Host Network",
		"type": "openpmf_internal/network",
		"id": "tyuiyttryuiytry567",
		"features": {
			"macs": [{
				"mac": "B8:27:EB:44:96:B5",
				"direction": "bidir",
				"ips": [{
					"ip": "192.168.0.101",
					"direction": "bidir",
					"ports": [{
						"port": "80",
						"direction": "inbound"
					},
					{
						"port": "123",
						"direction": "outbound"
					}]
				}]
			}]
		}
	},{
		"name": "DEMO_APPLICATION User Attributes",
		"type": "openpmf_internal/attributes",
		"id": "xyuiyttryuiytry560",
		"features": {
			"requestor_attributes": [{
				"name" : "DEMO_APPLICATION Requestor Identity",
				"type"	: "identity"
			},{
				"name" : "DEMO_APPLICATION Requestor Group",
				"type"	: "group"
			}]
		}
	}]
}}