From a1e34a9b7b51540bf704467257243d33f36d6622 Mon Sep 17 00:00:00 2001 From: Jesus Fernandez Date: Sat, 21 Sep 2024 15:34:23 +0300 Subject: [PATCH] Module: Identity (MSAL.NET) (#26) --- Directory.Packages.props | 1 + PowerAutomate.Desktop.sln | 7 + PowerAutomate.Desktop.sln.DotSettings | 1 + .../Modules.Identity.Actions/ErrorCodes.cs | 10 + .../GetAccessTokenAction.cs | 56 +++++ .../Modules.Identity.Actions.csproj | 31 +++ .../Properties/Resources.Designer.cs | 215 ++++++++++++++++++ .../Properties/Resources.resx | 176 ++++++++++++++ .../Modules.Actions.Tests.csproj | 1 + 9 files changed, 498 insertions(+) create mode 100644 modules/Modules.Identity.Actions/ErrorCodes.cs create mode 100644 modules/Modules.Identity.Actions/GetAccessTokenAction.cs create mode 100644 modules/Modules.Identity.Actions/Modules.Identity.Actions.csproj create mode 100644 modules/Modules.Identity.Actions/Properties/Resources.Designer.cs create mode 100644 modules/Modules.Identity.Actions/Properties/Resources.resx diff --git a/Directory.Packages.props b/Directory.Packages.props index ffc195e..b259616 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,6 +10,7 @@ + diff --git a/PowerAutomate.Desktop.sln b/PowerAutomate.Desktop.sln index 20f4b02..35168ab 100644 --- a/PowerAutomate.Desktop.sln +++ b/PowerAutomate.Desktop.sln @@ -65,6 +65,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Conditionals.Action EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.PowerFx.Actions", "modules\Modules.PowerFx.Actions\Modules.PowerFx.Actions.csproj", "{86C08ED2-7025-4898-BE9B-BCD10A0C5774}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Identity.Actions", "modules\Modules.Identity.Actions\Modules.Identity.Actions.csproj", "{7D933F4B-9793-4B10-B63D-4247F7E70FF2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -139,6 +141,10 @@ Global {86C08ED2-7025-4898-BE9B-BCD10A0C5774}.Debug|Any CPU.Build.0 = Debug|Any CPU {86C08ED2-7025-4898-BE9B-BCD10A0C5774}.Release|Any CPU.ActiveCfg = Release|Any CPU {86C08ED2-7025-4898-BE9B-BCD10A0C5774}.Release|Any CPU.Build.0 = Release|Any CPU + {7D933F4B-9793-4B10-B63D-4247F7E70FF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D933F4B-9793-4B10-B63D-4247F7E70FF2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D933F4B-9793-4B10-B63D-4247F7E70FF2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D933F4B-9793-4B10-B63D-4247F7E70FF2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -173,6 +179,7 @@ Global {22D1EE4E-815F-48F2-AB46-754518B1F914} = {FEFFE5BC-DCBD-466C-87DE-5B9D8A553256} {791698E0-931E-4F35-97A4-B050FD0B4F82} = {22D1EE4E-815F-48F2-AB46-754518B1F914} {86C08ED2-7025-4898-BE9B-BCD10A0C5774} = {3B78C634-DFD6-43DA-A30E-33AC42224BD4} + {7D933F4B-9793-4B10-B63D-4247F7E70FF2} = {3B78C634-DFD6-43DA-A30E-33AC42224BD4} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution Modules.Actions.Shared\Modules.Actions.Shared.projitems*{7e19e2f1-6de7-4a0e-aed8-7cea38b166af}*SharedItemsImports = 13 diff --git a/PowerAutomate.Desktop.sln.DotSettings b/PowerAutomate.Desktop.sln.DotSettings index c19ff0a..22a60fc 100644 --- a/PowerAutomate.Desktop.sln.DotSettings +++ b/PowerAutomate.Desktop.sln.DotSettings @@ -429,6 +429,7 @@ Storyboard.*, From, To, Duration True True True + True True True False diff --git a/modules/Modules.Identity.Actions/ErrorCodes.cs b/modules/Modules.Identity.Actions/ErrorCodes.cs new file mode 100644 index 0000000..0782dd4 --- /dev/null +++ b/modules/Modules.Identity.Actions/ErrorCodes.cs @@ -0,0 +1,10 @@ +// --------------------------------------------------- +// Copyright (c) Jesus Fernandez. All Rights Reserved. +// --------------------------------------------------- + +namespace PowerAutomate.Desktop.Modules.Identity.Actions; + +internal static class ErrorCodes +{ + public const string Unknown = "UnknownError"; +} \ No newline at end of file diff --git a/modules/Modules.Identity.Actions/GetAccessTokenAction.cs b/modules/Modules.Identity.Actions/GetAccessTokenAction.cs new file mode 100644 index 0000000..6c3c8c9 --- /dev/null +++ b/modules/Modules.Identity.Actions/GetAccessTokenAction.cs @@ -0,0 +1,56 @@ +// --------------------------------------------------- +// Copyright (c) Jesus Fernandez. All Rights Reserved. +// --------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Identity.Client; +using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK; +using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK.Attributes; + +namespace PowerAutomate.Desktop.Modules.Identity.Actions; + +[Action(Id = "GetAccessToken")] +[Throws(ErrorCodes.Unknown)] +[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global", Justification = "PowerAutomate.Desktop.Module.Action")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global", Justification = "PowerAutomate.Desktop.Module.Action")] +[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global", Justification = "PowerAutomate.Desktop.Module.Action")] +[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "PowerAutomate.Desktop.Module.Action")] +[SuppressMessage("ReSharper", "UnusedType.Global", Justification = "PowerAutomate.Desktop.Module.Action")] +public class GetAccessTokenAction : ActionBase +{ + [InputArgument(Order = 3, Required = true)] + public string Authority { get; set; } = null!; + + [InputArgument(Order = 1, Required = true)] + public string ClientId { get; set; } = null!; + + [InputArgument(Order = 2, Required = true)] + public string ClientSecret { get; set; } = null!; + + [InputArgument(Order = 4, Required = true)] + public List Scopes { get; set; } = null!; + + [OutputArgument(Order = 1)] + public string Token { get; set; } = null!; + + public override void Execute(ActionContext context) + { + try + { + var app = ConfidentialClientApplicationBuilder.Create(ClientId) + .WithClientSecret(ClientSecret) + .WithAuthority(new Uri(Authority)) + .Build(); + + var clientParameterBuilder = app.AcquireTokenForClient(Scopes); + var authenticationResult = clientParameterBuilder.ExecuteAsync().GetAwaiter().GetResult(); + Token = authenticationResult.AccessToken; + } + catch (Exception ex) + { + throw new ActionException(ErrorCodes.Unknown, ex.Message, ex); + } + } +} \ No newline at end of file diff --git a/modules/Modules.Identity.Actions/Modules.Identity.Actions.csproj b/modules/Modules.Identity.Actions/Modules.Identity.Actions.csproj new file mode 100644 index 0000000..ee7e4a3 --- /dev/null +++ b/modules/Modules.Identity.Actions/Modules.Identity.Actions.csproj @@ -0,0 +1,31 @@ + + + + Identity + net472 + latest + enable + true + + + + + + + + + + True + True + Resources.resx + + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/modules/Modules.Identity.Actions/Properties/Resources.Designer.cs b/modules/Modules.Identity.Actions/Properties/Resources.Designer.cs new file mode 100644 index 0000000..b8aff49 --- /dev/null +++ b/modules/Modules.Identity.Actions/Properties/Resources.Designer.cs @@ -0,0 +1,215 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PowerAutomate.Desktop.Modules.Identity.Actions.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PowerAutomate.Desktop.Modules.Identity.Actions.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Indicates that there was a problem when executing the operation.. + /// + public static string Error_UnknownError_Description { + get { + return ResourceManager.GetString("Error_UnknownError_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Operation failed. + /// + public static string Error_UnknownError_FriendlyName { + get { + return ResourceManager.GetString("Error_UnknownError_FriendlyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The authority.. + /// + public static string GetAccessToken_Authority_Description { + get { + return ResourceManager.GetString("GetAccessToken_Authority_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Authority. + /// + public static string GetAccessToken_Authority_FriendlyName { + get { + return ResourceManager.GetString("GetAccessToken_Authority_FriendlyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The client identifier.. + /// + public static string GetAccessToken_ClientId_Description { + get { + return ResourceManager.GetString("GetAccessToken_ClientId_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Client ID. + /// + public static string GetAccessToken_ClientId_FriendlyName { + get { + return ResourceManager.GetString("GetAccessToken_ClientId_FriendlyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The client secret.. + /// + public static string GetAccessToken_ClientSecret_Description { + get { + return ResourceManager.GetString("GetAccessToken_ClientSecret_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Client Secret. + /// + public static string GetAccessToken_ClientSecret_FriendlyName { + get { + return ResourceManager.GetString("GetAccessToken_ClientSecret_FriendlyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gets the access token.. + /// + public static string GetAccessToken_Description { + get { + return ResourceManager.GetString("GetAccessToken_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Get access token. + /// + public static string GetAccessToken_FriendlyName { + get { + return ResourceManager.GetString("GetAccessToken_FriendlyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The scopes.. + /// + public static string GetAccessToken_Scopes_Description { + get { + return ResourceManager.GetString("GetAccessToken_Scopes_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Scopes. + /// + public static string GetAccessToken_Scopes_FriendlyName { + get { + return ResourceManager.GetString("GetAccessToken_Scopes_FriendlyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Get an access token.. + /// + public static string GetAccessToken_Summary { + get { + return ResourceManager.GetString("GetAccessToken_Summary", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The token.. + /// + public static string GetAccessToken_Token_Description { + get { + return ResourceManager.GetString("GetAccessToken_Token_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Token. + /// + public static string GetAccessToken_Token_FriendlyName { + get { + return ResourceManager.GetString("GetAccessToken_Token_FriendlyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Perform operations related to Microsoft Authentication.. + /// + public static string Identity_Description { + get { + return ResourceManager.GetString("Identity_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Microsoft Authentication. + /// + public static string Identity_FriendlyName { + get { + return ResourceManager.GetString("Identity_FriendlyName", resourceCulture); + } + } + } +} diff --git a/modules/Modules.Identity.Actions/Properties/Resources.resx b/modules/Modules.Identity.Actions/Properties/Resources.resx new file mode 100644 index 0000000..7a9f133 --- /dev/null +++ b/modules/Modules.Identity.Actions/Properties/Resources.resx @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + Microsoft Authentication + + + Perform operations related to Microsoft Authentication. + + + Get access token + + + Gets the access token. + + + Get an access token. + + + Client ID + + + The client identifier. + + + Client Secret + + + The client secret. + + + Authority + + + The authority. + + + Scopes + + + The scopes. + + + Token + + + The token. + + + Operation failed + + + Indicates that there was a problem when executing the operation. + + \ No newline at end of file diff --git a/tests/Modules.Actions.Tests/Modules.Actions.Tests.csproj b/tests/Modules.Actions.Tests/Modules.Actions.Tests.csproj index 1bd42fc..3e8527d 100644 --- a/tests/Modules.Actions.Tests/Modules.Actions.Tests.csproj +++ b/tests/Modules.Actions.Tests/Modules.Actions.Tests.csproj @@ -16,6 +16,7 @@ +