Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Scout/HowTo/3.8/Use permissions in your Scout application"

< Scout‎ | HowTo‎ | 3.8
(Fine-grained access control)
(Removing all content from page)
 
Line 1: Line 1:
{{ScoutPage|cat=HowTo 3.8}}
 
  
{{Note|TODO|Check and Merge of [[Scout/HowTo/Create Permissions]]. Possibility: This How-to is more "how can I store and load the permission", the other How To is more on "how should I handle Permissions". This separation makes maybe no sense.}}
 
 
==How to use permissions in your Scout application==
 
===1. Create AccessControlService to load your permissions===
 
First of all, create a custom access control service which inherits from <code>AbstractAccessControlService</code>. This is typically created by Scout SDK itself. Furthermore, this service has to be registered in plugin.xml similar to:
 
<source lang="xml">
 
  <service
 
    class="x.y.server.services.custom.security.AccessControlService"
 
    factory="org.eclipse.scout.rt.server.services.ServerServiceFactory"
 
    session="x.y.server.ServerSession"
 
  />
 
</source>
 
 
===2. Load permissions from database===
 
Add some logic for the {{ScoutEvent|LoadPermissions}} event of your <code>AccessControlService</code> (by overwriting the <code>execLoadPermissions</code> method): there you load all the permissions that belong to the user of the given context.
 
 
Let us say you have a role based security concept with the 2 database tables '''USER_ROLE''' AND '''ROLE_PERMISSION'''. In the table '''USER_ROLE''', there you link the user to several roles whereas the table '''ROLE_PERMISSION''' holds all the permissions that belong to those roles.
 
 
{{Note|TODO|Add an ER Diagram}}
 
 
By running the following SQL statement, you get all the permission that belong to the given user:
 
<source lang="java">
 
Object[][] permissionData = SQL.select("" +
 
  "SELECT    P.PERMISSION_NAME, " +
 
  "          P.PERMISSION_LEVEL " +
 
  "FROM      USER_ROLE R " +
 
  "LEFT JOIN ROLE_PERMISSION P " +
 
  "          ON P.ROLE_ID = R.ROLE_ID " +
 
  "WHERE    R.USER_ID = :userId");
 
</source>
 
 
In turn, you call <code>AccessControlUtility.createPermissions(permissionData)</code> to create the associated Java permissions.
 
 
Last but not least, you add the permission <code>RemoteServiceAccessPermission</code> to the collection of permissions to allow the user to call backend services. The two arguments allow you to constrain the kind of services this user is allowed to call. You can use the wilcard character <code>*</code> to specify a matching pattern.
 
 
All in all, your <code>AccessControlService</code> looks as follows:
 
 
<source lang="java">
 
public class AccessControlService extends AbstractAccessControlService {
 
 
  @Override
 
  protected Permissions execLoadPermissions() {
 
    Object[][] permissionData = SQL.select("" +
 
      "SELECT    P.PERMISSION_NAME, " +
 
      "          P.PERMISSION_LEVEL " +
 
      "FROM      USER_ROLE R " +
 
      "LEFT JOIN ROLE_PERMISSION P " +
 
      "          ON P.ROLE_ID = R.ROLE_ID " +
 
      "WHERE    R.USER_ID = :userId");
 
     
 
    Permissions p = AccessControlUtility.createPermissions(permissionData);
 
    p.add(new RemoteServiceAccessPermission("*.shared.*", "*"));
 
    return p;
 
  }
 
}
 
</source>
 
 
Please note: There exists the permission '''AllPermission''' which implies all other permission. For full-access, please add this permission to the collection.
 
 
===3. Create java.security.Permission representatives===
 
All the permissions you like to have available in your application must be represented by a 'java.security.Permission' permission. Let us assume you require a permission to allow a user to access companies. Thereto, you create the permission class <code>ReadCompanyPermission</code> in the package <code>x.y.shared.security</code>:
 
 
<source lang="java">
 
public class ReadCompanyPermission extends BasicPermission {
 
 
 
  public ReadCompanyPermission() {
 
    super("ReadCompany");
 
  }
 
}
 
</source>
 
 
The name you provide in the constructor is the name of the permission. Among other things, its is used to decide whether to grant access to a specific resource. For more detail, please refer to <code>BasicPermission#implies(Permission p)</code> which is evaluated in <code>IAccessControlService#checkPermission(Permission p)</code>.
 
 
===4. Populate database tables ROLE_PERMISSION AND USER_ROLE===
 
Put an entry into the table '''ROLE_PERMISSION''' to represent this permission. Also, create a role entry to associate this permission with a role the user belongs to. Please note, that in the example above, the '''PERMISSION_NAME''' would be <code>x.y.shared.security.ReadCompanyPermission</code>. The level is not of interest for this kind of permission, so simply put <code>PERMISSION_LEVEL=100</code>. More on the topic 'level' will follow further down.
 
 
===5. Protect resources===
 
Finally, you're done. In your business logic, you now can check for that permission. This is done as follows:
 
 
<source lang="java">
 
if (!ACCESS.check(new ReadCompanyPermission())) {
 
  throw new VetoException("Authorization failed");
 
} else {
 
  // user is authorized, do some business logic here
 
}
 
</source>
 
 
Please note, that the class <code>ACCESS</code> is simply a delegate to <code>IAccessControlService</code>.
 
 
In the following, please find some more information about the topic.
 
 
==How permissions are discovered==
 
 
Permission are discovered by IPermissionService. The default implementation looks for permission classes in all bundles installed in the OSGi environemnt. Thereby, the following criteria must be satisfied:
 
* The class must be of the type '''java.security.Permission'''
 
* The type must be a public concrete class, meaning not an interface nor an abstract class
 
* Class must have the token '''Permission''' in its name
 
* The class must be located in a package with '''.security.''' in its package path
 
 
Please note: This behavior can be overwritten by writing an own implementation for <code>IPermissionService</code>.
 

Latest revision as of 08:43, 7 May 2012

Back to the top