From 0413e25cb359762255b89246d753936236bbbdee Mon Sep 17 00:00:00 2001 From: "David G. Moore, Jr." Date: Fri, 26 Jan 2024 18:53:28 -0500 Subject: [PATCH] ADDED: Razor extension project files and classes for rendering Razor pages. ADDED: `Dgmjr.AspNetCore.Razor.csproj` with necessary package references. ADDED: `Dgmjr.AspNetCore.Razor.sln` solution file. ADDED: `LICENSE.md` file with MIT License information. ADDED: `PageModel.cs` and `PageModel.cs` files for base page models. ADDED: `icon.png` file. --- .../{ => Abstractions}/ConfigurationOrder.cs | 0 .../IConfigureIApplicationBuilder.cs | 0 .../IConfigureIHostApplicationBuilder.cs | 0 .../IConfigureStuffInOrder.cs | 0 .../AutoConfiguratorConfiguration.cs | 0 src/Configuration/ConfigurationExtensions.cs | 13 --- .../JsonFileAutoConfigurator.cs | 5 +- ...oConfigureIApplicationBuilderExtensions.cs | 0 ...figureIApplicationHostBuilderExtensions.cs | 0 ...figurationExtensions.JsonParseException.cs | 0 .../KeyPerJsonFileConfigurationExtensions.cs | 2 +- .../Dgmjr.Configuration.Extensions.props | 2 +- .../AssemblyLoadExtensions.cs | 0 .../{ => Extensions}/CompositeChangeToken.cs | 0 .../{ => Extensions}/CompositeDisposable.cs | 0 .../Extensions/ConfigurationExtensions.cs | 12 +++ .../Extensions/LoggerExtensions.cs | 27 ++++++ .../MultiServiceCollection.cs | 0 .../{ => Json}/ConfigurationJsonConverter.cs | 2 +- src/Configuration/LoggerExtensions.cs | 12 --- src/Http/Mime/Dgmjr.Mime.csproj | 1 - src/Http/Mime/Dgmjr.Mime.sln | 26 +++--- src/Http/Mime/icon.png | Bin 0 -> 26997 bytes .../Controllers/DirectoryObjectsController.cs | 2 +- .../Controllers/MeController.cs | 8 +- .../Controllers/UsersController.cs | 8 +- src/MicrosoftGraph/Dgmjr.Graph.csproj | 7 ++ src/MicrosoftGraph/Dgmjr.Graph.sln | 26 +++--- .../Extensions/LoggingExtensions.cs | 44 ++++----- ...crosoftGraphServiceCollectionExtensions.cs | 41 +++++++++ src/MicrosoftGraph/Telemetry/Activities.cs | 84 ++++++++++++++++++ .../BearerTokenAuthenticationProvider.cs | 33 +++++++ .../TokenAcquisitionTokenProvider.cs | 70 +++++++++++++++ src/Razor/Dgmjr.AspNetCore.Razor.csproj | 20 +++++ src/Razor/Dgmjr.AspNetCore.Razor.sln | 42 +++++++++ src/Razor/LICENSE.md | 35 ++++++++ src/Razor/Models/PageModelOfT.cs | 51 +++++++++++ src/Razor/icon.png | Bin 0 -> 26997 bytes 38 files changed, 486 insertions(+), 87 deletions(-) rename src/Configuration/{ => Abstractions}/ConfigurationOrder.cs (100%) rename src/Configuration/{ => Abstractions}/IConfigureIApplicationBuilder.cs (100%) rename src/Configuration/{ => Abstractions}/IConfigureIHostApplicationBuilder.cs (100%) rename src/Configuration/{ => Abstractions}/IConfigureStuffInOrder.cs (100%) rename src/Configuration/{ => Configuration}/AutoConfiguratorConfiguration.cs (100%) delete mode 100644 src/Configuration/ConfigurationExtensions.cs rename src/Configuration/{ => Configurators}/JsonFileAutoConfigurator.cs (60%) rename src/Configuration/{ => DependencyInjection}/AutoConfigureIApplicationBuilderExtensions.cs (100%) rename src/Configuration/{ => DependencyInjection}/AutoConfigureIApplicationHostBuilderExtensions.cs (100%) rename src/Configuration/{ => DependencyInjection}/JsonFileConfigurationExtensions.JsonParseException.cs (100%) rename src/Configuration/{ => DependencyInjection}/KeyPerJsonFileConfigurationExtensions.cs (96%) rename src/Configuration/{ => Extensions}/AssemblyLoadExtensions.cs (100%) rename src/Configuration/{ => Extensions}/CompositeChangeToken.cs (100%) rename src/Configuration/{ => Extensions}/CompositeDisposable.cs (100%) create mode 100644 src/Configuration/Extensions/ConfigurationExtensions.cs create mode 100644 src/Configuration/Extensions/LoggerExtensions.cs rename src/Configuration/{ => Extensions}/MultiServiceCollection.cs (100%) rename src/Configuration/{ => Json}/ConfigurationJsonConverter.cs (92%) delete mode 100644 src/Configuration/LoggerExtensions.cs create mode 100644 src/Http/Mime/icon.png create mode 100644 src/MicrosoftGraph/Telemetry/Activities.cs create mode 100644 src/MicrosoftGraph/TokenProviders/BearerTokenAuthenticationProvider.cs create mode 100644 src/MicrosoftGraph/TokenProviders/TokenAcquisitionTokenProvider.cs create mode 100644 src/Razor/Dgmjr.AspNetCore.Razor.csproj create mode 100644 src/Razor/Dgmjr.AspNetCore.Razor.sln create mode 100644 src/Razor/LICENSE.md create mode 100644 src/Razor/Models/PageModelOfT.cs create mode 100644 src/Razor/icon.png diff --git a/src/Configuration/ConfigurationOrder.cs b/src/Configuration/Abstractions/ConfigurationOrder.cs similarity index 100% rename from src/Configuration/ConfigurationOrder.cs rename to src/Configuration/Abstractions/ConfigurationOrder.cs diff --git a/src/Configuration/IConfigureIApplicationBuilder.cs b/src/Configuration/Abstractions/IConfigureIApplicationBuilder.cs similarity index 100% rename from src/Configuration/IConfigureIApplicationBuilder.cs rename to src/Configuration/Abstractions/IConfigureIApplicationBuilder.cs diff --git a/src/Configuration/IConfigureIHostApplicationBuilder.cs b/src/Configuration/Abstractions/IConfigureIHostApplicationBuilder.cs similarity index 100% rename from src/Configuration/IConfigureIHostApplicationBuilder.cs rename to src/Configuration/Abstractions/IConfigureIHostApplicationBuilder.cs diff --git a/src/Configuration/IConfigureStuffInOrder.cs b/src/Configuration/Abstractions/IConfigureStuffInOrder.cs similarity index 100% rename from src/Configuration/IConfigureStuffInOrder.cs rename to src/Configuration/Abstractions/IConfigureStuffInOrder.cs diff --git a/src/Configuration/AutoConfiguratorConfiguration.cs b/src/Configuration/Configuration/AutoConfiguratorConfiguration.cs similarity index 100% rename from src/Configuration/AutoConfiguratorConfiguration.cs rename to src/Configuration/Configuration/AutoConfiguratorConfiguration.cs diff --git a/src/Configuration/ConfigurationExtensions.cs b/src/Configuration/ConfigurationExtensions.cs deleted file mode 100644 index e96474f2..00000000 --- a/src/Configuration/ConfigurationExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Dgmjr.Extensions.Configuration; - -public static class ConfigurationExtensions -{ - public static string ToJson(this IConfiguration config) - { - return JsonSerializer.Serialize(config, new Jso - { - WriteIndented = true, - Converters = { new ConfigurationJsonConverter() } - }); - } -} diff --git a/src/Configuration/JsonFileAutoConfigurator.cs b/src/Configuration/Configurators/JsonFileAutoConfigurator.cs similarity index 60% rename from src/Configuration/JsonFileAutoConfigurator.cs rename to src/Configuration/Configurators/JsonFileAutoConfigurator.cs index 73c165bb..3f91a022 100644 --- a/src/Configuration/JsonFileAutoConfigurator.cs +++ b/src/Configuration/Configurators/JsonFileAutoConfigurator.cs @@ -9,7 +9,10 @@ public class JsonFileAutoConfigurator : IConfigureIHostApplicationBuilder public void Configure(IHostApplicationBuilder builder) { - builder.Configuration.AddKeyPerJsonFile(Path.Join(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Configuration")); + builder.Configuration.AddKeyPerJsonFile( + Path.Join(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Configuration") + ); builder.Configuration.AddSubstitution(); + Console.WriteLine($"Configuration: {builder.Configuration.ToJson()}"); } } diff --git a/src/Configuration/AutoConfigureIApplicationBuilderExtensions.cs b/src/Configuration/DependencyInjection/AutoConfigureIApplicationBuilderExtensions.cs similarity index 100% rename from src/Configuration/AutoConfigureIApplicationBuilderExtensions.cs rename to src/Configuration/DependencyInjection/AutoConfigureIApplicationBuilderExtensions.cs diff --git a/src/Configuration/AutoConfigureIApplicationHostBuilderExtensions.cs b/src/Configuration/DependencyInjection/AutoConfigureIApplicationHostBuilderExtensions.cs similarity index 100% rename from src/Configuration/AutoConfigureIApplicationHostBuilderExtensions.cs rename to src/Configuration/DependencyInjection/AutoConfigureIApplicationHostBuilderExtensions.cs diff --git a/src/Configuration/JsonFileConfigurationExtensions.JsonParseException.cs b/src/Configuration/DependencyInjection/JsonFileConfigurationExtensions.JsonParseException.cs similarity index 100% rename from src/Configuration/JsonFileConfigurationExtensions.JsonParseException.cs rename to src/Configuration/DependencyInjection/JsonFileConfigurationExtensions.JsonParseException.cs diff --git a/src/Configuration/KeyPerJsonFileConfigurationExtensions.cs b/src/Configuration/DependencyInjection/KeyPerJsonFileConfigurationExtensions.cs similarity index 96% rename from src/Configuration/KeyPerJsonFileConfigurationExtensions.cs rename to src/Configuration/DependencyInjection/KeyPerJsonFileConfigurationExtensions.cs index 695b1b04..830b61d2 100644 --- a/src/Configuration/KeyPerJsonFileConfigurationExtensions.cs +++ b/src/Configuration/DependencyInjection/KeyPerJsonFileConfigurationExtensions.cs @@ -14,7 +14,7 @@ namespace Microsoft.Extensions.DependencyInjection; using System.IO; using static KeyPerJsonFileConfigurationExtensions; -public static partial class KeyPerJsonFileConfigurationExtensions +internal static partial class KeyPerJsonFileConfigurationExtensions { public const string AppSettings = "all_appsettings"; public const string AppSettings_Json = "/" + AppSettings + ".json"; diff --git a/src/Configuration/Dgmjr.Configuration.Extensions.props b/src/Configuration/Dgmjr.Configuration.Extensions.props index 7aa223cf..cb4c707f 100644 --- a/src/Configuration/Dgmjr.Configuration.Extensions.props +++ b/src/Configuration/Dgmjr.Configuration.Extensions.props @@ -6,6 +6,6 @@ - + diff --git a/src/Configuration/AssemblyLoadExtensions.cs b/src/Configuration/Extensions/AssemblyLoadExtensions.cs similarity index 100% rename from src/Configuration/AssemblyLoadExtensions.cs rename to src/Configuration/Extensions/AssemblyLoadExtensions.cs diff --git a/src/Configuration/CompositeChangeToken.cs b/src/Configuration/Extensions/CompositeChangeToken.cs similarity index 100% rename from src/Configuration/CompositeChangeToken.cs rename to src/Configuration/Extensions/CompositeChangeToken.cs diff --git a/src/Configuration/CompositeDisposable.cs b/src/Configuration/Extensions/CompositeDisposable.cs similarity index 100% rename from src/Configuration/CompositeDisposable.cs rename to src/Configuration/Extensions/CompositeDisposable.cs diff --git a/src/Configuration/Extensions/ConfigurationExtensions.cs b/src/Configuration/Extensions/ConfigurationExtensions.cs new file mode 100644 index 00000000..aa093177 --- /dev/null +++ b/src/Configuration/Extensions/ConfigurationExtensions.cs @@ -0,0 +1,12 @@ +namespace Dgmjr.Configuration.Extensions; + +public static class ConfigurationExtensions +{ + public static string ToJson(this IConfiguration config) + { + return JsonSerializer.Serialize( + config, + new Jso { WriteIndented = true, Converters = { new ConfigurationJsonConverter() } } + ); + } +} diff --git a/src/Configuration/Extensions/LoggerExtensions.cs b/src/Configuration/Extensions/LoggerExtensions.cs new file mode 100644 index 00000000..478b6b4b --- /dev/null +++ b/src/Configuration/Extensions/LoggerExtensions.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.Logging; + +namespace Dgmjr.Configuration.Extensions; + +public static partial class LoggerExtensions +{ + [LoggerMessage( + 1, + LogLevel.Trace, + "Found {Files} JSON files in {Directory} for environment {env}", + EventName = "FilesFound" + )] + public static partial void FilesFound( + this ILogger logger, + int files, + string directory, + string env + ); + + [LoggerMessage( + 2, + LogLevel.Trace, + "File {Filename}: {Lines} lines", + EventName = "JSONConfigFileRead" + )] + public static partial void JsonConfigFileRead(this ILogger logger, string filename, int lines); +} diff --git a/src/Configuration/MultiServiceCollection.cs b/src/Configuration/Extensions/MultiServiceCollection.cs similarity index 100% rename from src/Configuration/MultiServiceCollection.cs rename to src/Configuration/Extensions/MultiServiceCollection.cs diff --git a/src/Configuration/ConfigurationJsonConverter.cs b/src/Configuration/Json/ConfigurationJsonConverter.cs similarity index 92% rename from src/Configuration/ConfigurationJsonConverter.cs rename to src/Configuration/Json/ConfigurationJsonConverter.cs index a7a710ba..ab2f3d7a 100644 --- a/src/Configuration/ConfigurationJsonConverter.cs +++ b/src/Configuration/Json/ConfigurationJsonConverter.cs @@ -1,4 +1,4 @@ -namespace Dgmjr.Extensions.Configuration; +namespace Dgmjr.Configuration.Extensions; public class ConfigurationJsonConverter : JsonConverter { diff --git a/src/Configuration/LoggerExtensions.cs b/src/Configuration/LoggerExtensions.cs deleted file mode 100644 index 28ed5c1b..00000000 --- a/src/Configuration/LoggerExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.Extensions.Logging; - -namespace Dgmjr.Configuration.Extensions; - -public static partial class LoggerExtensions -{ - [LoggerMessage(1, LogLevel.Trace, "Found {Files} JSON files in {Directory} for environment {env}", EventName = "FilesFound")] - public static partial void LogFilesFound(this ILogger logger, int files, string directory, string env); - - [LoggerMessage(2, LogLevel.Trace, "File {Filename}: {Lines} lines", EventName = "JSONConfigFileRead")] - public static partial void LogJsonConfigFileRead(this ILogger logger, string filename, int lines); -} diff --git a/src/Http/Mime/Dgmjr.Mime.csproj b/src/Http/Mime/Dgmjr.Mime.csproj index 0554c662..12200945 100644 --- a/src/Http/Mime/Dgmjr.Mime.csproj +++ b/src/Http/Mime/Dgmjr.Mime.csproj @@ -32,7 +32,6 @@ - diff --git a/src/Http/Mime/Dgmjr.Mime.sln b/src/Http/Mime/Dgmjr.Mime.sln index d86bb846..91859dfc 100644 --- a/src/Http/Mime/Dgmjr.Mime.sln +++ b/src/Http/Mime/Dgmjr.Mime.sln @@ -8,7 +8,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\..\..\..\..\Packages\Versions.Local.props = ..\..\..\..\..\Packages\Versions.Local.props EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Mime", "Dgmjr.Mime.csproj", "{7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Mime", "Dgmjr.Mime.csproj", "{03655B61-669E-42F1-913F-C1D7BD387EEE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -20,18 +20,18 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Local|Any CPU.ActiveCfg = Local|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Local|Any CPU.Build.0 = Local|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Testing|Any CPU.ActiveCfg = Testing|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Testing|Any CPU.Build.0 = Testing|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Staging|Any CPU.ActiveCfg = Staging|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Staging|Any CPU.Build.0 = Staging|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Production|Any CPU.ActiveCfg = Local|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Production|Any CPU.Build.0 = Local|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7251BA6B-4FF8-45FB-9380-9E4EBC5A867B}.Release|Any CPU.Build.0 = Release|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Local|Any CPU.ActiveCfg = Local|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Local|Any CPU.Build.0 = Local|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Testing|Any CPU.ActiveCfg = Testing|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Testing|Any CPU.Build.0 = Testing|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Staging|Any CPU.ActiveCfg = Staging|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Staging|Any CPU.Build.0 = Staging|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Production|Any CPU.ActiveCfg = Local|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Production|Any CPU.Build.0 = Local|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03655B61-669E-42F1-913F-C1D7BD387EEE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Http/Mime/icon.png b/src/Http/Mime/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..db07a039193d57c5147e651a7ab732121bfd20ba GIT binary patch literal 26997 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 CAey28 literal 0 HcmV?d00001 diff --git a/src/MicrosoftGraph/Controllers/DirectoryObjectsController.cs b/src/MicrosoftGraph/Controllers/DirectoryObjectsController.cs index dcf6ad0e..8db2bb83 100644 --- a/src/MicrosoftGraph/Controllers/DirectoryObjectsController.cs +++ b/src/MicrosoftGraph/Controllers/DirectoryObjectsController.cs @@ -27,7 +27,7 @@ IServiceProvider services [HttpGet(Uris.ExtensionProperties)] public async Task GetExtensionPropertiesAsync() { - Logger.PageVisited(Http.Get, Request.Path); + Logger.Get(Request.Path); return Ok( ( await DirectoryObjectsService.GetExtensionPropertiesAsync(default) diff --git a/src/MicrosoftGraph/Controllers/MeController.cs b/src/MicrosoftGraph/Controllers/MeController.cs index f4c99346..a83ff349 100644 --- a/src/MicrosoftGraph/Controllers/MeController.cs +++ b/src/MicrosoftGraph/Controllers/MeController.cs @@ -19,7 +19,7 @@ public class MeController(ILogger logger, IServiceProvider service [Produces(MsGraphUserJson, MsGraphUserXml, MsGraphUserBson, MsGraphUserMsgPack)] public async Task Get() { - Logger.PageVisited(Http.Get, Me); + Logger.Get(Me); return Ok(await _users.GetMeAsync()); } @@ -30,7 +30,7 @@ public async Task Get() [ProducesResponseType(typeof(long), Status200OK)] public async Task Get([FromRoute] string property) { - Logger.PageVisited(Http.Get, Request.Path); + Logger.Get(Request.Path); var propertyFullName = new DGraphExtensionProperty(property).Name; var result = await Graph.Me.Request().Select(u => u.AdditionalData[propertyFullName]).GetAsync(); var value = result.AdditionalData[new DGraphExtensionProperty(property).Name]; @@ -41,7 +41,7 @@ public async Task Get([FromRoute] string property) [Produces(MsGraphUserJson, MsGraphUserXml, MsGraphUserBson, MsGraphUserMsgPack)] public async Task Post([FromRoute] string property, [FromQuery] string value) { - Logger.PageVisited(Http.Post, Request.Path); + Logger.Post(Request.Path); var me = await Graph.Me.Request().GetAsync(); me.AdditionalData[property] = value; return Ok(await Graph.Me.Request().UpdateAsync(me)); @@ -52,7 +52,7 @@ public async Task Post([FromRoute] string property, [FromQuery] s [Produces(MsGraphExtensionPropertiesListJson, MsGraphExtensionPropertiesListXml, MsGraphExtensionPropertiesListBson, MsGraphExtensionPropertiesListMsgPack)] public async Task GetExtensionProperties() { - Logger.PageVisited(Http.Get, $"{Me}/{Uris.ExtensionProperties}"); + Logger.Get($"{Me}/{Uris.ExtensionProperties}"); return Ok((await _users.GetExtensionPropertiesAsync(default)).Cast()); } } diff --git a/src/MicrosoftGraph/Controllers/UsersController.cs b/src/MicrosoftGraph/Controllers/UsersController.cs index 7c084642..dad1e88a 100644 --- a/src/MicrosoftGraph/Controllers/UsersController.cs +++ b/src/MicrosoftGraph/Controllers/UsersController.cs @@ -18,7 +18,7 @@ public class UsersController(ILogger logger, IServiceProvider s [Produces(MsGraphUserJson, MsGraphUserXml, MsGraphUserBson, MsGraphUserMsgPack)] public async Task Get([FromRoute] guid userId) { - Logger.PageVisited(Http.Get, Request.Path); + Logger.Get(Request.Path); return Ok(await _users.GetAsync(userId.ToString())); } @@ -35,7 +35,7 @@ public async Task Get([FromRoute] guid userId) [ProducesResponseType(typeof(long), Status200OK)] public async Task Get([FromRoute] string property) { - Logger.PageVisited(Http.Get, Request.Path); + Logger.Get(Request.Path); var result = await _users.GetAsync((await _users.GetMyIdAsync()).ToString(), property); var value = result.AdditionalData[new DGraphExtensionProperty(property).Name]; return Ok(value); @@ -49,7 +49,7 @@ public async Task Post( [FromQuery] string value ) { - Logger.PageVisited(Http.Post, Request.Path); + Logger.Post(Request.Path); var user = await _users.UpdateAsync(userId.ToString(), property, value); return Ok(user); } @@ -64,7 +64,7 @@ [FromQuery] string value )] public async Task GetExtensionProperties() { - Logger.PageVisited(Http.Get, Request.Path); + Logger.Get(Request.Path); return Ok( (await _users.GetExtensionPropertiesAsync(default)).Cast() ); diff --git a/src/MicrosoftGraph/Dgmjr.Graph.csproj b/src/MicrosoftGraph/Dgmjr.Graph.csproj index a7043f37..178196dd 100644 --- a/src/MicrosoftGraph/Dgmjr.Graph.csproj +++ b/src/MicrosoftGraph/Dgmjr.Graph.csproj @@ -9,11 +9,18 @@ + + diff --git a/src/MicrosoftGraph/Dgmjr.Graph.sln b/src/MicrosoftGraph/Dgmjr.Graph.sln index 9caa597d..4d8b5f91 100644 --- a/src/MicrosoftGraph/Dgmjr.Graph.sln +++ b/src/MicrosoftGraph/Dgmjr.Graph.sln @@ -10,7 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Web.DownstreamApis", "..\DownstreamApis\Dgmjr.Web.DownstreamApis.csproj", "{0EB63FC8-4D68-471C-BF25-FF7FBE57A33F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Graph", "Dgmjr.Graph.csproj", "{8F6C27A5-36AD-4A74-BF09-B0C02B346412}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Graph", "Dgmjr.Graph.csproj", "{137D8567-6811-417D-B62F-B0980EB5C5D7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -34,18 +34,18 @@ Global {0EB63FC8-4D68-471C-BF25-FF7FBE57A33F}.Production|Any CPU.Build.0 = Local|Any CPU {0EB63FC8-4D68-471C-BF25-FF7FBE57A33F}.Release|Any CPU.ActiveCfg = Release|Any CPU {0EB63FC8-4D68-471C-BF25-FF7FBE57A33F}.Release|Any CPU.Build.0 = Release|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Local|Any CPU.ActiveCfg = Local|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Local|Any CPU.Build.0 = Local|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Testing|Any CPU.ActiveCfg = Testing|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Testing|Any CPU.Build.0 = Testing|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Staging|Any CPU.ActiveCfg = Staging|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Staging|Any CPU.Build.0 = Staging|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Production|Any CPU.ActiveCfg = Local|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Production|Any CPU.Build.0 = Local|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8F6C27A5-36AD-4A74-BF09-B0C02B346412}.Release|Any CPU.Build.0 = Release|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Local|Any CPU.ActiveCfg = Local|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Local|Any CPU.Build.0 = Local|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Testing|Any CPU.ActiveCfg = Testing|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Testing|Any CPU.Build.0 = Testing|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Staging|Any CPU.ActiveCfg = Staging|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Staging|Any CPU.Build.0 = Staging|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Production|Any CPU.ActiveCfg = Local|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Production|Any CPU.Build.0 = Local|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {137D8567-6811-417D-B62F-B0980EB5C5D7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/MicrosoftGraph/Extensions/LoggingExtensions.cs b/src/MicrosoftGraph/Extensions/LoggingExtensions.cs index 86036235..b4997606 100644 --- a/src/MicrosoftGraph/Extensions/LoggingExtensions.cs +++ b/src/MicrosoftGraph/Extensions/LoggingExtensions.cs @@ -1,24 +1,24 @@ -namespace Dgmjr.Graph; +// namespace Dgmjr.Graph; -internal static partial class LoggingExtensions -{ - [LoggerMessage( - EventId = 1, - Level = LogLevel.Information, - Message = "{Method} {Path}", - EventName = nameof(PageVisited) - )] - public static partial void PageVisited( - this ILogger logger, - System.Net.Http.HttpMethod method, - string path - ); +// internal static partial class LoggingExtensions +// { +// [LoggerMessage( +// EventId = 1, +// Level = LogLevel.Information, +// Message = "{Method} {Path}", +// EventName = nameof(PageVisited) +// )] +// public static partial void PageVisited( +// this ILogger logger, +// System.Net.Http.HttpMethod method, +// string path +// ); - [LoggerMessage( - EventId = 1, - Level = LogLevel.Information, - Message = "{Method} {Path}", - EventName = nameof(PageVisited) - )] - public static partial void PageVisited(this ILogger logger, string method, string path); -} +// [LoggerMessage( +// EventId = 1, +// Level = LogLevel.Information, +// Message = "{Method} {Path}", +// EventName = nameof(PageVisited) +// )] +// public static partial void PageVisited(this ILogger logger, string method, string path); +// } diff --git a/src/MicrosoftGraph/Extensions/MicrosoftGraphServiceCollectionExtensions.cs b/src/MicrosoftGraph/Extensions/MicrosoftGraphServiceCollectionExtensions.cs index 3fdd497b..924d189d 100644 --- a/src/MicrosoftGraph/Extensions/MicrosoftGraphServiceCollectionExtensions.cs +++ b/src/MicrosoftGraph/Extensions/MicrosoftGraphServiceCollectionExtensions.cs @@ -1,3 +1,10 @@ +using System.Security.Claims; + +using Microsoft.Kiota.Abstractions.Authentication; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Dgmjr.Graph.TokenProviders; +using IAuthenticationProvider = Microsoft.Graph.IAuthenticationProvider; + namespace Microsoft.Extensions.DependencyInjection; public static class MicrosoftGraphServiceCollectionExtensions @@ -16,6 +23,10 @@ IConfiguration config services.AddScoped(); services.Configure(configSection); services.AddScoped(); + services.Configure(options => + { + options.Events.OnTokenValidated = OnTokenValidated; + }); services.AddPassphraseGenerator(config); return services; } @@ -31,4 +42,34 @@ IConfiguration config services.AddSingleton(); return services; } + + private static async Task OnTokenValidated(TokenValidatedContext context) + { + var services = context.HttpContext.RequestServices; + var tokenAcquisition = services.GetRequiredService(); + var graphClientOptions = services.GetRequiredService>().Value; + + var graphClient = new GraphServiceClient( + new BaseBearerTokenAuthenticationProvider( + new TokenAcquisitionTokenProvider( + tokenAcquisition, + [MsGraphScopes.Default], + context.Principal + ) + ) as IAuthenticationProvider + ); + var me = await graphClient.Me.Request().GetAsync(); + var app = await graphClient.Applications[graphClientOptions.AzureAdB2CExtensionsApplicationId.ToString()].Request().GetAsync(); + var appRoles = app.AppRoles; + var myAppRoles = me.AppRoleAssignments.Where(x => x.ResourceId == graphClientOptions.AzureAdB2CExtensionsApplicationId).ToList(); + var claims = new List(); + foreach (var appRole in myAppRoles) + { + var theAppRole = appRoles.FirstOrDefault(x => x.Id.ToString() == appRole.Id); + if(theAppRole != null) + { + claims.Add(new(ClaimTypes.Role, theAppRole.Value)); + } + } + } } diff --git a/src/MicrosoftGraph/Telemetry/Activities.cs b/src/MicrosoftGraph/Telemetry/Activities.cs new file mode 100644 index 00000000..0d68b163 --- /dev/null +++ b/src/MicrosoftGraph/Telemetry/Activities.cs @@ -0,0 +1,84 @@ +/* + * Activities.cs + * + * Created: 2024-03-26T11:03:20-05:00 + * Modified: 2024-03-26T11:03:22-05:00 + * + * Author: David G. Moore, Jr. + * + * Copyright © 2023 - 2024 David G. Moore, Jr., All Rights Reserved + * License: MIT (https://opensource.org/licenses/MIT) + */ + +namespace Dgmjr.Graph.Telemetry; + +public static class Activities +{ + private static readonly Version AssemblyVersion = typeof(Activities).Assembly.GetName().Version; + + /// + /// Base ActivitySource + /// + public static readonly ActivitySource BasicActivitySource = + new(TraceNames.Basic, ServiceVersion); + + /// + /// Store ActivitySource + /// + public static readonly ActivitySource StoreActivitySource = + new(TraceNames.Store, ServiceVersion); + + /// + /// Cache ActivitySource + /// + public static readonly ActivitySource CacheActivitySource = + new(TraceNames.Cache, ServiceVersion); + + /// + /// Cache ActivitySource + /// + public static readonly ActivitySource ServiceActivitySource = + new(TraceNames.Services, ServiceVersion); + + /// + /// Detailed validation ActivitySource + /// + public static readonly ActivitySource ValidationActivitySource = + new(TraceNames.Validation, ServiceVersion); + + /// + /// Service version + /// + public static readonly string ServiceVersion = + $"{AssemblyVersion.Major}.{AssemblyVersion.Minor}.{AssemblyVersion.Build}"; +} + +public static class TraceNames +{ + /// + /// Service name for base traces + /// + public const string Basic = "Dgmjr.Graph"; + + /// + /// Service name for store traces + /// + public const string Store = Basic + ".Stores"; + + /// + /// Service name for caching traces + /// + public const string Cache = Basic + ".Cache"; + + /// + /// Service name for caching traces + /// + public const string Services = Basic + ".Services"; + + /// + /// Service name for detailed validation traces + /// + public const string Validation = Basic + ".Validation"; + + public static readonly string ServiceVersion = Activities.ServiceVersion; +} diff --git a/src/MicrosoftGraph/TokenProviders/BearerTokenAuthenticationProvider.cs b/src/MicrosoftGraph/TokenProviders/BearerTokenAuthenticationProvider.cs new file mode 100644 index 00000000..686dd1e2 --- /dev/null +++ b/src/MicrosoftGraph/TokenProviders/BearerTokenAuthenticationProvider.cs @@ -0,0 +1,33 @@ +/* + * BearerTokenAuthenticationProvider.cs + * + * Created: 2024-12-26T12:12:00-05:00 + * Modified: 2024-12-26T12:12:00-05:00 + * + * Author: David G. Moore, Jr. + * + * Copyright © 2023 - 2024 David G. Moore, Jr., All Rights Reserved + * License: MIT (https://opensource.org/licenses/MIT) + */ + +using System.Net.Http; +using System.Threading.Tasks; + +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Abstractions.Authentication; + +using IAuthenticationProvider = Microsoft.Graph.IAuthenticationProvider; + +namespace Dgmjr.Graph; + +public class BearerTokenAuthenticationProvider(IAccessTokenProvider accessTokenProvider) + : BaseBearerTokenAuthenticationProvider(accessTokenProvider), + IAuthenticationProvider +{ + public Task AuthenticateRequestAsync(HttpRequestMessage request) + { + return base.AuthenticateRequestAsync(new HttpRequestMessageWrapper(request)); + } +} + +internal class HttpRequestMessageWrapper(HttpRequestMessage request) : RequestInformation { } diff --git a/src/MicrosoftGraph/TokenProviders/TokenAcquisitionTokenProvider.cs b/src/MicrosoftGraph/TokenProviders/TokenAcquisitionTokenProvider.cs new file mode 100644 index 00000000..ed039179 --- /dev/null +++ b/src/MicrosoftGraph/TokenProviders/TokenAcquisitionTokenProvider.cs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +using System.Security; +using System.Security.Claims; +using Microsoft.Identity.Web; +using Microsoft.Kiota.Abstractions.Authentication; + +namespace Dgmjr.Graph.TokenProviders +{ + /// + /// Access token provider used during login. + /// + /// + /// Initializes a new instance of the class. + /// + /// The service to use to acquire tokens. + /// The permission scopes to use for the token request. + /// The user's . + /// Thrown if the is null. + public class TokenAcquisitionTokenProvider( + ITokenAcquisition tokenAcquisition, + string[] scopes, + ClaimsPrincipal? user + ) : IAccessTokenProvider + { + private readonly string[] validHosts = + { + "graph.microsoft.com", + "graph.microsoft.us", + "dod-graph.microsoft.us", + "graph.microsoft.de", + "microsoftgraph.chinacloudapi.cn", + }; + private readonly ClaimsPrincipal _user = + user ?? throw new SecurityException("User claims principal is required."); + + /// + /// Gets the allowed host validator. + /// + public AllowedHostsValidator AllowedHostsValidator => new(validHosts); + + /// + /// Gets an access token for the user. + /// + /// The API URI of the request that the token will be added to. + /// Additional name value pairs to add to the token request. + /// The cancellation token. + /// The access token. + /// Thrown if the URI is not HTTPS. + public async Task GetAuthorizationTokenAsync( + Uri uri, + Dictionary? additionalAuthenticationContext = null, + CancellationToken cancellationToken = default + ) + { + if (!AllowedHostsValidator.IsUrlHostValid(uri)) + { + return string.Empty; + } + + if (uri.Scheme != "https") + { + throw new ArgumentOutOfRangeException(nameof(uri), "URL must use https."); + } + + return await tokenAcquisition.GetAccessTokenForUserAsync(scopes, user: _user); + } + } +} diff --git a/src/Razor/Dgmjr.AspNetCore.Razor.csproj b/src/Razor/Dgmjr.AspNetCore.Razor.csproj new file mode 100644 index 00000000..4ba599dc --- /dev/null +++ b/src/Razor/Dgmjr.AspNetCore.Razor.csproj @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/src/Razor/Dgmjr.AspNetCore.Razor.sln b/src/Razor/Dgmjr.AspNetCore.Razor.sln new file mode 100644 index 00000000..78173457 --- /dev/null +++ b/src/Razor/Dgmjr.AspNetCore.Razor.sln @@ -0,0 +1,42 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B283EBC2-E01F-412D-9339-FD56EF114549}" + ProjectSection(SolutionItems) = preProject + ..\..\Directory.Build.props = ..\..\Directory.Build.props + ..\..\..\..\Directory.Build.targets = ..\..\..\..\Directory.Build.targets + ..\..\..\..\global.json = ..\..\..\..\global.json + ..\..\..\..\Packages\Versions.Local.props = ..\..\..\..\Packages\Versions.Local.props + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.AspNetCore.Razor", "Dgmjr.AspNetCore.Razor.csproj", "{79B76DDB-509E-49B7-9A96-0CFFE607AF60}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Local|Any CPU = Local|Any CPU + Debug|Any CPU = Debug|Any CPU + Testing|Any CPU = Testing|Any CPU + Staging|Any CPU = Staging|Any CPU + Production|Any CPU = Production|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Local|Any CPU.ActiveCfg = Local|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Local|Any CPU.Build.0 = Local|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Testing|Any CPU.ActiveCfg = Testing|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Testing|Any CPU.Build.0 = Testing|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Staging|Any CPU.ActiveCfg = Staging|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Staging|Any CPU.Build.0 = Staging|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Production|Any CPU.ActiveCfg = Local|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Production|Any CPU.Build.0 = Local|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79B76DDB-509E-49B7-9A96-0CFFE607AF60}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6BFD3120-6A1B-430D-A333-79043786681A} + EndGlobalSection +EndGlobal diff --git a/src/Razor/LICENSE.md b/src/Razor/LICENSE.md new file mode 100644 index 00000000..4f592f86 --- /dev/null +++ b/src/Razor/LICENSE.md @@ -0,0 +1,35 @@ +--- +date: 2023-07-13T05:44:46:00-05:00Z +description: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files, yadda, yadda, yadda... +keywords: +- IP +- copyright +- license +- mit +permissions: +- commercial-use +- modifications +- distribution +- private-use +conditions: +- include-copyright +limitations: +- liability +- warranty +lastmod: 2024-01-0T00:39:00.0000+05:00Z +license: MIT +slug: mit-license +title: MIT License +type: license +--- + +# MIT License + +## Copyright © 2022-2024 [David G. Moore, Jr.](mailto:david@dgmjr.io "Send Dr. Moore") ([@dgmjr](https://github.com/dgmjr "Contact Dr. Moore on GitHub")), All Rights Reserved + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/src/Razor/Models/PageModelOfT.cs b/src/Razor/Models/PageModelOfT.cs new file mode 100644 index 00000000..650baf82 --- /dev/null +++ b/src/Razor/Models/PageModelOfT.cs @@ -0,0 +1,51 @@ +/* + * PageModel.cs + * + * Created: 2024-27-26T16:27:46-05:00 + * Modified: 2024-27-26T16:27:46-05:00 + * + * Author: David G. Moore, Jr. + * + * Copyright © 2023 - 2024 David G. Moore, Jr., All Rights Reserved + * License: MIT (https://opensource.org/licenses/MIT) + */ + +namespace Dgmjr.AspNetCore.Razor; + +using Microsoft.AspNetCore.Mvc.RazorPages; +using PageModelBase = Microsoft.AspNetCore.Mvc.RazorPages.PageModel; + +public class PageModel(object? model = default) : PageModelBase +{ + public object? ViewModel { get; set; } = model; + + public string? Title + { + get => ViewData[nameof(Title)]?.ToString(); + set => ViewData[nameof(Title)] = value; + } + public string? Description + { + get => ViewData[nameof(Description)]?.ToString(); + set => ViewData[nameof(Description)] = value; + } + public string[]? Keywords + { + get => ViewData[nameof(Keywords)] as string[]; + set => ViewData[nameof(Keywords)] = value; + } + public string? Author + { + get => ViewData[nameof(Author)]?.ToString(); + set => ViewData[nameof(Author)] = value; + } +} + +public class PageModel(T? model) : PageModel(model) +{ + public new T? ViewModel + { + get => (T?)base.ViewModel; + set => base.ViewModel = value; + } +} diff --git a/src/Razor/icon.png b/src/Razor/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..db07a039193d57c5147e651a7ab732121bfd20ba GIT binary patch literal 26997 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 CAey28 literal 0 HcmV?d00001