We recently provided a new way of controlling access to the REST API via the privileges and the ds.authentify function: Force Login. This feature offers much more than previously available authentication mechanisms and was clearly explained in this blog post.
With 4D 20 R6, Force Login has become the default mode for REST authentications. Curious about the reasons behind this change and how to manage the transition? Keep reading to find out more.
Default in new projects
When you create a project in 4D 20 R6, a roles.json file is automatically created in the Sources folder. This file includes the forceLogin attribute set to “True” and a “none“ privilege, which by default denies access to the entire REST API.
This approach ensures a high level of security by design.
You can customize permissions by editing the provided roles.json file or using the Qodly Studio for 4D Roles and Privileges editor for a more user-friendly experience.
You are now able to fine-control REST access to your data and functions!
What about existing projects?
For existing projects, a new button in the Web/Web Features tab of the Structure Settings dialog allows you to convert your project to Force Login.
By clicking this button, 4D will:
- Remove the group of users with Read/Write access to the REST API from the settings.
- Move the “On REST Authentication” database method into the system bin.
- If a “roles.json” file doesn’t already exist, create one in the Sources folder and set its forceLogin attribute to True.
Remember to restart your project after performing this conversion. If the button is not displayed, your project is already compatible with Force Login.
Moving from legacy settings
Until Force Login was introduced, you had three options for REST access control. We explain below how to mimic all of them when Force Login is enabled.
In these examples, we will use an “Administrator” privilege created in the Qodly Studio for 4D Roles and Privileges editor:
1: Server exposed as Rest without access group
The first option consisted of exposing the REST server without defining an access group or filtering the requests in the “On REST Authentication” database method.
To reproduce this behavior with Force Login, you simply need to give full access to the entire REST API:
Class extends DataStoreImplementation
exposed Function authentify() : Boolean
return Session.setPrivileges(“Administrator”)
Note that this implementation is not recommended because it lacks security. All data and functions are accessible to everyone.
2: Server exposed as Rest with access group defined
The second option was to define a group of 4D users with Read/Write access to the REST API.
To reproduce this behavior, simply check the credentials and give full access to the members of the Read/Write group that was defined in the Structure Settings dialog (the “RestAccess” group in this sample):
Class extends DataStoreImplementation
exposed Function authentify($identifier : Text; $pwd : Text) : Boolean
If ($identifier#"")
If (Validate password($identifier; $pwd)
If (User in group($identifier; "RestAccess"))
return Session.setPrivileges(“Administrator”)
End if
End if
End if
This restriction secures data access and functions against malicious connections. Each authorized connection has the same rights.
3: on rest authentication method
The third option was to check the user credentials using the “On REST Authentication” database method. This method was often used to check accesses from a custom user management system. To reproduce this behavior, you can almost copy the code of the “On REST Authentication” method into the ds.authentify() function, like in this example.
The original “On REST Authentication” method:
#DECLARE($identifier : Text; $pwd : Text) : Boolean
If ($identifier#"")
var $user : cs.UserEntity:=ds.User.query("identifier = :1"; $identifier).first()
If ($user#Null)
If (Verify password hash($pwd; $user.pwd))
return True
End if
End if
End if
The replacing “ds.authentify()” function:
Class extends DataStoreImplementation
exposed Function authentify($identifier : Text; $pwd : Text) : Boolean
If ($identifier#"")
var $user : cs.UserEntity:=ds.User.query("identifier = :1"; $identifier).first()
If ($user#Null)
If (Verify password hash($pwd; $user.pwd))
return Session.setPrivileges(“Administrator”)
End if
End if
End if
As for the previous option, each authorized connection has the same rights; data and function access need to be coded on your own.
Next Level
The power of Force Login is that you can apply the same business logic and restrictions you want to REST connections. This is particularly true for requests from Qodly Pages, Remote Datastore connections, or external REST requests.
In the following example, instead of defining the “Administrator” privilege when the user is authenticated, we simply set the privileges stored in the user entity. This allows you to give fine-grained access to the datastore, data classes, data class attributes, and functions you want and restrict all the rest!
Class extends DataStoreImplementation
exposed Function authentify($credentials : Object) : Boolean
If ($credentials#Null)
var $user : cs.UserEntity:=ds.User.query("identifier = :1"; $credentials.identifier).first()
If ($user#Null)
If (Verify password hash($credentials.pwd; $user.pwd))
return Session.setPrivileges($user.privileges)
End if
End if
End if
To conclude
Force Login provides precise control over access to your data and functions from the REST API.
It allows you to deport the access logic from the code to defined permissions, thus avoiding code oversights on access and offering a more reliable level of security. This integrated security layer is much more precise because you can define the permissions for each datastore element (datastore itself, data classes, data class attributes, functions) and give each of them rights (Create, Read, Update, Delete, etc.).
Define your privileges, and utilize the Qodly Studio for 4D Roles and Privileges editor for an enhanced experience.
Share your feedback about this feature on the 4D Forums!