In Which Access Control Context Are Concepts Evaluated

Can a concept evaluation depend on where it is evaluated?

Can a concept evaluation depend on where it is evaluated?

No.

It used to be the case that this was true (as my answer before this edit stated), but it turns out that this severely inhibits compiler throughput (since you cannot cache the result of a concept check) and the motivation for having it to begin with was pretty weak. This was a very late change, adopted as part of P2104 in the Prague 2020 meeting which adds the following sentence to [temp.constr.atomic]:

If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, the program is ill-formed, no diagnostic required.

As a result, this:

template<class T>
concept Complete = sizeof(T) == sizeof(T);

struct A;
static_assert(!Complete<A>);
struct A {};
static_assert(Complete<A>);

is ill-formed, NDR (practically speaking, Complete<A> will still be false after A becomes complete). In other words, we "memoize" concepts in the same way we "memoize" template instantiations.

C++ concepts see a function for my type, but don't see it for std::vector

I think this is a defect in this experimental Clang concept implementation. [temp.concept]/8 says:

A concept is not instantiated ([temp.spec]).

See also: In which access control context are evaluated concepts?

That means that name resolution as it is described in [temp.res] does not apply to an expression that is a concept definition. If concepts had to be instantiated, then the function add could not be find by unqualified name look-up. This is why Clang generates an error.

According to the standard, when a id-expression names a concept, the normalized constraint-expression is evaluated where appears the id-expression ([expr.prim.id]/4).

Less formaly, the expression that is the definition of the concept is evaluated in the context of the expression that names the concept. So Addable<vector<int>> should be true, because in the context of this expression, add can be found by unqualified name look-up.

Amazon S3 performs the following context evaluation - clarification

To illustrate the concept of context, consider this scenario:

  • My AWS account owns a bucket
  • Your AWS account creates an IAM user
  • We agree that your user needs to access my account's bucket

How do we allow that?

It is not sufficient for my account to allow your user to access my bucket.

It is also not sufficient for your account to authorize your IAM user to access my bucket.

Both of these things must be granted.

When the request arrives, it passes through two layers of authorization checks:

  • user context: does this user's account allow him or her to make this request? If no, then access denied; otherwise, next.
  • bucket context: does the bucket owner account allow this user to make this request? If no, then access denied; otherwise, access granted.

The system needs both sides to agree that the access should be allowed.

However... in the example you cited, everything needed is learned while evaluating the user context, since the same account controls/owns the user and the bucket. Evaluating the bucket context is redundant, so it isn't done in that case.

"User context" is user account context, and "bucket context" is bucket account context.


Or, perhaps your question is actually more simple than this.

what happens in the case where an IAM user created the Bucket?

It doesn't matter who creates the bucket. The bucket is owned by the AWS account that created it, whether it is the root user or an IAM user from that account. Users never own buckets, and which specific user created a bucket has no further significance once the bucket has been created.

The AWS account that creates a resource owns that resource. For example, if you create an IAM user in your AWS account and grant the user permission to create a bucket, the user can create a bucket. But the user does not own the bucket; the AWS account to which the user belongs owns the bucket. The user will need additional permission from the resource owner to perform any other bucket operations.

http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html#create-bucket-intro

Implementing std::iter_­difference_­t

Step 1. Be the owner of std::iterator_traits. This lets you write something in the primary like:

template <typename T>
struct iterator_traits {
using __secret_am_i_the_primary_alias = iterator_traits;
};

Which you can check:

template <typename T>
concept is_iterator_primary = std::same_as<
typename iterator_traits<T>::__secret_am_i_the_primary_alias,
iterator_traits<T>>;

Step 2. Now it's pretty easy:

template <typename T>
struct iter_difference {
using type = typename iterator_­traits<I>​::​​difference_­type;
};

template <is_iterator_primary T>
struct iter_difference<T> {
using type = typename incrementable_­traits<I>​::​difference_­type;
};

template <typename T>
using iter_difference_t = typename iter_difference<T>::type;

Role-based access control (RBAC) vs. Claims-based access control (CBAC) in ASP.NET MVC

I will try to explain the Role/Claim/Permission-based Access Control concept in layman's terms. The code snippet I will present here, are pseudocode, may or may not compile.

What are Roles?

Roles can be thought of as Job Titles. Like "Sales Manager", "Marketing Manager", "Admin" etc.

What are the claims?

Claims can be broader than a Role. You can think about Claim as a TAG. For example, you can tag a person as "Friendly", "Talkative", "European", "Photographer", "Adult-who-is-18-years-old" etc. Technically, a role can be thought of as a claim too.

Role-Based Access Control

Very simple. Instead of using words, let's show some examples.
Say, you allow visiting some pages on your website by checking Roles. Like this:

    [Authorize(Roles="Sales Manager")]
public ActionResult CreateCustomer()
{
return View();
}

[Authorize(Roles="Marketing Manager")]
public ActionResult EditLandingPage()
{
return View();
}

Claims Based Access Control

In layman's terms, in Claims Based Access control, you check for claims instead of a role when determining access to a page.

(This is a pseudo code. ClaimsAuthorize is not a built-in class in MVC, rather, you may find some NuGet packages for that or you can write your own)

    [ClaimsAuthorize(Claims="Senior-Employee, Award-Winner-Employee, Experienced-On-Sales")]
public ActionResult CreateCustomer()
{
return View();
}

[ClaimsAuthorize(Claims="Trust-worthy-Employee, President")]
public ActionResult DeleteCustomer()
{
return View();
}

[ClaimsAuthorize(Claims="Adult-over-18years")]
public ActionResult ViewImagesOfViolence()
{
return View();
}

Notice that, instead of checking for roles, we are allowing to visit a page based on WHO the user is claiming to be.

RBAC vs CBAC

Ok, now, if you ask what is the benefit of Role-based access control or Claim based access control, then, think about this page "ViewImagesOfViolence". Is not it more intuitive to check for a claim "Adult-over-18years" when determining if you should allow the user to visit that page? In a word, using Claims, you can create more segments within your users comparing roles. In an abstract sense, all roles can be claims too, but claims cannot be thought of as roles.

Permission-based access control

Instead of checking for Roles or Claims when allowing permissions to view a page, you should rather think about Permission-based access control. Let me show you some pain points.

When you are using Role-based authentication, if you have an action for creating customers and you want that the people who are in the 'Sale' role should be able to do that, then you write code like this:

[Authorize(Roles="Sale")]
public ActionResult CreateCustomer()
{
return View();
}

Later, you realized that, sometimes, people from the 'Marketing' role should be able to create Customers. Then, you update your Action method like that

[Authorize(Roles = "Sale", "Marketing")]
public ActionResult CreateCustomer()
{
return View();
}

Now, you realized that some of the marketing people must not be able to create Customers, but it is not possible to assign a different role for those people who are in Marketing. So, you are forced to allow all marketing people to create Customers.

you spotted another problem, anytime you decide that Marketing people should be allowed to create customers, you have to update all of your MVC Action methods Authorize attribute, compile your application, test, and deploy. Some days later, you decided, not marketing but some other role should be allowed to do the task, so you search in your codebase and delete all 'Marketing' from Authorize attribute and add your new role name in Authorize attribute... Not a healthy solution. At that point, you would realize a need for Permission-Based Access Control.

Permission-Based access control is a way of assigning various permissions to various users or various roles or various claims and checking if a user has permission to execute an action from the code in run time. If you assign permission to a role or a claim, then, you would check what are the roles or claims for that logged-in user. And then, you will check what permissions are available for those roles or claims.

You can define some set of permissions like this :

"CanCreateCustomer", "CanDeleteCustomer", "CanEditCustomer".. etc..

Now, you can decorate your Action Method like this:

[Authorize(Permission="CanCreateCustomer")]
public ActionResult CreateCustomer()
{
return View();
}

Please note, [Authorize(Permission="CanCreateCustomer")] may not
be built into the MVC class library, I am just showing as an example in an abstract sense. There can be a NuGet package that will have Permission property in Authorize class.

Now, you can see that, CreateCustomer action method will always need permission 'CanCreateCustomer' and it will never change or hardly change.

Who will get the permissions?

You can assign a set of permissions directly to a user. But do not do that. It will be tremendously difficult to manage that. Rather,

You can assign a set of permissions to a Role Or you can assign a set of permissions to a Claim (Recommended).

As I mentioned, roles can be thought of as claims too. So, you can treat the roles as claims. Then, you can create a table of Claims in your database.
Then, create another table for holding the relations where each claim can contain multiple permissions.

This security model offers you clean code practice. Moreover, when you write your Action Method, you don't have to think about who can use this method, rather you can always be assured that whoever is using this method will have proper permission given by the Admin. Then, Admin can decide who will be able to do what. Not you as a developer. That's how your business logic is separated from Security logic.

Whenever someone signs in, your application will check whatever permissions are available for that user and that permission set will be available as additional properties of the currently logged-in user, so you don't have to check permission set all the time from the database. The bottom line is, you get more control of your security logic in your application if you apply permission-based access control.

If your application is a very little application where there would be only 2 roles: Customer and Admin and there is no chance that Customers will be able to do anything else other than what they are meant to do in your application, then perhaps, simple Role-based access control will serve the purpose, but as your application grows, you will start to feel the need of permission based access control at some point.

ACL ordering and evaluation. what should take precedence Account or group, aco or parent aco

Given the above information we can write some simple tooling, in my case I am working with a content management system so my ACL's are about page access.

First I define what my ACL entries look like ...

using System;
namespace Core.Objects.CMS
{
/// <summary>
/// Represents a record on an access control list
/// </summary>
public class PageACLEntry
{
/// <summary>
/// Gets or sets the access control entry id.
/// </summary>
/// <value>
/// The access control entry id.
/// </value>
public int PageACLEntryId { get; set; }
/// <summary>
/// Gets or sets the page id.
/// </summary>
/// <value>
/// The page id.
/// </value>
public int PageId { get; set; }
/// <summary>
/// Gets or sets the name of the role.
/// </summary>
/// <value>
/// The name of the role.
/// </value>
public string RoleName { get; set; }
/// <summary>
/// Gets or sets the read.
/// </summary>
/// <value>
/// The read.
/// </value>
public bool? Read { get; set; }
/// <summary>
/// Gets or sets the content of the update.
/// </summary>
/// <value>
/// The content of the update.
/// </value>
public bool? UpdateContent { get; set; }
/// <summary>
/// Gets or sets the update meta.
/// </summary>
/// <value>
/// The update meta.
/// </value>
public bool? UpdateMeta { get; set; }
/// <summary>
/// Gets or sets the delete.
/// </summary>
/// <value>
/// The delete.
/// </value>
public bool? Delete { get; set; }
/// <summary>
/// Gets or sets the full control.
/// </summary>
/// <value>
/// The full control.
/// </value>
public bool? FullControl { get; set; }
}
}

Then I create a helper class to handle the evaluations ...

using System.Collections.Generic;
using System.Security.Principal;
using Core.Objects.CMS;

namespace Core.Utilities
{
/// <summary>
/// Tools for permission calculation
/// </summary>
public static class PermissionHelper
{
/// <summary>
/// Calculates the page permissions the given user has on the given page.
/// </summary>
/// <param name="page">The page.</param>
/// <param name="user">The user.</param>
/// <returns>the effective permissions</returns>
private static PageACLEntry CalculatePagePermissions(Page page, IPrincipal user)
{
PageACLEntry result = new PageACLEntry();
// start with acl for the current page
List<PageACLEntry> acl = new List<PageACLEntry>(page.AclRules);
// append all the way up the tree until parent == null
acl = AppendTreePermissions(acl, page, user);
// reverse the list so we evaluate root first then work up to here
acl.Reverse();
// because of the order in which these are applied the most local rules overrule the less local
// the wider the scope the less it applies
acl.ForEach(ace =>
{
// only apply rules that apply to roles that our current user is in
if (user.IsInRole(ace.RoleName))
{
result.Read = Eval(result.Read, ace.Read);
result.Delete = Eval(result.Delete, ace.Delete);
result.UpdateMeta = Eval(result.UpdateMeta, ace.UpdateMeta);
result.UpdateContent = Eval(result.UpdateContent, ace.UpdateContent);
result.FullControl = Eval(result.FullControl, ace.FullControl);
}
});

return result;
}

/// <summary>
/// Evaluates the specified permission level.
/// </summary>
/// <param name="target">The target.</param>
/// <param name="suggestion">The suggestion.</param>
/// <returns>evaluation result</returns>
private static bool? Eval(bool? target, bool? suggestion)
{
bool? result = null;
switch (target)
{
case false:
result = false;
break;
case true:
result = true;
break;
case null:
break;
}

return result;
}

/// <summary>
/// Appends the tree acl from the tree root up to this point.
/// </summary>
/// <param name="acl">The acl.</param>
/// <param name="page">The page.</param>
/// <param name="user">The user.</param>
/// <returns>the complete acl</returns>
private static List<PageACLEntry> AppendTreePermissions(List<PageACLEntry> acl, Page page, IPrincipal user)
{
Page currentPage = page.Parent;
while (currentPage != null)
{
acl.AddRange(currentPage.AclRules);
currentPage = page.Parent;
}

return acl;
}

/// <summary>
/// Determines if the current User can read the given page.
/// Unless an explicit deny rule is in place the default is to make everything read only.
/// </summary>
/// <param name="page">The page.</param>
/// <param name="user">The user.</param>
/// <returns>
/// access right indication as bool
/// </returns>
public static bool UserCanRead(Page page, IPrincipal user)
{
PageACLEntry permissions = CalculatePagePermissions(page, user);
if (permissions.Read != false)
{
return true;
}

return false;
}
/// <summary>
/// Determines if the current User can delete the given page.
/// </summary>
/// <param name="page">The page.</param>
/// <param name="user">The user.</param>
/// <returns>
/// access right indication as bool
/// </returns>
public static bool UserCanDelete(Page page, IPrincipal user)
{
PageACLEntry permissions = CalculatePagePermissions(page, user);

if (permissions.FullControl == true || permissions.Delete == true)
{
return true;
}

return false;
}
/// <summary>
/// Determines if the current User can update the given page.
/// </summary>
/// <param name="page">The page.</param>
/// <param name="user">The user.</param>
/// <returns>
/// access right indication as bool
/// </returns>
public static bool UserCanUpdate(Page page, IPrincipal user)
{
PageACLEntry permissions = CalculatePagePermissions(page, user);

if (permissions.FullControl == true || permissions.UpdateMeta == true)
{
return true;
}

return false;
}
public static bool UserCanUpdateContent(Page page, IPrincipal user)
{
PageACLEntry permissions = CalculatePagePermissions(page, user);

if (permissions.FullControl == true || permissions.UpdateContent == true)
{
return true;
}

return false;
}
/// <summary>
/// Determines if the current User can append children to the given page.
/// </summary>
/// <param name="page">The page.</param>
/// <param name="user">The user.</param>
/// <returns>
/// access right indication as bool
/// </returns>
public static bool UserCanAddChildTo(Page page, IPrincipal user)
{
PageACLEntry permissions = CalculatePagePermissions(page, user);

if (permissions.FullControl == true || permissions.UpdateMeta == true)
{
return true;
}

return false;
}
}
}

This now gives me all the control I simply pass that a page and an IPrincipal object and I get back an ACLEntry that represents the level of access.

I decided to further abstract away my security implementation by making the Calculation method private and only the CanX methods public.

So now it's as simple as

bool result = PermissionsHelper.UserCanRead(page, user);

It seems like theres a lot of code but if you take out the formatting and comments (to meet coding standards) there's actually very little code, and if you copy this in in to a class file in Visual Studio it's actually very easy to follow and maintain.

You may also note, not once do I pass in a repository or service class to get data, that's because I use this to build objects that are written using code first EF modelling an i'm using lazy loading, so your implementation might require a bit more than page.parent.AClEntries to go crawling up the tree.

Oh just in case you need it here's my page class ...

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace Core.Objects.CMS
{
/// <summary>
/// Represents a managed CMS page
/// </summary>
[Table("Pages")]
public class Page
{
/// <summary>
/// Gets or sets the page id.
/// </summary>
/// <value>
/// The page id.
/// </value>
public int PageId { get; set; }
/// <summary>
/// Gets or sets the version.
/// </summary>
/// <value>
/// The version.
/// </value>
public int Version { get; set; }
/// <summary>
/// Gets or sets the title.
/// </summary>
/// <value>
/// The title.
/// </value>
public string Title { get; set; }
/// <summary>
/// Gets or sets the template.
/// </summary>
/// <value>
/// The template.
/// </value>
public string Template { get; set; }
/// <summary>
/// Gets or sets the path.
/// </summary>
/// <value>
/// The path.
/// </value>
public string Path { get; set; }
/// <summary>
/// Gets or sets the parent.
/// </summary>
/// <value>
/// The parent.
/// </value>
public virtual Page Parent { get; set; }
/// <summary>
/// Gets or sets the children.
/// </summary>
/// <value>
/// The children.
/// </value>
public virtual List<Page> Children { get; set; }
/// <summary>
/// Gets or sets the content.
/// </summary>
/// <value>
/// The content.
/// </value>
public virtual List<PageContent> Content { get; set; }
/// <summary>
/// Gets or sets the component stacks.
/// </summary>
/// <value>
/// The component stacks.
/// </value>
public virtual List<Stack> ComponentStacks { get; set; }
/// <summary>
/// Gets or sets the acl rules.
/// </summary>
/// <value>
/// The acl rules.
/// </value>
public virtual List<PageACLEntry> AclRules { get; set; }
}
}

Very simple poco ... using the power of EF to do all my on demand SQL crawling.
The one down side ... i doubt it's particularly efficient if you have a page deeply nested in a tree.

I'm still open to suggestions on improving this but this felt like the cleanest way to implement a managable solution at the time.
Now i have total visibility of the problem I can look to make those efficiency gains.

But at least you have a point of reference right :)

Operator Precedence vs Order of Evaluation

Yes, the MSDN article is in error, at least with respect to standard C and C++1.

Having said that, let me start with a note about terminology: in the C++ standard, they (mostly--there are a few slip-ups) use "evaluation" to refer to evaluating an operand, and "value computation" to refer to carrying out an operation. So, when (for example) you do a + b, each of a and b is evaluated, then the value computation is carried out to determine the result.

It's clear that the order of value computations is (mostly) controlled by precedence and associativity--controlling value computations is basically the definition of what precedence and associativity are. The remainder of this answer uses "evaluation" to refer to evaluation of operands, not to value computations.

Now, as to evaluation order being determined by precedence, no it's not! It's as simple as that. Just for example, let's consider your example of x<y<z. According to the associativity rules, this parses as (x<y)<z. Now, consider evaluating this expression on a stack machine. It's perfectly allowable for it to do something like this:

 push(z);    // Evaluates its argument and pushes value on stack
push(y);
push(x);
test_less(); // compares TOS to TOS(1), pushes result on stack
test_less();

This evaluates z before x or y, but still evaluates (x<y), then compares the result of that comparison to z, just as it's supposed to.

Summary: Order of evaluation is independent of associativity.

Precedence is the same way. We can change the expression to x*y+z, and still evaluate z before x or y:

push(z);
push(y);
push(x);
mul();
add();

Summary: Order of evaluation is independent of precedence.

When/if we add in side effects, this remains the same. I think it's educational to think of side effects as being carried out by a separate thread of execution, with a join at the next sequence point (e.g., the end of the expression). So something like a=b++ + ++c; could be executed something like this:

push(a);
push(b);
push(c+1);
side_effects_thread.queue(inc, b);
side_effects_thread.queue(inc, c);
add();
assign();
join(side_effects_thread);

This also shows why an apparent dependency doesn't necessarily affect order of evaluation either. Even though a is the target of the assignment, this still evaluates a before evaluating either b or c. Also note that although I've written it as "thread" above, this could also just as well be a pool of threads, all executing in parallel, so you don't get any guarantee about the order of one increment versus another either.

Unless the hardware had direct (and cheap) support for thread-safe queuing, this probably wouldn't be used in in a real implementation (and even then it's not very likely). Putting something into a thread-safe queue will normally have quite a bit more overhead than doing a single increment, so it's hard to imagine anybody ever doing this in reality. Conceptually, however, the idea is fits the requirements of the standard: when you use a pre/post increment/decrement operation, you're specifying an operation that will happen sometime after that part of the expression is evaluated, and will be complete at the next sequence point.

Edit: though it's not exactly threading, some architectures do allow such parallel execution. For a couple of examples, the Intel Itanium and VLIW processors such as some DSPs, allow a compiler to designate a number of instructions to be executed in parallel. Most VLIW machines have a specific instruction "packet" size that limits the number of instructions executed in parallel. The Itanium also uses packets of instructions, but designates a bit in an instruction packet to say that the instructions in the current packet can be executed in parallel with those in the next packet. Using mechanisms like this, you get instructions executing in parallel, just like if you used multiple threads on architectures with which most of us are more familiar.

Summary: Order of evaluation is independent of apparent dependencies

Any attempt at using the value before the next sequence point gives undefined behavior -- in particular, the "other thread" is (potentially) modifying that data during that time, and you have no way of synchronizing access with the other thread. Any attempt at using it leads to undefined behavior.



Related Topics



Leave a reply



Submit