Policy and Authorization

Extensibility
Extensibility covers the mechanisms by which you, as the user or developer, can extend the functionality of the Teradata Database, for example with the use of User Defined Functions, or UDFs.
Teradata Employee

Policy and Authorization

The VISA policy/authorization/verdict engine may initially seem a a little daunting, but it's really quite simple. Firstly, you should have read Domains, Permissions and Resources and Identity and authentication.

Query

That being done, we begin with:

VISA renders a verdict on an authorization query by evaluating the set of authorization statements related to the resource in question.

So, what is an authorization query? Well, firstly it's an English-language question such as:

Does user Bob have permission VIEW_SQL on the system PROD1 in the MyQueries portlet?

In the question above:

  • Bob is the principal, or the entity trying to perform some protected action. A user and a role are both examples of a principal, so the question above could just as easily have read: "Does role Manager have permission VIEW_SQL on ...?" etc.
  • VIEW_SQL is name of the permission, or action, that Bob wants to perform.
  • PROD1 is the resource on which Bob is trying to perform the action VIEW_SQL.
  • MyQueries is the domain (typically a portlet) in which all this is happening.

So, an authorization query (from now on we'll just call it a query) is a question of the form:

Does principal X have permission Y on resource Z in domain A?

For the purposes of this article, we'll introduce a little shorthand and say that the following represents Bob's query above:

Bob ? VIEW_SQL | PROD1@MyQueries

Of course, a query is a really a Java class: com.teradata.viewpoint.security.policy.Query. You can create a query like this:

Query examples

// We first need to create the principal (user) and resource
User bob = new User("Bob");
Resource prod1 = new Resource(new Domain("MyQueries"), "PROD1");

// Use the convenience methods in QueryBuilder to build your Query
Query query = QueryBuilder.buildResourceQuery(bob, prod1, "VIEW_SQL");
// Your query is ready! Now do something with it....

Verdict Engine

A query is no good unless you can get an answer. And for that, we need the VerdictEngine. It's really pretty simple to use.

VerdictEngine stuff

// let's use our query from above
boolean verdict = verdictEngine.isGranted(query);

if (verdict)
{
System.out.println("I can view the SQL! How exciting!");
}

An important consideration is that when a query is executed, the results for all of the user's roles are also calculated, and then combined to arrive at a verdict. So, if Bob is in role User and role Manager, then this query:


Bob ? VIEW_SQL | PROD1@MyQueries

is really equivalent to:

Bob ? VIEW_SQL | PROD1@MyQueries

User ? VIEW_SQL | PROD1@MyQueries

Manager ? VIEW_SQL | PROD1@MyQueries

Note that the order of evaluation of the queries is important.

Statement

Query allows you to ask policy questions, and its close relative, the Statement, allows you to make policy assertions. A statement looks like a Query but with an extra field, of type Decision. So, if a query looks like this:

Bob ? VIEW_SQL | PROD1@MyQueries

Then a statement looks like so:

Bob ? VIEW_SQL | PROD1@MyQueries : GRANT

Note that a Decision can have one of three values: GRANTABSTAIN, and DENY. So, how do we use these statement things? We pass 'em to the PolicyManager.

Statement and PolicyManager stuff

// let's use our query from above, and let's grant access!
Statement statement = new StatementBuilder(query, Decision.grant).toStatement();
policyManager.applyStatements(statement);
// now bob can see the sql!

// hmmmn, maybe I've changed my mind, let's undo that
statement = new StatementBuilder(query, Decision.deny).toStatement();
policyManager.applyStatements(statement);
// now bob is out of luck...

// well, maybe that's a little harsh. Maybe I just don't care...
statement = new StatementBuilder(query, Decision.abstain).toStatement();
policyManager.applyStatements(statement);
// now bob is dependent on other factors, since we're staying out of it

Setting policy is essentially a matter of building statements incorporating a Decision, and then applying the statements. Note that there is no method for "removing" a statement; you simply apply a statement that counteracts the previous statement. Also, note that the Decision class is a three-state enum with values grantdeny, and abstain. The first two values should be self-explanatory. The abstain value indicates that there should be no assertion made about the query. Essentially, abstain will "undo" either of the other two values.

VerdictEngine Part Deux

It's time to learn a few rules of the VerdictEngine. Let's go back to the Bob query:

Bob ? VIEW_SQL | PROD1@MyQueries

We already know that the query is really equivalent to:

Bob ? VIEW_SQL | PROD1@MyQueries

User ? VIEW_SQL | PROD1@MyQueries

Manager ? VIEW_SQL | PROD1@MyQueries

What does this mean exactly? Well, the evaluation process goes something like this:

  1. First check if there is a statement that matches the first query. That is, is there a statement of the form:

    Bob ? VIEW_SQL | PROD1@MyQueries : SOME_DECISION

    If there is a Decision of GRANT or DENY, then that's the verdict right there. If the Decision is ABSTAIN (or if there's no statement, which is the equivalent of ABSTAIN), then proceed to the next query.

  2. Now check if there is a statement that matches the second query. If the Decision is GRANT or DENY, then that's the verdict. If not, continue to the third query, etc.
  3. If there are no statements that match the query, or all statements are ABSTAIN, then return DENY.

Role precedence

Bob again. Let's say that he's in role User and role Manager we've got the following policy statements in the datastore:

User ? VIEW_SQL | PROD1@MyQueries : DENY

Manager ? VIEW_SQL | PROD1@MyQueries : GRANT

Bob's result is going to be DENY, because the User statement was evaluated before the Manager statement. So, clearly the order of evaluation is important. This is known as role precedence, and it is set on per-user basis, administratively via the User Manager portlet, and programmatically via IdentityManager#setUserRoleMappings.