- External Entitlement System
- Pugpig Content Module
- Pugpig Credentials Module
- Pugpig Authorization Module
Pugpig has been designed to handle publications that may not be available freely to all users. The architecture supports two kinds of access:
- Subscription - an active subscriber has access to all editions. If a subscription lapses, they will retain editions already downloaded, but not be able to download new issues, or access older issues on new devices.
- One-off purchases - editions can be purchased, in which case they should be available forever from any device
The same Pugpig application could support multiple external subscription or purchases services. For example, Apple iTunes or existing traditional print/digital subscription systems.
The four main components in the security subsystem are:
- The External Entitlement System holds the lists of products, and knows which users have access to which products. It provides the ability for users to obtain entitlements, via payment, gifting or any other means. When a user enters their details into Pugpig, they will be validated directly with this system.
- The Pugpig Content Module returns a list of all the editions (in the OPDS feed). Each of these has a unique identifier, which must match the identifier of the edition in the entitlement system of the External Subscription System.
- The Pugpig Credentials Module is responsible for communicating with the external subscription system to validate a users access, and to generate tokens that can be passed to the authorization module. The module consists of many connectors, each of which understands how to communicate with a different external system.
- The Pugpig Authorization Module decodes and validates Basic HTTP authentication headers, and will only allow authorised users to access secure content.
List of products
Pugpig security operates at the edition level, so the Entitlement System must maintain a list of editions. Pugpig will then ask the system if a user has access to an edition. To enable this, each edition must have a unique ID that matches those in the ODPS feed from the Pugpig Content Module. The example below shows the Product ID using Apple's In App purchases.
Note: At present, if your application supports multiple entitlement systems, the unique ID accross all the systems needs to be the same.
Initial Login To External System
Some Pugpig Apps will allow the user to sign in to an external system, either as part of the initial app user journey. When a user enters their initial details, the Pugpig client will communicate directly with the external system to validate the details. This could happen over either HTTP or HTTPS. If the details are not valid, the user should be presented with an error. If they are valid, the Pugpig client will store credentials on the device to be used for future requests. If the details entered by the user are deemed to sensitive to store on the device, the external system should return alternative credentials/tokens to be stored on the device instead.
It is good practice to allow the user to sign out or sign in as another user somewhere in the interface.
Acquiring New Entitlements
The way the user obtains a new subscription or an entitlement to an new edition is entirely up to the external system. The Pugpig security system does not write back to the External Entitlement System. If the Pugpig app allows new registrations, this communicate should happen directly between the Pugpig client and the External Entitlement System
The Content Module is not strictly part of the security subsystem, but there are some integration points
Matching Product IDs
The Product IDs of the editions in the OPDS feed must match the Product IDs in the external entitlements system to ensure access is granted to the correct editions
The OPDS feed should have a different acquisition URL if the content is not free. For paid content, the relation type must be “http://opds-spec.org/acquisition/buy”, and a price should be specified. Not that this price is purely for display before interaction with the source subscription system begins. The source system will hold the master price as it is responsible for the transactions.
<link rel="http://opds-spec.org/acquisition" type="application/atom+xml" href="http://editions.pugpig.com/my_free_edition.xml"/>
<link rel="http://opds-spec.org/acquisition/buy" type="application/atom+xml" href="http://editions.pugpig.com/my_paid_edition.xml"> <opds:price currencycode="GBP">3.50</opds:price> </link>
NOTE: If the concept of an Internal User is supported, the fact that they can access all editions needs to be indicated. Currently, the Pugpig Connectors act as if all editions are free for internal users.
Passing subscription information
The Pugpig client will request subscription information from the user. The information is stored in the Pugpig client. If the subscription information is sensitive, then the client should communicate directly with the source subscription system over HTTPS to obtain credentials which can safely be stored on the device and transmitted over HTTP.
The system can support multiple subscription systems, including Apple iTunes and traditional print subscription systems.
The subscription information is submitted to the Pugpig server, who will validate it against the source system. If the subscription information is valid, the server will return edition specific credentials. These are then used to access secure content. Each edition requires its own credentials. The client will extract the username and password from the response, and use them to generate the Authorization header when trying to access secured content. The flow is shown below:
A sample HTTP request would be:
GET /mysystem/get_entitlement?subscription_id=12345&product=com.pugpig.magazines.september2011 HTTP/1.1 Host: www.pugpigserver.com
The response should return a HTTP status code of 200 in all cases. The recommended response body for returning these credentials is given below:
<?xml version="1.0" encoding="UTF-8"?> <credentials> <userid>6acbd3975c364cac1fc419d9af13ed266718e8df</userid> <password>23668378520503425c49960b7347b648f7b61d35</password> <!-- Items below this line are ignored by the client and used for debug only --> <productid>com.pugpig.magazines.september2011</productid> </credentials>
If the user is not valid, or does not have the entitlement, an error should be returned. The recommended format is given below:
<?xml version="1.0" encoding="UTF-8"?> <error status="ERROR_STATUS_CODE" />
Checking Current Subscription
If a user is a current subscriber, they will have access to every edition in the system. This will mean a “Download” option should appear instead of a “Buy” option for every edition on the Edition Selector interface of the application. In order to prevent the Pugpig client having to check the entitlement for every edition, a convenience API method can be provided that indicates a user has access to everything. The flow is similar to Receiving Credentials. Note that the response here does not actually give the client access to anything - they will have to get the credentials when initiating a download. It simply aids the user interface creation.
GET /mysystem/verify_subscription?subscription_id=12345 HTTP/1.1 Host: www.pugpigserver.com
Response (always HTTP 200):
User is a subscriber with access to everyone:
<?xml version="1.0" encoding="UTF-8"?> <subscription state="active" />
User is a subscriber with access to only certain issues:
<?xml version="1.0" encoding="UTF-8"?> <subscription state="active"> <productid>com.pugpig.magazines.september2011</productid> <productid>com.pugpig.magazines.october2011</productid> <productid>com.pugpig.magazines.december2011</productid> </subscription>
User is not a subscriber:
<?xml version="1.0" encoding="UTF-8"?> <subscription state="inactive" />
Credentials not valid:
<?xml version="1.0" encoding="UTF-8"?> <subscription state="unknown" />
If the source subscription system cannot be reached (it may be down for scheduled maintenance or otherwise), the system should fail open. It will assume that ALL subscription information is valid, and return the success credentials for any request. This means that all users with subscription information will be able to access all content as long as the subscription system is unreachable.
The flow for a typical request to a secured resource is shown below:
When requesting secure content, the client will send the following header, assuming it has been able to acquire credentials. The Authorization header is generated using
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
If the client has not provided credentials, or the credentials are invalid, the server will send the following:
HTTP/1.0 401 Unauthorized WWW-Authenticate: Basic realm="Pugpig secure content"
A typical decision tree for allowing access to a URL by the Authorization module is outlined below. The steps are evaluated in order:
- If the content is part of a free edition AND the content is published, allow access
- If the request is from an “Internal User”, allow access
- If the content is not published, the user should not know of its existance. Return a 404 Not Found
- If the request has no Authorization header, deny access and send a 401 Unauthorized
- If the request has a valid Authorization header, allow access
- Deny access with a 403 Unauthorized
An Internal User is normally someone who is:
- Logged into the CMS OR
- Coming from a specified IP range (configured in the module)
Different kinds of content require different security. Typically:
- The OPDS feed is open to the public, although will return different content for Internal and External users
- The ATOM feed is protected unless the edition is free
- The HTML pages and HTML5 manifests are protected unless the edition is free
- Sometimes the static assets are protected, depending on the perceived value of the assets