<access_control_voter>

Abstract

Learn to configure the <access_control_voter> element for Pull Reports™ Ad Hoc report and data service software.


Table of Contents

Catalog Configuration Java API reference:  AccessControlVoter

The <access_control_voter> element specifies the fully qualified name of a Java AccessControlVoter to control access to the parent element.

Usage

Using <access_control_voter> to control column access

The following AccessControlVoter permits access if the user has the ADMIN role. The fulfillment of the isUserInRole method is not a feature of Pull Reports™, and must be provided by the installation WAR or Servlet Container.

package com.pullreports.examples.accesscontrol;

import jakarta.servlet.http.HttpServletRequest;
import com.pullreports.model.AccessControlVoter;

public class AdminAccessControlVoter implements AccessControlVoter{

    @Override
    public boolean vote(HttpServletRequest request) {
        return request.isUserInRole("ADMIN");
    }
}
Example 1. Via an XML Catalog file

The following XML Catalog file applies the AdminAccessControlVoter to the salary <column>. Only users with the ADMIN role will see the salary column within the Pull Reports™ Report Creator and be able to include the salary column in report exports. Users without the ADMIN role will receive a 403, FORBIDDEN HTTP response when requesting the salary column via the Pull Reports REST API.

<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="http://www.pullreports.com/catalog-1.7.0" id="employee" name="Employee Reports"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.pullreports.com/catalog-1.7.0
    https://www.pullreports.com/docs/xsd/pullreports-catalog-1.7.0.xsd">
    <report id="employee" name="Employees">
        <table id="employee" name='company.employee' displayName="Employee"> 
            <column id="name" name="employee_name" displayName="Employee Name"/>
            <column id="salary" name="salary" displayName="Salary" paramType="java.lang.Double">
                <access_control_voter voter="com.pullreports.examples.accesscontrol.AdminAccessControlVoter"/>
            </column>
        </table>
    </report>
</catalog>
                

Example 2. Via the Catalog Configuration Java API

The following example is an identical Catalog Configuration Java API configuration.

package com.pullreports.examples.accesscontrol;

import com.pullreports.model.CatalogId;
import com.pullreports.model.ColumnId;
import com.pullreports.model.ParamType;
import com.pullreports.model.ReportId;
import com.pullreports.model.TableId;
import com.pullreports.model.config.CatalogConfiguration;
import com.pullreports.model.config.CatalogConfigurationFactory;
import com.pullreports.model.config.ColumnConfiguration;
import com.pullreports.model.config.ReportConfiguration;
import com.pullreports.model.config.TableConfiguration;

import jakarta.servlet.ServletContext;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class AccessControlVoterColumnExampleCatalogConfigurationFactory 
implements CatalogConfigurationFactory {

    @Override
    public CatalogConfiguration makeCatalog(ServletContext servletContext) {

        ReportConfiguration.Builder employeeReportBuilder = makeEmployeeReportConfigurationBuilder();
        
        List<ReportConfiguration> reportConfigurations =
                Collections.singletonList(employeeReportBuilder.build());

        return new CatalogConfiguration(new CatalogId("employee"),"Employee",reportConfigurations);
    }

    protected ReportConfiguration.Builder makeEmployeeReportConfigurationBuilder(){

        TableConfiguration.Builder employeeTableBuilder = makeEmployeeTableConfigurationBuilder();

        return new ReportConfiguration.Builder(
            new ReportId("employee"),"Employee",employeeTableBuilder.build());
    }

    protected TableConfiguration.Builder makeEmployeeTableConfigurationBuilder(){

        ColumnConfiguration.Builder nameColumnBuilder = new ColumnConfiguration.Builder(
            new ColumnId("name"),"employee_name")
            .setDisplayName("Employee Name");

        ColumnConfiguration.Builder salaryColumnBuilder = new ColumnConfiguration.Builder(
            new ColumnId("salary"),"salary")
            .setDisplayName("Salary")
            .setParamType(ParamType.DOUBLE)
            .setAccessControlVoter(new AdminAccessControlVoter());
        
        List<ColumnConfiguration> columnConfigurations = Arrays.asList(
                nameColumnBuilder.build(),salaryColumnBuilder.build()
        );

        return new TableConfiguration.Builder(
                new TableId("employee"),"Employee",columnConfigurations)
                .setName("company.employee");
    }
}
                

Using <access_control_voter> to control report access

Building from the previous example, the following AccessControlVoter limits access to users with the USER or ADMIN role.

package com.pullreports.examples.accesscontrol;

import jakarta.servlet.http.HttpServletRequest;

public class AdminOrUserAccessControlVoter extends AdminAccessControlVoter {

    @Override
    public boolean vote(HttpServletRequest request) {
        return request.isUserInRole("USER") || super.vote(request);
    }
}
Example 3. Via an XML Catalog file

Apply the AdminOrUserAccessControlVoter to the employee <report> with an <access_control_voter> nested within the <report> element. Now the employee report will only be available to users with the ADMIN or USER role, but only users with the ADMIN role may access the salary column.

<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="http://www.pullreports.com/catalog-1.7.0" id="employee" name="Employee Reports"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.pullreports.com/catalog-1.7.0
    https://www.pullreports.com/docs/xsd/pullreports-catalog-1.7.0.xsd">
    <report id="employee" name="Employees">
        <access_control_voter voter="com.pullreports.examples.accesscontrol.AdminOrUserAccessControlVoter"/>
        <table id="employee" name='company.employee' displayName="Employee"> 
            <column id="name" name="employee_name" displayName="Employee Name"/>
            <column id="salary" name="salary" displayName="Salary" paramType="java.lang.Double">
                <access_control_voter voter="com.pullreports.examples.accesscontrol.AdminAccessControlVoter"/>
            </column>
        </table>
    </report>
</catalog>

Example 4. Via the Catalog Configuration Java API

The following example is an identical Catalog Configuration Java API configuration.

package com.pullreports.examples.accesscontrol;

import com.pullreports.model.CatalogId;
import com.pullreports.model.config.CatalogConfiguration;
import com.pullreports.model.config.ReportConfiguration;

import jakarta.servlet.ServletContext;
import java.util.Collections;
import java.util.List;

public class AccessControlVoterReportExampleCatalogConfigurationFactory 
extends AccessControlVoterColumnExampleCatalogConfigurationFactory {

    @Override
    public CatalogConfiguration makeCatalog(ServletContext servletContext) {

        ReportConfiguration.Builder employeeReportBuilder = makeEmployeeReportConfigurationBuilder();
        employeeReportBuilder.setAccessControlVoter(new AdminOrUserAccessControlVoter());
        
        List<ReportConfiguration> reportConfigurations =
                Collections.singletonList(employeeReportBuilder.build());

        return new CatalogConfiguration(new CatalogId("employee"),"Employee",reportConfigurations);
    }
}
                

Using <access_control_voter> to control relationship access

The following AccessControlVoter limits access to users with the ADMIN role within the month of October.

package com.pullreports.examples.accesscontrol;

import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.util.Date;
import jakarta.servlet.http.HttpServletRequest;

public class AdminDateAccessControlVoter extends AdminAccessControlVoter {

    @Override
    public boolean vote(HttpServletRequest request) {

        Date date = new Date();
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        Month month = localDate.getMonth();

        return Month.OCTOBER.equals(month) && super.vote(request);
    }
}
Example 5. Via an XML Catalog file

Use the AdminDateAccessControlVoter to control access to the benefits_selections <relationship> by nesting an <access_control_voter> within a <relationship> element. The <relationship> will be available within the Pull Reports REST API if the user has the ADMIN role and the API request is in October.

<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="http://www.pullreports.com/catalog-1.7.0" id="employee" name="Employee Reports"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.pullreports.com/catalog-1.7.0
    https://www.pullreports.com/docs/xsd/pullreports-catalog-1.7.0.xsd">
    <report id="employee" name="Employees">
        <access_control_voter voter="com.pullreports.examples.accesscontrol.AdminOrUserAccessControlVoter"/>
        <table id="employee" name='company.employee' displayName="Employee"> 
            <column id="name" name="employee_name" displayName="Employee Name"/>
            <column id="salary" name="salary" displayName="Salary" paramType="java.lang.Double">
                <access_control_voter voter="com.pullreports.examples.accesscontrol.AdminAccessControlVoter"/>
            </column>
            <relationship cardinality="one">
                <access_control_voter voter="com.pullreports.examples.accesscontrol.AdminDateAccessControlVoter"/>
                <join_column columnName="employee_name" referencedColumnName="name"/>
                <table id="benefits_selections" displayName="Benefits Selections" name="company.benefits_selections">
                    <column id="health_care_coverage" name="health" displayName="Health Care Coverage Level"/>
                    <column id="dental_care_coverage" name="dental" displayName="Dental Care Coverage Level"/>
                </table>
            </relationship>
        </table>
    </report>
</catalog>

Example 6. Via the Catalog Configuration Java API

The following example is an identical Catalog Configuration Java API configuration.

package com.pullreports.examples.accesscontrol;

import com.pullreports.model.Cardinality;
import com.pullreports.model.ColumnId;
import com.pullreports.model.JoinColumn;
import com.pullreports.model.TableId;
import com.pullreports.model.config.ColumnConfiguration;
import com.pullreports.model.config.JoinColumnsRelationshipConfiguration;
import com.pullreports.model.config.RelationshipConfiguration;
import com.pullreports.model.config.TableConfiguration;

import java.util.Arrays;
import java.util.Collections;

public class AccessControlVoterRelationshipExampleCatalogConfigurationFactory 
extends AccessControlVoterReportExampleCatalogConfigurationFactory {

    @Override
    protected TableConfiguration.Builder makeEmployeeTableConfigurationBuilder(){
        ColumnConfiguration healthColumnConfiguration = new ColumnConfiguration.Builder(
            new ColumnId("health_care_coverage"),"health")
            .setDisplayName("Health Care Coverage Level").build();

        ColumnConfiguration dentalColumnConfiguration = new ColumnConfiguration.Builder(
            new ColumnId("dental_care_coverage"),"dental")
            .setDisplayName("Dental Care Coverage Level").build();

        TableConfiguration benefitsSelections = new TableConfiguration.Builder(
            new TableId("benefits_selections"),"Benefits Selections"
            ,Arrays.asList(healthColumnConfiguration,dentalColumnConfiguration))
            .setName("company.benefits_selections").build();

        RelationshipConfiguration benefitsSelectionsRelationship = 
            new JoinColumnsRelationshipConfiguration.Builder(
            benefitsSelections, Collections.singletonList(new JoinColumn("employee_name","name")))
            .setCardinality(Cardinality.ONE)
            .setAccessControlVoter(new AdminDateAccessControlVoter()).build();

        return super.makeEmployeeTableConfigurationBuilder()
            .setRelationshipConfigurations(Collections.singletonList(benefitsSelectionsRelationship));
    }
}
                

Parents

<canned_query>
<catalog>
<column>
<relationship>
<report>

Attributes

voter

Fully qualified name of a Java class which implements AccessControlVoter. The class must have a public, no argument constructor.