Versions Compared

Key

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

...

Table of Contents
maxLevel2

Epic: Capture ownership of newly created resources

This epic covers all the stories needed to capture resource ownership on each resource stored in the Ed-Fi ODS by the API. It can be implemented independently from the use of this information to perform ownership-based authorization of API requests.

Story: Create EF migrations in EdFi_Admin to enable storage of ownership-based claims information

As an API host I want to manage ownership tokens for API clients so that I can authorize access to Ed-Fi ODS API resources based on ownership.

Description

The schema of the EdFi_Admin database must be updated to support the creation of ownership tokens, the association of a single (stable) token to an API client, and the assignment of one or more ownership tokens to an API client.

The current state of the EdFi_Admin is such that certain changes will likely fail due to previous migration(s) having renamed some columns, but having failed to rename certain artifacts (such as FK constraints or indices using the columns). These affected artifacts have retained their original names which are derived from the previous column names, but the new migrations will fail to delete them correctly. This work to modify the model to reflect actual usage, and proper data constraints is probably actually going to be the trickiest work of the entire feature.

Tasks

  • Create EF migration in EdFi_Admin (in the Migrations subfolder of the EdFi.Ods.Admin.Models project) to support storing information needed for the ownership-based security model:
    • Create an OwnershipToken entity/table with .
      • Add an OwnershipTokenId (short/smallint) property as the primary key, and .
      • Add a Description (string/nvarchar with maxlength a maximum length of 50) property to hold a descriptive name worthy of display in a management UI.
    • Modify the ApiClient entity/table, as follows:
      • Add optional OwnershipTokenId an optional CreatorOwnershipTokenId property (short/smallint) as a foreign key reference to the ApiClient OwnershipToken entity/table.
    • Create the an ApiClientOwnershipToken entity/table with ApiClientOwnershipTokenId .
      • Add an ApiClientOwnershipTokenId (int IDENTITY) , with foreign key references to property/column as the primary key.
      • Add OwnershipTokenId (short/smallint) and ApiClientId (int) properties as foreign key references to their respective tables.
      • Create a unique constraint/index on ApiClientId and OwnershipTokenId properties/columns.

Story: Make ownership-based authorization claims available to the Ed-Fi ODS API

As an API developer, I want to access the ownership-based claims so that I can perform appropriate authorization.

Description

In order to make the claims available to the API authorization logic, data must flow from the EdFi_Admin

...

database to the API through the AccessTokenIsValid stored procedure, into the ApiClientDetails class, and finally into the ApiKeyContext. Primarily, this story involves the enhancement of existing artifacts to carry this additional information through to the ApiKeyContext so that it is available for authorization decisions.

Tasks

  • Create EF migration in EdFi_Admin (in the Migrations subfolder of the EdFi.Ods.Admin.Models project) to enhance the AccessTokenIsValid stored procedure to support return ownership-based claims information.
    • Stored procedure must be modified to also return:
      • the OwnershipTokenId CreatorOwnershipTokenId associated with the API client (for "stamping" newly created resources)
      • Stored procedure must also return the collection of the API client's current OwnershipTokens (for authorizing access to existing resources)
    • Updated stored procedure SQL must be added as a .sql file as an Embedded Resource in the Sql subfolder. The up/down migrations will then use a helper function to execute these files. Review any of the existing migrations that modify this stored procedure as a precedence for implementation.
  • Enhance OAuthTokenValidator class to populate the ApiClientDetails with the new ownership-based claims into the ApiClientDetails class
    • Add OwnershipTokenId to the ApiClientDetails class and populate.
    • Add OwnershipTokens collection to the ApiClientDetails class, and populate from stored procedure results.
  • Add ODS support for capturing resource ownership
    • Create a script for adding boilerplate ownership column to each aggregate root table
    • TODO: MetaEd feature toggle ala "Change Queries"
  • Initialize owner upon entity creation
  • Define an IHasOwner interface exposing a single property CreatedByOwnershipTokenId
  • Create an ICreateEntity decorator from the stored procedure results:
    • CreatorOwnershipTokenId   (short)
    • OwnershipTokenIds (List<short>)
  • Enhance the OAuthAuthenticationProvider's Authenticate method to copy the CreatorOwnershipTokenId and OwnershipTokenIds from the ApiClientDetails to new corresponding properties on the ApiKeyContext.

Story: Add CreatedByOwnershipTokenId columns to all aggregate root tables

As an API developer I want to have a column in each aggregate root table in the ODS database for storing the creator's ownership token so that I have a basis for performing ownership-based authorization on subsequent requests.

Description

Each aggregate root table in the ODS will need a new CreatedByOwnershipTokenId column (smallint) added. Suggestion for initial implementation is to run the following query in SQL Server Management Studio:

Code Block
languagesql
select 'ALTER TABLE ' + c.TABLE_SCHEMA +'.' + c.TABLE_NAME + ' ADD CreatedByOwnershipTokenId smallint NOT NULL;'
from INFORMATION_SCHEMA.COLUMNS c
where c.COLUMN_NAME = 'Id'
	and c.TABLE_SCHEMA NOT IN ('dbo', 'auth', 'interop')
order by c.TABLE_SCHEMA, c.TABLE_NAME

Copy the result from the grid into a new text file and incorporate into the database script execution appropriately.

NOTE: In the future, this will be produced by a MetaEd plugin similar to how Change Queries is handled.

Story: Identify and capture resource ownership during entity creation

As an API host, I want to be able to turn on the "Ownership-Based Authorization" functionality as an optional feature of the API so that I can capture ownership of new resources and perform subsequent ownership-based authorizations.

Description

This story adds all the components actually needed in order to identify the owner (from the current API client), assign the ownership token id to the corresponding aggregate root entity, and map the property to the ODS table.

Optional features in the Ed-Fi ODS API are now developed as "Features". All new classes described in the tasks below should be added to a new project named EdFi.Ods.Features.OwnershipBasedAuthorization. Review the recently added EdFi.Ods.ChangeQueries for a basis for code organization with the project.

Tasks

  • Add a new CreatedByOwnershipTokenId property (short) to the AggregateRootWithCompositeKey class.
  • Add a new IHasCreator interface (containing just the CreatedByOwnershipTokenId property) in the EdFi.Ods.Common project (alongside IHasIdentifier)
  • Add a generic constraint (of IHasCreator) on the TEntity generic types defined on the ICreateEntity, CreateEntity and CreateEntityAuthorizationDecorator interfaces and implementations.
  • Provide an INHibernateBeforeBindMappingActivity implementation (OwnershipBasedAuthorizationNHibernateConfigurationActivity)  that adds the necessary run-time ORM mapping of the CreatedByOwnershipTokenId property in all aggregate roots. Use the ChangeQueryMappingNHibernateConfigurationActivity as a reference implementation.
  • Create an ICreateEntity decorator (OwnershipInitializationCreateEntityDecorator, with a generic constraint of IHasCreator on the generic type argument TEntity) to assign the CreatedByOwnershipTokenId upon entity creation.
    • Cast the entity to IHasOwner and assign the ownership token value from the API key context (OwnershipTokenId) before creation.
    • Modify generated assets to conditionally support ownership
      • Modify generated entities - Check the feature toggle and add an implementation of the IHasOwner interface on to the aggregate root entities
      • Modify ORM mappings - Check the feature toggle and add a mapping for the CreatedByOwnershipTokenId property/column.
      • NOTE: No need to modify the entity mappers.
    Phase 2 - Authorize Access Based on Ownership
    • Inject the IApiKeyContextProvider into the decorator (along with the decorated ICreateEntity instance). (NOTE: Following this pattern and registering the decorator first will result in Castle Windsor automatically injecting the decorated instance into the decorator.)
    • Assign the CreatedByOwnershipTokenId property from the current API key context (CreatorOwnershipTokenId property) before calling decorated instance's Create method.
  • Implement API Feature for Ownership-Based Authorizations
    • Create a OwnershipBasedAuthorizationInstaller class (using ChangeQueriesInstaller as a referenced) to register all new components with the Castle Windsor container.
    • Create a OwnershipBasedAuthorizationFeature class (using ChangeQueriesFeature as a reference implementation) to allow for configuration-based activation of the feature and invoke the installer.
    • Add an instance of the OwnershipBasedAuthorizationFeature instance to the feature list built in the constructor of the FeatureProvider class (in EdFi.Ods.Api.Startup).