Support and Documentation

Deploying Access

Developers perform this task.

Overview of deploying Access

When you deploy the Access plugin, Brightspot reviews every request for content as indicated in the following diagram.

Access request flow
Figure 149. Access request flow


Referring to the previous diagram, Brightspot reviews every request as follows:

  • If the content is not restricted, retrieve and send it to the client.

  • If the content is restricted:

    1. Brightspot checks if the user associated with the request has the required credentials.

    2. If so, Brightspot retrieves the content and returns it to the client.

    3. If not, Brightspot returns substitute content (such as a pay wall) to the client.

Note

Brightspot checks for access control at the content type requested by a client, and does not check access control at lower levels. If a client requests a parent item that is unrestricted, and that item contains a child item that is restricted, the client receives the restricted child item.

Create a form for assigning access control

In a typical scenario, administrators use a form in Brightspot to assign access control to various content types as described in Configuring content substitutions. You provide that form by declaring a class that implements the interface Access.

import com.psddev.access.Access;
import com.psddev.cms.db.Content;
import com.psddev.cms.db.ToolUi;
import com.psddev.dari.db.CompoundPredicate;
import com.psddev.dari.db.ObjectType;
import com.psddev.dari.db.Predicate;
import com.psddev.dari.db.PredicateParser;

public class ContentAccess extends Content implements Access { 1

    private String accessLabel; 2

    @ToolUi.DropDown
    @Where("groups = content.article.Article OR groups = content.page.Page") 3
    private Set<ObjectType> contentTypes; 4

    public Set<ObjectType> getTypes() {
        if (contentTypes == null) {
            contentTypes = new HashSet<>();
        }
        return contentTypes;
    }

    @Override
    public Predicate itemsPredicate() { 5
        List<Predicate> predicateList = new ArrayList<>();

        if (!getTypes().isEmpty()) {
            predicateList.add(PredicateParser.Static.parse("_type = ?", getTypes()));
        }

        return new CompoundPredicate(PredicateParser.AND_OPERATOR, predicateList);
    }
}

1

Declares this class implements the interface Access, which requires overriding the method itemsPredicate.

2

Provides a label for the access control rule that appears in Brightspot.

3

Determines which content types an administrator can select for access control. (For more information about this annotation, see @Recordable.Where.) If the content types listed in this annotation contain child content types that also require access control, include those child content types as well.

4

Displays a list containing the items satisfying the @Where annotation.

5

Implements the method itemsPredicate, returning a list of conditions that indicate access control. At run time, Brightspot accumulates the conditions of all implemented itemsPredicate methods, and determines if the request satisfies one of those conditions. If so, the request is under access control, and Brightspot checks the visitor's credentials accordingly. (See the illustration Access request flow.)

The following illustration is an example of a class implementing Access in the content edit form.

access-content-edit-form.png
Checking for access to requested content

Checking for access requires two steps:

  • Find the accesses assigned to the requested resource that were established by implementing Access as described in Create a form for assigning access control. This step is implementation dependent, and usually involves determining the content type requested from the incoming query string and then checking if the content type is under access control.

  • Determine if the user associated with the request has the required access. This step is also very much implementation dependent: some Brightspot projects have an API to the publisher's subscription system, and other projects have internal subscription tables.

For an overview of this process, see the diagram Access request flow.

You perform both of these steps by declaring a class that implements the interface AccessProvider.

import com.psddev.access.Access;
import com.psddev.access.AccessProvider;
import com.psddev.cms.db.PageFilter;
import com.psddev.cms.db.Site;
import com.psddev.dari.db.Predicate;
import com.psddev.dari.db.PredicateParser;

import javax.servlet.http.HttpServletRequest;

public class ContentAccessProvider implements AccessProvider { 1

    @Override
    public boolean requiresAccess(HttpServletRequest request) { 2
        Site site = PageFilter.Static.getSite(request) 3;
        Object mainObject = PageFilter.Static.getMainObject(request);

        if (mainObject == null) { 4
            return false;
        }

        List<SubscriptionPlan> plans = site.getSubscriptionPlans(); 5

        for (SubscriptionPlan plan : plans) { 6
            Set<Access> accesses = plan.getAccesses();

            for (Access access : accesses) {
                Predicate predicate = access.itemsPredicate();
                if (PredicateParser.Static.evaluate(mainObject, predicate)) {
                    return true;
                }
            }
        }
        return false; 7
    }

    @Override
    public Collection<? extends Access> findAccesses(HttpServletRequest request) { 8
        Set<Access> accesses = new HashSet<>();

        ExampleUser user = ExampleAuthFilter.getUser(request); 9

        if (user != null) {
            for (ExampleSubscription subscription : user.getSubscriptions()) { 10
                accesses.addAll(subscription.getAccesses());
            }
        }

        return accesses;
    }
}

1

Indicates this class implements AccessProvider, so Brightspot runs this class each time a request arrives for content.

2

Overrides the method requiresAccess and return a boolean true if the requested content type is under access control, false otherwise. The code within this method is usually implementation dependent. The following statements describe a basic implementation.

3

Extracts the site and content type associated with the incoming request.

4

Null check that returns false if there is no content type associated with the request.

5

Retrieves all the subscription plans associated with the site.

6

Examines each of the retrieved subscription plans. If any of them contain the requested content type, return true.

7

Returns false if the requested content type is not included in any subscription plan. As a result, Brightspot delivers the requested content to the client.

8

Overrides the method findAccesses and return a HashSet<Access> containing a set of accesses associated with the user who sent the request. Brightspot runs this method if requiresAccess returns true.

9

Retrieves the user associated with the incoming request.

10

Retrieves all of the subscriptions associated with the user.

Brightspot denies access to an item when requiresAccess returns true and one of the following is also true:

  • findAccesses returns an empty set of accesses.

  • findAccesses returns a non-empty set of accesses, none of which match those associated with the requested content.