Skip to content

Commit

Permalink
feat: Remove dependency on IdentityServer
Browse files Browse the repository at this point in the history
  • Loading branch information
BerendWouters committed Jan 30, 2024
1 parent a1c2163 commit 501ca10
Show file tree
Hide file tree
Showing 44 changed files with 242 additions and 6,979 deletions.
4 changes: 2 additions & 2 deletions Singer.API/ClientApp/package-lock.json

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

2 changes: 1 addition & 1 deletion Singer.API/ClientApp/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Singer",
"version": "0.1.0-issue-msal.1585",
"version": "0.1.0-issue-msal.1586",
"scripts": {
"ng": "ng",
"start": "ng serve",
Expand Down
106 changes: 2 additions & 104 deletions Singer.API/Configuration/Seed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,12 @@
using System.Security.Claims;
using System.Threading.Tasks;

using Duende.IdentityServer.EntityFramework.DbContexts;
using Duende.IdentityServer.EntityFramework.Entities;
using Duende.IdentityServer.EntityFramework.Mappers;

using IdentityModel;

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

using Singer.Data;
using Singer.Identity;
using Singer.Models;
using Singer.Models.Users;

Expand Down Expand Up @@ -44,7 +38,7 @@ public static class Seed
public static async Task SeedUsersAsync(IServiceScope serviceScope, ApplicationDbContext applicationDbContext, string initialAdminPassword)
{
var userMgr = serviceScope.ServiceProvider.GetRequiredService<UserManager<User>>();
var roleMgr = serviceScope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole<Guid>>>();

var admin = await userMgr.FindByNameAsync("admin");
var adminUsersInDatabase = applicationDbContext.AdminUsers.Any();
if (!adminUsersInDatabase)
Expand Down Expand Up @@ -171,103 +165,7 @@ public static async Task SeedRolesAsync(IServiceScope serviceScope)
}
}

public static void SeedIdentityResources(ConfigurationDbContext configrationDbContext)
{
var identityResources = new List<IdentityResource>
{
new Duende.IdentityServer.Models.IdentityResources.OpenId().ToEntity(),
new Duende.IdentityServer.Models.IdentityResources.Email().ToEntity(),
new Duende.IdentityServer.Models.IdentityResources.Profile().ToEntity(),
new Duende.IdentityServer.Models.IdentityResources.Phone().ToEntity(),
new Duende.IdentityServer.Models.IdentityResources.Address().ToEntity(),
new IdentityResource{
Name = "Role",
UserClaims = new List<IdentityResourceClaim>()
{
new IdentityResourceClaim()
{
Type = JwtClaimTypes.Role
}
}}
};


foreach (var identityResource in identityResources)
{
var identityResourceInDb = configrationDbContext.IdentityResources.SingleOrDefault(x => x.Name == identityResource.Name);
if (identityResourceInDb == null)
{
configrationDbContext.IdentityResources.Add(identityResource);
}
}
}

public static void CreateAPIAndClient(ConfigurationDbContext configrationDbContext)
{
var singerApiResourceName = "singer.api";
var apiResource = configrationDbContext.ApiResources.SingleOrDefault(x => x.Name == singerApiResourceName);
if (apiResource == null)
{
apiResource = new ApiResource()
{
Name = singerApiResourceName,
ShowInDiscoveryDocument = true,
Scopes = new()
{
new ()
{
Scope = "apiRead",
ApiResource = new()
{
Name = "apiRead",
ShowInDiscoveryDocument = true,
DisplayName = "Readonly scope for SingerAPI",
UserClaims = new ()
{
new ()
{
Type = ClaimTypes.Role,
},
new ()
{
Type = ClaimTypes.Name
}
}
}
}
},
UserClaims = new List<ApiResourceClaim>()
{
new ApiResourceClaim()
{
Type = ClaimTypes.Name,
},
new ApiResourceClaim()
{
Type = ClaimTypes.Email
},
}
};


configrationDbContext.ApiResources.Add(apiResource);
}


var clientId = "singer.client";
var singerApiClient = configrationDbContext.Clients.SingleOrDefault(x => x.ClientId == clientId);
if (singerApiClient == null)
{
singerApiClient = Config.GetClient().ToEntity();
configrationDbContext.Clients.Add(singerApiClient);
}

UpdateAccessTokenLifeTime(singerApiClient);
}

private static void UpdateAccessTokenLifeTime(Client singerApiClient) =>
singerApiClient.AccessTokenLifetime = 3600 * 24;


public static void SeedSingerLocations(ApplicationDbContext applicationDbContext)
{
if (!applicationDbContext.SingerLocations.Any())
Expand Down
16 changes: 7 additions & 9 deletions Singer.API/Controllers/CareUserController.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Threading.Tasks;

using Duende.IdentityServer.Extensions;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -65,13 +63,13 @@ public override async Task<IActionResult> Update(Guid id, [FromBody] UpdateCareU
return Ok(result);
}

[HttpGet("self")]
public async Task<IActionResult> GetOwnCareUsers(string search)
{
var userId = Guid.Parse(User.GetSubjectId());
//[HttpGet("self")]
//public async Task<IActionResult> GetOwnCareUsers(string search)
//{
// var userId = Guid.Parse(User.GetSubjectId());

var relatedCareUsers = await _careUserService.GetRelatedCareUserAsync(userId, search);
return Ok(relatedCareUsers);
// var relatedCareUsers = await _careUserService.GetRelatedCareUserAsync(userId, search);
// return Ok(relatedCareUsers);

}
//}
}
2 changes: 2 additions & 0 deletions Singer.API/Controllers/DataControllerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web.Resource;

using Singer.DTOs;
using Singer.Helpers;
Expand Down Expand Up @@ -64,6 +65,7 @@ protected DataControllerBase(IDatabaseService<TEntity, TDTO, TCreateDTO, TUpdate
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[RequiredScope("https://vzwstijn.onmicrosoft.com/4ea3a07f-5db9-4290-b930-88806df40e9d/Events.Read")]
public virtual async Task<IActionResult> Create([FromBody] TCreateDTO dto)
{
var model = ModelState;
Expand Down
7 changes: 4 additions & 3 deletions Singer.API/Controllers/EventController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@

using CsvHelper;

using Duende.IdentityServer.Extensions;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;

using Singer.Configuration;
using Singer.DTOs;
Expand Down Expand Up @@ -108,7 +108,7 @@ public async Task<ActionResult<RegistrationDTO>> Create(Guid eventId, [FromBody]
// Since admins automatically approve a registration, it's needed to register this.
if (User.IsInRole(Roles.ROLE_ADMINISTRATOR))
{
var executedByUserId = Guid.Parse(User.GetSubjectId());
var executedByUserId = Guid.Parse(User.GetObjectId());
await _actionNotificationService.RegisterEventRegistrationStatusChange(eventSlotRegistration.Id, executedByUserId,
RegistrationStatus.Pending, eventSlotRegistration.Status);
}
Expand Down Expand Up @@ -307,6 +307,7 @@ await _eventRegistrationService
#endregion delete

[HttpPost("search")]
[RequiredScope("Events.Read")]
public async Task<IActionResult> GetPublicEvents([FromBody] EventFilterParametersDTO searchEventParams)
{
var model = ModelState;
Expand Down
8 changes: 5 additions & 3 deletions Singer.API/Controllers/RegistrationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
using System.Linq;
using System.Threading.Tasks;

using Duende.IdentityServer.Extensions;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;

using Singer.Configuration;
using Singer.DTOs;
Expand All @@ -30,6 +30,7 @@ public RegistrationController(IRegistrationService registrationService, ICareUse
[HttpPost("search")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[RequiredScope("Events.Read")]
public async Task<IActionResult> Search([FromBody] RegistrationSearchDTO searchDTO)
{
var model = ModelState;
Expand All @@ -38,7 +39,8 @@ public async Task<IActionResult> Search([FromBody] RegistrationSearchDTO searchD

if (!User.IsInRole(Roles.ROLE_ADMINISTRATOR))
{
var careUserDTOs = await _careUserService.GetCareUsersForLegalGuardianAsync(Guid.Parse(User.GetSubjectId()));
var name = User.GetNameIdentifierId();
var careUserDTOs = await _careUserService.GetCareUsersForLegalGuardianAsync(Guid.Parse(name));
if (careUserDTOs.Count == 0)
return NotFound(model);
searchDTO.CareUserIds = careUserDTOs.Select(x => x.UserId).ToList();
Expand Down
56 changes: 27 additions & 29 deletions Singer.API/Data/ApplicationDbContext.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
using System;

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

using Singer.Models;
using Singer.Models.Users;

namespace Singer.Data;

public class ApplicationDbContext : IdentityDbContext<User, IdentityRole<Guid>, Guid>
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}

public DbSet<User> Users { get; set; }
public DbSet<CareUser> CareUsers { get; set; }
public DbSet<LegalGuardianUser> LegalGuardianUsers { get; set; }
public DbSet<LegalGuardianCareUser> LegalGuardianCareUsers { get; set; }
Expand All @@ -30,45 +28,45 @@ protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<LegalGuardianCareUser>()
.HasKey(x => new { x.CareUserId, x.LegalGuardianId });
.HasKey(x => new { x.CareUserId, x.LegalGuardianId });
builder.Entity<LegalGuardianCareUser>()
.HasOne(x => x.LegalGuardian)
.WithMany(x => x.LegalGuardianCareUsers)
.OnDelete(DeleteBehavior.Restrict);
.HasOne(x => x.LegalGuardian)
.WithMany(x => x.LegalGuardianCareUsers)
.OnDelete(DeleteBehavior.Restrict);
builder.Entity<LegalGuardianCareUser>()
.HasOne(x => x.CareUser)
.WithMany(x => x.LegalGuardianCareUsers)
.OnDelete(DeleteBehavior.Restrict);
.HasOne(x => x.CareUser)
.WithMany(x => x.LegalGuardianCareUsers)
.OnDelete(DeleteBehavior.Restrict);

builder.Entity<Event>()
.HasMany(x => x.EventSlots)
.WithOne(x => x.Event)
.OnDelete(DeleteBehavior.Restrict);
.HasMany(x => x.EventSlots)
.WithOne(x => x.Event)
.OnDelete(DeleteBehavior.Restrict);

builder.Entity<Registration>()
.HasOne(x => x.EventSlot)
.WithMany(x => x.Registrations);
.HasOne(x => x.EventSlot)
.WithMany(x => x.Registrations);

builder.Entity<Registration>()
.HasIndex(x => new { x.CareUserId, x.EventSlotId }).IsUnique();
.HasIndex(x => new { x.CareUserId, x.EventSlotId }).IsUnique();

builder.Entity<CareUser>()
.HasMany(x => x.EventRegistrations)
.WithOne(x => x.CareUser)
.OnDelete(DeleteBehavior.Restrict);
.HasMany(x => x.EventRegistrations)
.WithOne(x => x.CareUser)
.OnDelete(DeleteBehavior.Restrict);

builder.Entity<EventRegistrationLog>()
.ToTable("EventRegistrationLogs")
.HasDiscriminator(x => x.EventRegistrationChanges)
.HasValue<EventRegistrationLocationChange>(EventRegistrationChanges.LocationChange)
.HasValue<EventRegistrationStatusChange>(EventRegistrationChanges.RegistrationStatusChange);
//builder.Entity<EventRegistrationLog>()
// .ToTable("EventRegistrationLogs")
// .HasDiscriminator(x => x.EventRegistrationChanges)
// .HasValue<EventRegistrationLocationChange>(EventRegistrationChanges.LocationChange)
// .HasValue<EventRegistrationStatusChange>(EventRegistrationChanges.RegistrationStatusChange);

builder.Entity<EventRegistrationLog>()
.HasOne(x => x.EventRegistration);
.HasOne(x => x.EventRegistration);

builder.Entity<EventRegistrationStatusChange>()
.HasBaseType<EventRegistrationLog>();
.HasBaseType<EventRegistrationLog>();
builder.Entity<EventRegistrationLocationChange>()
.HasBaseType<EventRegistrationLog>();
.HasBaseType<EventRegistrationLog>();
}
}
}
25 changes: 4 additions & 21 deletions Singer.API/Helpers/Extensions/AuthenticationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,18 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

using Singer.Data.Models.Configuration;
using Microsoft.Identity.Web;

namespace Singer.Helpers.Extensions;

public static class AuthenticationExtensions
{
public static WebApplicationBuilder AddAuthenticationAndAuthorization(this WebApplicationBuilder builder)
{
var applicationConfig = builder.Configuration.GetSection("Application").Get<ApplicationConfig>();

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
// The API resource scope issued in authorization server
options.TokenValidationParameters.ValidAudience = "singer.api";
// URL of my authorization server
options.Authority = applicationConfig.Authority;
});

// Making JWT authentication scheme the default
builder.Services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
});
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration);

return builder;
}
Expand Down
Loading

0 comments on commit 501ca10

Please sign in to comment.