LCP License Server API - readium/readium-lcp-server GitHub Wiki
This server is never exposed on the wild Web: it is safely setup in a trusted zone, and the use of its API requires proper authentication.
The server stores, for each license: its ID, date of issue, provider's name, the (hashed) user key processed from the user passphrase, the associated hint, usage rights relative to the protected content and a reference to the encrypted content data.
The License server exposes several private REST API methods:
- Store an encrypted publication
- Fetch an encrypted publication
- Generate and fetch a license
- Generate and fetch a protected publication
- Update the rights associated with a license
- List licenses
- Update a license
This method stores data generated by e.g. lcpencrypt. See the corresponding lcpencrypt spec.
PUT <LCPbaseURL>/contents/<content_id>
Payload: it is a json payload structured like:
{
"content-id" : "<value>",
"storage-mode" : 0,
"content-encryption-key" : "<value>",
"protected-content-location" : "<value>",
"protected-content-length" : "<value>",
"protected-content-sha256" : "<value>",
"protected-content-disposition" : "<value>"
}
The method can load the encrypted file using a local storage (file:) or http(s).
The protected-content-location field contains the location where the lcpserver will search for the file.
The protected-content-disposition in the json struct is used as target filename. When retrieving the encrypted file, the user therefore gets this filename in the Content-Disposition http header. The content_id in the URL equals the content-id in the json payload and will be the effective content_id for the lcpserver.
Return:
- 200: content found (OK: file updated and db updated )
- 201: the content was added (created)
- 400: bad request (File not saved) (type http://readium.org/licensed-content-protection/error/notsaved)
- 401: unauthorized (type http://readium.org/license-status-document/error/unauthorized)
- 404: not found (File not found) (type http://readium.org/licensed-content-protection/error/notfound)
- 500: internal server error (File was copied, but database was not updated) (type http://readium.org/licensed-content-protection/error/internal).
This method fetches the encrypted publication previously stored by the License Server.
Warning: It does not return anything if the encryption tools manages the storage of the encrypted publication.
Note that an encrypted publication is not associated with any LCP license; this is the result of the initial encryption process applied by e.g. the LCP encryption tool. Do not confuse it with a protected publication.
GET <LCPbaseURL>/contents/<content_id>
Return:
- 200: Content found
- 404: File not found (type http://readium.org/licensed-content-protection/error/notfound)
- 500: Internal server error (type http://readium.org/licensed-content-protection/error/internal)
This method generates a license from the data resulting from a user transaction on the content management system.
The caller passes the following arguments:
- The provider identifier (a URL),
- User information the provider wants to embed in the license (id, name, email; optional),
- The (hashed) passphrase and corresponding user hint
- The rights the user gets on the content.
POST <LCPbaseURL>/contents/<content_id>/license
Payload: {partial license} (json)
The payload structure is a partial LCP license document, which will be completed by the License Server.
The payload MUST contain the following json properties:
-
provider
: a URI that identifies the provider in an unambiguous way; -
user
: the user information the provider wants in the license, either in clear or encrypted; check the LCP specification for more details.id
is mandatory, all other properties are optional; allowed properties are:-
id
: an identifier for the user. -
email
: the user email. -
name
: the user name. -
encrypted
: the array of properties the provider wants encrypted.
-
-
encryption/user_key
: an object with 3 properties:-
text_hint
: the hint proposed by the provider to the user for selecting its passphrase. -
hex_value
orvalue
: the hashed value of the user passphrase. Its format is specified below. Warning: it is not part of the LCP specification. -
algorithm
: the URI of the hashing algorithm used for calculating the above value. The algorithm used in the context of the basic and 1.0 profiles ishttp://www.w3.org/2001/04/xmlenc#sha256
. As this is the default value used by the server, setting this property is optional.
-
-
rights
: the set of rights associated with the license. Unused properties can be skipped. Allowed sub-properties are:-
start
: date and time when the license begins. -
end
: date and time when the license ends. -
print
: maximum number of pages that can be printed over the lifetime of the license. -
copy
: maximum number of characters that can be copied to the clipboard over the lifetime of the license.
-
Extensibility: The payload MAY contain other license properties, which will be included in the final license if they are not set by the License Server.
Sample partial license:
{
"provider": "http://www.imaginaryebookretailer.com",
"user": {
"id": "d9f298a7-7f34-49e7-8aae-4378ecb1d597",
"email": "[email protected]",
"encrypted": ["email"]
},
"encryption": {
"user_key": {
"text_hint": "The title of the first book you ever read",
"hex_value": "4981AA0A50D563040519E9032B5D74367B1D129E239A1BA82667A57333866494",
}
},
"rights": {
"print": 10,
"copy": 2048,
"start": "2019-11-04T01:08:15+01:00",
"end": "2019-11-25T01:08:15+01:00"
}
}
Calculating hex_value
: A server should never directly store the user passphrases, which are personal info, but rather hashed values, as hex-encoded strings. For instance the passphrase "123 456" becomes "4981AA0A50D563040519E9032B5D74367B1D129E239A1BA82667A57333866494" when hashed using the sha256 algorithm (just try with this online tool). hex_value is simply the result of the hash calculation, as an hex-encoded string.
Calculating value
: This property, alternative to hex_value
, is only kept for backward compatibility with the initial version of the API. From the hashed value of the passphrase, expressed as an hex-encoded string, calculate a byte array (32-bytes / 256-bits binary buffer); for instance, "4981AA..." becomes [49, 81, 170, ...]. The expected value is the Base64 encoding of this byte array (a base64 conversion is usually implicitly applied to byte arrays when converted to json structures). More info can be found in this issue.
Storage: No personal data is stored in the License server database.
The only data stored into the License server database are:
- The provider identifier
- The user identifier
- The content identifier
- The rights associated with the license (print, copy, start, end)
- The date of issue of the license, added after the license has been generated.
Links: The links that will be included in the complete license are specified in the license
section of the configuration file (as templated links), not in the partial license.
Return:
- 201 + the license: Created
- 404 Content not found (type http://readium.org/licensed-content-protection/error/notfound)
Processing of the partial license
The following data will be deleted from the structure before the license is returned to the sender:
- The custom user key value property
The following data will be added to the returned license:
- The license identifier
- The date of issue of the license
- Optionally, the date of update of the license
- The encryption profile
- The content key information (encrypted value and algorithm)
- The link to the publication
- The link to the status document
- A signature
Note:
- Licenses are generated to be served as .lcpl file, i.e. outside of their associated publication; this is why the link to the publication is provided.
- The use of License Status Documents is mandatory for license providers.
This method returns an already existing license, using its identifier as key.
The caller must pass the following user information:
- passphrase hash,
- passphrase hint,
- any user information the provider wants embedded in the license (an exception is the user id, which has been passed to the License Server when the license was generated and does not need to be repeated here).
POST <LCPbaseURL>/licenses/<license_id>
Payload: {partial license} (json)
The payload structure is a partial LCP license document, which will be completed by the License Server. Its structure is similar to the structure used for the generation of a new license (see above), but the provider
property and the rights
section should be omitted.
Sample partial license:
{
"user": {
"email": "[email protected]",
"encrypted": ["email"]
},
"encryption": {
"user_key": {
"text_hint": "The title of the first book you ever read",
"hex_value": "4981AA0A50D563040519E9032B5D74367B1D129E239A1BA82667A57333866494",
}
}
}
Return:
- 200 + the requested license: ok
- 404 License not found (type http://readium.org/licensed-content-protection/error/notfound)
This method returns a sequence of partial licenses, in ante-chronological order (on date of issue).
It may be used as a simple way for an external processor to extract periodically the newly created licenses e.g. for indexation in an analytics system or search engine.
The pagination mechanism is based on the Link headers RFC (https://tools.ietf.org/html/rfc5988 ) and the Github pagination syntax (https://developer.github.com/v3/#pagination).
Note that page numbering is 1-based and that omitting the ?page parameter will return the first page. Requests that return multiple items will be paginated to 30 items by default.
GET <LCPbaseURL>/licenses{page?, per_page?}
Return:
- 200 + the requested array of licenses: ok
- 400 Wrong pagination parameters (type http://readium.org/licensed-content-protection/error/badparam)
Example: http://lcpserver.my.org/licenses?page=2&per_page=50
Sample partial license returned by the list request:
{
"id": "e698a7-7f34-49e7-8aae-4378ecb1d5ff",
"issued": "2016-11-04T01:08:15+01:00",
"updated": "2016-11-04T01:09:15+01:00",
"provider": "http://www.imaginaryebookretailer.com",
"user": {
"id": "d9f298a7-7f34-49e7-8aae-4378ecb1d597",
},
"rights": {
"print": 10,
"copy": 2048,
"start": "2016-11-04T01:08:15+01:00",
"end": "2016-11-25T01:08:15+01:00"
}
}
This method returns a sequence of partial licenses, in ante-chronological order (on date of issue).
GET <LCPbaseURL>/contents/<content_id>/licenses{page?, per_page?}
Return:
- 200 + the requested array of licenses: ok
- 400 (bad request) The pagination parameters are wrong (type http://readium.org/licensed-content-protection/error/badparam)
- 404 Content not found (type http://readium.org/licensed-content-protection/error/notfound)
This method can force the update of the information stored in the License Server database, I.e.
- The license provider
- The user identifier
- the rights associated with a license
It is usually called from the License Status server (for lending return or renewal), and in this case only contains a rights object.
PATCH <LCPbaseURL>/licenses/<license_id>
Payload: {partial-license} (json). The licence structure is a partial LCP license document. All fields listed above are updated if present in the source partial license.
Return:
- 200: ok
- 400 (bad request) The partial license is malformed (type http://readium.org/licensed-content-protection/error/malformed)
- 404 (not found) The license does not exist in the database (type http://readium.org/licensed-content-protection/error/notfound)
Sample partial license:
{
"rights": {
"end": "2016-11-20T11:30:00+01:00"
}
}
This method generates a license from the data resulting from a user transaction on the content management system, and embeds the license in the encrypted publication identified in the request.
Warning 1: It does not return anything if the encryption tools manages the storage of the encrypted publication.
Warning 2: The License Server provides such functionality mostly for testing purposes. Generating a protected publication is CPU and memory intensive, which goes against the philosophy of the License Server. Providers should not use it unless they have a very good reason to do so; an equivalent functionality can easily be created as part of the content management system.
The resulting stream should be returned to the caller. The CMS may return the stream directly to the user as a direct download, or save it as a file in a Web accessible location and present to the user a "download" button.
POST <LCPbaseURL>/contents/<content_id>/publication
Payload: {partial license} (json): the structure of the partial license is strictly identical to the one specified for generating licenses.
Return:
- 201+ the protected publication: Created
- 400 Bad request
- 404 Content not found (type http://readium.org/licensed-content-protection/error/notfound)
This method returns a protected publication, using its license identifier as key.
Warning 1: It does not return anything if the encryption tools manages the storage of the encrypted publication.
Warning 2: The License Server provides such functionality mostly for testing purposes. Generating a protected publication is CPU and memory intensive, which goes against the philosophy of the License Server. Providers should not use it unless they have a very good reason to do so; an equivalent functionality can easily be created as part of the provider's content management system.
The resulting stream is returned to the caller. The caller may return the stream directly to the user as a direct download, or save it as a file in a Web accessible location and present to the user a "download" button.
POST <LCPbaseURL>/licenses/<license_id>/publication
Payload: {partial license} (json): the structure of the partial license is strictly identical to the one specified for fetching licenses.
Return:
- 200+ the protected publication: ok
- 404 License not found (type http://readium.org/licensed-content-protection/error/notfound)