Summary#
A policy is a question about the caller. Sometimes you need its answer about somebody else — who on a list is a lead,
whom to tell. Ask it of them:
if (Security.Authorize(member, LeadsInbox)) { leads.Add(member); }Signature#
bool Security.Authorize(Principal person, PolicyName) // a policy that takes no argument, named bare
bool Security.Authorize(Principal person, PolicyName(argument)) // a parameterised one, with its argument
// person: the principal row, or its idDescription#
Whose answer#
The person's. The policy is evaluated with THEM as user — their account and their roles, the way a request of
theirs is armed — so a workflow body (which reads everything) and an admin's request get the same answer as anybody
else would about that person. An id that is nobody answers false, never what an anonymous visitor would be granted.
It is the same evaluation [Authorize(PolicyName)] and if (PolicyName) use for the caller, so a policy means one thing
in all three places.
It grants nothing#
It answers one yes or no about one person, and nothing else. Nothing runs as them, nothing is written as them, nothing
they could read is handed back, and the caller's own access is untouched: asking whether somebody is a lead does not
make the caller one — the next line's if (IsLead) and every row rule still answer for the caller.
Only a policy you can see#
The second argument NAMES a declared policy; it is not a condition to evaluate. It must be one this code can see — the
app's own, or (in a kit) one the kit declares, or a package it uses declares. A kit therefore asks only about a rule the
app was handed and filled in — policy LeadsInbox; in the kit, policy LeadsInbox => IsLead; in the app — and never
about the app's other rules. Anything else is a compile error that lists every policy there is to name:
Security.Authorize(m, IsLeed) // there is no `policy IsLeed` this code can see — the policies this code can name: …
Security.Authorize(m, m.Grade == 1) // the second argument names a policy; it is not a condition to evaluate
Security.Authorize(m, IsAuthenticated) // `IsAuthenticated` is the platform's own state of a caller, not a declared policyIn a kit#
This is how a kit reaches "the people the app says" without knowing the app's roles. The WorkQueues kit declares who leads it as a policy the app supplies, and finds a queue's leads by asking it of each member:
// in the kit
policy LeadsInbox;
public List<Principal> InboxLeads(WorkItem item) {
List<Principal> leads = [];
foreach (var m in QueueMember.Where(m => m.Queue == item.Queue && m.Active).Include(m => m.Member).ToList()) {
if (Security.Authorize(m.Member, LeadsInbox)) { leads.Add(m.Member); }
}
return leads;
}
// in the app — the only thing it writes about its leads
policy LeadsInbox => IsLead;What it costs#
One evaluation per person asked: their principal and roles (kept between requests, as a request's are) and whatever the policy itself reads. Ask it of the people a decision is about — a queue's members — not of every account.
Examples#
enum Grade { Lead, Nurse }
[Principal] entity Carer {
[MaxLength(100)] string Name = "";
security { allow read, create when IsAnonymous || IsAuthenticated; }
}
entity Grading {
[Required] Carer Who;
[Required] Grade Grade;
security { allow read, create when IsAnonymous || IsAuthenticated; }
}
entity Ward {
[Required, MaxLength(40)] string Name;
Carer? Head;
security { allow read, create when IsAnonymous || IsAuthenticated; }
}
policy LeadsWards => Grading.Any(g => g.Who == user && g.Grade == Grade.Lead);
policy Heads(Ward w) => w.Head == user;
/// The leads on the rota — asked of each carer, by the app's own rule, whoever is asking.
List<string> LeadsOnTheRota() {
List<string> leads = [];
foreach (var c in Carer.OrderBy(c => c.Name).ToList()) {
if (Security.Authorize(c, LeadsWards)) { leads.Add(c.Name); }
}
return leads;
}
/// Whether `carer` heads `ward` — a parameterised policy, with its argument.
bool HeadsIt(Carer carer, Ward ward) { return Security.Authorize(carer, Heads(ward)); }See also#
- policy — declaring a policy, and asking it of the caller
- Security.MayRead — may THIS person read this row, under their own rules — the same idea for a row: may THIS person read it
- security { } — the rules a policy is used in
- Inbox.Notifications — the people the inbox names, told in their bell — a queue's leads told, by the app's
LeadsInbox