1
0
mirror of https://github.com/bitwarden/server.git synced 2025-02-02 23:41:21 +01:00

added user orgs to claims

This commit is contained in:
Kyle Spearrin 2017-04-05 15:31:33 -04:00
parent fee9bde12f
commit a474449354
7 changed files with 81 additions and 5 deletions

View File

@ -20,7 +20,10 @@ namespace Bit.Api.IdentityServer
"email",
"sstamp", // security stamp
"plan",
"device"
"device",
"orgowner",
"orgadmin",
"orguser"
})
};
}

View File

@ -18,7 +18,7 @@ namespace Bit.Api.IdentityServer
public class ApiClient : Client
{
public ApiClient(string id)
public ApiClient(string id, string[] additionalScopes = null)
{
ClientId = id;
RequireClientSecret = false;
@ -26,7 +26,13 @@ namespace Bit.Api.IdentityServer
UpdateAccessTokenClaimsOnRefresh = true;
AccessTokenLifetime = 60 * 60; // 1 hour
AllowOfflineAccess = true;
AllowedScopes = new string[] { "api" };
var scopes = new List<string> { "api" };
if(additionalScopes != null)
{
scopes.AddRange(additionalScopes);
}
AllowedScopes = scopes;
}
}
}

View File

@ -16,15 +16,18 @@ namespace Bit.Api.IdentityServer
{
private readonly IUserService _userService;
private readonly IUserRepository _userRepository;
private readonly IOrganizationUserRepository _organizationUserRepository;
private IdentityOptions _identityOptions;
public ProfileService(
IUserRepository userRepository,
IUserService userService,
IOrganizationUserRepository organizationUserRepository,
IOptions<IdentityOptions> identityOptionsAccessor)
{
_userRepository = userRepository;
_userService = userService;
_organizationUserRepository = organizationUserRepository;
_identityOptions = identityOptionsAccessor?.Value ?? new IdentityOptions();
}
@ -42,7 +45,7 @@ namespace Bit.Api.IdentityServer
new Claim("sstamp", user.SecurityStamp),
new Claim("email", user.Email),
// Deprecated claims for backwards compatability,
// Deprecated claims for backwards compatability
new Claim(_identityOptions.ClaimsIdentity.UserNameClaimType, user.Email),
new Claim(_identityOptions.ClaimsIdentity.SecurityStampClaimType, user.SecurityStamp)
});
@ -51,11 +54,47 @@ namespace Bit.Api.IdentityServer
{
newClaims.Add(new Claim("name", user.Name));
}
// Orgs that this user belongs to
var orgs = await _organizationUserRepository.GetManyByUserAsync(user.Id);
if(orgs.Any())
{
var groupedOrgs = orgs.Where(o => o.Status == Core.Enums.OrganizationUserStatusType.Confirmed)
.GroupBy(o => o.Type);
foreach(var group in groupedOrgs)
{
switch(group.Key)
{
case Core.Enums.OrganizationUserType.Owner:
foreach(var org in group)
{
newClaims.Add(new Claim("orgowner", org.Id.ToString()));
}
break;
case Core.Enums.OrganizationUserType.Admin:
foreach(var org in group)
{
newClaims.Add(new Claim("orgadmin", org.Id.ToString()));
}
break;
case Core.Enums.OrganizationUserType.User:
foreach(var org in group)
{
newClaims.Add(new Claim("orguser", org.Id.ToString()));
}
break;
default:
break;
}
}
}
}
// filter out any of the new claims
var existingClaimsToKeep = existingClaims
.Where(c => newClaims.Count == 0 || !newClaims.Any(nc => nc.Type == c.Type)).ToList();
.Where(c => !c.Type.StartsWith("org") && (newClaims.Count == 0 || !newClaims.Any(nc => nc.Type == c.Type)))
.ToList();
newClaims.AddRange(existingClaimsToKeep);
if(newClaims.Any())

View File

@ -10,6 +10,7 @@ namespace Bit.Core.Repositories
public interface IOrganizationUserRepository : IRepository<OrganizationUser, Guid>
{
Task<OrganizationUser> GetByOrganizationAsync(Guid organizationId, Guid userId);
Task<ICollection<OrganizationUser>> GetManyByUserAsync(Guid userId);
Task<ICollection<OrganizationUser>> GetManyByOrganizationAsync(Guid organizationId, OrganizationUserType? type);
Task<OrganizationUser> GetByOrganizationAsync(Guid organizationId, string email);
Task<Tuple<OrganizationUserUserDetails, ICollection<SubvaultUserSubvaultDetails>>> GetDetailsByIdAsync(Guid id);

View File

@ -47,6 +47,19 @@ namespace Bit.Core.Repositories.SqlServer
}
}
public async Task<ICollection<OrganizationUser>> GetManyByUserAsync(Guid userId)
{
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<OrganizationUser>(
"[dbo].[OrganizationUser_ReadByUserId]",
new { UserId = userId },
commandType: CommandType.StoredProcedure);
return results.ToList();
}
}
public async Task<ICollection<OrganizationUser>> GetManyByOrganizationAsync(Guid organizationId,
OrganizationUserType? type)
{

View File

@ -183,5 +183,6 @@
<Build Include="dbo\Stored Procedures\Subvault_ReadByOrganizationIdAdminUserId.sql" />
<Build Include="dbo\User Defined Types\GuidIdArray.sql" />
<Build Include="dbo\Stored Procedures\SubvaultCipher_ReadByCipherId.sql" />
<Build Include="dbo\Stored Procedures\OrganizationUser_ReadByUserId.sql" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,13 @@
CREATE PROCEDURE [dbo].[OrganizationUser_ReadByUserId]
@UserId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
*
FROM
[dbo].[OrganizationUserView]
WHERE
[UserId] = @UserId
END