Skip to content
Architecture > Authentication

Data Filter

Overview

This plugin control at a granular level what data a user can see. Here are the steps:

  1. A user is successfully logged in, determined by com.f1.ami.web.auth.AmiAuthenticator plugin which can return as set of variables that are assigned to the user's session (these variables often come from some external corporate entitlements system).

  2. This user-session is passed into the com.f1.ami.web.datafilter.AmiWebDataFilterPlugin which then returns a com.f1.ami.web.datafilter.AmiWebDataFilterinstance. Note that each user will generally have there "own" AmiWebDataFilter assigned to there session.

  3. As data is passed from the backend to the frontend its is first visited by the user's AmiWebDataFilter where the DataFilter can choose to suppress the data or not. There are two distinct ways data can be transferred from the "backend" to the user:

    1. Realtime - As data is streamed into AMI, individual records are transported to the front end for display on a per-row basis. More specifically as rows are added(1), updated(2) and deleted from the backend a corresponding message is sent to the frontend.

      1. See AmiWebDataFilter::evaluateNewRow(...)
      2. See AmiWebDataFilter::evaluateUpdateRow(...)

      (Note, that deletes do not have a callback as it is not applicable for data filtering)

    2. Query results - when the user invokes a query (generally via the EXECUTE command within a datamodel) a query object is constructed and sent back to the back end for execution(1). Then, the backend responds with a table (or multiple tables) of data(2).

      1. See AmiWebDataFilter::evaluateQueryRequest(...)
      2. See AmiWebDataFilter::evaluateQueryResponse(...)

Java interface

com.f1.ami.web.datafilter.AmiWebDataFilterPlugin
com.f1.ami.web.datafilter.AmiWebDataFilter

Properties

ami.web.data.filter.plugin.class=fully_qualified_class_name

Example

See below for the configuration, make sure this matches the package and class names used in the data filter plugin java file.

ami.web.data.filter.plugin.class=com.mysamples.SampleDataFilterPlugin

See below for the plugin java code, this describes what the plugin should do when a user logs in and logs out e.g. querying an external database to see what groups a user should have permission for.

package com.mysamples;

import com.f1.ami.web.datafilter.AmiWebDataFilter;
import com.f1.ami.web.datafilter.AmiWebDataFilterPlugin;
import com.f1.ami.web.datafilter.AmiWebDataSession;
import com.f1.container.ContainerTools;
import com.f1.utils.PropertyController;

public class SampleDataFilterPlugin implements AmiWebDataFilterPlugin {

        @Override
        public void init(ContainerTools tools, PropertyController props) {
        }

        @Override
        public String getPluginId() {
                return "DATAFILTER_PLUGIN";
        }

        @Override
        public void onLogin() {
                //Code to implement when the user logs in;
        }

        @Override
        public void onLogout() {
                //Code to implement when the user logs out;
        }

        @Override
        public AmiWebDataFilter createDataFilter(AmiWebDataSession session) {
                return new SampleDataFilter(session);
        }
}

See below for the filter java code, this describes how realtime feeds should be filtered (using evaluateNewRow and evaluateUpdatedRow) and how EXECUTE queries in datamodels should be filtered (using evaluateQueryRequest and evaluateQueryResponse).

package com.mysamples;

import com.f1.ami.web.AmiWebObject;
import com.f1.ami.web.datafilter.AmiWebDataFilter;
import com.f1.ami.web.datafilter.AmiWebDataFilterQuery;
import com.f1.ami.web.datafilter.AmiWebDataSession;
import com.f1.base.Column;
import com.f1.base.Row;
import com.f1.utils.structs.table.columnar.ColumnarTable;

public class SampleDataFilter implements AmiWebDataFilter {

        private AmiWebDataSession userSession;
        private String allowedRegion;

        public SampleDataFilter(AmiWebDataSession session) {
                this.userSession = session;
                allowedRegion = (String) userSession.getVariableValue("region");
                if(allowedRegion==null)
                        throw new RuntimeException("no 'region' specified");
        }

        @Override
        public byte evaluateNewRow(AmiWebObject realtimeRow) {
                String region = (String) realtimeRow.getParam("region");
                return allowedRegion.equals(region) ? SHOW_ALWAYS : HIDE_ALWAYS;
        }

        @Override
        public byte evaluateUpdatedRow(AmiWebObject realtimeRow, byte currentStatus) {
                Object region = (String) realtimeRow.getParam("region");
                return allowedRegion.equals(region) ? SHOW_ALWAYS : HIDE_ALWAYS;
        }

        @Override
        public AmiWebDataFilterQuery evaluateQueryRequest(AmiWebDataFilterQuery query) {
                return query;
        }

        @Override
        public void evaluateQueryResponse(AmiWebDataFilterQuery query, ColumnarTable table) {
                Column regionColumn = table.getColumnsMap().get("region");
                if (regionColumn == null)
                        return;
                for (int i = table.getSize() - 1; i >= 0; i--) {
                        Row row = table.getRow(i);
                        String region = row.getAt(regionColumn.getLocation(), String.class);
                        if (!allowedRegion.equals(region))
                                table.removeRow(row);
                }
        }
}