mirror of
https://github.com/bitwarden/server.git
synced 2025-04-07 05:58:13 -05:00
added installations, push scoped tokens, push api
This commit is contained in:
parent
6ff9aeac97
commit
e538817eb6
26
src/Api/Controllers/PushController.cs
Normal file
26
src/Api/Controllers/PushController.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
namespace Bit.Api.Controllers
|
||||||
|
{
|
||||||
|
[Route("push")]
|
||||||
|
[Authorize("Push")]
|
||||||
|
public class PushController : Controller
|
||||||
|
{
|
||||||
|
private readonly IPushRegistrationService _pushRegistrationService;
|
||||||
|
|
||||||
|
public PushController(
|
||||||
|
IPushRegistrationService pushRegistrationService)
|
||||||
|
{
|
||||||
|
_pushRegistrationService = pushRegistrationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("register")]
|
||||||
|
public Object Register()
|
||||||
|
{
|
||||||
|
return new { Foo = "bar" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -86,6 +86,11 @@ namespace Bit.Api
|
|||||||
policy.RequireClaim(JwtClaimTypes.Scope, "api");
|
policy.RequireClaim(JwtClaimTypes.Scope, "api");
|
||||||
policy.RequireClaim(JwtClaimTypes.ClientId, "web");
|
policy.RequireClaim(JwtClaimTypes.ClientId, "web");
|
||||||
});
|
});
|
||||||
|
config.AddPolicy("Push", policy =>
|
||||||
|
{
|
||||||
|
policy.RequireAuthenticatedUser();
|
||||||
|
policy.RequireClaim(JwtClaimTypes.Scope, "api.push");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddScoped<AuthenticatorTokenProvider>();
|
services.AddScoped<AuthenticatorTokenProvider>();
|
||||||
@ -179,9 +184,8 @@ namespace Bit.Api
|
|||||||
var options = new IdentityServerAuthenticationOptions
|
var options = new IdentityServerAuthenticationOptions
|
||||||
{
|
{
|
||||||
Authority = globalSettings.BaseServiceUri.InternalIdentity,
|
Authority = globalSettings.BaseServiceUri.InternalIdentity,
|
||||||
AllowedScopes = new string[] { "api" },
|
AllowedScopes = new string[] { "api", "api.push" },
|
||||||
RequireHttpsMetadata = !env.IsDevelopment() && globalSettings.BaseServiceUri.InternalIdentity.StartsWith("https"),
|
RequireHttpsMetadata = !env.IsDevelopment() && globalSettings.BaseServiceUri.InternalIdentity.StartsWith("https"),
|
||||||
ApiName = "api",
|
|
||||||
NameClaimType = ClaimTypes.Email,
|
NameClaimType = ClaimTypes.Email,
|
||||||
// Suffix until we retire the old jwt schemes.
|
// Suffix until we retire the old jwt schemes.
|
||||||
AuthenticationScheme = $"Bearer{suffix}",
|
AuthenticationScheme = $"Bearer{suffix}",
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using IdentityModel;
|
using IdentityModel;
|
||||||
using IdentityServer4.Models;
|
using IdentityServer4.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
namespace Bit.Core.IdentityServer
|
namespace Bit.Core.IdentityServer
|
||||||
{
|
{
|
||||||
@ -21,7 +20,8 @@ namespace Bit.Core.IdentityServer
|
|||||||
"orgowner",
|
"orgowner",
|
||||||
"orgadmin",
|
"orgadmin",
|
||||||
"orguser"
|
"orguser"
|
||||||
})
|
}),
|
||||||
|
new ApiResource("api.push")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
49
src/Core/IdentityServer/ClientStore.cs
Normal file
49
src/Core/IdentityServer/ClientStore.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using IdentityServer4.Stores;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using IdentityServer4.Models;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Bit.Core.Repositories;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bit.Core.IdentityServer
|
||||||
|
{
|
||||||
|
public class ClientStore : IClientStore
|
||||||
|
{
|
||||||
|
private static IDictionary<string, Client> _apiClients = StaticClients.GetApiClients();
|
||||||
|
|
||||||
|
private readonly IInstallationRepository _installationRepository;
|
||||||
|
public ClientStore(
|
||||||
|
IInstallationRepository installationRepository)
|
||||||
|
{
|
||||||
|
_installationRepository = installationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Client> FindClientByIdAsync(string clientId)
|
||||||
|
{
|
||||||
|
if(clientId.StartsWith("installation."))
|
||||||
|
{
|
||||||
|
var idParts = clientId.Split('.');
|
||||||
|
Guid id;
|
||||||
|
if(idParts.Length > 1 && Guid.TryParse(idParts[1], out id))
|
||||||
|
{
|
||||||
|
var installation = await _installationRepository.GetByIdAsync(id);
|
||||||
|
if(installation != null)
|
||||||
|
{
|
||||||
|
return new Client
|
||||||
|
{
|
||||||
|
ClientId = $"installation.{installation.Id}",
|
||||||
|
RequireClientSecret = true,
|
||||||
|
ClientSecrets = { new Secret(installation.Key.Sha256()) },
|
||||||
|
AllowedScopes = new string[] { "api.push" },
|
||||||
|
AllowedGrantTypes = GrantTypes.ClientCredentials,
|
||||||
|
AccessTokenLifetime = 3600 * 24,
|
||||||
|
Enabled = installation.Enabled
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _apiClients.ContainsKey(clientId) ? _apiClients[clientId] : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
using IdentityServer4.Models;
|
using IdentityServer4.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Bit.Core.IdentityServer
|
namespace Bit.Core.IdentityServer
|
||||||
{
|
{
|
||||||
public class Clients
|
public class StaticClients
|
||||||
{
|
{
|
||||||
public static IEnumerable<Client> GetClients()
|
public static IDictionary<string, Client> GetApiClients()
|
||||||
{
|
{
|
||||||
return new List<Client>
|
return new List<Client>
|
||||||
{
|
{
|
||||||
@ -14,7 +15,7 @@ namespace Bit.Core.IdentityServer
|
|||||||
new ApiClient("browser", 30, 1),
|
new ApiClient("browser", 30, 1),
|
||||||
new ApiClient("desktop", 30, 1),
|
new ApiClient("desktop", 30, 1),
|
||||||
new ApiClient("connector", 30, 24)
|
new ApiClient("connector", 30, 24)
|
||||||
};
|
}.ToDictionary(c => c.ClientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ApiClient : Client
|
public class ApiClient : Client
|
19
src/Core/Models/Table/Installation.cs
Normal file
19
src/Core/Models/Table/Installation.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using Bit.Core.Utilities;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Table
|
||||||
|
{
|
||||||
|
public class Installation : ITableObject<Guid>
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string Key { get; set; }
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
public void SetNewId()
|
||||||
|
{
|
||||||
|
Id = CoreHelpers.GenerateComb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
src/Core/Repositories/IInstallationRepository.cs
Normal file
9
src/Core/Repositories/IInstallationRepository.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Models.Table;
|
||||||
|
|
||||||
|
namespace Bit.Core.Repositories
|
||||||
|
{
|
||||||
|
public interface IInstallationRepository : IRepository<Installation, Guid>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
16
src/Core/Repositories/SqlServer/InstallationRepository.cs
Normal file
16
src/Core/Repositories/SqlServer/InstallationRepository.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Models.Table;
|
||||||
|
|
||||||
|
namespace Bit.Core.Repositories.SqlServer
|
||||||
|
{
|
||||||
|
public class InstallationRepository : Repository<Installation, Guid>, IInstallationRepository
|
||||||
|
{
|
||||||
|
public InstallationRepository(GlobalSettings globalSettings)
|
||||||
|
: this(globalSettings.SqlServer.ConnectionString)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InstallationRepository(string connectionString)
|
||||||
|
: base(connectionString)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,7 @@ namespace Bit.Core.Services
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var installation = new Installation
|
var installation = new Microsoft.Azure.NotificationHubs.Installation
|
||||||
{
|
{
|
||||||
InstallationId = device.Id.ToString(),
|
InstallationId = device.Id.ToString(),
|
||||||
PushChannel = device.PushToken,
|
PushChannel = device.PushToken,
|
||||||
@ -85,8 +85,8 @@ namespace Bit.Core.Services
|
|||||||
await _client.CreateOrUpdateInstallationAsync(installation);
|
await _client.CreateOrUpdateInstallationAsync(installation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildInstallationTemplate(Installation installation, string templateId, string templateBody,
|
private void BuildInstallationTemplate(Microsoft.Azure.NotificationHubs.Installation installation,
|
||||||
Guid userId, string deviceIdentifier)
|
string templateId, string templateBody, Guid userId, string deviceIdentifier)
|
||||||
{
|
{
|
||||||
if(templateBody == null)
|
if(templateBody == null)
|
||||||
{
|
{
|
||||||
|
@ -39,6 +39,7 @@ namespace Bit.Core.Utilities
|
|||||||
services.AddSingleton<ICollectionCipherRepository, SqlServerRepos.CollectionCipherRepository>();
|
services.AddSingleton<ICollectionCipherRepository, SqlServerRepos.CollectionCipherRepository>();
|
||||||
services.AddSingleton<IGroupRepository, SqlServerRepos.GroupRepository>();
|
services.AddSingleton<IGroupRepository, SqlServerRepos.GroupRepository>();
|
||||||
services.AddSingleton<IU2fRepository, SqlServerRepos.U2fRepository>();
|
services.AddSingleton<IU2fRepository, SqlServerRepos.U2fRepository>();
|
||||||
|
services.AddSingleton<IInstallationRepository, SqlServerRepos.InstallationRepository>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddBaseServices(this IServiceCollection services)
|
public static void AddBaseServices(this IServiceCollection services)
|
||||||
@ -158,7 +159,7 @@ namespace Bit.Core.Utilities
|
|||||||
{
|
{
|
||||||
SecurityStampClaimType = "sstamp",
|
SecurityStampClaimType = "sstamp",
|
||||||
UserNameClaimType = JwtClaimTypes.Email,
|
UserNameClaimType = JwtClaimTypes.Email,
|
||||||
UserIdClaimType = JwtClaimTypes.Subject,
|
UserIdClaimType = JwtClaimTypes.Subject
|
||||||
};
|
};
|
||||||
options.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider;
|
options.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider;
|
||||||
});
|
});
|
||||||
@ -190,11 +191,11 @@ namespace Bit.Core.Utilities
|
|||||||
options.Endpoints.EnableCheckSessionEndpoint = false;
|
options.Endpoints.EnableCheckSessionEndpoint = false;
|
||||||
options.Endpoints.EnableTokenRevocationEndpoint = false;
|
options.Endpoints.EnableTokenRevocationEndpoint = false;
|
||||||
options.IssuerUri = globalSettings.BaseServiceUri.InternalIdentity;
|
options.IssuerUri = globalSettings.BaseServiceUri.InternalIdentity;
|
||||||
|
options.Caching.ClientStoreExpiration = new TimeSpan(0, 5, 0);
|
||||||
})
|
})
|
||||||
|
.AddInMemoryCaching()
|
||||||
.AddInMemoryApiResources(ApiResources.GetApiResources())
|
.AddInMemoryApiResources(ApiResources.GetApiResources())
|
||||||
.AddInMemoryClients(Clients.GetClients());
|
.AddClientStoreCache<ClientStore>();
|
||||||
|
|
||||||
services.AddTransient<ICorsPolicyService, AllowAllCorsPolicyService>();
|
|
||||||
|
|
||||||
if(env.IsDevelopment())
|
if(env.IsDevelopment())
|
||||||
{
|
{
|
||||||
@ -217,6 +218,8 @@ namespace Bit.Core.Utilities
|
|||||||
throw new Exception("No identity certificate to use.");
|
throw new Exception("No identity certificate to use.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
services.AddTransient<ClientStore>();
|
||||||
|
services.AddTransient<ICorsPolicyService, AllowAllCorsPolicyService>();
|
||||||
services.AddScoped<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
|
services.AddScoped<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
|
||||||
services.AddScoped<IProfileService, ProfileService>();
|
services.AddScoped<IProfileService, ProfileService>();
|
||||||
services.AddSingleton<IPersistedGrantStore, PersistedGrantStore>();
|
services.AddSingleton<IPersistedGrantStore, PersistedGrantStore>();
|
||||||
|
@ -204,5 +204,11 @@
|
|||||||
<Build Include="dbo\Stored Procedures\Organization_UpdateStorage.sql" />
|
<Build Include="dbo\Stored Procedures\Organization_UpdateStorage.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\User_UpdateStorage.sql" />
|
<Build Include="dbo\Stored Procedures\User_UpdateStorage.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\Cipher_DeleteAttachment.sql" />
|
<Build Include="dbo\Stored Procedures\Cipher_DeleteAttachment.sql" />
|
||||||
|
<Build Include="dbo\Tables\Installation.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\Installation_Create.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\Installation_DeleteById.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\Installation_ReadById.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\Installation_Update.sql" />
|
||||||
|
<Build Include="dbo\Views\InstallationView.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
27
src/Sql/dbo/Stored Procedures/Installation_Create.sql
Normal file
27
src/Sql/dbo/Stored Procedures/Installation_Create.sql
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[Installation_Create]
|
||||||
|
@Id UNIQUEIDENTIFIER,
|
||||||
|
@Email NVARCHAR(50),
|
||||||
|
@Key VARCHAR(150),
|
||||||
|
@Enabled BIT,
|
||||||
|
@CreationDate DATETIME2(7)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
INSERT INTO [dbo].[Installation]
|
||||||
|
(
|
||||||
|
[Id],
|
||||||
|
[Email],
|
||||||
|
[Key],
|
||||||
|
[Enabled],
|
||||||
|
[CreationDate]
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
@Id,
|
||||||
|
@Email,
|
||||||
|
@Key,
|
||||||
|
@Enabled,
|
||||||
|
@CreationDate
|
||||||
|
)
|
||||||
|
END
|
12
src/Sql/dbo/Stored Procedures/Installation_DeleteById.sql
Normal file
12
src/Sql/dbo/Stored Procedures/Installation_DeleteById.sql
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[Installation_DeleteById]
|
||||||
|
@Id UNIQUEIDENTIFIER
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
DELETE
|
||||||
|
FROM
|
||||||
|
[dbo].[Installation]
|
||||||
|
WHERE
|
||||||
|
[Id] = @Id
|
||||||
|
END
|
13
src/Sql/dbo/Stored Procedures/Installation_ReadById.sql
Normal file
13
src/Sql/dbo/Stored Procedures/Installation_ReadById.sql
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[Installation_ReadById]
|
||||||
|
@Id UNIQUEIDENTIFIER
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[InstallationView]
|
||||||
|
WHERE
|
||||||
|
[Id] = @Id
|
||||||
|
END
|
20
src/Sql/dbo/Stored Procedures/Installation_Update.sql
Normal file
20
src/Sql/dbo/Stored Procedures/Installation_Update.sql
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[Installation_Update]
|
||||||
|
@Id UNIQUEIDENTIFIER,
|
||||||
|
@Email NVARCHAR(50),
|
||||||
|
@Key VARCHAR(150),
|
||||||
|
@Enabled BIT,
|
||||||
|
@CreationDate DATETIME2(7)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
UPDATE
|
||||||
|
[dbo].[Installation]
|
||||||
|
SET
|
||||||
|
[Email] = @Email,
|
||||||
|
[Key] = @Key,
|
||||||
|
[Enabled] = @Enabled,
|
||||||
|
[CreationDate] = @CreationDate
|
||||||
|
WHERE
|
||||||
|
[Id] = @Id
|
||||||
|
END
|
9
src/Sql/dbo/Tables/Installation.sql
Normal file
9
src/Sql/dbo/Tables/Installation.sql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE [dbo].[Installation] (
|
||||||
|
[Id] UNIQUEIDENTIFIER NOT NULL,
|
||||||
|
[Email] NVARCHAR (50) NOT NULL,
|
||||||
|
[Key] VARCHAR (150) NOT NULL,
|
||||||
|
[Enabled] BIT NOT NULL,
|
||||||
|
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||||
|
CONSTRAINT [PK_Installation] PRIMARY KEY CLUSTERED ([Id] ASC)
|
||||||
|
);
|
||||||
|
|
6
src/Sql/dbo/Views/InstallationView.sql
Normal file
6
src/Sql/dbo/Views/InstallationView.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
CREATE VIEW [dbo].[InstallationView]
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[Installation]
|
Loading…
x
Reference in New Issue
Block a user