Providing authorization at the property level in domain objects

I am implementing a RESTful service, which has a security model that requires authorization at three levels:

  • Resource level resolution - determining whether a user has access to a resource (entity). For example, the current user has permission to view clients in general. If not, then everything stops there.
  • instance level authorization - determining whether a user has access to a specific instance of a resource (object). Due to the different rules and condition of the object, the current user may not be able to access one of several clients within the clients. For example, a client may view its information, but not the information of another client.
  • property level authorization - determine what properties a user has access to an instance of a resource (object). We have a lot of business rules that determine whether a user can see and / or change the individual properties of a resource (object). For example, the current user can see the name of the client, but not the address or phone number, as well as the ability to view and add notes.

The implementation of authorization at the resource level is straightforward; however, the other two are not. I believe that the instance-level authorization solution will show itself with the (tighter, imo) property-level authorization issue. The last problem is complicated by the fact that I need to pass authorization decisions on the property in the response message (ala hypermedia) - in other words, this is not something that I can simply apply in property installers.

With every request to the service, I must use the current user information to perform these authorization checks. In the case of a GET request for a list of resources or an individual resource, I need to specify the API level that the attributes of the current user can see (apparently), and whether the attribute is read-only or is being edited. The API layer will then use this information to create the appropriate response message. For example, any property that is not displayed will not be included in the message. Read-only properties will be marked so that the client application can display the property in the appropriate state for the user.

Solutions, such as application services, aspects, etc., are great for authorization at the resource level and can even be used for verification at the instance level, but I am delaying the definition of how best to model my domain so that business rules and checks provided security restrictions included.

NOTE. Keep in mind that this goes beyond role-based security because I get the final authorization result based on business rules using the current state of the resource and environment (along with access control using permissions granted by the current user through their roles).

How do I simulate a domain so that I apply all three types of authorization checks (in a test way, with DI, etc.)?

+9
security rest authorization domain-driven-design
source share
2 answers

Initial assumptions

I assume the following architecture:

Stateless Scaling Sharding . . . . . . +=========================================+ | Service Layer | +----------+ | +-----------+ +---------------+ | +------------+ | | HTTP | | | | | | Driver, Wire, etc. | | | Client | <============> | RESTful | <====> | Data Access | <=======================> | Database | | | JSON | | Service | DTO | Layer | | ORM, Raw, etc. | | | | | | | | | | | | +----------+ | +-----------+ +---------------+ | +------------+ +=========================================+ . . . . . . 

First, suppose you authenticate Client using the Service Layer and get a specific token that encodes authentication and authorization information in it.

First of all, I first think about processing all requests, and then filtering them only depending on authorization. This will simplify and simplify the work. However, of course, some queries may require expensive processing, in which case this approach is completely ineffective. High load requests, on the other hand, are likely to be associated with access to a resource, which, as you said, is easily organized and can be detected and resolved in the Service Layer in the API or at least Data Access levels.

Further thoughts

As for authorization at the instance level and property, I will not even try to put it in the Data Access Layer and completely isolate it outside the API level, that is, starting from the Data Access Layer none of the levels will even know about it. Even if you request a list of 1M objects and want to release one or two properties from all objects for this particular client, it would be preferable to extract all the objects, and then only hide the properties.

Another assumption is that your model is a clear DTO , that is, just a data container, and all business logic is implemented at the Service Layer level, especially the API . And say that you are transmitting data via HTTP encoded as JSON . Anyway, somewhere in front of the API layer you will have a small serialization stage to convert your model to JSON . Thus, this stage - this is the place where I think is the ideal place to place an instance and permit property.

Sentence

If it comes to authorization at the property level, I think that there is no reasonable way to isolate the model from security logic. Whether it is rule-based authorization, role-based authorization, or at any other level, this process will be checked for value from the authentication / authorization token provided by Client . So, at the serialization level, you will basically get two parameters, a token and a model, and accordingly serialize the corresponding properties or the instance as a whole.

When it comes to defining rules, roles, and whatevers for a property for a model, this can be done in various ways depending on the available paradigms, that is, depending on the language that the Service Layer will implement. Definitions can be heavily used by Annotations (Java) or Decorators (Python) . For emitting specific properties, Python will be convenient due to its dynamic collections and hacker functions, for example. Descriptors . In the case of Java, you can complete the encapsulation of properties in a template class, such as AuthField<T> .

Summary

To summarize, I would suggest placing instance and property authorization in front of API Layer at the serialization stage. Thus, in principle, roles / rules will be assigned in the model, and authorization will be performed in the serializer, providing the model and token.

+1
source share

Since a comment was recently added, I thought that I would update this post with my knowledge, since I originally asked a question ...

Simply put, my initial logic was erroneous, and I tried to do too much in my business objects. Following the CQRS approach helped make the solution more understandable.

For state changes, the “record model” uses a business object, and the “command handler” / “domain service” performs authorization checks to ensure that the user has the necessary permissions to update the requested object and, where applicable, to change certain properties, this an object. I still argue about whether property level checks belong inside the methods of the business object or outside (in the handler / service).

In the case of the "reading model", the "request handler" / "domain service" checks the resource- and authorization rules at the instance level, so only objects that the user has access to are returned. The handler / service uses a mapping object that applies property-level authorization rules to the data when constructing the returned DTOs. In other words, the data access level returns a “projection” (or view) regardless of authorization rules, and the converter ignores any properties that the current user does not have access to.

I messed around using dynamic query generation based on a list of fields the user has access to, but in our case this turned out to be redundant. But in a more complex solution with larger and more complex objects, I see that it is more viable.

0
source share

All Articles