Skip to content

Commit

Permalink
Ticket #687 : Support gotify
Browse files Browse the repository at this point in the history
  • Loading branch information
thabart committed Mar 6, 2024
1 parent 3d41b07 commit 8738bae
Show file tree
Hide file tree
Showing 27 changed files with 421 additions and 89 deletions.
7 changes: 7 additions & 0 deletions SimpleIdServer.IdServer.Host.sln
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.IdServer.Sql
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.IdServer.Otp", "src\IdServer\SimpleIdServer.IdServer.Otp\SimpleIdServer.IdServer.Otp.csproj", "{3655F8EA-FACF-44FD-A403-4263387F2CCB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.IdServer.Notification.Gotify", "src\IdServer\SimpleIdServer.IdServer.Notification.Gotify\SimpleIdServer.IdServer.Notification.Gotify.csproj", "{A69586FF-DD28-48C0-B227-64157D840053}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -241,6 +243,10 @@ Global
{3655F8EA-FACF-44FD-A403-4263387F2CCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3655F8EA-FACF-44FD-A403-4263387F2CCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3655F8EA-FACF-44FD-A403-4263387F2CCB}.Release|Any CPU.Build.0 = Release|Any CPU
{A69586FF-DD28-48C0-B227-64157D840053}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A69586FF-DD28-48C0-B227-64157D840053}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A69586FF-DD28-48C0-B227-64157D840053}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A69586FF-DD28-48C0-B227-64157D840053}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -286,6 +292,7 @@ Global
{A23E9D61-30A1-4331-A53C-687E705F8F52} = {E5886E09-671E-4B3E-AA8F-824C39DF94E4}
{5B787625-82D6-4A2E-8D5D-ED20B87ACBB7} = {DA65BA14-7FA4-4D99-A11D-C67F75F03771}
{3655F8EA-FACF-44FD-A403-4263387F2CCB} = {E5886E09-671E-4B3E-AA8F-824C39DF94E4}
{A69586FF-DD28-48C0-B227-64157D840053} = {E5886E09-671E-4B3E-AA8F-824C39DF94E4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1FE1E2C8-475E-4592-8609-D331B1D01730}
Expand Down
1 change: 1 addition & 0 deletions default.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ task pack -depends release, compile, buildTemplate {
exec { dotnet pack $source_dir\IdServer\SimpleIdServer.IdServer.MySQLMigrations\SimpleIdServer.IdServer.MySQLMigrations.csproj -c $config --no-build $versionSuffix --output $result_dir }
exec { dotnet pack $source_dir\IdServer\SimpleIdServer.OpenIdConnect\SimpleIdServer.OpenIdConnect.csproj -c $config --no-build $versionSuffix --output $result_dir }
exec { dotnet pack $source_dir\IdServer\SimpleIdServer.IdServer.Notification.Fcm\SimpleIdServer.IdServer.Notification.Fcm.csproj -c $config --no-build $versionSuffix --output $result_dir }
exec { dotnet pack $source_dir\IdServer\SimpleIdServer.IdServer.Notification.Gotify\SimpleIdServer.IdServer.Notification.Gotify.csproj -c $config --no-build $versionSuffix --output $result_dir }
exec { dotnet pack $source_dir\Scim\SimpleIdServer.Scim\SimpleIdServer.Scim.csproj -c $config --no-build $versionSuffix --output $result_dir }
exec { dotnet pack $source_dir\Scim\SimpleIdServer.Scim.Domains\SimpleIdServer.Scim.Domains.csproj -c $config --no-build $versionSuffix --output $result_dir }
exec { dotnet pack $source_dir\Scim\SimpleIdServer.Scim.Parser\SimpleIdServer.Scim.Parser.csproj -c $config --no-build $versionSuffix --output $result_dir }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ public class ConfigurationKeyPairValueRecord
{
public string Name { get; set; } = null!;
public string Value { get; set; } = null!;
}
}
9 changes: 9 additions & 0 deletions src/IdServer/SimpleIdServer.IdServer.Domains/GotifySession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) SimpleIdServer. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace SimpleIdServer.IdServer.Domains;

public class GotifySession
{
public string ApplicationToken { get; set; } = null!;
public string ClientToken { get; set; } = null!;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using SimpleIdServer.IdServer.Store;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
Expand All @@ -13,13 +14,16 @@ public class GotifyConnectionsController
{
private readonly IConfiguration _configuration;
private readonly Infrastructures.IHttpClientFactory _httpClientFactory;
private readonly IGotiySessionStore _gotiySessionStore;

public GotifyConnectionsController(
IConfiguration configuration,
Infrastructures.IHttpClientFactory httpClientFactory)
Infrastructures.IHttpClientFactory httpClientFactory,
IGotiySessionStore gotiySessionStore)
{
_configuration = configuration;
_httpClientFactory = httpClientFactory;
_gotiySessionStore = gotiySessionStore;
}

[HttpPost]
Expand All @@ -32,27 +36,52 @@ public async Task<IActionResult> Add(
var newUserPassword = Guid.NewGuid().ToString();
using (var httpClient = _httpClientFactory.GetHttpClient())
{
// create the user.
var options = GetOptions();
var msg = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri($"{options.BaseUrl}/user"),
Content = new StringContent(JsonSerializer.Serialize(new { admin = false, name = newUserName, pass = newUserPassword }))
Content = new StringContent(JsonSerializer.Serialize(new { admin = false, name = newUserName, pass = newUserPassword }), Encoding.UTF8, "application/json")
};
msg.Headers.Add("Authorization", $"Basic {Basic(options.AdminLogin, options.AdminPassword)}");
var httpResult = await httpClient.SendAsync(msg);
var httpResult = await httpClient.SendAsync(msg, cancellationToken);
httpResult.EnsureSuccessStatusCode();
var basic = Basic(newUserName, newUserPassword);

// create the simpleidserver application.
msg = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri($"{options.BaseUrl}/application"),
Content = new StringContent(JsonSerializer.Serialize(new { defaultPriority = 1, name = "SimpleIdServer", description = "SimpleIdServer" }), Encoding.UTF8, "application/json")
};
msg.Headers.Add("Authorization", $"Basic {basic}");
httpResult = await httpClient.SendAsync(msg, cancellationToken);
httpResult.EnsureSuccessStatusCode();
var json = await httpResult.Content.ReadAsStringAsync(cancellationToken);
var applicationToken = JsonObject.Parse(json)["token"].ToString();

// create the mobile client.
msg = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri($"{options.BaseUrl}/client"),
Content = new StringContent(JsonSerializer.Serialize(new { name = "SimpleIdServer" }))
Content = new StringContent(JsonSerializer.Serialize(new { name = "MobileClient" }), Encoding.UTF8, "application/json")
};
msg.Headers.Add("Authorization", $"Basic {Basic(newUserName, newUserPassword)}");
httpResult = await httpClient.SendAsync(msg);
msg.Headers.Add("Authorization", $"Basic {basic}");
httpResult = await httpClient.SendAsync(msg, cancellationToken);
httpResult.EnsureSuccessStatusCode();
var content = await httpResult.Content.ReadAsStringAsync();
return new OkObjectResult(JsonObject.Parse(content));
json = await httpResult.Content.ReadAsStringAsync(cancellationToken);
var jObj = JsonObject.Parse(json);
var clientToken = jObj["token"].ToString();
_gotiySessionStore.Add(new Domains.GotifySession
{
ClientToken = clientToken,
ApplicationToken = applicationToken
});
await _gotiySessionStore.SaveChanges(cancellationToken);
return new OkObjectResult(jObj);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,67 @@
using Microsoft.Extensions.Configuration;
using SimpleIdServer.IdServer.Api;
using SimpleIdServer.IdServer.Domains;
using SimpleIdServer.IdServer.Exceptions;
using SimpleIdServer.IdServer.Resources;
using SimpleIdServer.IdServer.Store;
using System.Text;
using System.Text.Json;

namespace SimpleIdServer.IdServer.Notification.Gotify;

public class GotifyUserNotificationService : IUserNotificationService
{
private readonly IConfiguration _configuration
private readonly IConfiguration _configuration;
private readonly Infrastructures.IHttpClientFactory _httpClientFactory;
private readonly IGotiySessionStore _gotifySessionStore;

public GotifyUserNotificationService(IConfiguration configuration)
public GotifyUserNotificationService(
IConfiguration configuration,
Infrastructures.IHttpClientFactory httpClientFactory,
IGotiySessionStore gotifySessionStore)
{
_configuration = configuration;
_httpClientFactory = httpClientFactory;
_gotifySessionStore = gotifySessionStore;
}

public string Name => Constants.NotificationName;

public Task Send(string title, string body, Dictionary<string, string> data, User user)
public async Task Send(string title, string body, Dictionary<string, string> data, User user)
{
throw new NotImplementedException();
if (user.Devices == null || !user.Devices.Any(d => d.PushType == Constants.NotificationName)) throw new OAuthException(ErrorCodes.UNEXPECTED_ERROR, Global.MissingRegisteredUserDevice);
var userDevice = user.Devices.First(d => d.PushType == Constants.NotificationName);
await Send(title, body, data, userDevice.PushToken);
}

public Task Send(string title, string body, Dictionary<string, string> data, string destination)
public async Task Send(string title, string body, Dictionary<string, string> data, string destination)
{
throw new NotImplementedException();
var options = GetOptions();
using (var httpClient = _httpClientFactory.GetHttpClient())
{
var obj = new
{
message = body,
title = title,
extras = data,
priority = 1
};
var requestMessage = new HttpRequestMessage
{
RequestUri = new Uri($"{options.BaseUrl}/message"),
Content = new StringContent(JsonSerializer.Serialize(obj), Encoding.UTF8, "application/json"),
Method = HttpMethod.Post
};
var session = await _gotifySessionStore.GetByClientToken(destination, CancellationToken.None);
requestMessage.Headers.Add("X-Gotify-Key", session.ApplicationToken);
var httpResult = await httpClient.SendAsync(requestMessage);
httpResult.EnsureSuccessStatusCode();
}
}

private GotifyOptions GetOptions()
{
var section = _configuration.GetSection(typeof(GotifyOptions).Name);
return section.Get<GotifyOptions>();
}
}
5 changes: 5 additions & 0 deletions src/IdServer/SimpleIdServer.IdServer.Startup/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using SimpleIdServer.IdServer.Domains;
using SimpleIdServer.IdServer.Email;
using SimpleIdServer.IdServer.Fido;
using SimpleIdServer.IdServer.Notification.Gotify;
using SimpleIdServer.IdServer.Provisioning.LDAP;
using SimpleIdServer.IdServer.Provisioning.SCIM;
using SimpleIdServer.IdServer.Pwd;
Expand Down Expand Up @@ -115,6 +116,7 @@
.UseWsFederation()
.UseFIDO()
.UseSamlIdp()
.UseGotifyNotification()
.UseAutomaticConfiguration();

app.Run();
Expand Down Expand Up @@ -145,6 +147,7 @@ void ConfigureIdServer(IServiceCollection services)
.AddOtpAuthentication()
.AddSmsAuthentication()
.AddFcmNotification()
.AddGotifyNotification()
.AddSamlIdp()
.AddFidoAuthentication(f =>
{
Expand Down Expand Up @@ -185,6 +188,7 @@ void ConfigureCentralizedConfiguration(WebApplicationBuilder builder)
o.Add<IdServerPasswordOptions>();
o.Add<FidoOptions>();
o.Add<IdServerConsoleOptions>();
o.Add<GotifyOptions>();
o.Add<SimpleIdServer.IdServer.Notification.Fcm.FcmOptions>();
if (conf.Type == DistributedCacheTypes.REDIS)
{
Expand Down Expand Up @@ -423,6 +427,7 @@ void SeedData(WebApplication application, string scimBaseUrl)
AddMissingConfigurationDefinition<IdServerPasswordOptions>(dbContext);
AddMissingConfigurationDefinition<FidoOptions>(dbContext);
AddMissingConfigurationDefinition<IdServerConsoleOptions>(dbContext);
AddMissingConfigurationDefinition<GotifyOptions>(dbContext);
AddMissingConfigurationDefinition<SimpleIdServer.IdServer.Notification.Fcm.FcmOptions>(dbContext);
AddMissingConfigurationDefinition<GoogleOptionsLite>(dbContext);
AddMissingConfigurationDefinition<NegotiateOptionsLite>(dbContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<ProjectReference Include="..\SimpleIdServer.IdServer.Fido\SimpleIdServer.IdServer.Fido.csproj" />
<ProjectReference Include="..\SimpleIdServer.IdServer.MySQLMigrations\SimpleIdServer.IdServer.MySQLMigrations.csproj" />
<ProjectReference Include="..\SimpleIdServer.IdServer.Notification.Fcm\SimpleIdServer.IdServer.Notification.Fcm.csproj" />
<ProjectReference Include="..\SimpleIdServer.IdServer.Notification.Gotify\SimpleIdServer.IdServer.Notification.Gotify.csproj" />
<ProjectReference Include="..\SimpleIdServer.IdServer.Otp\SimpleIdServer.IdServer.Otp.csproj" />
<ProjectReference Include="..\SimpleIdServer.IdServer.PostgreMigrations\SimpleIdServer.IdServer.PostgreMigrations.csproj" />
<ProjectReference Include="..\SimpleIdServer.IdServer.Provisioning.LDAP\SimpleIdServer.IdServer.Provisioning.LDAP.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,10 @@
},
"FcmOptions": {
"ServiceAccountFilePath": ""
},
"GotifyOptions": {
"BaseUrl": "https://gotify.simpleidserver.com",
"AdminLogin": "admin",
"AdminPassword": "admin"
}
}
9 changes: 7 additions & 2 deletions src/IdServer/SimpleIdServer.IdServer.Startup/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
"SCIMBaseUrl": "https://localhost:5003",
"Authority": "https://localhost:5001",
"DistributedCacheConfiguration": {
"Type": "SQLSERVER",
"Type": "INMEMORY",
"ConnectionString": "Server=.;Database=IdServerSecond;Trusted_Connection=True;TrustServerCertificate=true",
"InstanceName": ""
},
"StorageConfiguration": {
"Type": "SQLSERVER",
"Type": "INMEMORY",
"ConnectionString": "Server=.;Database=IdServerSecond;Trusted_Connection=True;TrustServerCertificate=true"
},
"Facebook": {
Expand Down Expand Up @@ -101,5 +101,10 @@
},
"FcmOptions": {
"ServiceAccountFilePath": ""
},
"GotifyOptions": {
"BaseUrl": "https://gotify.simpleidserver.com",
"AdminLogin": "admin",
"AdminPassword": "admin"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) SimpleIdServer. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using SimpleIdServer.IdServer.Domains;

namespace SimpleIdServer.IdServer.Store.Configurations;

public class GotifySessionConfiguration : IEntityTypeConfiguration<GotifySession>
{
public void Configure(EntityTypeBuilder<GotifySession> builder)
{
builder.HasKey(g => g.ApplicationToken);
}
}
33 changes: 33 additions & 0 deletions src/IdServer/SimpleIdServer.IdServer.Store/GotifySessionStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) SimpleIdServer. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using SimpleIdServer.IdServer.Domains;

namespace SimpleIdServer.IdServer.Store;

public interface IGotiySessionStore
{
void Add(GotifySession session);
Task<GotifySession> GetByClientToken(string clientToken, CancellationToken cancellationToken);
Task<int> SaveChanges(CancellationToken cancellationToken);
}

public class GotiySessionStore : IGotiySessionStore
{
private readonly StoreDbContext _dbContext;

public GotiySessionStore(StoreDbContext dbContext)
{
_dbContext = dbContext;
}

public void Add(GotifySession session)
=> _dbContext.GotifySessions.Add(session);

public Task<GotifySession> GetByClientToken(string clientToken, CancellationToken cancellationToken)
=> _dbContext.GotifySessions.SingleOrDefaultAsync(c => c.ClientToken == clientToken, cancellationToken);

public Task<int> SaveChanges(CancellationToken cancellationToken)
=> _dbContext.SaveChangesAsync(cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ private static void RegisterDepedencies(IServiceCollection services)
services.AddTransient<IRegistrationWorkflowRepository, RegistrationWorkflowRepository>();
services.AddTransient<ILanguageRepository, LanguageRepository>();
services.AddTransient<IProvisioningStagingStore, ProvisioningStagingStore>();
services.AddTransient<IGotiySessionStore, GotiySessionStore>();
}
}
}
2 changes: 2 additions & 0 deletions src/IdServer/SimpleIdServer.IdServer.Store/StoreDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public StoreDbContext(DbContextOptions<StoreDbContext> options) : base(options)
public DbSet<Language> Languages { get; set; }
public DbSet<GroupRealm> GroupRealm { get; set; }
public DbSet<GroupUser> GroupUser { get; set; }
public DbSet<GotifySession> GotifySessions { get; set; }

protected override void OnModelCreating(ModelBuilder builder)
{
Expand Down Expand Up @@ -101,6 +102,7 @@ protected override void OnModelCreating(ModelBuilder builder)
builder.ApplyConfiguration(new ExtractedRepresentationStagingConfiguration());
builder.ApplyConfiguration(new GroupRealmConfiguration());
builder.ApplyConfiguration(new GroupUserConfiguration());
builder.ApplyConfiguration(new GotifySessionConfiguration());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@
return result + "/MachineClient.png";
case "otp":
return result + "/OTP.png";
case "gotify":
return result + "/gotify.png";
default:
return result + "/pwd.png";
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 8738bae

Please sign in to comment.