14. Access rule definition technique
Let’s remember that a Softnet domain contains two built-in users – Owner and Guest. The administrator can also create Private users and Contact users. Owner is associated with the project owner. Guest is a generalized user that represents all anonymous clients. Guest clients can be stateful or stateless. The latter connects to the site without authentication using a shared guest URI. The user membership of a service contains domain users added to the site by assigning them access rights. When the service connects to the site, Softnet loads the user membership into the service application. Every client on the site is associated with a particular user from the user membership and inherits its access rights. With each request, Softnet provides the service with a membership user object corresponding to the client from which the request has been received. This membership user can represent Guest, StatelessGuest, or a named user. In the latter case, the membership user contains the name of the user, as well as its roles if the application employs role-based access control (RBAC).
You might be wondering why guest clients are divided into two categories: stateful and stateless. The only reason is the ability to receive Private events, i.e., notifications from services. A stateful client can receive Private events, but requires to have an account and a unique URI, which is inconvenient for anonymous users. In contrast, a stateless client does not have an account and use a shared guest URI, but unable to receive Private events. Both are guest clients, but differ in capabilities and usability. If a request handler you define can raise Private events and is expected to serve guest clients, you must deny stateless guest clients in the handler’s access rule while allowing stateful guest clients. To do this, specify the StatelessGuestDenied value from the GuestAccess enumeration. Of course, along with the stateful guest, this rule also grants access to all named users.
Softnet implements four communication patterns, and all of them support access control. The platform uses a unified technique for defining access rules. Each of the Softnet library methods designed to handle client requests has three overloaded variants that differ in the way of defining access rules. The first variant applies no access restrictions to clients. The second overloaded method has at the end one more parameter of GuestAccess enumeration type. This parameter specifies what kind of guest clients are denied. The enumeration contains two elements:
public enum GuestAccess { GuestDenied, StatelessGuestDenied }
If you provide GuestDenied, all guest clients will be denied, but all clients from named membership users will be allowed. If you provide StatelessGuestDenied, stateless guest clients will be denied, but stateful guest clients and clients from named membership users will be allowed. The third variant of the method also has one more parameter at the end, but it is of string type. In this parameter, you provide the list of authorized roles delimited with a semicolon. Of course, the third variant of the method is only applicable if your application employs RBAC. Note that the entire list of user roles must be defined in advance using the SiteStructure.setRoles method.
The following list presents five built-in Softnet API methods that apply the described technique. Each of them has three overloads for different ways of defining access rules:
- SiteStructure.addReplacingEvent(…) – defines a Replacing event in the site structure;
- SiteStructure.addQueueingEvent(…) – defines a Queueing event in the site structure;
- SoftnetEndpoint.tcpListen(…) – creates a TCP listener bound to a virtual port that handles requests for establishing TCP connections;
- SoftnetEndpoint.udpListen(…) – creates a UDP listener bound to a virtual port that handles requests for establishing UDP connections;
- SoftnetEndpoint.registerProcedure(…) – registers a procedure for handling RPC requests.
Let’s see how it all looks with examples.
Example 1. The SiteStructure interface has three overloaded methods for defining a Replacing event. They differ in the way of defining access rules:
void addReplacingEvent(String eventName)
void addReplacingEvent(String eventName, GuestAccess guestAccess)
void addReplacingEvent(String eventName, String roles)
Corresponding use cases:
1) A Replacing event with no access restrictions – all users including Guest as well as stateless Guest are authorized to subscribe to the event:
siteStructure.addReplacingEvent("Current Temperature");
2) A Replacing event “Soil Moisture”. All named users and Guest are authorized, but stateless guest is denied:
siteStructure.addReplacingEvent("Soil Moisture", GuestAccess.StatelessGuestDenied);
3) A Replacing event “Current Pressure”. Here, only two user roles are authorized to subscribe to the event:
siteStructure.addReplacingEvent("Current Pressure", "Administrator; Operator");
Example 2. The ServiceEndpoint class has three overloaded methods for listening a TCP virtual port. They follow the same technique described above for defining access rules:
void tcpListen(int virtualPort, TCPOptions tcpOptions, int backlog)
void tcpListen(int virtualPort, TCPOptions tcpOptions, int backlog, GuestAccess guestAccess)
void tcpListen(int virtualPort, TCPOptions tcpOptions, int backlog, String roles)
Corresponding use cases:
1) The TCP listener accepts connection requests on virtual port 10. All users including Guest are authorized:
serviceEndpoint.tcpListen(10, null, 5);
2) The listener binds to the virtual port 11. All named membership users are authorized to the method. Guest and Stateless Guest are denied:
serviceEndpoint.tcpListen(11, null, 5, GuestAccess.GuestDenied);
3) The listener accepts connection requests on virtual port 12. Only two roles, “Administrator “ and “Operator “, are authorized:
serviceEndpoint.tcpListen(12, null, 5, "Administrator; Operator");