• Type: Improvement
    • Status: Closed
    • Severity: High
    • Resolution: Won't Fix
    • Affects Version/s: 3.6.x (5.0.0 GA Backlog)
    • Fix Version/s: None
    • Component/s: None
    • Story Points:
    • Notice:
      When an issue is open, the "Fix Version/s" field conveys a target, not necessarily a commitment. When an issue is closed, the "Fix Version/s" field conveys the version that the issue was fixed in.


      There is commonly a need to make roles dynamic, particularly for OEMs and large enterprises. A standard scenario might be to restrict a user to only seeing certain members in a level that are specific to that user, such as geography or employee. The common approach, short of creating individual roles for each user, is to create a custom delegating role and set the role as part of the creation of the MDX connection using a custom class. There are two problems with this approach. First, it's complex to create and test these classes. Second, there is no optimization that Mondrian can apply because the typical role approach is circumvented. An alternative approach is needed that would allow these roles to be modified with minimal code and provide more standard roles to Mondrian. Note that any solution should still allow the use of a shared cache as you can currently do with roles.

      One approach might be a new MDX connection class that has properties to inject or modify a role when a connection is made. A custom class with a single method would then add a role via standard XML as if the role were defined in the schema. This would give the opportunity to provide custom roles for each user. Ideally this method would receive the set of roles being passed by the role mapper so that they could be queried for role existence and possibly replaced.

      For example (just rough concept):

      class CustomRoles {

      public void modifyRole (Connection cnx, Schema schema, List<String> roles) {
      if (!roles.contains("Authenticated"))

      { throw new ConnectionException ("Role 'Authenticated' has not been defined."); }


      { Schema.setRole("Authenticated", """ <SchemaGrant access="none"> <CubeGrant cube="Sales" access="all"> <HierarchyGrant hierarchy="geography" access="custom"> <MemberGrant access="all" member="[Geography].[Country].[pentahoSession.getAttribute('country')]/> </HierarchyGrant> </CubeGrant> </SchemaGrant> """"); }



      Deliverables, as specified by Julian below:

      1. Add a new role SPI:

      package mondrian.spi;

      interface DeclarativeRole

      { String asXml(Map<String, Object> context); }

      At the start of the session, Mondrian will call the asXml method with the current context (which would likely include "tenant-id" and maybe other properties like "department-id", "employee-id" or "user").

      If asXml returns null, and the role object implements the old Role SPI, Mondrian would fall back to that. This will allow roles too complex to be represented in XML.

      If asXml returns null and the role object does not implement the old Role SPI, Mondrian will give an error, and the session will fail to authenticate.

      It is illegal for the asXml method to return a programmatic role of any kind. Otherwise we might loop.

      The Pentaho role mapper would supply an implementation of DeclarativeRole that uses information in the role mapper to generate the XML.

      2. Add a method to add roles to an existing schema.

      In Schema:

      String createRole(String xml, NamePolicy namePolicy);

      enum NamePolicy


      The createRole method returns the name of the role, or null if it is NAMELESS. The xml may any role definition that can occur in a schema file.

      3. Forms of XML role declaration.

      There would now be 6 kinds of role declaration in XML. 5 and 6 are new. All 6 can occur in a Mondrian schema file (and they require names). createRole also accepts all 6. The asXml method can only return types 1 and 2 (or null).

      1. traditional role

      <SchemaGrant .../>

      2. Union role

      <RoleUsage name='role1'/>
      <RoleUsage name='role2'/>

      3. programmatic role that implements the old Role SPI in java:

      <Role className='com.acme.MyRole'/>

      class MyRole implements Role

      { ... }

      4. programmatic role that implements the old Role SPI in script:

      <Script language='JavaScript'>
      function getAccess(element) { return true; }
      function getAccessDetails(hierarchy) { return null; }

      5. programmatic role that implements the new DeclarativeRole SPI in java:

      <Role className='com.acme.MyDeclarativeRole'/>

      6. programmatic role that implements the new DeclarativeRole SPI in script:

      <Script language='JavaScript'>
      function asXml(xml, namePolicy) { return "<Role>something</Role>"; }

      class MyDeclarativeRole implements DeclarativeRole { ... }

      Note that each such DeclarativeRole is instantiated, its asXml method is called, then Mondrian converts that XML into a Role (actually a RoleImpl) and that is the object that will really be used for access control. So these roles are more like role factories.

      QA Requirements:

      • No impact
        Doc Requirements:
      • None for Doc Team, Mondrian team would document in the way they have traditionally done.


          Issue Links



              inaumovic Ivana Naumovic (Inactive)
              wback William Back (Inactive)
              14 Vote for this issue
              25 Start watching this issue