Skip to content

Authorization Design Core

Allan Kerr edited this page Apr 6, 2018 · 10 revisions

Application and Database Design

The authorization and identity service is designed as a CRUD application. This design requires HTTP endpoints and a database for persistence. To facilitate this, a core package was developed to abstract over basic HTTP and database functionality.

App UML

The first major component of the design is the app which is used to create a new CRUD application. The app maintains references to the two items required for a CRUD application: an HTTP router and a data store.

Router

Gorilla Mux is used as the underlying HTTP router. To reduce coupling, the router is not designed to be directly accessible. The following operations are offered to interact with the router:

  • AddEndpoint. Adds a new HTTP path for the router to listen on.
  • Start. Starts listening for requests on the HTTP endpoints and serving responses.

Data Store

The app is not responsible for creating its own data store. Instead, the data store is passed in as a dependency to increase testability and provide support for different underlying databases.

Readiness

Initializing a CRUD application may take a long time due to waiting for the data store to start, connecting to the data store and creating the data store schema. This was accounted for by adding an HTTP readiness endpoint. The application is automatically configured to respond at /monitor/readiness when finished starting. This design allows for external services to probe the application to detect when the application is ready for handling requests.

Data Store UML

The second major component is the data store. The data store is designed as interface to allow CRUD applications to be created with different databases ranging from in-memory data stores to Cassandra or PostgreSQL databases.

Data stores must implement:

  • CreateTable. Create a single table in the data store.
  • CreateSchema. Create a new schema in the data store.
  • GetSession. Get the underlying database session to perform CRUD operations.
  • Close. Close the database session when finished.

A session interface to provide additional abstraction over the underlying database may be added in the future to increase evolvability.

Only a single concrete implementation of the data store interface was designed. This was designed to provide a data store interface for interacting with a Cassandra database. Cassandra was used because the set of queries used by the authorization and identity service can be accomplished without the use of joins. Therefore, designing the datastore to use Cassandra allows for it to scale easily by sharding user accounts and tokens across many nodes.

Creation

Creating a new CQL data store requires connecting to the database's host. Because Cassandra instances take substantially longer to startup than a simple CRUD application, the Cassandra host may not be up when attempting to create a new data store. To account for this in the design, a retry constructor is used that polls the database on a consistent interval until the database connection can succeed. The design does not use a random exponential or linear backoff because a failure to connect is a result of the database not being up rather than interference.

Keyspace

All Cassandra operations must be performed inside a keyspace. Because of this, the CQL data store is designed to maintain a session within a keyspace rather than a reference to the cluster. When a new CQL data store is created, the specified keyspace is automatically created if it does not exist.

Schemas

Cassandra schema operations like creating new tables, keyspaces, or indexes often take longer than CRUD operations performed on data. To account for this, the CQL data store was designed to use a separate session for schema operations. When performing schema operations, a session with a longer timeout is created to ensure the operations are given sufficient time to complete.

Schema UML

Although some data stores may be schema-less, a database schema interface was designed to support databases that require schemas. The design uses an interface because the implementation of the schema may differ depending on the underlying database for which it is used. Schemas are not responsible for validating the objects they provide to the data store. Instead, validation is delegated to the data store to allow the underlying database to perform validation when attempting to create the schema object.

Data store schemas must implement:

  • GetObjects. Returns a list of strings with each string containing the definition for a single schema object whether it be a table, index, user or keyspace.

To support the CQL data store, a corresponding CQL schema was designed. This schema is designed based on defining schema objects in .cql files.

Creation

To create a new schema, a directory is provided. The provided directory is searched for CQL files containing schema objects which are stored in the objects array to satisfy the interface requirements.

Although schema validation is performed by the data store, the CQL schema is designed to only accept schema files that contain a single object definition. More than one object definition in a single file will result in an error. For CQL schemas, a single object is defined as a single table, keyspace, index or query.

Clone this wiki locally