1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-06 05:28:15 -05:00

added installations, push scoped tokens, push api

This commit is contained in:
Kyle Spearrin 2017-08-10 14:39:11 -04:00
parent 6ff9aeac97
commit e538817eb6
17 changed files with 234 additions and 14 deletions

View 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" };
}
}
}

View File

@ -86,6 +86,11 @@ namespace Bit.Api
policy.RequireClaim(JwtClaimTypes.Scope, "api");
policy.RequireClaim(JwtClaimTypes.ClientId, "web");
});
config.AddPolicy("Push", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim(JwtClaimTypes.Scope, "api.push");
});
});
services.AddScoped<AuthenticatorTokenProvider>();
@ -179,9 +184,8 @@ namespace Bit.Api
var options = new IdentityServerAuthenticationOptions
{
Authority = globalSettings.BaseServiceUri.InternalIdentity,
AllowedScopes = new string[] { "api" },
AllowedScopes = new string[] { "api", "api.push" },
RequireHttpsMetadata = !env.IsDevelopment() && globalSettings.BaseServiceUri.InternalIdentity.StartsWith("https"),
ApiName = "api",
NameClaimType = ClaimTypes.Email,
// Suffix until we retire the old jwt schemes.
AuthenticationScheme = $"Bearer{suffix}",

View File

@ -1,7 +1,6 @@
using IdentityModel;
using IdentityServer4.Models;
using System.Collections.Generic;
using System.Security.Claims;
namespace Bit.Core.IdentityServer
{
@ -21,7 +20,8 @@ namespace Bit.Core.IdentityServer
"orgowner",
"orgadmin",
"orguser"
})
}),
new ApiResource("api.push")
};
}
}

View 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;
}
}
}

View File

@ -1,11 +1,12 @@
using IdentityServer4.Models;
using System.Collections.Generic;
using System.Linq;
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>
{
@ -14,7 +15,7 @@ namespace Bit.Core.IdentityServer
new ApiClient("browser", 30, 1),
new ApiClient("desktop", 30, 1),
new ApiClient("connector", 30, 24)
};
}.ToDictionary(c => c.ClientId);
}
public class ApiClient : Client

View 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();
}
}
}

View File

@ -0,0 +1,9 @@
using System;
using Bit.Core.Models.Table;
namespace Bit.Core.Repositories
{
public interface IInstallationRepository : IRepository<Installation, Guid>
{
}
}

View 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)
{ }
}
}

View File

@ -30,7 +30,7 @@ namespace Bit.Core.Services
return;
}
var installation = new Installation
var installation = new Microsoft.Azure.NotificationHubs.Installation
{
InstallationId = device.Id.ToString(),
PushChannel = device.PushToken,
@ -85,8 +85,8 @@ namespace Bit.Core.Services
await _client.CreateOrUpdateInstallationAsync(installation);
}
private void BuildInstallationTemplate(Installation installation, string templateId, string templateBody,
Guid userId, string deviceIdentifier)
private void BuildInstallationTemplate(Microsoft.Azure.NotificationHubs.Installation installation,
string templateId, string templateBody, Guid userId, string deviceIdentifier)
{
if(templateBody == null)
{

View File

@ -39,6 +39,7 @@ namespace Bit.Core.Utilities
services.AddSingleton<ICollectionCipherRepository, SqlServerRepos.CollectionCipherRepository>();
services.AddSingleton<IGroupRepository, SqlServerRepos.GroupRepository>();
services.AddSingleton<IU2fRepository, SqlServerRepos.U2fRepository>();
services.AddSingleton<IInstallationRepository, SqlServerRepos.InstallationRepository>();
}
public static void AddBaseServices(this IServiceCollection services)
@ -158,7 +159,7 @@ namespace Bit.Core.Utilities
{
SecurityStampClaimType = "sstamp",
UserNameClaimType = JwtClaimTypes.Email,
UserIdClaimType = JwtClaimTypes.Subject,
UserIdClaimType = JwtClaimTypes.Subject
};
options.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider;
});
@ -190,11 +191,11 @@ namespace Bit.Core.Utilities
options.Endpoints.EnableCheckSessionEndpoint = false;
options.Endpoints.EnableTokenRevocationEndpoint = false;
options.IssuerUri = globalSettings.BaseServiceUri.InternalIdentity;
options.Caching.ClientStoreExpiration = new TimeSpan(0, 5, 0);
})
.AddInMemoryCaching()
.AddInMemoryApiResources(ApiResources.GetApiResources())
.AddInMemoryClients(Clients.GetClients());
services.AddTransient<ICorsPolicyService, AllowAllCorsPolicyService>();
.AddClientStoreCache<ClientStore>();
if(env.IsDevelopment())
{
@ -217,6 +218,8 @@ namespace Bit.Core.Utilities
throw new Exception("No identity certificate to use.");
}
services.AddTransient<ClientStore>();
services.AddTransient<ICorsPolicyService, AllowAllCorsPolicyService>();
services.AddScoped<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
services.AddScoped<IProfileService, ProfileService>();
services.AddSingleton<IPersistedGrantStore, PersistedGrantStore>();

View File

@ -204,5 +204,11 @@
<Build Include="dbo\Stored Procedures\Organization_UpdateStorage.sql" />
<Build Include="dbo\Stored Procedures\User_UpdateStorage.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>
</Project>

View 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

View 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

View 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

View 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

View 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)
);

View File

@ -0,0 +1,6 @@
CREATE VIEW [dbo].[InstallationView]
AS
SELECT
*
FROM
[dbo].[Installation]