-
Notifications
You must be signed in to change notification settings - Fork 58
Integrating the LCP server with a content management system
Integrating the LCP server in an existing CMS (content management system) or distribution platform takes some time, and requires reading the following instructions:
Every incoming publication is encrypted by a service external to the License Server. We provide the open-source Encryption Tool to do so, but integrators may prefer to develop their own software for that.
This external service must use the Store Method of the License Server after encrypting each file, so that the License Server can then generate licenses for this content.
Your CMS must integrate four methods of the LCP server API:
For that, you'll have to modify your CMS as follows
Each time a user acquires a publication, your CMS must call the License Server to generate a new license. The CMS must pass as a payload some user information (the level of details is chosen by the provider), the user passphrase hint and hash, plus the rights which will be inserted in the license. The CMS gets a new license in return.
The CMS must then associate the license identifier with the user transaction for future use. This information must be stored in the CMS database.
Your CMS database must therefore have a structure similar to this:
A client application that is LCP-compliant will request a "fresh" license (i.e. a previously generated license which may have been updated) each time it detects that a license has been modified. It can be after a loan extension, a return, a cancellation or a revocation. In such a case, the client application will use an HTTPS (!) GET (!) method to call your License Gateway.
As its name indicates, the License Gateway is a bridge between a client application and your License Server. We need this bridge because the License Server generates licences, but it is not visible from the Web and it doesn't store any user information (id, name, email, passphrase hint of passphrase). The License Gateway is a service you have to develop. It is exposed on the Web and it is called with a license identifier as a parameter.
When receiving a license request (again via an https GET request) your License Gateway must check in the database of your CMS if the license identifier exists; it gets the associated user identifier; then it gets information about the user: its id, and usually name or email, its passphrase hint and hash. There is no need to retrieve the rights associated with the license, they have been saved by the License Server.
You License Gateway then calls the Licence Server via a POST (!) request, with the license identifier and the user information just retrieved, to fetch a fresh license. It gets the fresh license in return. Then it returns the license to the caller application.
You can shape the URL of the fresh license as you like. For a license with id d038611c-b0b2-4afe-a23b-3322ff3e1f4b, it may be something like:
- https://yourdomain.com/somepath/d038611c-b0b2-4afe-a23b-3322ff3e1f4b
- https://yourdomain.com/somepath?license_id=d038611c-b0b2-4afe-a23b-3322ff3e1f4b
- https://yourdomain.com/somepath?user=xxx&license_id=d038611c-b0b2-4afe-a23b-3322ff3e1f4b
The use of "license_id" is imposed as name of the query string parameter.
The templated URL associated with the License Gateway must be inserted in the License Status Server configuration, in the line lsd
section, as value of the license_link_url
parameter. The license identifier must be represented by the parameter {license_id}
.
Templated URLs must conform to RFC6570. Let's show what it means for the previous examples:
- https://yourdomain.com/somepath/{license_id}
- https://yourdomain.com/somepath{?license_id}
- https://yourdomain.com/somepath?user=xxx{&licenseid}
The License Status Server and the License Fetcher are accessible from the Web, therefore, for security reasons, each provider has a requirement to use HTTPS URLs for accessing their services. This is part of the Content Conformance section in the Readium License Status Document specification.
To setup HTTPS, you may consider using an NGINX reverse-proxy. There are many how-to for this free software, and its configuration is quite easy. If you're not using TCP port 80 for the Status Document Server, a proper configuration of the reverse-proxy will enable you to show to the Web clean URLs with no TCP port indication.
The License Status Server is notified of each use of a license by a new client app (this is what the register
message sent by any LCP-compliant client app is made for). The License Status Server stores this information, and it is able to list licences which seem overshared. By oversharing, we mean a sharing a license and its passphrase to a number of people you estimate too high. Let's take an example: if a license if shared on a social network, with its passphrase, you may have suddenly 100 or 1000 people using an LCP-compliant client app to open the corresponding ebook. This is a situation where you want to revoke the license first, and contact the faulty user later.
To do that, you have to develop an interactive tool (it may be a Web tool or a command-line tool, part of your CMS or not) that allows checking if some licenses have been overshared. The user of the system can choose the threshold (of number of device registrations). The server endpoint returns a paginated list that contains a license id, a status and a device count. Using this information, the user of the interactive tool can decide to revoke or not these licenses.
The tool revokes a license by calling the revocation service of the License Status Server. A revoked license cannot be un-revoked.
EPUB or PDF files, once encrypted, are stored on a Web server, so that reading applications can easily download them. They can be safely exposed on the Web because they are AES-256 encrypted: without the proper key, they cannot be open.
If your distribution platform is successful, these files will be downloaded hundreds of time and they can be large. Therefore you may decide to use some caching mechanism to optimise HTTP downloads. It can be a Varnish, it can be a Cloud CDN, that's your call. But customers will thank you for that.
A Licensed Publication is an encrypted publication (EPUB, PDF ...) that contains an LCP license.
The process we recommend is to let an LCP-compliant reading application fetch a license and do what is necessary to download the encrypted publications stored on your Web server.
If you are a bookseller or public library, the best experience you can offer to your clients/patrons is offering a personal OPDS feed containing LCP licenses. An application capable of processing such a feed (e.g. Thorium Reader and other applications based on the Readium toolkits) will then offer a wonderful experience to its user, who will only have to select a title, select "install" (or "import", "download" ...), wait until it's done, and read.
But what if what you can offer on your website is a simple download link for each publication the user has acquired?
The standard solution is to enable the download of .lcpl
licenses, and indicate to your users that they can import these small files into an LCP-compliant reading application. This is what Adobe has proposed for years with .acsm
files. The downside is that many users will not know what to do with such files and you'll have to document that they can be imported in any LCP-compliant reading app.
An alternative solution is to prepare a Licensed Publication server side by embedding the license inside the encrypted publication. Your users can therefore download a .epub
or .lcpdf
file. The advantage is that users will know that an .epub
file is the ebook they are expecting. The downside is that your server will have to do some I/O-intensive processing; that some users will try to open this .epub in e.g. iBooks, which will refuse it; and that you will loose the efficiency of the cache you should have applied to all encrypted publications.
There is no "best" solution, LCP is very flexible and you should choose the solution that fits your needs better.
Users will forget their passphrase. Whatever passphrase is chosen and whatever hint is displayed, some users will need a way to get their passphrase back. But as it is personal information, you, as a provider, should not store this passphrase in clear: you will store instead the passphrase hash in your CMS, and send this information to the License Server when needed.
This is why the URL of a helper page must be present in each license. This link is indicated in the License Server configuration in the license
section, links
sub-section, via the hint
property. This link may be templated and contain a license identifier, but this is not required. The corresponding resource should be an html page which gives advice on how to change the passphrase. After such change, the status document will indicate that the license has been updated and, if the user is online, he will be able to open his publications with the new passphrase.
By default, if the renew
parameter of the license_status
section of the configuration is set (details here), License Status documents embed a renew link which references the License Status Server via its standard API method. This is a templated url: the client can provide an end date-time, and it should provide a client id and name.
The License Status Server accepts renew request if they do not exceed the value of the renew_days
parameter of the same section of the configuration.
A provider may prefer to handle renew requests using its own rules, e.g. disallow a loan extension if there is a waiting queue or if the ebook is recent. This is the reason why the configuration provides two optional parameters:
- If
renew_page_url
is set, "renew" links in the status document will take this value, which references an html page of the distribution platform of the provider. Human interactions are expected (like filling a form). These interactions should ultimately result in an updated License Status or a failure message. - If
renew_custom_url
is set, "renew" links in the status document will take this value, which references a REST endpoint on the distribution platform of the provider; the provider will return an updated License Status or a failure message.
In both cases:
- if the rules setup by the provider conclude in a failure, the provider must send back to the client an error consisting of an http code specified in the LSD specification (400 if the request is erroneous, 403 if the renewal period is incorrect, 404 if the license was not found, 5xx in case of an internal server error) and a Problem Details JSON object as defined in [RFC7807].
- if the rules setup by the provider conclude in a possible loan extension, the provider must call the License Status Server via its standard API method, including the expected query string parameters, and forward back to the client its return message.