Enabling Client Registrations¶
Client Registrations¶
In certain cases, such as when Download Tracking is enabled, the OData service needs to track registered clients.
For this purpose, the CSDL must contain a ClientRegistration
entity type and corresponding ClientRegistrationSet
entity set.
The ClientRegistration
entity type:
-
Must include a
ClientID
key property of typeEdm.Int64
-
Must include a
ClientGUID
property of typeEdm.Guid
-
May include an
AuthorizedUser
property of typeEdm.String
. If specified, this property will be populated automatically with the registration's authorized user name if the OData service is deployed with authentication enabled. Otherwise this property will benull
. -
May include arbitrary other properties of use to the client application.
Example:
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docs.oasis-open.org/odata/ns/edmx http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edmx.xsd http://docs.oasis-open.org/odata/ns/edm http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edm.xsd">
...
<edmx:DataServices>
<Schema Namespace="my.schema" Alias="Self" xmlns="http://docs.oasis-open.org/odata/ns/edm">
...
<EntityType Name="ClientRegistration">
<Key>
<PropertyRef Name="ClientID"/>
</Key>
<Property Name="ClientID" Type="Edm.Int64" Nullable="false"/>
<Property Name="ClientGUID" Type="Edm.Guid" Nullable="false"/>
<Property Name="AuthorizedUser" Type="Edm.String" Nullable="true" MaxLength="200"/>
</EntityType>
<EntityContainer Name="MyService">
...
<EntitySet Name="ClientRegistrationSet" EntityType="Self.ClientRegistration"/>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Client Credentials¶
Properties such as passwords, or other security credentials apart from AuthorizedUser
, should not be stored in the
ClientRegistration
entity type. Instead, the CSDL should contain a ClientCredentials
entity type and corresponding
ClientCredentialsSet
entity set.
Example:
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docs.oasis-open.org/odata/ns/edmx http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edmx.xsd http://docs.oasis-open.org/odata/ns/edm http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edm.xsd">
...
<edmx:DataServices>
<Schema Namespace="my.schema" Alias="Self" xmlns="http://docs.oasis-open.org/odata/ns/edm">
...
<EntityType Name="ClientCredentials">
<Key>
<PropertyRef Name="ClientID"/>
</Key>
<Property Name="ClientID" Type="Edm.Int64" Nullable="false"/>
<Property Name="BackendUsername" Type="Edm.String" Nullable="true" MaxLength="200"/>
<Property Name="BackendPassword" Type="Edm.String" Nullable="true" MaxLength="200"/>
</EntityType>
<EntityContainer Name="MyService">
...
<EntitySet Name="ClientCredentialsSet" EntityType="Self.ClientCredentials"/>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Client credentials should be stored in secure client-side storage, preferably encrypted by an application passcode or
similar mechanism. Any attempt to upload client credentials to the server, by POSTing to the ClientCredentialsSet
entity set for example, will be rejected with response status code 405 (Method Not Allowed).
To enable the server to access the client credentials when needed, without having to persist them in the server's
database, every request from a client application to an OData service with a ClientCredentials
entity type should be
accompanied by an X-Client-Credentials
HTTP request header, where the header value contains the credentials entity
encoded as a JSON object within a data URI, using media type
application/json
and Base64-encoded data. To facilitate this encoding of credentials, see ToJSON.dataURI
and
HttpHeaders.withData
in the client SDK documentation, or refer to the following example showing the encoding steps.
Example encoding of credentials entity with Username of secretuser
and Password of secretpass
:
- JSON-encoded entity:
{"Username":"secretuser","Password":"secretpass"}
- Base64-encoded JSON:
eyJVc2VybmFtZSI6InNlY3JldHVzZXIiLCJQYXNzd29yZCI6InNlY3JldHBhc3MifQ==
- Encoded as data URI:
data:application/json;base64,eyJVc2VybmFtZSI6InNlY3JldHVzZXIiLCJQYXNzd29yZCI6InNlY3JldHBhc3MifQ==
- HTTP header: X-Client-Credentials:
data:application/json;base64,eyJVc2VybmFtZSI6InNlY3JldHVzZXIiLCJQYXNzd29yZCI6InNlY3JldHBhc3MifQ==
When you use the SAP BTP SDK for Android or iOS to build a client application, specify the values for headers
such as X-Client-Credentials
in the customHeaders
property of the OfflineODataParameters
object, which is passed
to the constructor/initializer of OfflineODataProvider
.
The Android com.sap.cloud.mobile.foundation.securestore.SecureKeyValueStore
and iOS Keychain Services
APIs are recommended for storing client credentials across application restarts.
Registration Header¶
Every client request from a client application to an OData service with client registrations should be accompanied by a
Client-Instance-ID
HTTP request header, which uniquely identifies a particular instance of the client application on a
particular client computer. The header value should be in 36-character
UUID format, preferably a
Version 4 (random) variant.
When a client uses HTTP POST
to the ClientRegistrationSet
entity set to create a registration with the server, the
Client-Instance-ID
header value is copied into the ClientGUID
property of the newly created
ClientRegistration
entity, and a corresponding ClientID
property is automatically generated
by the server. The ClientID
can be considered a short form of the ClientGUID
, and is used by the server to associate
any client-specific information with the registration, such as download tracking data or client
identifiers for filter entities.
When you build client applications using the SAP BTP SDK for Android or iOS, you can specify values for
headers such as Client-Instance-ID
in the customHeaders
property of the OfflineODataParameters
object that is
passed to the constructor/initializer of OfflineODataProvider
. The client application should use the same
Client-Instance-ID
value across application restarts (unless the client database is recreated, in which case a new
Client-Instance-ID
should be used).
An application-specific local file can be used for storing Client-Instance-ID
values across application restarts.
Recent versions of the client SDKs have an autoRegisterClient
property in the OfflineODataParameters
class, which can simplify the process of obtaining and storing the necessary client registration.
Registration Expiry¶
Inactive client registrations are automatically deleted after 49 days (by default). The expiry interval for inactive
registrations is one day less than the retainDeletionsFor
property of the SQLDatabaseProvider
class in the Server
OData API. You can modify this property by editing the generated ProviderSettings
class and rebuilding/redeploying the
generated service.
The rationale for deferred expiration is as follows. Whenever data is to be deleted from the database, it is marked as logically deleted rather than being immediately physically deleted from the database. This allows for a client to be offline for an extended period, then come back online and execute delta queries to discover deletions (and other changes) that occurred while the client was offline. If the client was permitted to remain offline for longer than the deletion retention period, then, when the client comes online again to execute delta queries, it might fail to be notified of some deletions that occurred while it was offline. By forcing an inactive client's registration to expire one day before the deletion retention period, it can be ensured that the client will always be able either to successfully download all changes (including deletions) that occurred while the client was offline, or to be notified that the client's registration has expired.