mirror of
https://github.com/bitwarden/server.git
synced 2024-11-22 12:15:36 +01:00
internal identity authorization
This commit is contained in:
parent
25899fd326
commit
ff01ce5ca7
@ -11,6 +11,7 @@ namespace Bit.Core
|
||||
public virtual string LogDirectory { get; set; }
|
||||
public virtual string LicenseDirectory { get; set; }
|
||||
public virtual string PushRelayBaseUri { get; set; }
|
||||
public virtual string InternalIdentityKey { get; set; }
|
||||
public virtual bool DisableUserRegistration { get; set; }
|
||||
public virtual InstallationSettings Installation { get; set; } = new InstallationSettings();
|
||||
public virtual BaseServiceUriSettings BaseServiceUri { get; set; } = new BaseServiceUriSettings();
|
||||
|
@ -6,6 +6,7 @@ using Bit.Core.Repositories;
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using IdentityModel;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.IdentityServer
|
||||
{
|
||||
@ -14,15 +15,19 @@ namespace Bit.Core.IdentityServer
|
||||
private static IDictionary<string, Client> _apiClients = StaticClients.GetApiClients();
|
||||
|
||||
private readonly IInstallationRepository _installationRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
public ClientStore(
|
||||
IInstallationRepository installationRepository)
|
||||
IInstallationRepository installationRepository,
|
||||
GlobalSettings globalSettings)
|
||||
{
|
||||
_installationRepository = installationRepository;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
public async Task<Client> FindClientByIdAsync(string clientId)
|
||||
{
|
||||
if(clientId.StartsWith("installation."))
|
||||
if(!_globalSettings.SelfHosted && clientId.StartsWith("installation."))
|
||||
{
|
||||
var idParts = clientId.Split('.');
|
||||
if(idParts.Length > 1 && Guid.TryParse(idParts[1], out Guid id))
|
||||
@ -44,6 +49,29 @@ namespace Bit.Core.IdentityServer
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(_globalSettings.SelfHosted && clientId.StartsWith("internal.") &&
|
||||
CoreHelpers.SettingHasValue(_globalSettings.InternalIdentityKey))
|
||||
{
|
||||
var idParts = clientId.Split('.');
|
||||
if(idParts.Length > 1)
|
||||
{
|
||||
var id = idParts[1];
|
||||
if(!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
return new Client
|
||||
{
|
||||
ClientId = $"internal.{id}",
|
||||
RequireClientSecret = true,
|
||||
ClientSecrets = { new Secret(_globalSettings.InternalIdentityKey.Sha256()) },
|
||||
AllowedScopes = new string[] { "internal" },
|
||||
AllowedGrantTypes = GrantTypes.ClientCredentials,
|
||||
AccessTokenLifetime = 3600 * 24,
|
||||
Enabled = true,
|
||||
Claims = new List<Claim> { new Claim(JwtClaimTypes.Subject, id) }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _apiClients.ContainsKey(clientId) ? _apiClients[clientId] : null;
|
||||
}
|
||||
|
@ -12,35 +12,44 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public abstract class BaseRelayPushNotificationService
|
||||
public abstract class BaseIdentityClientService
|
||||
{
|
||||
private readonly string _identityScope;
|
||||
private readonly string _identityClientId;
|
||||
private readonly string _identityClientSecret;
|
||||
private readonly ILogger<BaseIdentityClientService> _logger;
|
||||
|
||||
private dynamic _decodedToken;
|
||||
private DateTime? _nextAuthAttempt = null;
|
||||
private readonly ILogger<BaseRelayPushNotificationService> _logger;
|
||||
|
||||
public BaseRelayPushNotificationService(
|
||||
GlobalSettings globalSettings,
|
||||
ILogger<BaseRelayPushNotificationService> logger)
|
||||
public BaseIdentityClientService(
|
||||
string baseClientServerUri,
|
||||
string baseIdentityServerUri,
|
||||
string identityScope,
|
||||
string identityClientId,
|
||||
string identityClientSecret,
|
||||
ILogger<BaseIdentityClientService> logger)
|
||||
{
|
||||
_identityScope = identityScope;
|
||||
_identityClientId = identityClientId;
|
||||
_identityClientSecret = identityClientSecret;
|
||||
_logger = logger;
|
||||
GlobalSettings = globalSettings;
|
||||
|
||||
PushClient = new HttpClient
|
||||
Client = new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri(globalSettings.PushRelayBaseUri)
|
||||
BaseAddress = new Uri(baseClientServerUri)
|
||||
};
|
||||
PushClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
|
||||
IdentityClient = new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri(globalSettings.Installation.IdentityUri)
|
||||
BaseAddress = new Uri(baseIdentityServerUri)
|
||||
};
|
||||
IdentityClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
}
|
||||
|
||||
protected HttpClient PushClient { get; private set; }
|
||||
protected HttpClient Client { get; private set; }
|
||||
protected HttpClient IdentityClient { get; private set; }
|
||||
protected GlobalSettings GlobalSettings { get; private set; }
|
||||
protected string AccessToken { get; private set; }
|
||||
|
||||
protected async Task<bool> HandleTokenStateAsync()
|
||||
@ -63,9 +72,9 @@ namespace Bit.Core.Services
|
||||
Content = new FormUrlEncodedContent(new Dictionary<string, string>
|
||||
{
|
||||
{ "grant_type", "client_credentials" },
|
||||
{ "scope", "api.push" },
|
||||
{ "client_id", $"installation.{GlobalSettings.Installation.Id}" },
|
||||
{ "client_secret", $"{GlobalSettings.Installation.Key}" }
|
||||
{ "scope", _identityScope },
|
||||
{ "client_id", _identityClientId },
|
||||
{ "client_secret", _identityClientSecret }
|
||||
})
|
||||
};
|
||||
|
||||
@ -76,7 +85,7 @@ namespace Bit.Core.Services
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
_logger.LogError(12339, e, "Unable to auth for push.");
|
||||
_logger.LogError(12339, e, "Unable to authenticate with identity server.");
|
||||
}
|
||||
|
||||
if(response == null)
|
@ -10,7 +10,7 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public class RelayPushNotificationService : BaseRelayPushNotificationService, IPushNotificationService
|
||||
public class RelayPushNotificationService : BaseIdentityClientService, IPushNotificationService
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<RelayPushNotificationService> _logger;
|
||||
@ -19,7 +19,13 @@ namespace Bit.Core.Services
|
||||
GlobalSettings globalSettings,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
ILogger<RelayPushNotificationService> logger)
|
||||
: base(globalSettings, logger)
|
||||
: base(
|
||||
globalSettings.PushRelayBaseUri,
|
||||
globalSettings.Installation.IdentityUri,
|
||||
"api.push",
|
||||
$"installation.{globalSettings.Installation.Id}",
|
||||
globalSettings.Installation.Key,
|
||||
logger)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_logger = logger;
|
||||
@ -168,12 +174,12 @@ namespace Bit.Core.Services
|
||||
var message = new TokenHttpRequestMessage(requestModel, AccessToken)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(string.Concat(PushClient.BaseAddress, "/push/send"))
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, "/push/send"))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await PushClient.SendAsync(message);
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -9,14 +9,20 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public class RelayPushRegistrationService : BaseRelayPushNotificationService, IPushRegistrationService
|
||||
public class RelayPushRegistrationService : BaseIdentityClientService, IPushRegistrationService
|
||||
{
|
||||
private readonly ILogger<RelayPushRegistrationService> _logger;
|
||||
|
||||
public RelayPushRegistrationService(
|
||||
GlobalSettings globalSettings,
|
||||
ILogger<RelayPushRegistrationService> logger)
|
||||
: base(globalSettings, logger)
|
||||
: base(
|
||||
globalSettings.PushRelayBaseUri,
|
||||
globalSettings.Installation.IdentityUri,
|
||||
"api.push",
|
||||
$"installation.{globalSettings.Installation.Id}",
|
||||
globalSettings.Installation.Key,
|
||||
logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
@ -42,12 +48,12 @@ namespace Bit.Core.Services
|
||||
var message = new TokenHttpRequestMessage(requestModel, AccessToken)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(string.Concat(PushClient.BaseAddress, "/push/register"))
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, "/push/register"))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await PushClient.SendAsync(message);
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@ -66,12 +72,12 @@ namespace Bit.Core.Services
|
||||
var message = new TokenHttpRequestMessage(AccessToken)
|
||||
{
|
||||
Method = HttpMethod.Delete,
|
||||
RequestUri = new Uri(string.Concat(PushClient.BaseAddress, "/push/", deviceId))
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, "/push/", deviceId))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await PushClient.SendAsync(message);
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@ -96,12 +102,12 @@ namespace Bit.Core.Services
|
||||
var message = new TokenHttpRequestMessage(requestModel, AccessToken)
|
||||
{
|
||||
Method = HttpMethod.Put,
|
||||
RequestUri = new Uri(string.Concat(PushClient.BaseAddress, "/push/add-organization"))
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, "/push/add-organization"))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await PushClient.SendAsync(message);
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@ -126,12 +132,12 @@ namespace Bit.Core.Services
|
||||
var message = new TokenHttpRequestMessage(requestModel, AccessToken)
|
||||
{
|
||||
Method = HttpMethod.Put,
|
||||
RequestUri = new Uri(string.Concat(PushClient.BaseAddress, "/push/delete-organization"))
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, "/push/delete-organization"))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await PushClient.SendAsync(message);
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -311,12 +311,9 @@ namespace Bit.Core.Utilities
|
||||
|
||||
public static bool SettingHasValue(string setting)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(setting) || setting.Equals("SECRET") || setting.Equals("REPLACE"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
var normalizedSetting = setting?.ToLowerInvariant();
|
||||
return !string.IsNullOrWhiteSpace(normalizedSetting) && !normalizedSetting.Equals("secret") &&
|
||||
!normalizedSetting.Equals("replace");
|
||||
}
|
||||
|
||||
public static string Base64UrlEncode(byte[] input)
|
||||
|
@ -234,7 +234,7 @@ namespace Bit.Core.Utilities
|
||||
|
||||
public static void AddIdentityAuthenticationServices(
|
||||
this IServiceCollection services, GlobalSettings globalSettings, IHostingEnvironment environment,
|
||||
Action<AuthorizationOptions> addAuthorization = null)
|
||||
Action<AuthorizationOptions> addAuthorization)
|
||||
{
|
||||
services
|
||||
.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
|
||||
@ -248,21 +248,13 @@ namespace Bit.Core.Utilities
|
||||
options.SupportedTokens = SupportedTokens.Jwt;
|
||||
});
|
||||
|
||||
services.AddAuthorization(config =>
|
||||
if(addAuthorization != null)
|
||||
{
|
||||
if(addAuthorization != null)
|
||||
services.AddAuthorization(config =>
|
||||
{
|
||||
addAuthorization?.Invoke(config);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.AddPolicy("Application", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser();
|
||||
policy.RequireClaim(JwtClaimTypes.AuthenticationMethod, "Application");
|
||||
});
|
||||
}
|
||||
});
|
||||
addAuthorization.Invoke(config);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static IIdentityServerBuilder AddCustomIdentityServerServices(
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Bit.Core;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using IdentityModel;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
@ -36,7 +37,15 @@ namespace Bit.Events
|
||||
services.AddScoped<CurrentContext>();
|
||||
|
||||
// Identity
|
||||
services.AddIdentityAuthenticationServices(globalSettings, Environment);
|
||||
services.AddIdentityAuthenticationServices(globalSettings, Environment, config =>
|
||||
{
|
||||
config.AddPolicy("Application", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser();
|
||||
policy.RequireClaim(JwtClaimTypes.AuthenticationMethod, "Application");
|
||||
policy.RequireClaim(JwtClaimTypes.Scope, "api");
|
||||
});
|
||||
});
|
||||
|
||||
// Services
|
||||
services.AddScoped<IEventService, EventService>();
|
||||
|
@ -6,7 +6,7 @@ using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace Bit.Hub
|
||||
{
|
||||
[Authorize("Application")]
|
||||
[Authorize("Internal")]
|
||||
public class EventsController : Controller
|
||||
{
|
||||
private readonly IHubContext<SyncHub> _syncHubContext;
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Bit.Core;
|
||||
using Bit.Core.Utilities;
|
||||
using IdentityModel;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
@ -37,7 +38,20 @@ namespace Bit.Hub
|
||||
services.AddScoped<CurrentContext>();
|
||||
|
||||
// Identity
|
||||
services.AddIdentityAuthenticationServices(globalSettings, Environment);
|
||||
services.AddIdentityAuthenticationServices(globalSettings, Environment, config =>
|
||||
{
|
||||
config.AddPolicy("Application", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser();
|
||||
policy.RequireClaim(JwtClaimTypes.AuthenticationMethod, "Application");
|
||||
policy.RequireClaim(JwtClaimTypes.Scope, "api");
|
||||
});
|
||||
config.AddPolicy("Internal", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser();
|
||||
policy.RequireClaim(JwtClaimTypes.Scope, "internal");
|
||||
});
|
||||
});
|
||||
|
||||
// SignalR
|
||||
services.AddSignalR();
|
||||
|
@ -49,7 +49,8 @@ namespace Bit.Setup
|
||||
["globalSettings__dataProtection__directory"] = $"{OutputDirectory}/core/aspnet-dataprotection",
|
||||
["globalSettings__logDirectory"] = $"{OutputDirectory}/logs",
|
||||
["globalSettings__licenseDirectory"] = $"{OutputDirectory}/core/licenses",
|
||||
["globalSettings__duo__aKey"] = $"{Helpers.SecureRandomString(64, alpha: true, numeric: true)}",
|
||||
["globalSettings__internalIdentityKey"] = Helpers.SecureRandomString(64, alpha: true, numeric: true),
|
||||
["globalSettings__duo__aKey"] = Helpers.SecureRandomString(64, alpha: true, numeric: true),
|
||||
["globalSettings__installation__id"] = InstallationId?.ToString(),
|
||||
["globalSettings__installation__key"] = InstallationKey,
|
||||
["globalSettings__yubico__clientId"] = "REPLACE",
|
||||
|
Loading…
Reference in New Issue
Block a user