Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Not all artifact reuse will be this simple. But the more complicated scenarios can be accommodated by finding ways to "graft" the reused artifact into the new component's artifact hierarchy - which will provide a means to assign permissions to the reused artifact.

Proposed Implementation Details

Existing Entities to Use:

UserLogin
UserLoginSecurityGroup
SecurityGroup

New Entities to Add:

SecurityArtifactAuth
-securityArtifactAuthId*
-securityGroupId
-securityArtifactGroupId
-authTypeEnumId (NotSpecified, Allow, Deny, AlwaysAllow (overrides Deny))
-authorizedActionEnumId (View, Create, Updated, Delete, All)
-recordViewEntityName
-recordFilterByDateEnumId (True, False, ByName)
-userMatchFieldName - for record level matching will lookup in recordViewEntityName view-entity for the currently logged in userLoginId or partyId, and if this field is set it will use this field name to match against, otherwise it will look for the userLoginId field or the partyId field in the view-entity
-authServiceName - this service will be called according to the pattern of current auth services and must return true/approved in addition to anything else passing that is populated in this entity

SecurityArtifactAuthConstraint
-securityArtifactAuthId*
-securityArtifactAuthConstraintSeqId*
-fieldName
-operatorEnumId (less-than, greater-than, etc)
-value (use ${} to expand from variable in artifact's context)

SecurityArtifactGroup
-securityArtifactGroupId*

SecurityArtifactGroupMember
-securityArtifactGroupId*
-artifactName* (can be securityArtifactGroupId; includes location#name when applicable)
-artifactTypeEnumId (Component, WebApp, ControllerRequest, ControllerRequestEvent, ControllerView, WidgetScreen, WidgetForm, WidgetFormField, FtlFile, Service, Entity, EntityField, ...)
-inheritParentArtifactAuth (Y, N) - defaults to Y; if Y then the user will have authorization for anything called by the artifact; if N user will need to have authorization for anything else called by the artifact

NOTE: we may want to move some fields between SecurityArtifactAuth and SecurityArtifactGroupMember as some things could go in either place, but should only go into one and which one they make sense in is a good question (and I've taken a pass here, but we may want to change it)

Possible Entities to Add:

-Could use these to make view-entity configurations on the fly (this may be WAY too technical for most users, so considering this a pretty low priority)

DynamicViewEntity
dynamicViewEntityId*

DynamicViewEntityMember
dynamicViewEntityId*
entityAlias*
entityName

DynamicViewEntityAlias
dynamicViewEntityId*
entityAlias*
fieldAlias*
fieldName
functionEnumId

DynamicViewEntityJoin
entityAlias
relEntityAlias
keyName
relKeyName
relOptional

Order of Artifact Checking - For WebApp Request

An ExecutionContext object is maintained that has an artifactAccessStack. In the artifactAccessStack as each artifact calls/users another artifact it is pushed onto the stack, and when it finished it pops itself off the stack. With this at any point we can see which artifacts were used to get to where we are. For the higher-level webapp-specific artifacts this will be kept in the request, for the widgets this will be kept in their context, for services it will be in the context, and for entities it will be in a thread-local variable. This is called an ExecutionContext because it may be used for more than just security/authorization purposes, and in fact we should refactor the current code that keeps track of the user and other things in ThreadLocal variables (mostly for the entity engine) so that they are in this ExecutionContext object.

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.

Example Chain:

Component
WebApp
ControllerRequest

  • ControllerRequestEvent
    • Service
      • Entity
        • EntityField
          ControllerView
  • WidgetScreen
    • Service
      • Entity
        • EntityField
    • FtlFile
      • WidgetScreen
    • WidgetForm
      • WidgetFormField