Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ The documentation uses [MkDocs](https://www.mkdocs.org/) and [Material for
MkDocs](https://squidfunk.github.io/mkdocs-material/). This documentation is both provided on readthedocs and built
in to the application itself.

The application reads the configuration on start up and then populates an in-memory database with users and OpenID
connect clients. Additionally, users and clients can be created at runtime through the web interface at `/users` and
`/clients` respectively. Note that there is no persistence between application restarts, as the in-memory database is
wiped and a new one is used - any users or clients created at runtime will be lost upon restart.
The application reads the configuration on start up and then populates the database with users and OpenID connect
clients. By default, an in-memory database is used and all data is lost on restart — any users or clients created at
runtime through the web interface will not survive a restart. Optionally, a SQLite database file can be configured to
persist data between restarts; see the [Database configuration](DevOidcToolkit.Documentation/docs/configuration.md)
for details.

The frontend is styled using basic styling, using the [Sakura CSS library](https://github.com/oxalorg/sakura).

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
- Add optional SQLite persistence via `Database.SqliteFile` config option; defaults to in-memory when not set (see [#20](https://github.com/BusinessSimulations/dev-oidc-toolkit/issues/20))
## [0.5.0]
- Add configurable user roles through `DevOidcToolkit__Users__INDEX__Roles__INDEX` (see [#17](https://github.com/BusinessSimulations/dev-oidc-toolkit/pull/17))
- Add runtime user registration at `/users` page (see [#15](https://github.com/BusinessSimulations/dev-oidc-toolkit/issues/15))
Expand Down
76 changes: 76 additions & 0 deletions DevOidcToolkit.Documentation/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ This is a list of all of the environment variables that can be used to configure
<td>https://fake-issuer.example.com</td>
<td>None (derived from request URL)</td>
</tr>
<tr>
<td>DevOidcToolkit__Database__SqliteFile</td>
<td>The path to the SQLite database file. When set, data is persisted to this file and survives restarts. When not set, an in-memory database is used and all data is lost on restart.</td>
<td>/data/dev-oidc-toolkit.db</td>
<td>None (in-memory)</td>
</tr>
<tr>
<td>DevOidcToolkit__Logging__MinimumLevel</td>
<td>The minimum log level, possible values are Trace, Debug, Information, Warning, Error, Critical.</td>
Expand Down Expand Up @@ -204,6 +210,13 @@ details](#example-json-configuration)).
<td>https://fake-issuer.example.com</td>
<td>None</td>
</tr>
<tr>
<td>Database</td>
<td>object</td>
<td>The database configuration, see <a href="#database">Database</a> for more information.</td>
<td>See <a href="#database">Database</a> for more information.</td>
<td>None (in-memory)</td>
</tr>
<tr>
<td>Https</td>
<td>object</td>
Expand Down Expand Up @@ -352,6 +365,38 @@ details](#example-json-configuration)).
</tbody>
</table>

#### Database

The database configuration controls how data is stored. By default, an in-memory database is used and all data
(including users and clients created at runtime) is lost when the application stops. Set `SqliteFile` to a file path to
use a SQLite database instead, which persists data between restarts.

!!! note "Limitations"
The SQLite database schema is created automatically on first run using `EnsureCreated`. There are no migrations
supported — if the schema changes in a future version of dev-oidc-toolkit you may need to delete and recreate the
database file.

<table>
<thead>
<tr>
<th>Property</th>
<th>Type</th>
<th>Description</th>
<th>Example</th>
<th>Default Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>SqliteFile</td>
<td>string</td>
<td>Path to the SQLite database file. When set, all data is persisted to this file. When omitted, an in-memory database is used and data is lost on restart.</td>
<td>/data/dev-oidc-toolkit.db</td>
<td>None (in-memory)</td>
</tr>
</tbody>
</table>

#### Users

<table>
Expand Down Expand Up @@ -435,6 +480,8 @@ details](#example-json-configuration)).

### Example JSON configuration

In-memory database (default, no persistence):

```json
{
"DevOidcToolkit": {
Expand All @@ -459,3 +506,32 @@ details](#example-json-configuration)).
}
}
```

SQLite database (data persists across restarts):

```json
{
"DevOidcToolkit": {
"Port": 8080,
"Database": {
"SqliteFile": "/data/dev-oidc-toolkit.db"
},
"Users": [
{
"Email": "sudo@localhost",
"FirstName": "Test",
"LastName": "User"
}
],
"Clients": [
{
"Id": "test",
"Secret": "ThisIsNotARealSecret",
"RedirectUris": [
"http://localhost:3000/callback"
]
}
]
}
}
```
2 changes: 1 addition & 1 deletion DevOidcToolkit.Documentation/docs/runtime-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ URIs are validated on submission to ensure they are properly formatted.

## Important Notes

- **No Persistence**: Users and clients created at runtime exist only in the in-memory database. They will be lost when the application restarts.
- **Persistence**: By default, users and clients created at runtime exist only in the in-memory database and will be lost when the application restarts. To persist runtime changes, configure a [SQLite database](configuration.md#database).
- **Configuration + Runtime**: You can use both configuration-based users/clients and runtime-created ones simultaneously.
- **Role Management**: Roles created at runtime persist for the lifetime of the application and can be assigned to multiple users.
1 change: 1 addition & 0 deletions DevOidcToolkit/DevOidcToolkit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
Expand Down
6 changes: 6 additions & 0 deletions DevOidcToolkit/Infrastructure/Configuration/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class DevOidcToolkitConfiguration

[ValidateObjectMembers] public HttpsConfiguration? Https { get; set; }
[ValidateObjectMembers] public LoggingConfiguration Logging { get; set; } = new LoggingConfiguration();
[ValidateObjectMembers] public DatabaseConfiguration Database { get; set; } = new DatabaseConfiguration();
}

public class UserConfiguration
Expand Down Expand Up @@ -89,4 +90,9 @@ public class LoggingConfiguration
{
public LogEventLevel MinimumLevel { get; set; } = LogEventLevel.Information;
public bool UseXForwardedForHeader { get; set; } = false;
}

public class DatabaseConfiguration
{
public string? SqliteFile { get; set; }
}
30 changes: 29 additions & 1 deletion DevOidcToolkit/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using DevOidcToolkit.Infrastructure.Database;

using Microsoft.AspNetCore.Identity;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;

Expand All @@ -30,7 +31,18 @@

builder.Services.AddDbContext<DevOidcToolkitContext>(options =>
{
options.UseInMemoryDatabase("dev-auth");
if (config.Database.SqliteFile is not null)
{
var connectionString = new SqliteConnectionStringBuilder
{
DataSource = config.Database.SqliteFile
}.ToString();
options.UseSqlite(connectionString);
}
else
{
options.UseInMemoryDatabase("dev-auth");
}
options.UseOpenIddict();
});

Expand Down Expand Up @@ -179,12 +191,23 @@
var services = scope.ServiceProvider;
var db = services.GetRequiredService<DevOidcToolkitContext>();

if (config.Database.SqliteFile is not null)
{
db.Database.EnsureCreated();
}

// Set up users and clients in the DB
var userManager = services.GetRequiredService<UserManager<DevOidcToolkitUser>>();
var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
for (var i = 0; i < config.Users.Count; i++)
{
var user = config.Users[i];

if (await userManager.FindByEmailAsync(user.Email) is not null)
{
continue;
}

var userEntity = new DevOidcToolkitUser()
{
Id = i.ToString(),
Expand Down Expand Up @@ -215,6 +238,11 @@
var openIddictManager = scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();
foreach (var client in config.Clients)
{
if (await openIddictManager.FindByClientIdAsync(client.Id) is not null)
{
continue;
}

var clientApp = new OpenIddictApplicationDescriptor()
{
ClientId = client.Id,
Expand Down