Capcha fails with docker deployment

Dear SurveySolutions team,

We just ran into an issue where a user entered a wrong password several times in a row. This led to the account being locked for a certain amount of time. Following this, apparently, HQ tried to show a capcha, probably to prevent brute-force attacks. unfortunately, generation of the capcha failed and a 500 error page was shown instead. It looks like this happened because the software is running in a Docker container and the Times New Roman font is missing therein. This is the stack trace:

hq_1 | [13:35:17 ERR] Headquarters An unhandled exception has occurred while executing the request.
hq_1 | SixLabors.Fonts.Exceptions.FontFamilyNotFoundException: Times New Roman could not be found
hq_1 | at SixLabors.Fonts.FontCollection.FindInternal(String fontFamily, CultureInfo culture)
hq_1 | at SixLabors.Fonts.FontCollection.Find(String fontFamily)
hq_1 | at SixLabors.Fonts.SystemFontCollection.Find(String fontFamily)
hq_1 | at WB.UI.Shared.Web.Captcha.CaptchaImageGenerator.<>c__DisplayClass9_0.b__0(IImageProcessingContext ctx) in /src/UI/Shared/WB.UI.Shared.Web.Core/Captcha/CaptchaImageGenerator.cs:line 79
hq_1 | at SixLabors.ImageSharp.Processing.ProcessingExtensions.Mutate[TPixel](Image1 source, Configuration configuration, Action1 operation)
hq_1 | at SixLabors.ImageSharp.Processing.ProcessingExtensions.Mutate[TPixel](Image1 source, Action1 operation)
hq_1 | at WB.UI.Shared.Web.Captcha.CaptchaImageGenerator.Generate(String code, Int32 width, Int32 height) in /src/UI/Shared/WB.UI.Shared.Web.Core/Captcha/CaptchaImageGenerator.cs:line 77
hq_1 | at WB.UI.Shared.Web.Captcha.HostedCaptchaProvider.Render[T](IHtmlHelper1 html) in /src/UI/Shared/WB.UI.Shared.Web.Core/Captcha/HostedCaptchaProvider.cs:line 51 hq_1 | at AspNetCore.Views_Account_LogOn.ExecuteAsync() in /src/UI/WB.UI.Headquarters.Core/Views/Account/LogOn.cshtml:line 112 hq_1 | at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context) hq_1 | at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts) hq_1 | at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context) hq_1 | at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable1 statusCode)
hq_1 | at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable1 statusCode) hq_1 | at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, String contentType, Nullable1 statusCode)
hq_1 | at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
hq_1 | at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
hq_1 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
hq_1 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
hq_1 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
hq_1 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
hq_1 | — End of stack trace from previous location —
hq_1 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
hq_1 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
hq_1 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
hq_1 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
hq_1 | — End of stack trace from previous location —
hq_1 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
hq_1 | at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
hq_1 | at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
hq_1 | at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<b__1>d.MoveNext()
hq_1 | — End of stack trace from previous location —
hq_1 | at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.Invoke(HttpContext context)
hq_1 | at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
hq_1 | at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
hq_1 | at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
hq_1 | at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
hq_1 | at WB.UI.Headquarters.Code.Workspaces.WorkspaceRedirectMiddleware.Invoke(HttpContext context) in /src/UI/WB.UI.Headquarters.Core/Code/Workspaces/WorkspaceRedirectMiddleware.cs:line 62
hq_1 | at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
hq_1 | at Microsoft.AspNetCore.Builder.Extensions.MapMiddleware.Invoke(HttpContext context)
hq_1 | at WB.UI.Headquarters.Metrics.HeadquartersHttpMetricsMiddleware.<>c__DisplayClass5_0.<g__Next|0>d.MoveNext() in /src/UI/WB.UI.Headquarters.Core/Metrics/HeadquartersHttpMetricsMiddleware.cs:line 41
hq_1 | — End of stack trace from previous location —
hq_1 | at WB.UI.Headquarters.Metrics.HeadquartersHttpMetricsMiddleware.Invoke(HttpContext context) in /src/UI/WB.UI.Headquarters.Core/Metrics/HeadquartersHttpMetricsMiddleware.cs:line 92
hq_1 | at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)

Since the account is automatically unblocked after some time, we can sort of live with this, but still, it is a bit irritating. And others may want to use capchas more actively.

Kind regards,
Thorsten

Thank you for reporting the issue.
This indicates that “Times New Roman” is a requirement for a built-in captcha.
If this is causing troubles, please configure a Google captcha as a workaround.

Yeah, I understand what it means. The problem is, Times New Roman is not present in the container and it is a bit of a hassle to add it (would require building a new container with the font installed based on the existing one, which may not be straightforward for everyone). It feels wrong to get a 500 with the default setup. I guess you couldn’t bundle Times New Roman with the container, but maybe you could fall back to something that you can bundle, such as Liberation Serif or so.

And we cannot use Google stuff, unfortunately, due to data protection policies. Thanks for the tip, though.

Thank you for reporting it. As of now the only option for you is to build container on top of official one. We will address this issue in future releases.