diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 71badf6b..00000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,67 +0,0 @@ -# Please find the full example project here: -# https://gitlab.com/tobiaskoch/gitlab-ci-example-mono - -# see https://hub.docker.com/_/mono/ -image: mono:4.6.2.7 - -stages: - - build - - test - - deploy - -before_script: - - . /opt/mono-4.6/mono-env - - export GIT_SSL_NO_VERIFY=true - - curl --insecure -sSL https://lua.pschneider.fr/files/Paul/pub/dnx-install.sh | bash - - DNX_USER_HOME=`pwd -P`/dnx . ./dnx/dnvm/dnvm.sh - - cd src/OAuth.AspNet.Token && dnu restore --ignore-failed-sources - - cd ../OAuth.AspNet.AuthServer && dnu restore --ignore-failed-sources - - cd ../Yavsc.Abstract && dnu restore --ignore-failed-sources - - cd ../Yavsc.Server && dnu restore --ignore-failed-sources - - cd ../Yavsc && dnu restore --ignore-failed-sources - - cd ../cli && dnu restore --ignore-failed-sources - - cd ../../test/yavscTests && dnu restore --ignore-failed-sources - - cd ../.. - -after_script: - -debug: - stage: build - artifacts: - paths: - - test/yavscTests/bin - script: - - cd test/yavscTests - - dnu build - -non_reg: - stage: test - artifacts: - paths: - - test/yavscTests/test-results.xml - when: always - script: - - cd test/yavscTests - - cp $yavsc_client_secret_json yavsc-client-secret.json - - ASPNET_ENV=Development dnx test -trait ategory=non_reg -maxthreads 1 -xml test-results.xml - -release: - stage: deploy - only: - - vnext - artifacts: - paths: - - binaries/Debug - script: - - make packages - -deploy_staging: - stage: deploy - script: - - echo "Deploy to staging server" - - make strip_yavscd - - make packages - - isn push -s $ISNSOURCE -k $NUGETSOURCEAPIKEY src/Yavsc.Abstract/bin/*/*.nupkg - environment: - name: staging - url: https://yavscpre.pschneider.fr diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config deleted file mode 100644 index 3082130d..00000000 --- a/.nuget/NuGet.Config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/.nuget/packages.config b/.nuget/packages.config deleted file mode 100644 index eaeeed58..00000000 --- a/.nuget/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2a523d6b..00000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: csharp -os: linux -mono: -- beta -sudo: false -install: -- curl --insecure -sSL https://lua.pschneider.fr/files/Paul/pub/dnx-install.sh | bash -- DNX_USER_HOME=`pwd -P`/dnx . ./dnx/dnvm/dnvm.sh -- cd src/OAuth.AspNet.Token && dnu restore --ignore-failed-sources -- cd ../OAuth.AspNet.AuthServer && dnu restore --ignore-failed-sources -- cd ../Yavsc.Abstract && dnu restore --ignore-failed-sources -- cd ../Yavsc.Server && dnu restore --ignore-failed-sources -- cd ../Yavsc && dnu restore --ignore-failed-sources -- cd ../test -- make restore -- make -- cd ../.. -- make - -script: -- "dnu build" - diff --git a/global.json b/global.json index f2fb072c..030b02f6 100644 --- a/global.json +++ b/global.json @@ -1,11 +1,6 @@ { - "projects": [ - "src", - "test" - ], "sdk": { "runtime": "dotnet", "version": "8.0.405" - }, - "packages": "packages" + } } diff --git a/src/Api/Api.csproj b/src/Api/Api.csproj index b1e26b9c..6e024e9b 100644 --- a/src/Api/Api.csproj +++ b/src/Api/Api.csproj @@ -1,8 +1,9 @@ - + net8.0 enable enable + 1c73094f-959f-4211-b1a1-6a69b236c283 diff --git a/src/Api/Controllers/Blogspot/FileSystemApiController.cs b/src/Api/Controllers/Blogspot/FileSystemApiController.cs index e7b40dfe..2dc63d59 100644 --- a/src/Api/Controllers/Blogspot/FileSystemApiController.cs +++ b/src/Api/Controllers/Blogspot/FileSystemApiController.cs @@ -14,6 +14,8 @@ namespace Yavsc.ApiControllers using Yavsc.Attributes.Validation; using System.IO; using Yavsc.Exceptions; + using Yavsc.Server.Helpers; + using Yavsc.Abstract.Helpers; [Authorize,Route("api/fs")] public partial class FileSystemApiController : Controller diff --git a/src/Api/Controllers/Blogspot/FileSystemStream.cs b/src/Api/Controllers/Blogspot/FileSystemStream.cs index af80fe7d..e6b3c159 100644 --- a/src/Api/Controllers/Blogspot/FileSystemStream.cs +++ b/src/Api/Controllers/Blogspot/FileSystemStream.cs @@ -8,6 +8,7 @@ using Yavsc.Models; using Yavsc.Models.Messaging; using Yavsc.Services; using Microsoft.AspNetCore.SignalR; +using Yavsc.Server.Helpers; namespace Yavsc.ApiControllers { diff --git a/src/Api/Controllers/Business/ActivityApiController.cs b/src/Api/Controllers/Business/ActivityApiController.cs index c661857a..709fab7a 100644 --- a/src/Api/Controllers/Business/ActivityApiController.cs +++ b/src/Api/Controllers/Business/ActivityApiController.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Yavsc.Helpers; +using Yavsc.Api.Helpers; using Yavsc.Models; using Yavsc.Models.Workflow; diff --git a/src/Api/Controllers/Business/BillingController.cs b/src/Api/Controllers/Business/BillingController.cs index 041359a2..5ab4a332 100644 --- a/src/Api/Controllers/Business/BillingController.cs +++ b/src/Api/Controllers/Business/BillingController.cs @@ -15,6 +15,7 @@ namespace Yavsc.ApiControllers using Microsoft.Extensions.Options; using Microsoft.EntityFrameworkCore; using Yavsc.ViewModels.Auth; + using Yavsc.Server.Helpers; [Route("api/bill"), Authorize] public class BillingController : Controller diff --git a/src/Api/Controllers/accounting/AccountController.cs b/src/Api/Controllers/accounting/AccountController.cs index 6137c544..c1bb811a 100644 --- a/src/Api/Controllers/accounting/AccountController.cs +++ b/src/Api/Controllers/accounting/AccountController.cs @@ -1,15 +1,11 @@ using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using System.Security.Claims; using Microsoft.EntityFrameworkCore; using Yavsc.Models; -using Yavsc.Models.Account; -using Yavsc.ViewModels.Account; -using Yavsc.Helpers; -using Yavsc.Abstract.Identity; -using System.Diagnostics; +using Yavsc.Api.Helpers; +using Yavsc.Server.Helpers; namespace Yavsc.WebApi.Controllers { @@ -17,165 +13,54 @@ namespace Yavsc.WebApi.Controllers [Authorize("ApiScope")] public class ApiAccountController : Controller { - private UserManager _userManager; - private readonly SignInManager _signInManager; readonly ApplicationDbContext _dbContext; private readonly ILogger _logger; - public ApiAccountController(UserManager userManager, - SignInManager signInManager, - RoleManager roleManager, + public ApiAccountController( ILoggerFactory loggerFactory, ApplicationDbContext dbContext) { - UserManager = userManager; - this.roleManager = roleManager; - _signInManager = signInManager; _logger = loggerFactory.CreateLogger(nameof(ApiAccountController)); _dbContext = dbContext; } - public UserManager UserManager - { - get - { - return _userManager; - } - private set - { - _userManager = value; - } - } - - private readonly RoleManager roleManager; - - // POST api/Account/ChangePassword - - public async Task ChangePassword(ChangePasswordBindingModel model) - { - if (!ModelState.IsValid) - { - return new BadRequestObjectResult(ModelState); - } - var user = await _userManager.FindByIdAsync(User.GetUserId()); - if (user == null || !(await _userManager.IsEmailConfirmedAsync(user))) { - IdentityResult result = await UserManager.ChangePasswordAsync(user, model.OldPassword, - model.NewPassword); - - if (!result.Succeeded) - { - AddErrors("NewPassword",result); - return new BadRequestObjectResult(ModelState); - } - } - return Ok(); - } - - // POST api/Account/SetPassword - - public async Task SetPassword(SetPasswordBindingModel model) - { - if (!ModelState.IsValid) - { - return new BadRequestObjectResult(ModelState); - } - var user = await _userManager.FindByIdAsync(User.GetUserId()); - if (user == null || !(await _userManager.IsEmailConfirmedAsync(user))) { - IdentityResult result = await UserManager.AddPasswordAsync(user, model.NewPassword); - if (!result.Succeeded) - { - AddErrors ("NewPassword",result); - return new BadRequestObjectResult(ModelState); - } - } - return Ok(); - } - - // POST api/Account/Register - [AllowAnonymous] - public async Task Register(RegisterModel model) - { - if (!ModelState.IsValid) - { - return new BadRequestObjectResult(ModelState); - } - - var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; - - IdentityResult result = await UserManager.CreateAsync(user, model.Password); - - if (!result.Succeeded) - { - AddErrors ("Register",result); - return new BadRequestObjectResult(ModelState); - } - await _signInManager.SignInAsync(user, isPersistent: false); - return Ok(); - } - private void AddErrors(string key, IdentityResult result) - { - foreach (var error in result.Errors) - { - ModelState.AddModelError(key, error.Description); - } - } - protected override void Dispose(bool disposing) - { - if (disposing) - { - UserManager.Dispose(); - } - - base.Dispose(disposing); - } - [HttpGet("me")] public async Task Me() { - if (User==null) - return new BadRequestObjectResult( - new { error = "user not found" }); + if (User == null) + return new BadRequestObjectResult( + new { error = "user not found" }); var uid = User.GetUserId(); - - var userData = await _dbContext.Users - .Include(u=>u.PostalAddress) - .Include(u=>u.AccountBalance) - .FirstAsync(u=>u.Id == uid); - var user = new Yavsc.Models.Auth.Me(userData.Id, userData.UserName, userData.Email, - userData.Avatar , - userData.PostalAddress, userData.DedicatedGoogleCalendar ); + var userData = await GetUserData(uid); - var userRoles = _dbContext.UserRoles.Where(u=>u.UserId == uid).Select(r => r.RoleId).ToArray(); + var user = new Yavsc.Models.Auth.Me(userData.Id, userData.UserName, userData.Email, + userData.Avatar, + userData.PostalAddress, userData.DedicatedGoogleCalendar); - IdentityRole [] roles = _dbContext.Roles.Where(r=>userRoles.Contains(r.Id)).ToArray(); - - user.Roles = roles.Select(r=>r.Name).ToArray(); + var userRoles = _dbContext.UserRoles.Where(u => u.UserId == uid).Select(r => r.RoleId).ToArray(); + + IdentityRole[] roles = _dbContext.Roles.Where(r => userRoles.Contains(r.Id)).ToArray(); + + user.Roles = roles.Select(r => r.Name).ToArray(); return Ok(user); } + private async Task GetUserData(string uid) + { + return await _dbContext.Users + .Include(u => u.PostalAddress) + .Include(u => u.AccountBalance) + .FirstAsync(u => u.Id == uid); + } + [HttpGet("myhost")] public IActionResult MyHost () { return Ok(new { host = Request.ForHost() }); } - /// - /// Actually only updates the user's name. - /// - /// MyUpdate containing the new user name - /// Ok when all is ok. - [HttpPut("me")] - public async Task UpdateMe(UserInfo me) - { - if (!ModelState.IsValid) return new BadRequestObjectResult( - new { error = "Specify some valid user update request." }); - var user = await _userManager.FindByIdAsync(User.GetUserId()); - var result = await _userManager.SetUserNameAsync(user, me.UserName); - if (result.Succeeded) - return Ok(); - else return new BadRequestObjectResult(result); - } + /// /// Updates the avatar /// @@ -184,11 +69,11 @@ namespace Yavsc.WebApi.Controllers public async Task SetAvatar() { var root = User.InitPostToFileSystem(null); - var user = await _userManager.FindByIdAsync(User.GetUserId()); + var user = await GetUserData(User.GetUserId()); if (Request.Form.Files.Count!=1) return new BadRequestResult(); var info = user.ReceiveAvatar(Request.Form.Files[0]); - await _userManager.UpdateAsync(user); + await _dbContext.SaveChangesAsync(); return Ok(info); } diff --git a/src/Yavsc.Server/Helpers/RequestHelpers.cs b/src/Api/Helpers/RequestHelpers.cs similarity index 96% rename from src/Yavsc.Server/Helpers/RequestHelpers.cs rename to src/Api/Helpers/RequestHelpers.cs index 96f060c3..2c2fae27 100644 --- a/src/Yavsc.Server/Helpers/RequestHelpers.cs +++ b/src/Api/Helpers/RequestHelpers.cs @@ -8,7 +8,7 @@ using Yavsc.ViewModels; using Yavsc.Models; using System.Linq; -namespace Yavsc.Helpers +namespace Yavsc.Api.Helpers { public static class RequestHelpers { diff --git a/src/Api/Helpers/UserHelpers.cs b/src/Api/Helpers/UserHelpers.cs new file mode 100644 index 00000000..2d480ea1 --- /dev/null +++ b/src/Api/Helpers/UserHelpers.cs @@ -0,0 +1,17 @@ +using System.Security.Claims; +using System.Collections.Generic; +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Yavsc.Models; +using Yavsc.Models.Blog; + +namespace Yavsc.Api.Helpers +{ + public static class UserHelpers + { + public static string GetUserId(this ClaimsPrincipal user) + { + return user.FindFirstValue("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"); + } + } +} diff --git a/src/Api/Program.cs b/src/Api/Program.cs index f62f202c..5ef8afde 100644 --- a/src/Api/Program.cs +++ b/src/Api/Program.cs @@ -10,6 +10,7 @@ copies or substantial portions of the Software. */ +using IdentityModel; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Mvc; @@ -27,9 +28,11 @@ internal class Program var builder = WebApplication.CreateBuilder(args); var services = builder.Services; + // builder.Services.AddDistributedMemoryCache(); // accepts any access token issued by identity server - // adds an authorization policy for scope 'api1' + // adds an authorization policy for scope 'scope1' + services .AddAuthorization(options => { @@ -37,7 +40,7 @@ internal class Program { policy .RequireAuthenticatedUser() - .RequireClaim("scope", "scope2"); + .RequireClaim(JwtClaimTypes.Scope, new string[] { "scope2" }); }); }) .AddCors(options => @@ -45,13 +48,12 @@ internal class Program // this defines a CORS policy called "default" options.AddPolicy("default", policy => { - policy.WithOrigins("https://localhost:5003" - ,"http://localhost:5002") + policy.WithOrigins("https://localhost:5003") .AllowAnyHeader() .AllowAnyMethod(); }); }) - .AddControllersWithViews(); + .AddControllers(); // accepts any access token issued by identity server var authenticationBuilder = services.AddAuthentication("Bearer") @@ -62,21 +64,20 @@ internal class Program options.TokenValidationParameters = new() { ValidateAudience = false }; }); - services.AddDbContext(options => - options.UseNpgsql(builder.Configuration.GetConnectionString("Default"))); - services.AddScoped>(); - services.AddSingleton(); - services.AddSingleton(); - services.AddTransient(); - services.AddIdentityApiEndpoints(); - builder.Services.AddSession(); - - services.AddTransient() - .AddTransient() - .AddTransient() - .AddTransient, UserStore>() - .AddTransient(); + services.AddDbContext(options => + options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); + + services.AddTransient() + .AddTransient() + .AddTransient(); + /* + services.AddSingleton(); + services.AddSingleton(); + services.AddTransient(); + services.AddIdentityApiEndpoints(); + services.AddSession(); + */ using (var app = builder.Build()) { if (app.Environment.IsDevelopment()) @@ -85,18 +86,28 @@ internal class Program app .UseRouting() .UseAuthentication() - .UseAuthorization().UseCors("default") - .UseEndpoints(endpoints => - { - endpoints.MapDefaultControllerRoute().RequireAuthorization("ApiScope"); - }); - //app.MapIdentityApi().RequireAuthorization("ApiScope"); - app.MapGet("/identity", (HttpContext context) => - new JsonResult(context?.User?.Claims.Select(c => new { c.Type, c.Value })) - ).RequireAuthorization("ApiScope"); + .UseAuthorization() + .UseCors("default") + /* .UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute() + .RequireAuthorization(); + })*/ - // app.UseSession(); + ; + // app.MapIdentityApi().RequireAuthorization("ApiScope"); + app.MapDefaultControllerRoute(); + app.MapGet("/identity", (HttpContext context) => + new JsonResult(context?.User?.Claims.Select(c => new { c.Type, c.Value })) + ); + + // app.UseSession(); await app.RunAsync(); - }; + } + ; + + + + } } diff --git a/src/Api/Properties/launchSettings.json b/src/Api/Properties/launchSettings.json new file mode 100644 index 00000000..e27c888f --- /dev/null +++ b/src/Api/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "https://localhost:5001", + "sslPort": 6001 + } + }, + "profiles": { + + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:6001;", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/Yavsc.Abstract/Attributes/Validation/ValidRemoteUserDirAttribute.cs b/src/Yavsc.Abstract/Attributes/Validation/ValidRemoteUserDirAttribute.cs index 2c59f689..43c44054 100644 --- a/src/Yavsc.Abstract/Attributes/Validation/ValidRemoteUserDirAttribute.cs +++ b/src/Yavsc.Abstract/Attributes/Validation/ValidRemoteUserDirAttribute.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; -using Yavsc.Helpers; +using Yavsc.Server.Helpers; namespace Yavsc.Attributes.Validation { diff --git a/src/Yavsc.Abstract/Constants.cs b/src/Yavsc.Abstract/Constants.cs index c84eabaf..b6c7bf2e 100644 --- a/src/Yavsc.Abstract/Constants.cs +++ b/src/Yavsc.Abstract/Constants.cs @@ -54,5 +54,7 @@ namespace Yavsc public const string LivePath = "/live/cast"; public const string StreamingPath = "/api/stream/put"; + + public const string RoleClaimName = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"; } } diff --git a/src/Yavsc.Abstract/FileSystem/AbstractFileSystemHelpers.cs b/src/Yavsc.Abstract/FileSystem/AbstractFileSystemHelpers.cs index 0b4aefbb..5e571e24 100644 --- a/src/Yavsc.Abstract/FileSystem/AbstractFileSystemHelpers.cs +++ b/src/Yavsc.Abstract/FileSystem/AbstractFileSystemHelpers.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using Yavsc.ViewModels.UserFiles; -namespace Yavsc.Helpers +namespace Yavsc.Server.Helpers { public static class AbstractFileSystemHelpers { diff --git a/src/Yavsc.Abstract/FileSystem/FsOperationInfo.cs b/src/Yavsc.Abstract/FileSystem/FsOperationInfo.cs index ba748fbd..63c69cb4 100644 --- a/src/Yavsc.Abstract/FileSystem/FsOperationInfo.cs +++ b/src/Yavsc.Abstract/FileSystem/FsOperationInfo.cs @@ -1,4 +1,4 @@ -namespace Yavsc.Helpers +namespace Yavsc.Abstract.Helpers { public enum ErrorCode { NotFound, diff --git a/src/Yavsc.Abstract/FileSystem/UserDirectoryInfo.cs b/src/Yavsc.Abstract/FileSystem/UserDirectoryInfo.cs index 77b7e6e4..cced9397 100644 --- a/src/Yavsc.Abstract/FileSystem/UserDirectoryInfo.cs +++ b/src/Yavsc.Abstract/FileSystem/UserDirectoryInfo.cs @@ -2,7 +2,7 @@ using System; using System.IO; using System.Linq; using Yavsc.Abstract.FileSystem; -using Yavsc.Helpers; +using Yavsc.Server.Helpers; namespace Yavsc.ViewModels.UserFiles { diff --git a/src/Yavsc.Abstract/Yavsc.Abstract.csproj b/src/Yavsc.Abstract/Yavsc.Abstract.csproj index 4483fe35..6d0c7e5f 100644 --- a/src/Yavsc.Abstract/Yavsc.Abstract.csproj +++ b/src/Yavsc.Abstract/Yavsc.Abstract.csproj @@ -9,8 +9,5 @@ - - - diff --git a/src/Yavsc.Server/Config.cs b/src/Yavsc.Server/Config.cs index fe0ed6ac..bc579e5f 100644 --- a/src/Yavsc.Server/Config.cs +++ b/src/Yavsc.Server/Config.cs @@ -47,8 +47,8 @@ public static class Config public static IEnumerable ApiScopes => new ApiScope[] { - new ApiScope("scope1"), - new ApiScope("scope2"), + new ApiScope("scope1",new string[] {"scope1"}), + new ApiScope("scope2",new string[] {"scope2"}), }; public static IEnumerable Clients => @@ -73,6 +73,7 @@ public static class Config ClientSecrets = { new Secret("49C1A7E1-0C79-4A89-A3D6-A37998FB86B0".Sha256()) }, AllowedGrantTypes = GrantTypes.Code, + AlwaysIncludeUserClaimsInIdToken = true, RedirectUris = { "https://localhost:5003/signin-oidc", "http://localhost:5002/signin-oidc" }, @@ -80,7 +81,6 @@ public static class Config "http://localhost:5002/signout-callback-oidc", "https://localhost:5003/signout-callback-oidc" }, - AllowOfflineAccess = true, AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, diff --git a/src/Yavsc.Server/Helpers/BillingHelpers.cs b/src/Yavsc.Server/Helpers/BillingHelpers.cs index 0a826447..c10a7615 100644 --- a/src/Yavsc.Server/Helpers/BillingHelpers.cs +++ b/src/Yavsc.Server/Helpers/BillingHelpers.cs @@ -1,10 +1,7 @@ -using System.Collections.Generic; using System.Globalization; -using System.IO; -using System.Linq; -using Yavsc.Abstract.FileSystem; using Yavsc.Billing; using Yavsc.Models.Billing; +using Yavsc.Server.Helpers; using Yavsc.Services; namespace Yavsc.Helpers diff --git a/src/Yavsc.Server/Helpers/FileSystemHelpers.cs b/src/Yavsc.Server/Helpers/FileSystemHelpers.cs index 28721815..f0d5782b 100644 --- a/src/Yavsc.Server/Helpers/FileSystemHelpers.cs +++ b/src/Yavsc.Server/Helpers/FileSystemHelpers.cs @@ -11,8 +11,9 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.Processing; using Microsoft.AspNetCore.Http; using Yavsc.Exceptions; - -namespace Yavsc.Helpers +using Yavsc.Helpers; +using Yavsc.Abstract.Helpers; +namespace Yavsc.Server.Helpers { public static class FileSystemHelpers { diff --git a/src/Yavsc.Server/Helpers/UserHelpers.cs b/src/Yavsc.Server/Helpers/UserHelpers.cs index e6db8313..e319239d 100644 --- a/src/Yavsc.Server/Helpers/UserHelpers.cs +++ b/src/Yavsc.Server/Helpers/UserHelpers.cs @@ -9,7 +9,6 @@ namespace Yavsc.Helpers { public static class UserHelpers { - public static string GetUserId(this ClaimsPrincipal user) { return user.FindFirstValue("sub"); diff --git a/src/Yavsc.Server/Services/ProfileService.cs b/src/Yavsc.Server/Services/ProfileService.cs index b7705219..3239672a 100644 --- a/src/Yavsc.Server/Services/ProfileService.cs +++ b/src/Yavsc.Server/Services/ProfileService.cs @@ -9,16 +9,17 @@ using Yavsc.Models; namespace Yavsc.Services { - public class ProfileService : DefaultProfileService, IProfileService + public class ProfileService : IProfileService { private readonly UserManager _userManager; public ProfileService( - UserManager userManager, ILogger logger) : base(logger) + UserManager userManager, + ILogger logger) { _userManager = userManager; } - public async Task> GetClaimsFromUserAsync( + private async Task> GetClaimsFromUserAsync( ProfileDataRequestContext context, ApplicationUser user) { @@ -30,9 +31,11 @@ namespace Yavsc.Services foreach (var scope in context.RequestedResources.ParsedScopes) { - claims.Add(new Claim(JwtClaimTypes.Scope, scope.ParsedName)); - claimAdds.Add(scope.ParsedName); - // TODO scope has a ParsedParameter + if (context.Client.AllowedScopes.Contains(scope.ParsedName)) + { + claims.Add(new Claim(JwtClaimTypes.Scope, scope.ParsedName)); + claimAdds.Add(scope.ParsedName); + } } if (claimAdds.Contains(JwtClaimTypes.Profile)) @@ -54,13 +57,13 @@ namespace Yavsc.Services var roles = await this._userManager.GetRolesAsync(user); if (roles.Count()>0) { - claims.Add(new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role",String.Join(" ",roles))); + claims.AddRange(roles.Select(r => new Claim(Constants.RoleClaimName, r))); } } return claims; } - override public async Task GetProfileDataAsync(ProfileDataRequestContext context) + public async Task GetProfileDataAsync(ProfileDataRequestContext context) { var subjectId = GetSubjectId(context.Subject); if (subjectId==null) return; @@ -69,7 +72,7 @@ namespace Yavsc.Services context.IssuedClaims = await GetClaimsFromUserAsync(context, user); } - override public async Task IsActiveAsync(IsActiveContext context) + public async Task IsActiveAsync(IsActiveContext context) { string? subjectId = GetSubjectId(context.Subject); if (subjectId == null) diff --git a/src/Yavsc.Server/ViewModels/LiveCastHandler.cs b/src/Yavsc.Server/ViewModels/LiveCastHandler.cs index fc71e760..e5e83506 100644 --- a/src/Yavsc.Server/ViewModels/LiveCastHandler.cs +++ b/src/Yavsc.Server/ViewModels/LiveCastHandler.cs @@ -10,6 +10,7 @@ using Newtonsoft.Json; using Yavsc.Helpers; using Yavsc.Models; using Yavsc.Models.FileSystem; +using Yavsc.Server.Helpers; namespace Yavsc.ViewModels.Streaming { diff --git a/src/Yavsc/Controllers/Contracting/EstimateController.cs b/src/Yavsc/Controllers/Contracting/EstimateController.cs index d68c3656..b81af756 100644 --- a/src/Yavsc/Controllers/Contracting/EstimateController.cs +++ b/src/Yavsc/Controllers/Contracting/EstimateController.cs @@ -12,6 +12,7 @@ namespace Yavsc.Controllers using Models.Billing; using Models.Workflow; using ViewModels.Auth; + using Yavsc.Server.Helpers; [Authorize] public class EstimateController : Controller diff --git a/src/Yavsc/Controllers/Contracting/FrontOfficeController.cs b/src/Yavsc/Controllers/Contracting/FrontOfficeController.cs index 55a04fb0..666fa501 100644 --- a/src/Yavsc/Controllers/Contracting/FrontOfficeController.cs +++ b/src/Yavsc/Controllers/Contracting/FrontOfficeController.cs @@ -10,6 +10,7 @@ namespace Yavsc.Controllers using Microsoft.Extensions.Localization; using Models; using ViewModels.FrontOffice; + using Yavsc.Server.Helpers; using Yavsc.Services; public class FrontOfficeController : Controller diff --git a/src/Yavsc/Controllers/FileSystemController.cs b/src/Yavsc/Controllers/FileSystemController.cs index 36ebcb04..84579675 100644 --- a/src/Yavsc/Controllers/FileSystemController.cs +++ b/src/Yavsc/Controllers/FileSystemController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Yavsc.Helpers; +using Yavsc.Server.Helpers; namespace Yavsc.Controllers { diff --git a/src/Yavsc/Extensions/HostingExtensions.cs b/src/Yavsc/Extensions/HostingExtensions.cs index 7588f950..d86f8259 100644 --- a/src/Yavsc/Extensions/HostingExtensions.cs +++ b/src/Yavsc/Extensions/HostingExtensions.cs @@ -1,8 +1,10 @@ +using System.Diagnostics; using System.Globalization; using System.Security.Cryptography.X509Certificates; using Google.Apis.Util.Store; using IdentityServer8; using IdentityServer8.Services; +using IdentityServerHost.Quickstart.UI; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.DataProtection; @@ -27,6 +29,7 @@ using Yavsc.Models.Workflow; using Yavsc.Services; using Yavsc.Settings; using Yavsc.ViewModels.Auth; +using Yavsc.Server.Helpers; namespace Yavsc.Extensions; @@ -137,30 +140,28 @@ public static class HostingExtensions { IServiceCollection services = LoadConfiguration(builder); - services.AddRazorPages(); - - services.AddSignalR(o => - { - o.EnableDetailedErrors = true; - }); - - AddIdentityDBAndStores(builder).AddDefaultTokenProviders();; - - AddIdentityServer(builder); - //services.AddScoped(); + //services.AddRazorPages(); + services.AddSession(); // TODO .AddServerSideSessionStore() - AddAuthentication(services, builder.Configuration); // Add the system clock service _ = services.AddSingleton(); _ = services.AddSingleton(); _ = services.AddSingleton(); _ = services.AddTransient(); + + AddIdentityDBAndStores(builder).AddDefaultTokenProviders(); + AddIdentityServer(builder); + services.AddSignalR(o => + { + o.EnableDetailedErrors = true; + }); + services.AddMvc(config => { /* var policy = new AuthorizationPolicyBuilder() @@ -208,6 +209,7 @@ public static class HostingExtensions services.AddSingleton(); + AddAuthentication(builder); // accepts any access token issued by identity server return builder.Build(); @@ -297,20 +299,16 @@ public static class HostingExtensions return services; } - private static void AddAuthentication(IServiceCollection services, IConfigurationRoot configurationRoot) + private static void AddAuthentication(WebApplicationBuilder builder) { - string? googleClientId = configurationRoot["Authentication:Google:ClientId"]; + IServiceCollection services=builder.Services; + IConfigurationRoot configurationRoot=builder.Configuration; + string? googleClientId = configurationRoot["Authentication:Google:ClientId"]; string? googleClientSecret = configurationRoot["Authentication:Google:ClientSecret"]; - var authenticationBuilder = services.AddAuthentication() - .AddJwtBearer("Bearer", options => - { - options.IncludeErrorDetails = true; - options.Authority = "https://localhost:5001"; - options.TokenValidationParameters = - new() { ValidateAudience = false }; - }); - + var authenticationBuilder = services.AddAuthentication(); + + if (googleClientId!=null && googleClientSecret!=null) authenticationBuilder.AddGoogle(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; @@ -324,21 +322,31 @@ public static class HostingExtensions } private static IIdentityServerBuilder AddIdentityServer(WebApplicationBuilder builder) { - var identityServerBuilder = builder.Services.AddIdentityServer() + builder.Services.AddTransient(); + var identityServerBuilder = builder.Services.AddIdentityServer(options => + { + options.Events.RaiseErrorEvents = true; + options.Events.RaiseInformationEvents = true; + options.Events.RaiseFailureEvents = true; + options.Events.RaiseSuccessEvents = true; + + // see https://IdentityServer8.readthedocs.io/en/latest/topics/resources.html + options.EmitStaticAudienceClaim = true; + }) .AddInMemoryIdentityResources(Config.IdentityResources) .AddInMemoryClients(Config.Clients) .AddInMemoryApiScopes(Config.ApiScopes) .AddAspNetIdentity() - .AddJwtBearerClientAuthentication() - // .AddProfileService() - ; + .AddProfileService() + ; if (builder.Environment.IsDevelopment()) { identityServerBuilder.AddDeveloperSigningCredential(); } else { - var key = builder.Configuration["YOUR-KEY-NAME"]; + var key = builder.Configuration["YavscSigningCert"]; + Debug.Assert(key != null); var pfxBytes = Convert.FromBase64String(key); var cert = new X509Certificate2(pfxBytes, (string)null, X509KeyStorageFlags.MachineKeySet); identityServerBuilder.AddSigningCredential(cert); @@ -381,7 +389,7 @@ public static class HostingExtensions } - public static WebApplication ConfigurePipeline(this WebApplication app) + internal static WebApplication ConfigurePipeline(this WebApplication app) { if (app.Environment.IsDevelopment()) @@ -398,13 +406,10 @@ public static class HostingExtensions app.UseIdentityServer(); app.UseAuthorization(); app.UseCors("default"); - app.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - app.MapRazorPages() - .RequireAuthorization(); + app.MapDefaultControllerRoute(); + //pp.MapRazorPages(); app.MapHub("/chatHub"); - app.MapAreaControllerRoute("api", "api", "~/api/{controller}/{action}/{id?}"); + ConfigureWorkflow(); var services = app.Services; ILoggerFactory loggerFactory = services.GetRequiredService(); diff --git a/src/Yavsc/Helpers/UserHelpers.cs b/src/Yavsc/Helpers/UserHelpers.cs new file mode 100644 index 00000000..ade8cac0 --- /dev/null +++ b/src/Yavsc/Helpers/UserHelpers.cs @@ -0,0 +1,10 @@ +using System.Security.Claims; + +namespace Yavsc.Helpers +{ + public static class UserHelpers + { + + + } +} diff --git a/src/Yavsc/Properties/launchSettings.json b/src/Yavsc/Properties/launchSettings.json index c7aa64d5..a78ff8ae 100644 --- a/src/Yavsc/Properties/launchSettings.json +++ b/src/Yavsc/Properties/launchSettings.json @@ -1,27 +1,19 @@ -{ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { - "applicationUrl": "http://localhost:30089", - "sslPort": 44391 + "applicationUrl": "https://localhost:5001", + "sslPort": 5001 } }, "profiles": { - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "http://localhost:5172", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "https://localhost:7062;http://localhost:5172", + "applicationUrl": "https://localhost:5001;", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/src/Yavsc/ScaffoldingReadMe.txt b/src/Yavsc/ScaffoldingReadMe.txt deleted file mode 100644 index 6e6208dc..00000000 --- a/src/Yavsc/ScaffoldingReadMe.txt +++ /dev/null @@ -1,3 +0,0 @@ -Support for ASP.NET Core Identity was added to your project. - -For setup and configuration information, see https://go.microsoft.com/fwlink/?linkid=2116645. diff --git a/src/Yavsc/Startup.cs b/src/Yavsc/Startup.cs index 1625debf..93cf5dcf 100644 --- a/src/Yavsc/Startup.cs +++ b/src/Yavsc/Startup.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; using Yavsc.Helpers; +using Yavsc.Server.Helpers; using Yavsc.Settings; namespace Yavsc; diff --git a/src/Yavsc/ViewComponents/BillViewComponent.cs b/src/Yavsc/ViewComponents/BillViewComponent.cs index 4f7c3fc5..d0d0b9fe 100644 --- a/src/Yavsc/ViewComponents/BillViewComponent.cs +++ b/src/Yavsc/ViewComponents/BillViewComponent.cs @@ -8,6 +8,7 @@ using Yavsc.ViewModels; using Yavsc.ViewModels.Gen; using Yavsc.Services; using Microsoft.EntityFrameworkCore; +using Yavsc.Server.Helpers; namespace Yavsc.ViewComponents { diff --git a/src/Yavsc/ViewComponents/DirectoryViewComponent.cs b/src/Yavsc/ViewComponents/DirectoryViewComponent.cs index b5f5b902..af7f436b 100644 --- a/src/Yavsc/ViewComponents/DirectoryViewComponent.cs +++ b/src/Yavsc/ViewComponents/DirectoryViewComponent.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using Yavsc.Helpers; using Yavsc.Models; +using Yavsc.Server.Helpers; using Yavsc.ViewModels.UserFiles; namespace Yavsc.ViewComponents diff --git a/src/Yavsc/Views/Shared/Error.cshtml b/src/Yavsc/Views/Shared/Error.cshtml index d5a8de36..3bfd9196 100644 --- a/src/Yavsc/Views/Shared/Error.cshtml +++ b/src/Yavsc/Views/Shared/Error.cshtml @@ -12,14 +12,3 @@ Request ID: @Model.RequestId

} - -

Development Mode

-

- Swapping to Development environment will display more detailed information about the error that occurred. -

-

- The Development environment shouldn't be enabled for deployed applications. - It can result in displaying sensitive information from exceptions to end users. - For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development - and restarting the app. -

diff --git a/src/Yavsc/app.config b/src/Yavsc/app.config deleted file mode 100644 index 8460dd43..00000000 --- a/src/Yavsc/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/Yavsc/package.json b/src/Yavsc/package.json deleted file mode 100644 index 545fc0a6..00000000 --- a/src/Yavsc/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "yavsc", - "version": "1.0.7", - "description": "Yet Another Very Small Company", - "repository": { - "type": "Git", - "url": "https://github.com/pazof/yavsc" - }, - "license": "GPL-3.0", - "devDependencies": {}, - "dependencies": { - "paypal-permissions-sdk": "^1.0.10" - } -} diff --git a/src/sampleWebAsWebApiClient/Controllers/HomeController.cs b/src/sampleWebAsWebApiClient/Controllers/HomeController.cs index 4dadcc91..96eb7dfc 100755 --- a/src/sampleWebAsWebApiClient/Controllers/HomeController.cs +++ b/src/sampleWebAsWebApiClient/Controllers/HomeController.cs @@ -71,12 +71,11 @@ namespace testOauthClient.Controllers var accessToken = await HttpContext.GetTokenAsync("access_token"); var client = new HttpClient(new HttpClientHandler(){ AllowAutoRedirect=false }); client.DefaultRequestHeaders.Add("Accept", "application/json"); - client.SetBearerToken(accessToken); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); var content = await client.GetAsync("https://localhost:6001/identity"); content.EnsureSuccessStatusCode(); - var json = await content.Content.ReadAsStreamAsync(); - var obj = JsonSerializer.Deserialize(json); - return View("UserInfo", obj.ToString()); + var json = await content.Content.ReadAsStringAsync(); + return View("UserInfo", json); } diff --git a/src/sampleWebAsWebApiClient/Program.cs b/src/sampleWebAsWebApiClient/Program.cs index 966579dd..5cc25c36 100644 --- a/src/sampleWebAsWebApiClient/Program.cs +++ b/src/sampleWebAsWebApiClient/Program.cs @@ -1,19 +1,62 @@ -using Microsoft.AspNetCore.Authentication.OAuth; +/* + Copyright (c) 2024 HigginsSoft, Alexander Higgins - https://github.com/alexhiggins732/ + + Copyright (c) 2018, Brock Allen & Dominick Baier. All rights reserved. + + Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + Source code and license this software can be found + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. +*/ + +using System.IdentityModel.Tokens.Jwt; using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; - public class Program +JwtSecurityTokenHandler.DefaultMapInboundClaims = false; + + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllersWithViews(); +builder.Services + .AddAuthentication(options => { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } + options.DefaultScheme = "Cookies"; + options.DefaultChallengeScheme = "oidc"; + }) + .AddCookie("Cookies") + .AddOpenIdConnect("oidc", options => + { + options.Authority = "https://localhost:5001"; - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); - } + options.ClientId = "mvc"; + options.ClientSecret = "49C1A7E1-0C79-4A89-A3D6-A37998FB86B0"; + options.ResponseType = "code"; + + options.Scope.Add("openid"); + options.Scope.Add("profile"); + options.Scope.Add("scope2"); + options.MapInboundClaims = true; + options.ClaimActions.MapUniqueJsonKey("preferred_username","preferred_username"); + options.ClaimActions.MapUniqueJsonKey("gender", "gender"); + + options.SaveTokens = true; + }); + + +using (var app = builder.Build()) +{ + if (app.Environment.IsDevelopment()) + app.UseDeveloperExceptionPage(); + else + app.UseExceptionHandler("/Home/Error"); + + app.UseStaticFiles(); + app.UseRouting(); + app.UseAuthentication(); + app.UseAuthorization(); + app.MapDefaultControllerRoute().RequireAuthorization(); + + await app.RunAsync(); +} diff --git a/src/sampleWebAsWebApiClient/Startup.cs b/src/sampleWebAsWebApiClient/Startup.cs deleted file mode 100644 index 9abcab39..00000000 --- a/src/sampleWebAsWebApiClient/Startup.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.IdentityModel.Tokens; -using System.IdentityModel.Tokens.Jwt; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - - services.AddControllersWithViews(); - services - .AddAuthentication(options => - { - options.DefaultScheme = "Cookies"; - options.DefaultChallengeScheme = "oidc"; - }) - .AddCookie("Cookies") - .AddOpenIdConnect("oidc", options => - { - options.Authority = "https://localhost:5001"; - - options.ClientId = "mvc"; - options.ClientSecret = "49C1A7E1-0C79-4A89-A3D6-A37998FB86B0"; - options.ResponseType = "code"; - - options.Scope.Add("scope2"); - - options.SaveTokens = true; - - options.GetClaimsFromUserInfoEndpoint = true; - options.SaveTokens = true; - options.ClaimActions.MapUniqueJsonKey( - "http://schemas.microsoft.com/ws/2008/06/identity/claims/role", - "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"); - options.ClaimActions.MapUniqueJsonKey("role", - "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"); - options.ClaimActions.MapUniqueJsonKey("roles", - "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"); - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" - }; - }); - - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Home/Error"); - } - - app.UseStaticFiles(); - - app.UseRouting(); - app.UseAuthentication(); - app.UseAuthorization(); - - app.UseEndpoints(endpoints => - { - endpoints.MapDefaultControllerRoute() - .RequireAuthorization(); - }); - } -} diff --git a/yavsc.code-workspace b/yavsc.code-workspace deleted file mode 100644 index 29367081..00000000 --- a/yavsc.code-workspace +++ /dev/null @@ -1,38 +0,0 @@ -{ - "folders": [ - { - "path": ".vscode" - }, - { - "path": "." - }, - { - "path": "src/test" - }, - { - "path": "src/Yavsc" - }, - { - "path": "src/cli" - }, - { - "path": "src/GoogleCode" - }, - { - "path": "src/OAuth.AspNet.AuthServer" - }, - { - "path": "src/OAuth.AspNet.Token" - }, - { - "path": "src/Yavsc.Abstract" - }, - { - "path": "src/Yavsc.Server" - } - ], - "settings": { - "mocha.enabled": true, - "git.ignoreLimitWarning": true - } -} \ No newline at end of file diff --git a/yavsc.mdw b/yavsc.mdw deleted file mode 100644 index 45b134a7..00000000 --- a/yavsc.mdw +++ /dev/null @@ -1,6 +0,0 @@ - - - ZicMoove.sln - yagui/yagui.sln - - \ No newline at end of file