13 changed files with 460 additions and 84 deletions
@ -0,0 +1,25 @@ |
|||||||
|
using System; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Microsoft.AspNetCore.Authorization; |
||||||
|
using Microsoft.AspNetCore.Mvc; |
||||||
|
using Microsoft.AspNetCore.SignalR; |
||||||
|
|
||||||
|
namespace Bit.Hub |
||||||
|
{ |
||||||
|
[Authorize("Application")] |
||||||
|
public class EventsController : Controller |
||||||
|
{ |
||||||
|
private readonly IHubContext<SyncHub> _syncHubContext; |
||||||
|
|
||||||
|
public EventsController(IHubContext<SyncHub> syncHubContext) |
||||||
|
{ |
||||||
|
_syncHubContext = syncHubContext; |
||||||
|
} |
||||||
|
|
||||||
|
[HttpGet("~/events")] |
||||||
|
public async Task GetTest() |
||||||
|
{ |
||||||
|
await _syncHubContext.Clients.All.SendAsync("ReceiveMessage", "From API."); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,19 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web"> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<Version>1.22.0</Version> |
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework> |
||||||
|
<RootNamespace>Bit.Hub</RootNamespace> |
||||||
|
<UserSecretsId>bitwarden-Hub</UserSecretsId> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.6.0" /> |
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<ProjectReference Include="..\Core\Core.csproj" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
</Project> |
||||||
@ -0,0 +1,17 @@ |
|||||||
|
using Microsoft.AspNetCore; |
||||||
|
using Microsoft.AspNetCore.Hosting; |
||||||
|
|
||||||
|
namespace Bit.Hub |
||||||
|
{ |
||||||
|
public class Program |
||||||
|
{ |
||||||
|
public static void Main(string[] args) |
||||||
|
{ |
||||||
|
WebHost |
||||||
|
.CreateDefaultBuilder(args) |
||||||
|
.UseStartup<Startup>() |
||||||
|
.Build() |
||||||
|
.Run(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,27 @@ |
|||||||
|
{ |
||||||
|
"iisSettings": { |
||||||
|
"windowsAuthentication": false, |
||||||
|
"anonymousAuthentication": true, |
||||||
|
"iisExpress": { |
||||||
|
"applicationUrl": "http://localhost:61840", |
||||||
|
"sslPort": 0 |
||||||
|
} |
||||||
|
}, |
||||||
|
"profiles": { |
||||||
|
"IIS Express": { |
||||||
|
"commandName": "IISExpress", |
||||||
|
"launchBrowser": true, |
||||||
|
"environmentVariables": { |
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development" |
||||||
|
} |
||||||
|
}, |
||||||
|
"Bit.Hub": { |
||||||
|
"commandName": "Project", |
||||||
|
"launchBrowser": true, |
||||||
|
"applicationUrl": "http://localhost:5000", |
||||||
|
"environmentVariables": { |
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,121 @@ |
|||||||
|
using System.Security.Claims; |
||||||
|
using Bit.Core; |
||||||
|
using Bit.Core.IdentityServer; |
||||||
|
using Bit.Core.Services; |
||||||
|
using Bit.Core.Utilities; |
||||||
|
using IdentityModel; |
||||||
|
using IdentityServer4.AccessTokenValidation; |
||||||
|
using Microsoft.AspNetCore.Builder; |
||||||
|
using Microsoft.AspNetCore.Hosting; |
||||||
|
using Microsoft.AspNetCore.SignalR; |
||||||
|
using Microsoft.Extensions.Configuration; |
||||||
|
using Microsoft.Extensions.DependencyInjection; |
||||||
|
using Microsoft.Extensions.Logging; |
||||||
|
using Microsoft.IdentityModel.Logging; |
||||||
|
using Serilog.Events; |
||||||
|
|
||||||
|
namespace Bit.Hub |
||||||
|
{ |
||||||
|
public class Startup |
||||||
|
{ |
||||||
|
public Startup(IHostingEnvironment env, IConfiguration configuration) |
||||||
|
{ |
||||||
|
Configuration = configuration; |
||||||
|
Environment = env; |
||||||
|
} |
||||||
|
|
||||||
|
public IConfiguration Configuration { get; } |
||||||
|
public IHostingEnvironment Environment { get; set; } |
||||||
|
|
||||||
|
public void ConfigureServices(IServiceCollection services) |
||||||
|
{ |
||||||
|
// Options |
||||||
|
services.AddOptions(); |
||||||
|
|
||||||
|
// Settings |
||||||
|
var globalSettings = services.AddGlobalSettingsServices(Configuration); |
||||||
|
|
||||||
|
// Repositories |
||||||
|
services.AddSqlServerRepositories(globalSettings); |
||||||
|
|
||||||
|
// Context |
||||||
|
services.AddScoped<CurrentContext>(); |
||||||
|
|
||||||
|
// Identity |
||||||
|
services |
||||||
|
.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme) |
||||||
|
.AddIdentityServerAuthentication(options => |
||||||
|
{ |
||||||
|
options.Authority = globalSettings.BaseServiceUri.InternalIdentity; |
||||||
|
options.RequireHttpsMetadata = !Environment.IsDevelopment() && |
||||||
|
globalSettings.BaseServiceUri.InternalIdentity.StartsWith("https"); |
||||||
|
options.TokenRetriever = TokenRetrieval.FromAuthorizationHeaderOrQueryString(); |
||||||
|
options.NameClaimType = ClaimTypes.Email; |
||||||
|
options.SupportedTokens = SupportedTokens.Jwt; |
||||||
|
}); |
||||||
|
|
||||||
|
services.AddAuthorization(config => |
||||||
|
{ |
||||||
|
config.AddPolicy("Application", policy => |
||||||
|
{ |
||||||
|
policy.RequireAuthenticatedUser(); |
||||||
|
policy.RequireClaim(JwtClaimTypes.AuthenticationMethod, "Application"); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
// SignalR |
||||||
|
services.AddSignalR(); |
||||||
|
services.AddSingleton<IUserIdProvider, SubjectUserIdProvider>(); |
||||||
|
|
||||||
|
// Mvc |
||||||
|
services.AddMvc(); |
||||||
|
|
||||||
|
// Hosted Services |
||||||
|
services.AddHostedService<TimedHostedService>(); |
||||||
|
} |
||||||
|
|
||||||
|
public void Configure( |
||||||
|
IApplicationBuilder app, |
||||||
|
IHostingEnvironment env, |
||||||
|
ILoggerFactory loggerFactory, |
||||||
|
IApplicationLifetime appLifetime, |
||||||
|
GlobalSettings globalSettings) |
||||||
|
{ |
||||||
|
IdentityModelEventSource.ShowPII = true; |
||||||
|
loggerFactory.AddSerilog(app, env, appLifetime, globalSettings, (e) => |
||||||
|
{ |
||||||
|
var context = e.Properties["SourceContext"].ToString(); |
||||||
|
if(context.Contains("IdentityServer4.Validation.TokenValidator") || |
||||||
|
context.Contains("IdentityServer4.Validation.TokenRequestValidator")) |
||||||
|
{ |
||||||
|
return e.Level > LogEventLevel.Error; |
||||||
|
} |
||||||
|
|
||||||
|
return e.Level >= LogEventLevel.Error; |
||||||
|
}); |
||||||
|
|
||||||
|
if(env.IsDevelopment()) |
||||||
|
{ |
||||||
|
app.UseDeveloperExceptionPage(); |
||||||
|
} |
||||||
|
|
||||||
|
// Default Middleware |
||||||
|
app.UseDefaultMiddleware(env); |
||||||
|
|
||||||
|
// Add Cors |
||||||
|
app.UseCors(policy => policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials()); |
||||||
|
|
||||||
|
// Add authentication to the request pipeline. |
||||||
|
app.UseAuthentication(); |
||||||
|
|
||||||
|
// Add SignlarR |
||||||
|
app.UseSignalR(routes => |
||||||
|
{ |
||||||
|
routes.MapHub<SyncHub>("/sync"); |
||||||
|
}); |
||||||
|
|
||||||
|
// Add MVC to the request pipeline. |
||||||
|
app.UseMvc(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
using IdentityModel; |
||||||
|
using Microsoft.AspNetCore.SignalR; |
||||||
|
|
||||||
|
namespace Bit.Hub |
||||||
|
{ |
||||||
|
public class SubjectUserIdProvider : IUserIdProvider |
||||||
|
{ |
||||||
|
public string GetUserId(HubConnectionContext connection) |
||||||
|
{ |
||||||
|
return connection.User?.FindFirst(JwtClaimTypes.Subject)?.Value; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,33 @@ |
|||||||
|
using System; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Bit.Core; |
||||||
|
using Microsoft.AspNetCore.Authorization; |
||||||
|
|
||||||
|
namespace Bit.Hub |
||||||
|
{ |
||||||
|
[Authorize("Application")] |
||||||
|
public class SyncHub : Microsoft.AspNetCore.SignalR.Hub |
||||||
|
{ |
||||||
|
public override async Task OnConnectedAsync() |
||||||
|
{ |
||||||
|
var currentContext = new CurrentContext(); |
||||||
|
currentContext.Build(Context.User); |
||||||
|
foreach(var org in currentContext.Organizations) |
||||||
|
{ |
||||||
|
await Groups.AddToGroupAsync(Context.ConnectionId, $"Organization_{org.Id}"); |
||||||
|
} |
||||||
|
await base.OnConnectedAsync(); |
||||||
|
} |
||||||
|
|
||||||
|
public override async Task OnDisconnectedAsync(Exception exception) |
||||||
|
{ |
||||||
|
var currentContext = new CurrentContext(); |
||||||
|
currentContext.Build(Context.User); |
||||||
|
foreach(var org in currentContext.Organizations) |
||||||
|
{ |
||||||
|
await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"Organization_{org.Id}"); |
||||||
|
} |
||||||
|
await base.OnDisconnectedAsync(exception); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,47 @@ |
|||||||
|
using System; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Microsoft.AspNetCore.SignalR; |
||||||
|
using Microsoft.Extensions.Hosting; |
||||||
|
using Microsoft.Extensions.Logging; |
||||||
|
|
||||||
|
namespace Bit.Hub |
||||||
|
{ |
||||||
|
public class TimedHostedService : IHostedService, IDisposable |
||||||
|
{ |
||||||
|
private readonly ILogger _logger; |
||||||
|
private readonly IHubContext<SyncHub> _hubContext; |
||||||
|
private Timer _timer; |
||||||
|
|
||||||
|
public TimedHostedService(ILogger<TimedHostedService> logger, IHubContext<SyncHub> hubContext) |
||||||
|
{ |
||||||
|
_logger = logger; |
||||||
|
_hubContext = hubContext; |
||||||
|
} |
||||||
|
|
||||||
|
public Task StartAsync(CancellationToken cancellationToken) |
||||||
|
{ |
||||||
|
_logger.LogInformation("Timed Background Service is starting."); |
||||||
|
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5)); |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
private void DoWork(object state) |
||||||
|
{ |
||||||
|
_logger.LogInformation("Timed Background Service is working."); |
||||||
|
_hubContext.Clients.All.SendAsync("ReceiveMessage", "From BG!!"); |
||||||
|
} |
||||||
|
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken) |
||||||
|
{ |
||||||
|
_logger.LogInformation("Timed Background Service is stopping."); |
||||||
|
_timer?.Change(Timeout.Infinite, 0); |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public void Dispose() |
||||||
|
{ |
||||||
|
_timer?.Dispose(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,14 @@ |
|||||||
|
{ |
||||||
|
"globalSettings": { |
||||||
|
"baseServiceUri": { |
||||||
|
"vault": "https://vault.bitwarden.com", |
||||||
|
"api": "https://api.bitwarden.com", |
||||||
|
"identity": "https://identity.bitwarden.com", |
||||||
|
"admin": "https://admin.bitwarden.com", |
||||||
|
"internalAdmin": "https://admin.bitwarden.com", |
||||||
|
"internalIdentity": "https://identity.bitwarden.com", |
||||||
|
"internalApi": "https://api.bitwarden.com", |
||||||
|
"internalVault": "https://vault.bitwarden.com" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
{ |
||||||
|
"globalSettings": { |
||||||
|
"selfHosted": false, |
||||||
|
"projectName": "Hub", |
||||||
|
"baseServiceUri": { |
||||||
|
"vault": "https://localhost:8080", |
||||||
|
"api": "http://localhost:4000", |
||||||
|
"identity": "http://localhost:33656", |
||||||
|
"admin": "http://localhost:62911", |
||||||
|
"internalAdmin": "http://localhost:62911", |
||||||
|
"internalIdentity": "http://localhost:33656", |
||||||
|
"internalApi": "http://localhost:4000", |
||||||
|
"internalVault": "http://localhost:4001" |
||||||
|
}, |
||||||
|
"sqlServer": { |
||||||
|
"connectionString": "SECRET" |
||||||
|
}, |
||||||
|
"identityServer": { |
||||||
|
"certificateThumbprint": "SECRET" |
||||||
|
}, |
||||||
|
"storage": { |
||||||
|
"connectionString": "SECRET" |
||||||
|
}, |
||||||
|
"events": { |
||||||
|
"connectionString": "SECRET" |
||||||
|
}, |
||||||
|
"documentDb": { |
||||||
|
"uri": "SECRET", |
||||||
|
"key": "SECRET" |
||||||
|
}, |
||||||
|
"sentry": { |
||||||
|
"dsn": "SECRET" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue