@@ -1,4 +1,4 @@ | |||
<Project Sdk="Microsoft.NET.Sdk.Web"> | |||
<Project Sdk="Microsoft.NET.Sdk.Web"> | |||
<PropertyGroup> | |||
<TargetFramework>netcoreapp2.2</TargetFramework> | |||
@@ -18,7 +18,12 @@ namespace MQTTnet.Server.Web | |||
{ | |||
private readonly ILogger<AuthenticationHandler> _logger; | |||
public AuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory loggerFactory, UrlEncoder encoder, ISystemClock clock, ILogger<AuthenticationHandler> logger) | |||
public AuthenticationHandler( | |||
IOptionsMonitor<AuthenticationSchemeOptions> options, | |||
ILoggerFactory loggerFactory, | |||
UrlEncoder encoder, | |||
ISystemClock clock, | |||
ILogger<AuthenticationHandler> logger) | |||
: base(options, loggerFactory, encoder, clock) | |||
{ | |||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||
@@ -26,11 +31,9 @@ namespace MQTTnet.Server.Web | |||
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() | |||
{ | |||
await Task.CompletedTask; | |||
if (!Request.Headers.ContainsKey(HeaderNames.Authorization)) | |||
{ | |||
return AuthenticateResult.Fail("Missing Authorization Header"); | |||
return AuthenticateResult.NoResult(); | |||
} | |||
try | |||
@@ -83,6 +86,10 @@ namespace MQTTnet.Server.Web | |||
return AuthenticateResult.Fail(exception); | |||
} | |||
finally | |||
{ | |||
await Task.CompletedTask; | |||
} | |||
} | |||
private bool ValidateUser(PythonDictionary context) | |||
@@ -1,7 +1,9 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Net; | |||
using Microsoft.AspNetCore.Authentication; | |||
using Microsoft.AspNetCore.Authentication.Cookies; | |||
using Microsoft.AspNetCore.Builder; | |||
using Microsoft.AspNetCore.Hosting; | |||
using Microsoft.AspNetCore.Mvc; | |||
@@ -15,6 +17,7 @@ using MQTTnet.Server.Logging; | |||
using MQTTnet.Server.Mqtt; | |||
using MQTTnet.Server.Scripting; | |||
using MQTTnet.Server.Scripting.DataSharing; | |||
using Swashbuckle.AspNetCore.SwaggerGen; | |||
using Swashbuckle.AspNetCore.SwaggerUI; | |||
namespace MQTTnet.Server.Web | |||
@@ -115,17 +118,22 @@ namespace MQTTnet.Server.Web | |||
services.AddSwaggerGen(c => | |||
{ | |||
c.DescribeAllEnumsAsStrings(); | |||
c.AddSecurityDefinition("Basic", new OpenApiSecurityScheme | |||
var securityScheme = new OpenApiSecurityScheme | |||
{ | |||
Scheme = "Basic", | |||
Name = HeaderNames.Authorization, | |||
Type = SecuritySchemeType.Http, | |||
In = ParameterLocation.Header | |||
}); | |||
}; | |||
c.AddSecurityDefinition("Swagger", securityScheme); | |||
c.AddSecurityRequirement(new OpenApiSecurityRequirement | |||
{ | |||
[new OpenApiSecurityScheme { Name = "Basic" }] = new List<string>() | |||
[securityScheme] = new List<string>() | |||
}); | |||
c.SwaggerDoc("v1", new OpenApiInfo | |||
{ | |||
Title = "MQTTnet.Server API", | |||
@@ -145,7 +153,9 @@ namespace MQTTnet.Server.Web | |||
}); | |||
}); | |||
services.AddAuthentication("Basic").AddScheme<AuthenticationSchemeOptions, AuthenticationHandler>("Basic", null); | |||
services.AddAuthentication("Basic") | |||
.AddScheme<AuthenticationSchemeOptions, AuthenticationHandler>("Basic", null) | |||
.AddCookie(); | |||
} | |||
private void ReadMqttSettings(IServiceCollection services) | |||
@@ -200,7 +210,7 @@ namespace MQTTnet.Server.Web | |||
} | |||
else | |||
{ | |||
context.Response.StatusCode = 400; | |||
context.Response.StatusCode = (int)HttpStatusCode.BadRequest; | |||
} | |||
} | |||
else | |||
@@ -2,9 +2,19 @@ | |||
""" | |||
This function is invoked whenever a user tries to access protected HTTP resources. | |||
This function must exist and return a proper value. Otherwise the request is denied. | |||
All authentication data must be sent via using the "Authorization" header. This header | |||
will be parsed and all values will be exposed to the context. | |||
""" | |||
header_value = context["header_value"] # The untouched header value. | |||
username = context["username"] | |||
password = context["password"] | |||
scheme = context["scheme"] | |||
parameter = context["parameter"] | |||
context["is_authenticated"] = True # Change this to _False_ in case of invalid credentials. | |||
username = context["username"] # Only set if proper "Basic" authorization is used. | |||
password = context["password"] # Only set if proper "Basic" authorization is used. | |||
context["is_authenticated"] = True # Change this to _False_ in case of invalid credentials. | |||
# Example for an API key with proper format. | |||
if header_value == "APIKey 123456": | |||
context["is_authenticated"] = True |
@@ -38,10 +38,10 @@ | |||
}, | |||
"CommunicationTimeout": 15, // In seconds. | |||
"ConnectionBacklog": 10, // Set 0 to disable | |||
"EnablePersistentSessions": false, | |||
"EnablePersistentSessions": true, | |||
"MaxPendingMessagesPerClient": 250, | |||
"RetainedApplicationMessages": { | |||
"Persist": false, | |||
"Persist": true, | |||
"Path": "RetainedApplicationMessages.json", | |||
"WriteInterval": 10 // In seconds. | |||
}, | |||