Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

Since the current OFBiz security implementation uses indirect security control, there is no direct connection of permission logic to the artifact that the logic is trying to control access to. Access to a particular artifact could be (and often is) controlled by a handful of different scripts. While this may appear to be an advantage (because it's flexible), it becomes a problem when something about the artifact changes that requires a change in access control. Permission scripts that control the artifact must be tracked down and updated.

Permission checking is optional. Through oversight or laziness artifacts can be left unprotected - opening up security holes or attack vectors.

The coarse grained permission logic fosters an "all or nothing" design mentality. Smaller artifacts - like menu items and data entry fields - can be controlled individually by permissions, but it requires cumbersome conditional code. Many times the developer will just give the user access to all of these smaller artifacts - regardless of whether or not the user has permission to use them.

...

An execution path could be considered a hierarchy. We can build on that structure to set up a hierarchy of security-aware artifacts:

  • OFBiz
    • Component
      • WebApp
        • ControllerRequest
          • ControllerRequestEvent
            • Service
              • Entity
                • EntityField
        • ControllerView
          • WidgetScreen
            • Service
              • Entity
                • EntityField
            • FtlFile
              • WidgetScreen
            • WidgetForm
              • WidgetFormField
    • ...

Permissions assigned at the OFBiz/component/webapp level are inherited by all artifacts below that level. Permissions assigned at lower levels replace any inherited permissions. Permission inheritance is managed by the authorization manager.

...

Handling permissions with reused artifacts is greatly simplified with the Security-Aware Artifacts design. The problems associated with the existing intermediary design plus coarse-grained hard-coded permissions are eliminated.

When a screen widget artifact is reused in another component, that artifact's identifier changes - since its execution path is different. For example, if I reuse the Example component's EditExample screen in my specialpurpose/NewApplication component (by including it in my own screen definition), the reused EditExample screen artifact identifier changes from OFBiz/framework/example/screen/EditExample to OFBiz/specialpurpose/NewApplication/screen/EditExample. Permissions assigned to the latter will not grant access to the former.

The form in the reused EditExample screen will generate an updateExample event which, in turn, invokes the updateExample service. Just like the EditExample screen, the updateExample service artifact's identifier changes - I can give the users of NewApplication permission to access OFBiz/frameworkNewApplication/example/serviceupdateExample/updateExample without giving them access to any other Example component artifacts.

...

The result of each artifact access control check will include:

  • authTypeEnumId (NotSpecified, Allow, Deny, AlwaysAllow (overrides Deny))
  • inheritSubArtifactAuth (Y, N)

Whenever an artifact is hit the authorization (access control) will be checked and the results of it will be kept in the artifactAccessStack. In order to support the inheritParentArtifactAuth field, as part of the ExecutionContext we will maintain a parentAuthorizationState variable that keeps track of the authTypeEnumId of the last artifact that had inheritParentArtifactAuth=Y. If an artifact called by the parent artifact passed but does not have inheritParentArtifactAuth=Y then the parentAuthorizationState variable will not be changed.

...

The reason for this is that depending on the parentAuthorizationState the permission still needs to be checked but the results are interpreted differently:

  • if parentAuthorizationState=NotSpecified:
    • authTypeEnumId interpreted as-is
  • if parentAuthorizationState=Allow:
    • authTypeEnumId=NotSpecified: auth passed
    • authTypeEnumId=Allow: auth passed
    • authTypeEnumId=Deny: auth failed
    • authTypeEnumId=AlwaysAllow: auth passed
  • if parentAuthorizationState=AlwaysAllow:
    • authTypeEnumId=NotSpecified: auth passed
    • authTypeEnumId=Allow: auth passed
    • authTypeEnumId=Deny: auth passed
    • authTypeEnumId=AlwaysAllow: auth passed

Note that parentAuthorizationState will never be set to "Deny" because before that would happen the auth would have failed and an error sent back up the stack.

...