From 0b10747bd2480c9b8edd6762353dc953e9f1ecbf Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 17 Mar 2026 03:43:11 -0400 Subject: [PATCH] Fix Central launch profile: auth middleware, cookie auth, antiforgery, static files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add UseAuthentication/UseAuthorization/UseAntiforgery/UseStaticFiles middleware - Register ASP.NET Core cookie authentication scheme in AddSecurity() - Update auth endpoints to use SignInAsync/SignOutAsync (proper cookie auth) - Add [AllowAnonymous] to login page - Create wwwroot for static file serving - Regenerate clean EF migration after model changes Verified with launch profile "ScadaLink Central": - Host starts, connects to SQL Server, applies EF migrations - Akka.NET cluster forms (remoting on 8081, node joins self as leader) - /health/ready returns Healthy (DB + Akka checks) - LDAP auth works (admin/password via GLAuth → 302 + auth cookie set) - Login page renders (HTTP 200) - Unauthenticated requests redirect to /login --- src/ScadaLink.CentralUI/Auth/AuthEndpoints.cs | 61 +- .../Components/Pages/Login.razor | 2 + src/ScadaLink.Host/Program.cs | 6 + .../logs/scadalink-20260317.log | 1003 +++++++++++++++++ src/ScadaLink.Host/wwwroot/.gitkeep | 0 .../ServiceCollectionExtensions.cs | 13 + 6 files changed, 1061 insertions(+), 24 deletions(-) create mode 100644 src/ScadaLink.Host/wwwroot/.gitkeep diff --git a/src/ScadaLink.CentralUI/Auth/AuthEndpoints.cs b/src/ScadaLink.CentralUI/Auth/AuthEndpoints.cs index 319cf55..5e8263b 100644 --- a/src/ScadaLink.CentralUI/Auth/AuthEndpoints.cs +++ b/src/ScadaLink.CentralUI/Auth/AuthEndpoints.cs @@ -1,3 +1,6 @@ +using System.Security.Claims; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -8,7 +11,7 @@ namespace ScadaLink.CentralUI.Auth; /// /// Minimal API endpoints for login/logout. These run outside Blazor Server (standard HTTP POST). -/// On success, sets an HTTP-only cookie containing the JWT, then redirects to dashboard. +/// On success, signs in via ASP.NET Core cookie authentication and redirects to dashboard. /// public static class AuthEndpoints { @@ -41,37 +44,47 @@ public static class AuthEndpoints // Map LDAP groups to roles var roleMappingResult = await roleMapper.MapGroupsToRolesAsync(authResult.Groups ?? []); - var token = jwtService.GenerateToken( - authResult.DisplayName ?? username, - authResult.Username ?? username, - roleMappingResult.Roles, - roleMappingResult.IsSystemWideDeployment ? null : roleMappingResult.PermittedSiteIds); + // Build claims from LDAP auth + role mapping + var claims = new List + { + new(ClaimTypes.Name, authResult.Username ?? username), + new(JwtTokenService.DisplayNameClaimType, authResult.DisplayName ?? username), + new(JwtTokenService.UsernameClaimType, authResult.Username ?? username), + }; - // Set HTTP-only cookie with the JWT - context.Response.Cookies.Append( - CookieAuthenticationStateProvider.AuthCookieName, - token, - new CookieOptions + foreach (var role in roleMappingResult.Roles) + { + claims.Add(new Claim(JwtTokenService.RoleClaimType, role)); + } + + if (!roleMappingResult.IsSystemWideDeployment) + { + foreach (var siteId in roleMappingResult.PermittedSiteIds) { - HttpOnly = true, - Secure = context.Request.IsHttps, - SameSite = SameSiteMode.Strict, - Path = "/", - // Cookie expiry matches JWT idle timeout (30 min default) - MaxAge = TimeSpan.FromMinutes(30) + claims.Add(new Claim(JwtTokenService.SiteIdClaimType, siteId)); + } + } + + var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); + var principal = new ClaimsPrincipal(identity); + + await context.SignInAsync( + CookieAuthenticationDefaults.AuthenticationScheme, + principal, + new AuthenticationProperties + { + IsPersistent = true, + ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(30) }); context.Response.Redirect("/"); - }); + }).DisableAntiforgery(); - endpoints.MapPost("/auth/logout", (HttpContext context) => + endpoints.MapPost("/auth/logout", async (HttpContext context) => { - context.Response.Cookies.Delete(CookieAuthenticationStateProvider.AuthCookieName, new CookieOptions - { - Path = "/" - }); + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); context.Response.Redirect("/login"); - }); + }).DisableAntiforgery(); return endpoints; } diff --git a/src/ScadaLink.CentralUI/Components/Pages/Login.razor b/src/ScadaLink.CentralUI/Components/Pages/Login.razor index 8a266ad..4e30c6f 100644 --- a/src/ScadaLink.CentralUI/Components/Pages/Login.razor +++ b/src/ScadaLink.CentralUI/Components/Pages/Login.razor @@ -1,4 +1,6 @@ @page "/login" +@using Microsoft.AspNetCore.Authorization +@attribute [AllowAnonymous]
diff --git a/src/ScadaLink.Host/Program.cs b/src/ScadaLink.Host/Program.cs index 4ff4ab0..41dd2c9 100644 --- a/src/ScadaLink.Host/Program.cs +++ b/src/ScadaLink.Host/Program.cs @@ -108,6 +108,12 @@ try } } + // Middleware pipeline + app.UseStaticFiles(); + app.UseAuthentication(); + app.UseAuthorization(); + app.UseAntiforgery(); + // WP-12: Map readiness endpoint — returns 503 until all checks pass, 200 when ready app.MapHealthChecks("/health/ready", new HealthCheckOptions { diff --git a/src/ScadaLink.Host/logs/scadalink-20260317.log b/src/ScadaLink.Host/logs/scadalink-20260317.log index 42d0f55..61f0ceb 100644 --- a/src/ScadaLink.Host/logs/scadalink-20260317.log +++ b/src/ScadaLink.Host/logs/scadalink-20260317.log @@ -1460,3 +1460,1006 @@ LdapException: Invalid Credentials (49) Invalid Credentials LdapException: Matched DN: 2026-03-17 03:01:01.303 -04:00 [INF] Executed endpoint 'HTTP: POST /auth/login' 2026-03-17 03:01:01.303 -04:00 [INF] Request finished HTTP/1.1 POST http://localhost:5000/auth/login - 302 0 null 11.4004ms +2026-03-17 03:31:31.995 -04:00 [INF] Application is shutting down... +2026-03-17 03:31:31.998 -04:00 [INF] Shutting down Akka.NET actor system via CoordinatedShutdown... +2026-03-17 03:31:31.998 -04:00 [INF] Akka.NET actor system shutdown complete. +[INF] Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. +2026-03-17 03:30:52.516 -04:00 [INF] Executed DbCommand (20ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result +2026-03-17 03:30:52.582 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; +2026-03-17 03:30:52.599 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:30:52.603 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 03:30:52.608 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 03:30:52.614 -04:00 [INF] No migrations were applied. The database is already up to date. +2026-03-17 03:30:52.620 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result +2026-03-17 03:30:52.635 -04:00 [INF] Central health aggregator started, offline timeout 60s +2026-03-17 03:30:52.723 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [d].[Id], [d].[FriendlyName], [d].[Xml] +FROM [DataProtectionKeys] AS [d] +2026-03-17 03:30:52.897 -04:00 [INF] Akka.NET actor system 'scadalink' started. Role=Central, Roles=Central, Hostname=localhost, Port=8081, TransportHeartbeat=5s, TransportFailure=15s +2026-03-17 03:30:52.899 -04:00 [INF] Central actors registered. CentralCommunicationActor created. +2026-03-17 03:30:53.097 -04:00 [WRN] The ASP.NET Core developer certificate is not trusted. For information about trusting the ASP.NET Core developer certificate, see https://aka.ms/aspnet/https-trust-dev-cert +2026-03-17 03:30:53.105 -04:00 [ERR] Hosting failed to start +System.IO.IOException: Failed to bind to address http://127.0.0.1:5000: address already in use. + ---> Microsoft.AspNetCore.Connections.AddressInUseException: Address already in use + ---> System.Net.Sockets.SocketException (48): Address already in use + at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName) + at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress) + at System.Net.Sockets.Socket.Bind(EndPoint localEP) + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportOptions.CreateDefaultBoundListenSocket(EndPoint endpoint) + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind() + --- End of inner exception stack trace --- + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind() + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportFactory.BindAsync(EndPoint endpoint, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.BindAsync(EndPoint endPoint, ConnectionDelegate connectionDelegate, EndpointConfig endpointConfig, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<>c__DisplayClass28_0`1.<g__OnBind|0>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken) + --- End of inner exception stack trace --- + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.LocalhostListenOptions.BindAsync(AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.BindAsync(CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken) + at Microsoft.Extensions.Hosting.Internal.Host.b__14_1(IHostedService service, CancellationToken token) + at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation) +2026-03-17 03:30:53.111 -04:00 [ERR] BackgroundService failed +System.OperationCanceledException: The operation was canceled. + at System.Threading.PeriodicTimer.State.Signal(Boolean stopping, CancellationToken cancellationToken) + at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.DisposeAsync() + at Microsoft.Extensions.Hosting.Internal.Host.DisposeAsync() + at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) + at Microsoft.Extensions.Hosting.Internal.Host.DisposeAsync() + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 119 + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 40 + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(String targetMigration, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.<>c.<b__22_1>d.MoveNext() + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateImplementationAsync(DbContext context, String targetMigration, MigrationExecutionState state, Boolean useTransaction, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrationsAsync(CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task.FinishSlow(Boolean userDelegateExecute) + at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) + at System.Threading.Tasks.ThreadPoolTaskScheduler.TryExecuteTaskInline(Task task, Boolean taskWasPreviouslyQueued) + at System.Threading.Tasks.TaskScheduler.TryRunInline(Task task, Boolean taskWasPreviouslyQueued) + at System.Threading.Tasks.TaskContinuation.InlineIfPossibleOrElseQueue(Task task, Boolean needsProtection) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Threading.Tasks.UnwrapPromise`1.TrySetFromTask(Task task, Boolean lookForOce) + at System.Threading.Tasks.UnwrapPromise`1.ProcessInnerTask(Task task) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task.FinishSlow(Boolean userDelegateExecute) + at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) + at System.Threading.ThreadPoolWorkQueue.Dispatch() + at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart() + at System.Threading.Thread.StartCallback() +--- End of stack trace from previous location --- + at System.Threading.PeriodicTimer.State.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token) + at ScadaLink.HealthMonitoring.CentralHealthAggregator.ExecuteAsync(CancellationToken stoppingToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.HealthMonitoring/CentralHealthAggregator.cs:line 109 + at Microsoft.Extensions.Hosting.Internal.Host.TryExecuteBackgroundServiceAsync(BackgroundService backgroundService) +2026-03-17 03:30:53.113 -04:00 [FTL] The HostOptions.BackgroundServiceExceptionBehavior is configured to StopHost. A BackgroundService has thrown an unhandled exception, and the IHost instance is stopping. To avoid this behavior, configure this to Ignore; however the BackgroundService will not be restarted. +System.OperationCanceledException: The operation was canceled. + at System.Threading.PeriodicTimer.State.Signal(Boolean stopping, CancellationToken cancellationToken) + at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.DisposeAsync() + at Microsoft.Extensions.Hosting.Internal.Host.DisposeAsync() + at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) + at Microsoft.Extensions.Hosting.Internal.Host.DisposeAsync() + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 119 + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 40 + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(String targetMigration, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.<>c.<b__22_1>d.MoveNext() + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateImplementationAsync(DbContext context, String targetMigration, MigrationExecutionState state, Boolean useTransaction, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrationsAsync(CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task.FinishSlow(Boolean userDelegateExecute) + at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) + at System.Threading.Tasks.ThreadPoolTaskScheduler.TryExecuteTaskInline(Task task, Boolean taskWasPreviouslyQueued) + at System.Threading.Tasks.TaskScheduler.TryRunInline(Task task, Boolean taskWasPreviouslyQueued) + at System.Threading.Tasks.TaskContinuation.InlineIfPossibleOrElseQueue(Task task, Boolean needsProtection) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Threading.Tasks.UnwrapPromise`1.TrySetFromTask(Task task, Boolean lookForOce) + at System.Threading.Tasks.UnwrapPromise`1.ProcessInnerTask(Task task) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task.FinishSlow(Boolean userDelegateExecute) + at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) + at System.Threading.ThreadPoolWorkQueue.Dispatch() + at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart() + at System.Threading.Thread.StartCallback() +--- End of stack trace from previous location --- + at System.Threading.PeriodicTimer.State.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token) + at ScadaLink.HealthMonitoring.CentralHealthAggregator.ExecuteAsync(CancellationToken stoppingToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.HealthMonitoring/CentralHealthAggregator.cs:line 109 + at Microsoft.Extensions.Hosting.Internal.Host.TryExecuteBackgroundServiceAsync(BackgroundService backgroundService) +2026-03-17 03:30:53.115 -04:00 [INF] Application is shutting down... +2026-03-17 03:30:53.116 -04:00 [FTL] ScadaLink host terminated unexpectedly +System.IO.IOException: Failed to bind to address http://127.0.0.1:5000: address already in use. + ---> Microsoft.AspNetCore.Connections.AddressInUseException: Address already in use + ---> System.Net.Sockets.SocketException (48): Address already in use + at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName) + at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress) + at System.Net.Sockets.Socket.Bind(EndPoint localEP) + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportOptions.CreateDefaultBoundListenSocket(EndPoint endpoint) + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind() + --- End of inner exception stack trace --- + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind() + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportFactory.BindAsync(EndPoint endpoint, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.BindAsync(EndPoint endPoint, ConnectionDelegate connectionDelegate, EndpointConfig endpointConfig, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<>c__DisplayClass28_0`1.<g__OnBind|0>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken) + --- End of inner exception stack trace --- + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.LocalhostListenOptions.BindAsync(AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.BindAsync(CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken) + at Microsoft.Extensions.Hosting.Internal.Host.b__14_1(IHostedService service, CancellationToken token) + at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation) + at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 119 +2026-03-17 03:31:49.746 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 03:32:04.724 -04:00 [FTL] ScadaLink host terminated unexpectedly +Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 35 - An internal exception was caught) + ---> System.Net.Sockets.SocketException (61): Connection refused + at Microsoft.Data.SqlClient.ManagedSni.SniTcpHandle.Connect(String serverName, Int32 port, TimeoutTimer timeout, SqlConnectionIPAddressPreference ipPreference, String cachedFQDN, SQLDNSInfo& pendingDNSInfo) + at Microsoft.Data.SqlClient.ManagedSni.SniTcpHandle..ctor(String serverName, Int32 port, TimeoutTimer timeout, Boolean parallel, SqlConnectionIPAddressPreference ipPreference, String cachedFQDN, SQLDNSInfo& pendingDNSInfo, Boolean tlsFirst, String hostNameInCertificate, String serverCertificateFilename) + at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) + at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, SqlCommand command, Boolean callerHasConnectionLock, Boolean asyncClose) + at Microsoft.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, TimeoutTimer timeout, SqlConnectionString connectionOptions, Boolean withFailover) + at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, TimeoutTimer timeout, Boolean withFailover) + at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout) + at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance) + at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, IDbConnectionPool pool, Func`3 accessTokenCallback) + at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionPoolGroupProviderInfo poolGroupProviderInfo, IDbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) + at Microsoft.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(IDbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions) + at Microsoft.Data.SqlClient.ConnectionPool.WaitHandleDbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection) + at Microsoft.Data.SqlClient.ConnectionPool.WaitHandleDbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection) + at Microsoft.Data.SqlClient.ConnectionPool.WaitHandleDbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection) + at Microsoft.Data.SqlClient.ConnectionPool.WaitHandleDbConnectionPool.WaitForPendingOpen() +--- End of stack trace from previous location --- + at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected) + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.<>c__DisplayClass20_0.<b__0>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.<>c__DisplayClass20_0.<b__0>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.<>c__DisplayClass20_0.<b__0>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(String targetMigration, CancellationToken cancellationToken) + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 27 + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 107 +ClientConnectionId:00000000-0000-0000-0000-000000000000 +Error Number:10061,State:0,Class:20 +2026-03-17 03:34:58.510 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 03:34:58.988 -04:00 [INF] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:34:58.993 -04:00 [INF] Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. +2026-03-17 03:34:59.026 -04:00 [INF] Executed DbCommand (32ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result +2026-03-17 03:34:59.075 -04:00 [INF] Executed DbCommand (8ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; +2026-03-17 03:34:59.092 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:34:59.095 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 03:34:59.117 -04:00 [INF] Executed DbCommand (21ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 03:34:59.121 -04:00 [INF] Applying migration '20260317065749_InitialSchema'. +2026-03-17 03:34:59.159 -04:00 [INF] Executed DbCommand (7ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ApiKeys] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [KeyValue] nvarchar(500) NOT NULL, + [IsEnabled] bit NOT NULL, + CONSTRAINT [PK_ApiKeys] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.164 -04:00 [INF] Executed DbCommand (5ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ApiMethods] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Script] nvarchar(max) NOT NULL, + [ApprovedApiKeyIds] nvarchar(4000) NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + [TimeoutSeconds] int NOT NULL, + CONSTRAINT [PK_ApiMethods] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.166 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [AuditLogEntries] ( + [Id] int NOT NULL IDENTITY, + [User] nvarchar(200) NOT NULL, + [Action] nvarchar(100) NOT NULL, + [EntityType] nvarchar(200) NOT NULL, + [EntityId] nvarchar(200) NOT NULL, + [EntityName] nvarchar(200) NOT NULL, + [AfterStateJson] nvarchar(max) NULL, + [Timestamp] datetimeoffset NOT NULL, + CONSTRAINT [PK_AuditLogEntries] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.167 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DatabaseConnectionDefinitions] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [ConnectionString] nvarchar(4000) NOT NULL, + [MaxRetries] int NOT NULL, + [RetryDelay] time NOT NULL, + CONSTRAINT [PK_DatabaseConnectionDefinitions] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.168 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DataConnections] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Protocol] nvarchar(50) NOT NULL, + [Configuration] nvarchar(4000) NULL, + CONSTRAINT [PK_DataConnections] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.169 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DataProtectionKeys] ( + [Id] int NOT NULL IDENTITY, + [FriendlyName] nvarchar(max) NULL, + [Xml] nvarchar(max) NULL, + CONSTRAINT [PK_DataProtectionKeys] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.171 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ExternalSystemDefinitions] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [EndpointUrl] nvarchar(2000) NOT NULL, + [AuthType] nvarchar(50) NOT NULL, + [AuthConfiguration] nvarchar(4000) NULL, + [MaxRetries] int NOT NULL, + [RetryDelay] time NOT NULL, + CONSTRAINT [PK_ExternalSystemDefinitions] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.173 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [LdapGroupMappings] ( + [Id] int NOT NULL IDENTITY, + [LdapGroupName] nvarchar(500) NOT NULL, + [Role] nvarchar(100) NOT NULL, + CONSTRAINT [PK_LdapGroupMappings] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.175 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [NotificationLists] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + CONSTRAINT [PK_NotificationLists] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.177 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SharedScripts] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Code] nvarchar(max) NOT NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + CONSTRAINT [PK_SharedScripts] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.178 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Sites] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [SiteIdentifier] nvarchar(100) NOT NULL, + [Description] nvarchar(2000) NULL, + CONSTRAINT [PK_Sites] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.179 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SmtpConfigurations] ( + [Id] int NOT NULL IDENTITY, + [Host] nvarchar(500) NOT NULL, + [Port] int NOT NULL, + [AuthType] nvarchar(50) NOT NULL, + [Credentials] nvarchar(4000) NULL, + [TlsMode] nvarchar(50) NULL, + [FromAddress] nvarchar(500) NOT NULL, + [ConnectionTimeoutSeconds] int NOT NULL, + [MaxConcurrentConnections] int NOT NULL, + [MaxRetries] int NOT NULL, + [RetryDelay] time NOT NULL, + CONSTRAINT [PK_SmtpConfigurations] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.181 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SystemArtifactDeploymentRecords] ( + [Id] int NOT NULL IDENTITY, + [ArtifactType] nvarchar(100) NOT NULL, + [DeployedBy] nvarchar(200) NOT NULL, + [DeployedAt] datetimeoffset NOT NULL, + [PerSiteStatus] nvarchar(4000) NULL, + CONSTRAINT [PK_SystemArtifactDeploymentRecords] PRIMARY KEY ([Id]) +); +2026-03-17 03:34:59.184 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Templates] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Description] nvarchar(2000) NULL, + [ParentTemplateId] int NULL, + CONSTRAINT [PK_Templates] PRIMARY KEY ([Id]), + CONSTRAINT [FK_Templates_Templates_ParentTemplateId] FOREIGN KEY ([ParentTemplateId]) REFERENCES [Templates] ([Id]) ON DELETE NO ACTION +); +2026-03-17 03:34:59.186 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ExternalSystemMethods] ( + [Id] int NOT NULL IDENTITY, + [ExternalSystemDefinitionId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [HttpMethod] nvarchar(10) NOT NULL, + [Path] nvarchar(2000) NOT NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + CONSTRAINT [PK_ExternalSystemMethods] PRIMARY KEY ([Id]), + CONSTRAINT [FK_ExternalSystemMethods_ExternalSystemDefinitions_ExternalSystemDefinitionId] FOREIGN KEY ([ExternalSystemDefinitionId]) REFERENCES [ExternalSystemDefinitions] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.187 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [NotificationRecipients] ( + [Id] int NOT NULL IDENTITY, + [NotificationListId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [EmailAddress] nvarchar(500) NOT NULL, + CONSTRAINT [PK_NotificationRecipients] PRIMARY KEY ([Id]), + CONSTRAINT [FK_NotificationRecipients_NotificationLists_NotificationListId] FOREIGN KEY ([NotificationListId]) REFERENCES [NotificationLists] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.189 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Areas] ( + [Id] int NOT NULL IDENTITY, + [SiteId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [ParentAreaId] int NULL, + CONSTRAINT [PK_Areas] PRIMARY KEY ([Id]), + CONSTRAINT [FK_Areas_Areas_ParentAreaId] FOREIGN KEY ([ParentAreaId]) REFERENCES [Areas] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_Areas_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.191 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SiteDataConnectionAssignments] ( + [Id] int NOT NULL IDENTITY, + [SiteId] int NOT NULL, + [DataConnectionId] int NOT NULL, + CONSTRAINT [PK_SiteDataConnectionAssignments] PRIMARY KEY ([Id]), + CONSTRAINT [FK_SiteDataConnectionAssignments_DataConnections_DataConnectionId] FOREIGN KEY ([DataConnectionId]) REFERENCES [DataConnections] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_SiteDataConnectionAssignments_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.193 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SiteScopeRules] ( + [Id] int NOT NULL IDENTITY, + [LdapGroupMappingId] int NOT NULL, + [SiteId] int NOT NULL, + CONSTRAINT [PK_SiteScopeRules] PRIMARY KEY ([Id]), + CONSTRAINT [FK_SiteScopeRules_LdapGroupMappings_LdapGroupMappingId] FOREIGN KEY ([LdapGroupMappingId]) REFERENCES [LdapGroupMappings] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_SiteScopeRules_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.194 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateAlarms] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [Description] nvarchar(2000) NULL, + [PriorityLevel] int NOT NULL, + [IsLocked] bit NOT NULL, + [TriggerType] nvarchar(50) NOT NULL, + [TriggerConfiguration] nvarchar(4000) NULL, + [OnTriggerScriptId] int NULL, + CONSTRAINT [PK_TemplateAlarms] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateAlarms_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.196 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateAttributes] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [Value] nvarchar(4000) NULL, + [DataType] nvarchar(50) NOT NULL, + [IsLocked] bit NOT NULL, + [Description] nvarchar(2000) NULL, + [DataSourceReference] nvarchar(500) NULL, + CONSTRAINT [PK_TemplateAttributes] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateAttributes_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.197 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateCompositions] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [ComposedTemplateId] int NOT NULL, + [InstanceName] nvarchar(200) NOT NULL, + CONSTRAINT [PK_TemplateCompositions] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateCompositions_Templates_ComposedTemplateId] FOREIGN KEY ([ComposedTemplateId]) REFERENCES [Templates] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_TemplateCompositions_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.199 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateScripts] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [IsLocked] bit NOT NULL, + [Code] nvarchar(max) NOT NULL, + [TriggerType] nvarchar(50) NULL, + [TriggerConfiguration] nvarchar(4000) NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + [MinTimeBetweenRuns] time NULL, + CONSTRAINT [PK_TemplateScripts] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateScripts_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.201 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Instances] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [SiteId] int NOT NULL, + [AreaId] int NULL, + [UniqueName] nvarchar(200) NOT NULL, + [State] nvarchar(50) NOT NULL, + CONSTRAINT [PK_Instances] PRIMARY KEY ([Id]), + CONSTRAINT [FK_Instances_Areas_AreaId] FOREIGN KEY ([AreaId]) REFERENCES [Areas] ([Id]) ON DELETE SET NULL, + CONSTRAINT [FK_Instances_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_Instances_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE NO ACTION +); +2026-03-17 03:34:59.202 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DeployedConfigSnapshots] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [DeploymentId] nvarchar(100) NOT NULL, + [RevisionHash] nvarchar(100) NOT NULL, + [ConfigurationJson] nvarchar(max) NOT NULL, + [DeployedAt] datetimeoffset NOT NULL, + CONSTRAINT [PK_DeployedConfigSnapshots] PRIMARY KEY ([Id]), + CONSTRAINT [FK_DeployedConfigSnapshots_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.204 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DeploymentRecords] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [Status] nvarchar(50) NOT NULL, + [DeploymentId] nvarchar(100) NOT NULL, + [RevisionHash] nvarchar(100) NULL, + [DeployedBy] nvarchar(200) NOT NULL, + [DeployedAt] datetimeoffset NOT NULL, + [CompletedAt] datetimeoffset NULL, + [ErrorMessage] nvarchar(max) NULL, + [RowVersion] rowversion NOT NULL, + CONSTRAINT [PK_DeploymentRecords] PRIMARY KEY ([Id]), + CONSTRAINT [FK_DeploymentRecords_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE NO ACTION +); +2026-03-17 03:34:59.205 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [InstanceAttributeOverrides] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [AttributeName] nvarchar(200) NOT NULL, + [OverrideValue] nvarchar(4000) NULL, + CONSTRAINT [PK_InstanceAttributeOverrides] PRIMARY KEY ([Id]), + CONSTRAINT [FK_InstanceAttributeOverrides_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.207 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [InstanceConnectionBindings] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [AttributeName] nvarchar(200) NOT NULL, + [DataConnectionId] int NOT NULL, + CONSTRAINT [PK_InstanceConnectionBindings] PRIMARY KEY ([Id]), + CONSTRAINT [FK_InstanceConnectionBindings_DataConnections_DataConnectionId] FOREIGN KEY ([DataConnectionId]) REFERENCES [DataConnections] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_InstanceConnectionBindings_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE CASCADE +); +2026-03-17 03:34:59.280 -04:00 [INF] Executed DbCommand (72ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'Id', N'LdapGroupName', N'Role') AND [object_id] = OBJECT_ID(N'[LdapGroupMappings]')) + SET IDENTITY_INSERT [LdapGroupMappings] ON; +INSERT INTO [LdapGroupMappings] ([Id], [LdapGroupName], [Role]) +VALUES (1, N'SCADA-Admins', N'Admin'); +IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'Id', N'LdapGroupName', N'Role') AND [object_id] = OBJECT_ID(N'[LdapGroupMappings]')) + SET IDENTITY_INSERT [LdapGroupMappings] OFF; +2026-03-17 03:34:59.281 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ApiKeys_KeyValue] ON [ApiKeys] ([KeyValue]); +2026-03-17 03:34:59.282 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ApiKeys_Name] ON [ApiKeys] ([Name]); +2026-03-17 03:34:59.283 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ApiMethods_Name] ON [ApiMethods] ([Name]); +2026-03-17 03:34:59.284 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Areas_ParentAreaId] ON [Areas] ([ParentAreaId]); +2026-03-17 03:34:59.286 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Areas_SiteId_ParentAreaId_Name] ON [Areas] ([SiteId], [ParentAreaId], [Name]) WHERE [ParentAreaId] IS NOT NULL; +2026-03-17 03:34:59.286 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_Action] ON [AuditLogEntries] ([Action]); +2026-03-17 03:34:59.287 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_EntityId] ON [AuditLogEntries] ([EntityId]); +2026-03-17 03:34:59.288 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_EntityType] ON [AuditLogEntries] ([EntityType]); +2026-03-17 03:34:59.289 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_Timestamp] ON [AuditLogEntries] ([Timestamp]); +2026-03-17 03:34:59.289 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_User] ON [AuditLogEntries] ([User]); +2026-03-17 03:34:59.290 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DatabaseConnectionDefinitions_Name] ON [DatabaseConnectionDefinitions] ([Name]); +2026-03-17 03:34:59.291 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DataConnections_Name] ON [DataConnections] ([Name]); +2026-03-17 03:34:59.291 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_DeployedConfigSnapshots_DeploymentId] ON [DeployedConfigSnapshots] ([DeploymentId]); +2026-03-17 03:34:59.292 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DeployedConfigSnapshots_InstanceId] ON [DeployedConfigSnapshots] ([InstanceId]); +2026-03-17 03:34:59.293 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_DeploymentRecords_DeployedAt] ON [DeploymentRecords] ([DeployedAt]); +2026-03-17 03:34:59.293 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DeploymentRecords_DeploymentId] ON [DeploymentRecords] ([DeploymentId]); +2026-03-17 03:34:59.294 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_DeploymentRecords_InstanceId] ON [DeploymentRecords] ([InstanceId]); +2026-03-17 03:34:59.295 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ExternalSystemDefinitions_Name] ON [ExternalSystemDefinitions] ([Name]); +2026-03-17 03:34:59.295 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ExternalSystemMethods_ExternalSystemDefinitionId_Name] ON [ExternalSystemMethods] ([ExternalSystemDefinitionId], [Name]); +2026-03-17 03:34:59.296 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_InstanceAttributeOverrides_InstanceId_AttributeName] ON [InstanceAttributeOverrides] ([InstanceId], [AttributeName]); +2026-03-17 03:34:59.297 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_InstanceConnectionBindings_DataConnectionId] ON [InstanceConnectionBindings] ([DataConnectionId]); +2026-03-17 03:34:59.298 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_InstanceConnectionBindings_InstanceId_AttributeName] ON [InstanceConnectionBindings] ([InstanceId], [AttributeName]); +2026-03-17 03:34:59.298 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Instances_AreaId] ON [Instances] ([AreaId]); +2026-03-17 03:34:59.299 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Instances_SiteId_UniqueName] ON [Instances] ([SiteId], [UniqueName]); +2026-03-17 03:34:59.300 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Instances_TemplateId] ON [Instances] ([TemplateId]); +2026-03-17 03:34:59.316 -04:00 [INF] Executed DbCommand (16ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_LdapGroupMappings_LdapGroupName] ON [LdapGroupMappings] ([LdapGroupName]); +2026-03-17 03:34:59.317 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_NotificationLists_Name] ON [NotificationLists] ([Name]); +2026-03-17 03:34:59.318 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_NotificationRecipients_NotificationListId] ON [NotificationRecipients] ([NotificationListId]); +2026-03-17 03:34:59.318 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_SharedScripts_Name] ON [SharedScripts] ([Name]); +2026-03-17 03:34:59.319 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_SiteDataConnectionAssignments_DataConnectionId] ON [SiteDataConnectionAssignments] ([DataConnectionId]); +2026-03-17 03:34:59.320 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_SiteDataConnectionAssignments_SiteId_DataConnectionId] ON [SiteDataConnectionAssignments] ([SiteId], [DataConnectionId]); +2026-03-17 03:34:59.320 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Sites_Name] ON [Sites] ([Name]); +2026-03-17 03:34:59.321 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Sites_SiteIdentifier] ON [Sites] ([SiteIdentifier]); +2026-03-17 03:34:59.322 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_SiteScopeRules_LdapGroupMappingId_SiteId] ON [SiteScopeRules] ([LdapGroupMappingId], [SiteId]); +2026-03-17 03:34:59.323 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_SiteScopeRules_SiteId] ON [SiteScopeRules] ([SiteId]); +2026-03-17 03:34:59.324 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_SystemArtifactDeploymentRecords_DeployedAt] ON [SystemArtifactDeploymentRecords] ([DeployedAt]); +2026-03-17 03:34:59.324 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateAlarms_TemplateId_Name] ON [TemplateAlarms] ([TemplateId], [Name]); +2026-03-17 03:34:59.325 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateAttributes_TemplateId_Name] ON [TemplateAttributes] ([TemplateId], [Name]); +2026-03-17 03:34:59.326 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_TemplateCompositions_ComposedTemplateId] ON [TemplateCompositions] ([ComposedTemplateId]); +2026-03-17 03:34:59.327 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateCompositions_TemplateId_InstanceName] ON [TemplateCompositions] ([TemplateId], [InstanceName]); +2026-03-17 03:34:59.328 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Templates_Name] ON [Templates] ([Name]); +2026-03-17 03:34:59.328 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Templates_ParentTemplateId] ON [Templates] ([ParentTemplateId]); +2026-03-17 03:34:59.329 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateScripts_TemplateId_Name] ON [TemplateScripts] ([TemplateId], [Name]); +2026-03-17 03:34:59.331 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) +VALUES (N'20260317065749_InitialSchema', N'10.0.5'); +2026-03-17 03:34:59.338 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result +2026-03-17 03:34:59.352 -04:00 [INF] Central health aggregator started, offline timeout 60s +2026-03-17 03:34:59.433 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [d].[Id], [d].[FriendlyName], [d].[Xml] +FROM [DataProtectionKeys] AS [d] +2026-03-17 03:34:59.436 -04:00 [INF] Creating key {022bb6b3-5315-417e-a2d8-668db80f7c3e} with creation date 2026-03-17 07:34:59Z, activation date 2026-03-17 07:34:59Z, and expiration date 2026-06-15 07:34:59Z. +2026-03-17 03:34:59.438 -04:00 [WRN] No XML encryptor configured. Key {022bb6b3-5315-417e-a2d8-668db80f7c3e} may be persisted to storage in unencrypted form. +2026-03-17 03:34:59.501 -04:00 [INF] Executed DbCommand (19ms) [Parameters=[@p0='?' (Size = 4000), @p1='?' (Size = 4000)], CommandType='"Text"', CommandTimeout='30'] +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +INSERT INTO [DataProtectionKeys] ([FriendlyName], [Xml]) +OUTPUT INSERTED.[Id] +VALUES (@p0, @p1); +2026-03-17 03:34:59.511 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [d].[Id], [d].[FriendlyName], [d].[Xml] +FROM [DataProtectionKeys] AS [d] +2026-03-17 03:34:59.601 -04:00 [INF] Akka.NET actor system 'scadalink' started. Role=Central, Roles=Central, Hostname=localhost, Port=8081, TransportHeartbeat=5s, TransportFailure=15s +2026-03-17 03:34:59.602 -04:00 [INF] Central actors registered. CentralCommunicationActor created. +2026-03-17 03:34:59.766 -04:00 [WRN] The ASP.NET Core developer certificate is not trusted. For information about trusting the ASP.NET Core developer certificate, see https://aka.ms/aspnet/https-trust-dev-cert +2026-03-17 03:34:59.769 -04:00 [INF] Now listening on: https://localhost:5001 +2026-03-17 03:34:59.769 -04:00 [INF] Now listening on: http://localhost:5000 +2026-03-17 03:34:59.770 -04:00 [INF] Application started. Press Ctrl+C to shut down. +2026-03-17 03:34:59.770 -04:00 [INF] Hosting environment: Central +2026-03-17 03:34:59.770 -04:00 [INF] Content root path: /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host +2026-03-17 03:35:15.892 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/health/ready - null null +2026-03-17 03:35:15.899 -04:00 [INF] Executing endpoint 'Health checks' +2026-03-17 03:35:15.906 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:35:15.923 -04:00 [INF] Executed endpoint 'Health checks' +2026-03-17 03:35:15.924 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/health/ready - 200 null application/json 32.5915ms +2026-03-17 03:35:15.961 -04:00 [INF] Request starting HTTP/1.1 POST http://localhost:5000/auth/login - application/x-www-form-urlencoded 32 +2026-03-17 03:35:15.962 -04:00 [INF] Executing endpoint 'HTTP: POST /auth/login' +2026-03-17 03:35:15.998 -04:00 [INF] Executed DbCommand (6ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [l].[Id], [l].[LdapGroupName], [l].[Role] +FROM [LdapGroupMappings] AS [l] +2026-03-17 03:35:16.009 -04:00 [INF] Executed endpoint 'HTTP: POST /auth/login' +2026-03-17 03:35:16.009 -04:00 [INF] Request finished HTTP/1.1 POST http://localhost:5000/auth/login - 302 0 null 47.7577ms +2026-03-17 03:35:16.017 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/login - null null +2026-03-17 03:35:16.018 -04:00 [ERR] Connection id "0HNK3UUTNOF41", Request id "0HNK3UUTNOF41:00000001": An unhandled exception was thrown by the application. +System.InvalidOperationException: Endpoint /login (/login) contains anti-forgery metadata, but a middleware was not found that supports anti-forgery. +Configure your application startup by adding app.UseAntiforgery() in the application startup code. If there are calls to app.UseRouting() and app.UseEndpoints(...), the call to app.UseAntiforgery() must go between them. Calls to app.UseAntiforgery() must be placed after calls to app.UseAuthentication() and app.UseAuthorization(). + at Microsoft.AspNetCore.Routing.EndpointMiddleware.ThrowMissingAntiforgeryMiddlewareException(Endpoint endpoint) + at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) + at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application) +2026-03-17 03:35:16.018 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/login - 500 0 null 1.6082ms +2026-03-17 03:35:16.025 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/ - null null +2026-03-17 03:35:16.026 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:35:16.027 -04:00 [ERR] Connection id "0HNK3UUTNOF42", Request id "0HNK3UUTNOF42:00000001": An unhandled exception was thrown by the application. +System.InvalidOperationException: Unable to find the required 'IAuthenticationService' service. Please add all the required services by calling 'IServiceCollection.AddAuthentication' in the application startup code. + at Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.GetAuthenticationService(HttpContext context) + at Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.ChallengeAsync(HttpContext context) + at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.<>c__DisplayClass0_0.<g__Handle|0>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application) +2026-03-17 03:35:16.027 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/ - 500 0 null 1.9852ms +2026-03-17 03:35:16.033 -04:00 [INF] Request starting HTTP/1.1 POST http://localhost:5000/auth/login - application/x-www-form-urlencoded 29 +2026-03-17 03:35:16.034 -04:00 [INF] Executing endpoint 'HTTP: POST /auth/login' +2026-03-17 03:35:16.043 -04:00 [WRN] LDAP authentication failed for user admin +LdapException: Invalid Credentials (49) Invalid Credentials +LdapException: Matched DN: +2026-03-17 03:35:16.044 -04:00 [INF] Executed endpoint 'HTTP: POST /auth/login' +2026-03-17 03:35:16.044 -04:00 [INF] Request finished HTTP/1.1 POST http://localhost:5000/auth/login - 302 0 null 10.3918ms +2026-03-17 03:35:16.622 -04:00 [INF] Application is shutting down... +2026-03-17 03:35:16.624 -04:00 [INF] Shutting down Akka.NET actor system via CoordinatedShutdown... +2026-03-17 03:35:16.624 -04:00 [INF] Akka.NET actor system shutdown complete. +2026-03-17 03:38:51.968 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 03:38:52.469 -04:00 [INF] Executed DbCommand (12ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:38:52.474 -04:00 [INF] Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. +2026-03-17 03:38:52.490 -04:00 [INF] Executed DbCommand (15ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result +2026-03-17 03:38:52.535 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; +2026-03-17 03:38:52.542 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:38:52.544 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 03:38:52.552 -04:00 [INF] Executed DbCommand (8ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 03:38:52.556 -04:00 [INF] No migrations were applied. The database is already up to date. +2026-03-17 03:38:52.563 -04:00 [INF] Executed DbCommand (5ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result +2026-03-17 03:38:52.574 -04:00 [INF] Central health aggregator started, offline timeout 60s +2026-03-17 03:38:52.644 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [d].[Id], [d].[FriendlyName], [d].[Xml] +FROM [DataProtectionKeys] AS [d] +2026-03-17 03:38:52.746 -04:00 [INF] Akka.NET actor system 'scadalink' started. Role=Central, Roles=Central, Hostname=localhost, Port=8081, TransportHeartbeat=5s, TransportFailure=15s +2026-03-17 03:38:52.746 -04:00 [INF] Central actors registered. CentralCommunicationActor created. +2026-03-17 03:38:52.930 -04:00 [WRN] The ASP.NET Core developer certificate is not trusted. For information about trusting the ASP.NET Core developer certificate, see https://aka.ms/aspnet/https-trust-dev-cert +2026-03-17 03:38:52.933 -04:00 [INF] Now listening on: https://localhost:5001 +2026-03-17 03:38:52.934 -04:00 [INF] Now listening on: http://localhost:5000 +2026-03-17 03:38:52.934 -04:00 [INF] Application started. Press Ctrl+C to shut down. +2026-03-17 03:38:52.934 -04:00 [INF] Hosting environment: Central +2026-03-17 03:38:52.934 -04:00 [INF] Content root path: /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host +2026-03-17 03:38:58.597 -04:00 [INF] Request starting HTTP/2 GET https://localhost:5001/ - null null +2026-03-17 03:38:58.612 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:38:58.613 -04:00 [INF] AuthenticationScheme: Cookies was challenged. +2026-03-17 03:38:58.613 -04:00 [INF] Request finished HTTP/2 GET https://localhost:5001/ - 302 0 null 16.9372ms +2026-03-17 03:38:58.616 -04:00 [INF] Request starting HTTP/2 GET https://localhost:5001/login?ReturnUrl=%2F - null null +2026-03-17 03:38:58.618 -04:00 [INF] Executing endpoint '/login (/login)' +2026-03-17 03:38:58.644 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:38:58.645 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:38:58.657 -04:00 [INF] Executed endpoint '/login (/login)' +2026-03-17 03:38:58.657 -04:00 [INF] Request finished HTTP/2 GET https://localhost:5001/login?ReturnUrl=%2F - 200 null text/html; charset=utf-8 41.6812ms +2026-03-17 03:38:58.662 -04:00 [INF] Request starting HTTP/2 GET https://localhost:5001/_framework/blazor.server.js - null null +2026-03-17 03:38:58.663 -04:00 [INF] Request finished HTTP/2 GET https://localhost:5001/_framework/blazor.server.js - 404 0 null 1.2213ms +2026-03-17 03:38:58.664 -04:00 [INF] Request reached the end of the middleware pipeline without being handled by application code. Request path: GET https://localhost:5001/_framework/blazor.server.js, Response status code: 404 +2026-03-17 03:38:58.746 -04:00 [INF] Request starting HTTP/2 GET https://localhost:5001/favicon.ico - null null +2026-03-17 03:38:58.747 -04:00 [INF] Request finished HTTP/2 GET https://localhost:5001/favicon.ico - 404 0 null 0.2581ms +2026-03-17 03:38:58.747 -04:00 [INF] Request reached the end of the middleware pipeline without being handled by application code. Request path: GET https://localhost:5001/favicon.ico, Response status code: 404 +2026-03-17 03:39:01.481 -04:00 [INF] Request starting HTTP/2 GET https://localhost:5001/login?ReturnUrl=%2F - null null +2026-03-17 03:39:01.481 -04:00 [INF] Executing endpoint '/login (/login)' +2026-03-17 03:39:01.484 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:39:01.484 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:39:01.486 -04:00 [INF] Executed endpoint '/login (/login)' +2026-03-17 03:39:01.486 -04:00 [INF] Request finished HTTP/2 GET https://localhost:5001/login?ReturnUrl=%2F - 200 null text/html; charset=utf-8 5.5975ms +2026-03-17 03:39:01.497 -04:00 [INF] Request starting HTTP/2 GET https://localhost:5001/_framework/blazor.server.js - null null +2026-03-17 03:39:01.497 -04:00 [INF] Request finished HTTP/2 GET https://localhost:5001/_framework/blazor.server.js - 404 0 null 0.371ms +2026-03-17 03:39:01.498 -04:00 [INF] Request reached the end of the middleware pipeline without being handled by application code. Request path: GET https://localhost:5001/_framework/blazor.server.js, Response status code: 404 +2026-03-17 03:39:09.495 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/health/ready - null null +2026-03-17 03:39:09.495 -04:00 [INF] Executing endpoint 'Health checks' +2026-03-17 03:39:09.525 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:39:09.535 -04:00 [INF] Executed endpoint 'Health checks' +2026-03-17 03:39:09.535 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/health/ready - 200 null application/json 40.2438ms +2026-03-17 03:39:09.548 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/login - null null +2026-03-17 03:39:09.548 -04:00 [INF] Executing endpoint '/login (/login)' +2026-03-17 03:39:09.552 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:39:09.552 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:39:09.553 -04:00 [INF] Executed endpoint '/login (/login)' +2026-03-17 03:39:09.553 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/login - 200 null text/html; charset=utf-8 4.901ms +2026-03-17 03:39:09.561 -04:00 [INF] Request starting HTTP/1.1 POST http://localhost:5000/auth/login - application/x-www-form-urlencoded 32 +2026-03-17 03:39:09.561 -04:00 [INF] Executing endpoint 'HTTP: POST /auth/login' +2026-03-17 03:39:09.596 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [l].[Id], [l].[LdapGroupName], [l].[Role] +FROM [LdapGroupMappings] AS [l] +2026-03-17 03:39:09.607 -04:00 [INF] AuthenticationScheme: Cookies signed in. +2026-03-17 03:39:09.607 -04:00 [INF] Executed endpoint 'HTTP: POST /auth/login' +2026-03-17 03:39:09.607 -04:00 [INF] Request finished HTTP/1.1 POST http://localhost:5000/auth/login - 302 0 null 46.1232ms +2026-03-17 03:39:09.624 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/ - null null +2026-03-17 03:39:09.625 -04:00 [INF] Executing endpoint '/ (/)' +2026-03-17 03:39:09.629 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:39:09.631 -04:00 [INF] Executed endpoint '/ (/)' +2026-03-17 03:39:09.631 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/ - 302 null text/html; charset=utf-8 6.4418ms +2026-03-17 03:39:09.638 -04:00 [INF] Request starting HTTP/1.1 POST http://localhost:5000/auth/login - application/x-www-form-urlencoded 29 +2026-03-17 03:39:09.639 -04:00 [INF] Executing endpoint 'HTTP: POST /auth/login' +2026-03-17 03:39:09.648 -04:00 [WRN] LDAP authentication failed for user admin +LdapException: Invalid Credentials (49) Invalid Credentials +LdapException: Matched DN: +2026-03-17 03:39:09.648 -04:00 [INF] Executed endpoint 'HTTP: POST /auth/login' +2026-03-17 03:39:09.648 -04:00 [INF] Request finished HTTP/1.1 POST http://localhost:5000/auth/login - 302 0 null 10.215ms +2026-03-17 03:40:32.768 -04:00 [INF] Application is shutting down... +2026-03-17 03:40:32.771 -04:00 [INF] Shutting down Akka.NET actor system via CoordinatedShutdown... +2026-03-17 03:40:32.771 -04:00 [INF] Akka.NET actor system shutdown complete. +2026-03-17 03:40:35.161 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 03:40:35.617 -04:00 [INF] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:40:35.621 -04:00 [INF] Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. +2026-03-17 03:40:35.633 -04:00 [INF] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result +2026-03-17 03:40:35.673 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; +2026-03-17 03:40:35.682 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:40:35.683 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 03:40:35.686 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 03:40:35.689 -04:00 [INF] No migrations were applied. The database is already up to date. +2026-03-17 03:40:35.694 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result +2026-03-17 03:40:35.704 -04:00 [INF] Central health aggregator started, offline timeout 60s +2026-03-17 03:40:35.774 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [d].[Id], [d].[FriendlyName], [d].[Xml] +FROM [DataProtectionKeys] AS [d] +2026-03-17 03:40:35.877 -04:00 [INF] Akka.NET actor system 'scadalink' started. Role=Central, Roles=Central, Hostname=localhost, Port=8081, TransportHeartbeat=5s, TransportFailure=15s +2026-03-17 03:40:35.877 -04:00 [INF] Central actors registered. CentralCommunicationActor created. +2026-03-17 03:40:35.917 -04:00 [WRN] The WebRootPath was not found: /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/wwwroot. Static files may be unavailable. +2026-03-17 03:40:36.067 -04:00 [WRN] The ASP.NET Core developer certificate is not trusted. For information about trusting the ASP.NET Core developer certificate, see https://aka.ms/aspnet/https-trust-dev-cert +2026-03-17 03:40:36.070 -04:00 [INF] Now listening on: https://localhost:5001 +2026-03-17 03:40:36.070 -04:00 [INF] Now listening on: http://localhost:5000 +2026-03-17 03:40:36.071 -04:00 [INF] Application started. Press Ctrl+C to shut down. +2026-03-17 03:40:36.071 -04:00 [INF] Hosting environment: Central +2026-03-17 03:40:36.071 -04:00 [INF] Content root path: /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host +2026-03-17 03:40:52.849 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/health/ready - null null +2026-03-17 03:40:52.859 -04:00 [INF] Executing endpoint 'Health checks' +2026-03-17 03:40:52.884 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:40:52.900 -04:00 [INF] Executed endpoint 'Health checks' +2026-03-17 03:40:52.901 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/health/ready - 200 null application/json 52.5878ms +2026-03-17 03:40:52.911 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/login - null null +2026-03-17 03:40:52.912 -04:00 [INF] Executing endpoint '/login (/login)' +2026-03-17 03:40:52.934 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:40:52.935 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:40:52.940 -04:00 [INF] Executed endpoint '/login (/login)' +2026-03-17 03:40:52.940 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/login - 200 null text/html; charset=utf-8 29.0932ms +2026-03-17 03:40:52.948 -04:00 [INF] Request starting HTTP/1.1 POST http://localhost:5000/auth/login - application/x-www-form-urlencoded 32 +2026-03-17 03:40:52.949 -04:00 [INF] Executing endpoint 'HTTP: POST /auth/login' +2026-03-17 03:40:52.992 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [l].[Id], [l].[LdapGroupName], [l].[Role] +FROM [LdapGroupMappings] AS [l] +2026-03-17 03:40:53.004 -04:00 [INF] AuthenticationScheme: Cookies signed in. +2026-03-17 03:40:53.004 -04:00 [INF] Executed endpoint 'HTTP: POST /auth/login' +2026-03-17 03:40:53.004 -04:00 [INF] Request finished HTTP/1.1 POST http://localhost:5000/auth/login - 302 0 null 56.5205ms +2026-03-17 03:40:53.024 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/ - null null +2026-03-17 03:40:53.026 -04:00 [INF] Executing endpoint '/ (/)' +2026-03-17 03:40:53.030 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:40:53.031 -04:00 [INF] Executed endpoint '/ (/)' +2026-03-17 03:40:53.031 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/ - 302 null text/html; charset=utf-8 7.8149ms +2026-03-17 03:40:53.038 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/_framework/blazor.web.js - null null +2026-03-17 03:40:53.039 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/_framework/blazor.web.js - 404 0 null 0.5794ms +2026-03-17 03:40:53.039 -04:00 [INF] Request reached the end of the middleware pipeline without being handled by application code. Request path: GET http://localhost:5000/_framework/blazor.web.js, Response status code: 404 +2026-03-17 03:40:53.046 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/ - null null +2026-03-17 03:40:53.047 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:40:53.047 -04:00 [INF] AuthenticationScheme: Cookies was challenged. +2026-03-17 03:40:53.047 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/ - 302 0 null 1.3216ms +2026-03-17 03:41:06.276 -04:00 [INF] Request starting HTTP/2 GET https://localhost:5001/login?ReturnUrl=%2F - null null +2026-03-17 03:41:06.276 -04:00 [INF] Executing endpoint '/login (/login)' +2026-03-17 03:41:06.285 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:41:06.285 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:41:06.290 -04:00 [INF] Executed endpoint '/login (/login)' +2026-03-17 03:41:06.290 -04:00 [INF] Request finished HTTP/2 GET https://localhost:5001/login?ReturnUrl=%2F - 200 null text/html; charset=utf-8 13.99ms +2026-03-17 03:41:06.302 -04:00 [INF] Request starting HTTP/2 GET https://localhost:5001/_framework/blazor.server.js - null null +2026-03-17 03:41:06.302 -04:00 [INF] Request finished HTTP/2 GET https://localhost:5001/_framework/blazor.server.js - 404 0 null 0.3694ms +2026-03-17 03:41:06.303 -04:00 [INF] Request reached the end of the middleware pipeline without being handled by application code. Request path: GET https://localhost:5001/_framework/blazor.server.js, Response status code: 404 +2026-03-17 03:41:08.328 -04:00 [INF] Request starting HTTP/2 GET https://localhost:5001/.well-known/appspecific/com.chrome.devtools.json - null null +2026-03-17 03:41:08.329 -04:00 [INF] Request finished HTTP/2 GET https://localhost:5001/.well-known/appspecific/com.chrome.devtools.json - 404 0 null 0.5353ms +2026-03-17 03:41:08.329 -04:00 [INF] Request reached the end of the middleware pipeline without being handled by application code. Request path: GET https://localhost:5001/.well-known/appspecific/com.chrome.devtools.json, Response status code: 404 diff --git a/src/ScadaLink.Host/wwwroot/.gitkeep b/src/ScadaLink.Host/wwwroot/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/ScadaLink.Security/ServiceCollectionExtensions.cs b/src/ScadaLink.Security/ServiceCollectionExtensions.cs index 6bf984b..e7c6eff 100644 --- a/src/ScadaLink.Security/ServiceCollectionExtensions.cs +++ b/src/ScadaLink.Security/ServiceCollectionExtensions.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.Extensions.DependencyInjection; namespace ScadaLink.Security; @@ -9,6 +10,18 @@ public static class ServiceCollectionExtensions services.AddScoped(); services.AddScoped(); services.AddScoped(); + + // Register ASP.NET Core authentication with cookie scheme + services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) + .AddCookie(options => + { + options.LoginPath = "/login"; + options.LogoutPath = "/auth/logout"; + options.Cookie.Name = "ScadaLink.Auth"; + options.Cookie.HttpOnly = true; + options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict; + }); + services.AddScadaLinkAuthorization(); return services;