Skip to content

Commit

Permalink
Schema for organization membership requests (#5204)
Browse files Browse the repository at this point in the history
  • Loading branch information
chenriksson authored Dec 21, 2017
1 parent 39d8a40 commit fdd75b9
Show file tree
Hide file tree
Showing 16 changed files with 348 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/NuGetGallery.Core/Entities/Credential.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public Credential(string type, string value, TimeSpan? expiration)
[StringLength(maximumLength: 256)]
public string Value { get; set; }

[StringLength(maximumLength: 256)]
public string TenantId { get; set; }

[StringLength(maximumLength: 256)]
public string Description { get; set; }

Expand Down
22 changes: 22 additions & 0 deletions src/NuGetGallery.Core/Entities/EntitiesContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,18 +140,40 @@ protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity<Membership>()
.HasKey(m => new { m.OrganizationKey, m.MemberKey });

modelBuilder.Entity<MembershipRequest>()
.HasKey(m => new { m.OrganizationKey, m.NewMemberKey });

modelBuilder.Entity<OrganizationMigrationRequest>()
.HasKey(m => m.NewOrganizationKey);

modelBuilder.Entity<User>()
.HasMany(u => u.Organizations)
.WithRequired(m => m.Member)
.HasForeignKey(m => m.MemberKey)
.WillCascadeOnDelete(true); // Membership will be deleted with the Member account.

modelBuilder.Entity<User>()
.HasMany(u => u.OrganizationRequests)
.WithRequired(m => m.NewMember)
.HasForeignKey(m => m.NewMemberKey)
.WillCascadeOnDelete(false);

modelBuilder.Entity<User>()
.HasOptional(u => u.OrganizationMigrationRequest)
.WithRequired(m => m.NewOrganization);

modelBuilder.Entity<Organization>()
.HasMany(o => o.Members)
.WithRequired(m => m.Organization)
.HasForeignKey(m => m.OrganizationKey)
.WillCascadeOnDelete(true); // Memberships will be deleted with the Organization account.

modelBuilder.Entity<Organization>()
.HasMany(o => o.MemberRequests)
.WithRequired(m => m.Organization)
.HasForeignKey(m => m.OrganizationKey)
.WillCascadeOnDelete(false);

modelBuilder.Entity<Role>()
.HasKey(u => u.Key);

Expand Down
26 changes: 26 additions & 0 deletions src/NuGetGallery.Core/Entities/MembershipRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.ComponentModel.DataAnnotations;

namespace NuGetGallery
{
public class MembershipRequest
{
public int OrganizationKey { get; set; }

public virtual Organization Organization { get; set; }

public int NewMemberKey { get; set; }

public virtual User NewMember { get; set; }

public bool IsAdmin { get; set; }

[Required]
public string ConfirmationToken { get; set; }

public DateTime RequestDate { get; set; }
}
}
5 changes: 5 additions & 0 deletions src/NuGetGallery.Core/Entities/Organization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,10 @@ public Organization(string name) : base(name)
/// Organization Memberships to this organization.
/// </summary>
public virtual ICollection<Membership> Members { get; set; }

/// <summary>
/// Requests to become a member of this <see cref="Organization"/>.
/// </summary>
public virtual ICollection<MembershipRequest> MemberRequests { get; set; }
}
}
24 changes: 24 additions & 0 deletions src/NuGetGallery.Core/Entities/OrganizationMigrationRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.ComponentModel.DataAnnotations;

namespace NuGetGallery
{
public class OrganizationMigrationRequest
{
public int NewOrganizationKey { get; set; }

public virtual User NewOrganization { get; set; }

public int AdminUserKey { get; set; }

public virtual User AdminUser { get; set; }

[Required]
public string ConfirmationToken { get; set; }

public DateTime RequestDate { get; set; }
}
}
12 changes: 11 additions & 1 deletion src/NuGetGallery.Core/Entities/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,20 @@ public User(string username)
}

/// <summary>
/// Organization memberships for a non-organization <see cref="User"/> account.
/// Organization memberships, for a non-organization <see cref="User"/> account.
/// </summary>
public virtual ICollection<Membership> Organizations { get; set; }

/// <summary>
/// Organization membership requests, for a non-organization <see cref="User"/> account.
/// </summary>
public virtual ICollection<MembershipRequest> OrganizationRequests { get; set; }

/// <summary>
/// Request to transform a <see cref="User"/> account into an <see cref="Organization"/> account.
/// </summary>
public virtual OrganizationMigrationRequest OrganizationMigrationRequest { get; set; }

[StringLength(256)]
public string EmailAddress { get; set; }

Expand Down
2 changes: 2 additions & 0 deletions src/NuGetGallery.Core/NuGetGallery.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@
<Compile Include="Entities\Membership.cs" />
<Compile Include="Entities\Organization.cs" />
<Compile Include="Entities\AccountDelete.cs" />
<Compile Include="Entities\MembershipRequest.cs" />
<Compile Include="Entities\OrganizationMigrationRequest.cs" />
<Compile Include="Entities\PackageDelete.cs" />
<Compile Include="Entities\EmailMessage.cs" />
<Compile Include="Entities\EntitiesConfiguration.cs" />
Expand Down
9 changes: 8 additions & 1 deletion src/NuGetGallery/Authentication/AuthenticationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ namespace NuGetGallery.Authentication
{
public class AuthenticationService
{
private const string tenantIdClaimType = "http://schemas.microsoft.com/identity/claims/tenantid";

private Dictionary<string, Func<string, string>> _credentialFormatters;
private readonly IDiagnosticsSource _trace;
private readonly IAppConfiguration _config;
Expand Down Expand Up @@ -220,6 +222,9 @@ await Auditing.SaveAuditRecordAsync(
return null;
}

// store tenant (organization) id, if available
matched.TenantId = credential.TenantId;

// update last used timestamp
matched.LastUsed = _dateTimeProvider.UtcNow;
await Entities.SaveChangesAsync();
Expand Down Expand Up @@ -555,6 +560,8 @@ public virtual async Task<AuthenticateExternalLoginResult> ReadExternalLoginCred
var emailClaim = result.Identity.FindFirst(ClaimTypes.Email);
string emailSuffix = emailClaim == null ? String.Empty : (" <" + emailClaim.Value + ">");

var tenantIdClaim = result.Identity.FindFirst(tenantIdClaimType);

Authenticator auther;
string authenticationType = idClaim.Issuer;
if (!Authenticators.TryGetValue(idClaim.Issuer, out auther))
Expand All @@ -574,7 +581,7 @@ public virtual async Task<AuthenticateExternalLoginResult> ReadExternalLoginCred
Authentication = null,
ExternalIdentity = result.Identity,
Authenticator = auther,
Credential = _credentialBuilder.CreateExternalCredential(authenticationType, idClaim.Value, nameClaim.Value + emailSuffix)
Credential = _credentialBuilder.CreateExternalCredential(authenticationType, idClaim.Value, nameClaim.Value + emailSuffix, tenantIdClaim?.Value)
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,12 @@ public Credential CreatePackageVerificationApiKey(Credential originalApiKey, str
return credential;
}

public Credential CreateExternalCredential(string issuer, string value, string identity)
public Credential CreateExternalCredential(string issuer, string value, string identity, string tenantId = null)
{
return new Credential(CredentialTypes.ExternalPrefix + issuer, value)
{
Identity = identity
Identity = identity,
TenantId = tenantId
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public interface ICredentialBuilder

Credential CreatePackageVerificationApiKey(Credential originalApiKey, string id);

Credential CreateExternalCredential(string issuer, string value, string identity);
Credential CreateExternalCredential(string issuer, string value, string identity, string tenantId = null);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 59 additions & 0 deletions src/NuGetGallery/Migrations/201712211850074_MembershipRequests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
namespace NuGetGallery.Migrations
{
using System;
using System.Data.Entity.Migrations;

public partial class MembershipRequests : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.OrganizationMigrationRequests",
c => new
{
NewOrganizationKey = c.Int(nullable: false),
AdminUserKey = c.Int(nullable: false),
ConfirmationToken = c.String(nullable: false),
RequestDate = c.DateTime(nullable: false),
})
.PrimaryKey(t => t.NewOrganizationKey)
.ForeignKey("dbo.Users", t => t.AdminUserKey, cascadeDelete: true)
.ForeignKey("dbo.Users", t => t.NewOrganizationKey)
.Index(t => t.NewOrganizationKey)
.Index(t => t.AdminUserKey);

CreateTable(
"dbo.MembershipRequests",
c => new
{
OrganizationKey = c.Int(nullable: false),
NewMemberKey = c.Int(nullable: false),
IsAdmin = c.Boolean(nullable: false),
ConfirmationToken = c.String(nullable: false),
RequestDate = c.DateTime(nullable: false),
})
.PrimaryKey(t => new { t.OrganizationKey, t.NewMemberKey })
.ForeignKey("dbo.Organizations", t => t.OrganizationKey)
.ForeignKey("dbo.Users", t => t.NewMemberKey)
.Index(t => t.OrganizationKey)
.Index(t => t.NewMemberKey);

AddColumn("dbo.Credentials", "TenantId", c => c.String(maxLength: 256));
}

public override void Down()
{
DropForeignKey("dbo.MembershipRequests", "NewMemberKey", "dbo.Users");
DropForeignKey("dbo.MembershipRequests", "OrganizationKey", "dbo.Organizations");
DropForeignKey("dbo.OrganizationMigrationRequests", "NewOrganizationKey", "dbo.Users");
DropForeignKey("dbo.OrganizationMigrationRequests", "AdminUserKey", "dbo.Users");
DropIndex("dbo.MembershipRequests", new[] { "NewMemberKey" });
DropIndex("dbo.MembershipRequests", new[] { "OrganizationKey" });
DropIndex("dbo.OrganizationMigrationRequests", new[] { "AdminUserKey" });
DropIndex("dbo.OrganizationMigrationRequests", new[] { "NewOrganizationKey" });
DropColumn("dbo.Credentials", "TenantId");
DropTable("dbo.MembershipRequests");
DropTable("dbo.OrganizationMigrationRequests");
}
}
}
Loading

0 comments on commit fdd75b9

Please sign in to comment.