diff --git a/Directory.Packages.props b/Directory.Packages.props index dfb0f023f4..77ac7fafc2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -2,7 +2,7 @@ true - 0.16.2 + 0.18.0 4.61.0 diff --git a/LibsAndSamples.sln b/LibsAndSamples.sln index 8c0104c004..c49b1d2206 100644 --- a/LibsAndSamples.sln +++ b/LibsAndSamples.sln @@ -1,4 +1,4 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32708.82 MinimumVisualStudioVersion = 10.0.40219.1 @@ -178,6 +178,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CacheExtension", "tests\dev EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Client.Extensions.Msal", "src\client\Microsoft.Identity.Client.Extensions.Msal\Microsoft.Identity.Client.Extensions.Msal.csproj", "{87679336-95BE-47E4-B42B-8F6860A0B215}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "tests\devapps\WAM\NetWSLWam\test.csproj", "{43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug + MobileApps|Any CPU = Debug + MobileApps|Any CPU @@ -554,7 +556,6 @@ Global {24D2AF71-A01E-4450-8C3F-B9923A81134B}.Debug + MobileApps|x86.Build.0 = Debug + MobileApps|Any CPU {24D2AF71-A01E-4450-8C3F-B9923A81134B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {24D2AF71-A01E-4450-8C3F-B9923A81134B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {24D2AF71-A01E-4450-8C3F-B9923A81134B}.Debug|ARM.ActiveCfg = Debug|Any CPU {24D2AF71-A01E-4450-8C3F-B9923A81134B}.Debug|ARM.Build.0 = Debug|Any CPU {24D2AF71-A01E-4450-8C3F-B9923A81134B}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -610,7 +611,6 @@ Global {959A47D9-07E7-4BF3-A0F7-6D9CD42A2C46}.Debug|x86.Build.0 = Debug|Any CPU {959A47D9-07E7-4BF3-A0F7-6D9CD42A2C46}.Release|Any CPU.ActiveCfg = Release|Any CPU {959A47D9-07E7-4BF3-A0F7-6D9CD42A2C46}.Release|Any CPU.Build.0 = Release|Any CPU - {959A47D9-07E7-4BF3-A0F7-6D9CD42A2C46}.Release|ARM.ActiveCfg = Release|Any CPU {959A47D9-07E7-4BF3-A0F7-6D9CD42A2C46}.Release|ARM.Build.0 = Release|Any CPU {959A47D9-07E7-4BF3-A0F7-6D9CD42A2C46}.Release|ARM64.ActiveCfg = Release|Any CPU @@ -723,7 +723,6 @@ Global {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Debug + MobileApps|x86.Build.0 = Debug + MobileApps|Any CPU {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Debug|ARM.ActiveCfg = Debug|Any CPU {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Debug|ARM.Build.0 = Debug|Any CPU {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -738,7 +737,6 @@ Global {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Debug|x86.Build.0 = Debug|Any CPU {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Release|Any CPU.Build.0 = Release|Any CPU - {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Release|ARM.ActiveCfg = Release|Any CPU {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Release|ARM.Build.0 = Release|Any CPU {E7EB3226-D0F5-4A93-87DC-FAAC9A24D684}.Release|ARM64.ActiveCfg = Release|Any CPU @@ -767,7 +765,6 @@ Global {339E0B2B-4408-4947-B134-E8C5AAB11286}.Debug + MobileApps|x86.Build.0 = Debug + MobileApps|Any CPU {339E0B2B-4408-4947-B134-E8C5AAB11286}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {339E0B2B-4408-4947-B134-E8C5AAB11286}.Debug|Any CPU.Build.0 = Debug|Any CPU - {339E0B2B-4408-4947-B134-E8C5AAB11286}.Debug|ARM.ActiveCfg = Debug|Any CPU {339E0B2B-4408-4947-B134-E8C5AAB11286}.Debug|ARM.Build.0 = Debug|Any CPU {339E0B2B-4408-4947-B134-E8C5AAB11286}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -782,7 +779,6 @@ Global {339E0B2B-4408-4947-B134-E8C5AAB11286}.Debug|x86.Build.0 = Debug|Any CPU {339E0B2B-4408-4947-B134-E8C5AAB11286}.Release|Any CPU.ActiveCfg = Release|Any CPU {339E0B2B-4408-4947-B134-E8C5AAB11286}.Release|Any CPU.Build.0 = Release|Any CPU - {339E0B2B-4408-4947-B134-E8C5AAB11286}.Release|ARM.ActiveCfg = Release|Any CPU {339E0B2B-4408-4947-B134-E8C5AAB11286}.Release|ARM.Build.0 = Release|Any CPU {339E0B2B-4408-4947-B134-E8C5AAB11286}.Release|ARM64.ActiveCfg = Release|Any CPU @@ -811,7 +807,6 @@ Global {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Debug + MobileApps|x86.Build.0 = Debug + MobileApps|Any CPU {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Debug|ARM.ActiveCfg = Debug|Any CPU {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Debug|ARM.Build.0 = Debug|Any CPU {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -826,7 +821,6 @@ Global {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Debug|x86.Build.0 = Debug|Any CPU {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Release|Any CPU.ActiveCfg = Release|Any CPU {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Release|Any CPU.Build.0 = Release|Any CPU - {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Release|ARM.ActiveCfg = Release|Any CPU {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Release|ARM.Build.0 = Release|Any CPU {2AF48872-DD47-4DA1-A153-DF4DA13882C2}.Release|ARM64.ActiveCfg = Release|Any CPU @@ -1022,7 +1016,6 @@ Global {998D38B3-344C-4F19-833E-6181B0834AF6}.Debug + MobileApps|x86.Build.0 = Debug + MobileApps|Any CPU {998D38B3-344C-4F19-833E-6181B0834AF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {998D38B3-344C-4F19-833E-6181B0834AF6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {998D38B3-344C-4F19-833E-6181B0834AF6}.Debug|ARM.ActiveCfg = Debug|Any CPU {998D38B3-344C-4F19-833E-6181B0834AF6}.Debug|ARM.Build.0 = Debug|Any CPU {998D38B3-344C-4F19-833E-6181B0834AF6}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -1191,7 +1184,6 @@ Global {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Debug + MobileApps|x86.Build.0 = Debug|Any CPU {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Debug|ARM.ActiveCfg = Debug|Any CPU {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Debug|ARM.Build.0 = Debug|Any CPU {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -1206,7 +1198,6 @@ Global {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Debug|x86.Build.0 = Debug|Any CPU {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Release|Any CPU.ActiveCfg = Release|Any CPU {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Release|Any CPU.Build.0 = Release|Any CPU - {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Release|ARM.ActiveCfg = Release|Any CPU {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Release|ARM.Build.0 = Release|Any CPU {3A2042E9-8B03-4F2D-A2B7-EA4BEC36340C}.Release|ARM64.ActiveCfg = Release|Any CPU @@ -1242,9 +1233,7 @@ Global {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Debug + MobileApps|x86.Deploy.0 = Debug|x86 {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Debug|ARM.ActiveCfg = Debug|ARM {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Debug|ARM.Build.0 = Debug|ARM {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Debug|ARM.Deploy.0 = Debug|ARM @@ -1265,9 +1254,7 @@ Global {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Debug|x86.Deploy.0 = Debug|x86 {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Release|Any CPU.ActiveCfg = Release|Any CPU {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Release|Any CPU.Build.0 = Release|Any CPU - {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Release|Any CPU.Deploy.0 = Release|Any CPU - {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Release|ARM.ActiveCfg = Release|ARM {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Release|ARM.Build.0 = Release|ARM {34E323E8-E706-4DF4-B916-D614FC8CFCEB}.Release|ARM.Deploy.0 = Release|ARM @@ -1386,7 +1373,6 @@ Global {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Debug + MobileApps|x86.Build.0 = Debug|Any CPU {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Debug|ARM.ActiveCfg = Debug|Any CPU {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Debug|ARM.Build.0 = Debug|Any CPU {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -1401,7 +1387,6 @@ Global {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Debug|x86.Build.0 = Debug|Any CPU {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Release|Any CPU.ActiveCfg = Release|Any CPU {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Release|Any CPU.Build.0 = Release|Any CPU - {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Release|ARM.ActiveCfg = Release|Any CPU {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Release|ARM.Build.0 = Release|Any CPU {B381269F-44DA-4E46-8F51-1F1DF7D1F61D}.Release|ARM64.ActiveCfg = Release|Any CPU @@ -1430,7 +1415,6 @@ Global {4EA542D2-D4C9-403C-B615-0047D0A62790}.Debug + MobileApps|x86.Build.0 = Debug|Any CPU {4EA542D2-D4C9-403C-B615-0047D0A62790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4EA542D2-D4C9-403C-B615-0047D0A62790}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4EA542D2-D4C9-403C-B615-0047D0A62790}.Debug|ARM.ActiveCfg = Debug|Any CPU {4EA542D2-D4C9-403C-B615-0047D0A62790}.Debug|ARM.Build.0 = Debug|Any CPU {4EA542D2-D4C9-403C-B615-0047D0A62790}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -1445,7 +1429,6 @@ Global {4EA542D2-D4C9-403C-B615-0047D0A62790}.Debug|x86.Build.0 = Debug|Any CPU {4EA542D2-D4C9-403C-B615-0047D0A62790}.Release|Any CPU.ActiveCfg = Release|Any CPU {4EA542D2-D4C9-403C-B615-0047D0A62790}.Release|Any CPU.Build.0 = Release|Any CPU - {4EA542D2-D4C9-403C-B615-0047D0A62790}.Release|ARM.ActiveCfg = Release|Any CPU {4EA542D2-D4C9-403C-B615-0047D0A62790}.Release|ARM.Build.0 = Release|Any CPU {4EA542D2-D4C9-403C-B615-0047D0A62790}.Release|ARM64.ActiveCfg = Release|Any CPU @@ -1474,7 +1457,6 @@ Global {1B047736-9325-4F59-906B-89A3E12AC8FB}.Debug + MobileApps|x86.Build.0 = Debug|Any CPU {1B047736-9325-4F59-906B-89A3E12AC8FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1B047736-9325-4F59-906B-89A3E12AC8FB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B047736-9325-4F59-906B-89A3E12AC8FB}.Debug|ARM.ActiveCfg = Debug|Any CPU {1B047736-9325-4F59-906B-89A3E12AC8FB}.Debug|ARM.Build.0 = Debug|Any CPU {1B047736-9325-4F59-906B-89A3E12AC8FB}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -1710,6 +1692,48 @@ Global {87679336-95BE-47E4-B42B-8F6860A0B215}.Release|x64.Build.0 = Release|Any CPU {87679336-95BE-47E4-B42B-8F6860A0B215}.Release|x86.ActiveCfg = Release|Any CPU {87679336-95BE-47E4-B42B-8F6860A0B215}.Release|x86.Build.0 = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|Any CPU.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|Any CPU.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|ARM.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|ARM.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|ARM64.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|ARM64.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|iPhone.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|iPhone.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|iPhoneSimulator.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|x64.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|x64.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|x86.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug + MobileApps|x86.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|ARM.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|ARM.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|ARM64.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|iPhone.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|x64.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|x64.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|x86.ActiveCfg = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Debug|x86.Build.0 = Debug|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|Any CPU.Build.0 = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|ARM.ActiveCfg = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|ARM.Build.0 = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|ARM64.ActiveCfg = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|ARM64.Build.0 = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|iPhone.ActiveCfg = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|iPhone.Build.0 = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|x64.ActiveCfg = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|x64.Build.0 = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|x86.ActiveCfg = Release|Any CPU + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1761,6 +1785,7 @@ Global {74805FE3-2E0D-4EAB-8CFE-A9D46F8D5972} = {34BE693E-3496-45A4-B1D2-D3A0E068EEDB} {92064C48-0136-48CD-AE8D-C6FEDBC7B639} = {74805FE3-2E0D-4EAB-8CFE-A9D46F8D5972} {87679336-95BE-47E4-B42B-8F6860A0B215} = {1A37FD75-94E9-4D6F-953A-0DABBD7B49E9} + {43BCA8C7-E9F4-4067-9F54-C2127B82B5E8} = {5FAAD966-36B8-4C19-A5FA-5410DD53063D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {020399A9-DC27-4B82-9CAA-EF488665AC27} diff --git a/build/linux-install-deps.sh b/build/linux-install-deps.sh new file mode 100644 index 0000000000..63b7291503 --- /dev/null +++ b/build/linux-install-deps.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +apt install sudo +# This script must be run elevated. Adding a sudo wrapper if needed. +if [ "$UID" -ne 0 ]; then + exec sudo "$0" "$@" +fi + +set -o errexit # Exit the script if any command returns a non-true return value + +if [ -f '/usr/bin/apt' ]; then + DEBIAN_FRONTEND=noninteractive + # Install quietly, accepting all packages and not overriding user configurations + PKGINSTALL_CMD='apt-get install -q -y -o Dpkg::Options::=--force-confold' + PACKAGE_MANAGER=apt + PKGEXISTS_CMD='dpkg -s' +elif [ -f '/usr/bin/yum' ]; then + PACKAGE_MANAGER=yum + PKGINSTALL_CMD='yum -y install' + PKGEXISTS_CMD='yum list installed' +else + echo 'Package system currently not supported.' + exit 2 +fi + +if [ $PACKAGE_MANAGER == 'apt' ]; then + apt-get update || true # If apt update fails, see if we can continue anyway + $PKGINSTALL_CMD \ + libx11-dev \ + dbus-x11 \ + libsystemd0 \ + gnome-keyring \ + libsecret-tools \ + libsecret-1-dev \ + xdg-utils \ + x11-xserver-utils \ + xorg \ + libp11-kit-dev \ + libwebkit2gtk-4.0-dev +fi + +echo "Installing JavaBroker" +LINUX_VERSION=$(sed -r -n -e 's/^VERSION_ID="?([^"]+)"?/\1/p' /etc/os-release) +LINUX_VERSION_MAIN=$(echo $LINUX_VERSION | sed 's/\([0-9]*\)\..*/\1/') + +BROKER_PACKAGE_NAME='microsoft-identity-broker' +if [ -f '/usr/bin/apt' ]; then + curl https://packages.microsoft.com/config/ubuntu/$LINUX_VERSION/prod.list | sudo sudo tee /etc/apt/trusted.gpg.d/microsoft.asc +else + $PKGINSTALL_CMD yum-utils + yum-config-manager --add-repo=https://packages.microsoft.com/config/rhel/$LINUX_VERSION_MAIN/prod.repo + rpm --import http://packages.microsoft.com/keys/microsoft.asc +fi +echo "Installing latest published JavaBroker package" +$PKGINSTALL_CMD $BROKER_PACKAGE_NAME + +exit 0 \ No newline at end of file diff --git a/build/template-build-and-prep-automation.yaml b/build/template-build-and-prep-automation.yaml index d942634bf3..0a8aeba828 100644 --- a/build/template-build-and-prep-automation.yaml +++ b/build/template-build-and-prep-automation.yaml @@ -102,6 +102,16 @@ steps: } } + #check Linux runtime files + $linuxRuntimes = 'runtimes\linux-x64\native\libmsalruntime.so'; + $LinuxAppsToCheck = 'NetWSLWam\bin\Release\net8.0\'; + $appFullPath = $searchInFolder+$LinuxAppsToCheck+$linuxRuntimes + Write-Host $appFullPath + if (-not(Test-Path -Path $appFullPath -PathType Leaf)) + { + $errors += "Failed to find Linux runtime files in : " + $SearchInFolder + $app + "`n"; + } + #exit if there are errors IF (![string]::IsNullOrWhitespace($errors)) { diff --git a/build/template-build-and-run-all-tests.yaml b/build/template-build-and-run-all-tests.yaml index 1f8d2f7184..8ae22e11b0 100644 --- a/build/template-build-and-run-all-tests.yaml +++ b/build/template-build-and-run-all-tests.yaml @@ -82,3 +82,15 @@ jobs: #Build and stage projects fallbackOnPRTargetBranch: false baseDefinitionId: '905' #this is the PR build and it is used as a baseline baseBranchRef: 'main' + +- job: 'BuildandRunIntegrationTestsOnLinux' + pool: + vmImage: 'ubuntu-22.04' + demands: + - msbuild + variables: + runCodesignValidationInjection: false + Codeql.SkipTaskAutoInjection: true + + steps: + - template: template-test-on-linux.yaml \ No newline at end of file diff --git a/build/template-install-keyvault-secrets.yaml b/build/template-install-keyvault-secrets.yaml index 0e9b83ddb8..297b4be99b 100644 --- a/build/template-install-keyvault-secrets.yaml +++ b/build/template-install-keyvault-secrets.yaml @@ -16,11 +16,18 @@ steps: $kvSecretBytes = [System.Convert]::FromBase64String('$(LabAuth)') $certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection $certCollection.Import($kvSecretBytes, $null, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable) - - $protectedCertificateBytes = $certCollection.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12) - $pfxPath = '$(Build.SourcesDirectory)' + "\TestCert.pfx" + $CertPass = '' + $protectedCertificateBytes = $certCollection.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, $CertPass) + $pfxPath = '$(Build.SourcesDirectory)' + "/TestCert.pfx" [System.IO.File]::WriteAllBytes($pfxPath, $protectedCertificateBytes) - Import-PfxCertificate -FilePath $pfxPath -CertStoreLocation Cert:\LocalMachine\My - + if ([System.Environment]::OSVersion.Platform -eq 'Win32NT') { + Import-PfxCertificate -FilePath $pfxPath -CertStoreLocation "Cert:\LocalMachine\My" + } else { + Write-Output "This script is running on a non-Windows platform. Skipping Import-PfxCertificate." + } + Write-Host "Write $((Get-Item -Path $pfxPath).Length) PFX bytes to: $pfxPath" + Write-Host "##vso[task.setvariable variable=certDir;isOutput=true]$pfxPath" + Write-Host "##vso[task.setvariable variable=certPass;isSecret=true;isOutput=true]$CertPass" + name: generateLabCert displayName: 'Install Keyvault Secrets' diff --git a/build/template-test-on-linux.yaml b/build/template-test-on-linux.yaml new file mode 100644 index 0000000000..f0eca6131a --- /dev/null +++ b/build/template-test-on-linux.yaml @@ -0,0 +1,154 @@ +# template-test-on-linux.yaml +# Run all unit tests across the LibsAndSamples.sln project on Linux platform + +parameters: + BuildConfiguration: 'Release' + +steps: + +- template: template-install-keyvault-secrets.yaml + +- task: Bash@3 + displayName: Install broker and dependencies + inputs: + targetType: 'inline' + script: | + chmod +x ./build/linux-install-deps.sh + ./build/linux-install-deps.sh + +- task: Bash@3 + name: SetDbusSession + displayName: Set DBUS_SESSION_BUS_ADDRESS + inputs: + targetType: inline + script: | + echo "Setting DBUS_SESSION_BUS_ADDRESS" + # ensure that /var/lib/dbus/machine-id exists and has the uuid in it + sudo dbus-uuidgen --ensure + DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${UID}/bus" + # enable session lingering for the user + sudo loginctl enable-linger ${USER} + # enable and start dbus service + sudo systemctl enable dbus.service + sudo systemctl start dbus.service + # make sure per-user instance of systemd is running + /usr/bin/dbus-daemon --session --address=systemd: --nofork --print-address --nopidfile --systemd-activation --syslog-only + echo "dbus-launch finished" + + echo "##vso[task.setvariable variable=dbusSessionAddress;isOutput=true]$DBUS_SESSION_BUS_ADDRESS" + echo "Set dbusSessionAddress successfully" + echo "set DBUS_SESSION_BUS_ADDRESS=${DBUS_SESSION_BUS_ADDRESS}" + +- task: Bash@3 + name: SetTestKeyring + displayName: Set test key ring + timeoutInMinutes: 2 + inputs: + targetType: inline + script: | + echo "Setting DBUS_SESSION_BUS_ADDRESS" + echo "Set to DBUS_SESSION_BUS_ADDRESS=${DBUS_SESSION_BUS_ADDRESS}" + + killall -q -u "$(whoami)" gnome-keyring-daemon + echo "gnome-keyring-daemon was terminated" + + rm -f ~/.local/share/keyrings/login.keyring + echo "Login keyring deleted" + + _UNLOCK_KEYRING_DATA=`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 10 | head -n 1` + echo "_UNLOCK_KEYRING_DATA is set" + + eval $(echo -n "${_UNLOCK_KEYRING_DATA}" \ + | gnome-keyring-daemon --daemonize --login \ + | sed -e 's/^/export /') + echo "keyring daemon was set" + + unset _UNLOCK_KEYRING_DATA + /usr/bin/gnome-keyring-daemon --start --components=secrets + echo "keyring daemon started" + + secret-tool search --all version 1.0 + echo "secret-tool executed" + + echo "##vso[task.setvariable variable=keyRingControl;isOutput=true]$GNOME_KEYRING_CONTROL" + echo "GNOME_KEYRING_CONTROL was set." + env: + DBUS_SESSION_BUS_ADDRESS: $(SetDbusSession.dbusSessionAddress) + +- task: Bash@3 + displayName: Start Xvfb server and launch GUI + inputs: + targetType: inline + script: | + if [ -f '/usr/bin/apt' ]; then + sudo chmod 777 /etc/systemd/system/ + sudo rm -f /etc/systemd/system/xvfb.service + sudo touch /etc/systemd/system/xvfb.service + sudo chmod 777 /etc/systemd/system/xvfb.service + echo '[unit]' | sudo tee -a /etc/systemd/system/xvfb.service + echo 'Description=X Virtual Frame Buffer Service' | sudo tee -a /etc/systemd/system/xvfb.service + echo 'After=network.target' | sudo tee -a /etc/systemd/system/xvfb.service + echo '[Service]' | sudo tee -a /etc/systemd/system/xvfb.service + echo 'ExecStart=/usr/bin/Xvfb :1 -screen 0 1024x768x24' | sudo tee -a /etc/systemd/system/xvfb.service + echo 'Restart=always' | sudo tee -a /etc/systemd/system/xvfb.service + echo '[Install]' | sudo tee -a /etc/systemd/system/xvfb.service + echo 'WantedBy=multi-user.target' | sudo tee -a /etc/systemd/system/xvfb.service + + sudo systemctl enable /etc/systemd/system/xvfb.service + sudo service xvfb start + + wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg + sudo install -D -o root -g root -m 644 packages.microsoft.gpg /etc/apt/keyrings/packages.microsoft.gpg + sudo sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list' + rm -f packages.microsoft.gpg + sudo apt update + sudo apt install code + export DISPLAY=:1 + elif [ -f '/usr/bin/yum' ]; then + # install packages for GUI test + sudo yum -y install xorg-x11-server-Xvfb mesa-libEGL-devel glx-utils mesa-dri-drivers xorg-x11-server-utils + Xvfb -ac ${DISPLAY} 2>/dev/null & + sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc + sudo sh -c 'echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/vscode.repo' + dnf check-update + sudo dnf -y install code + fi + + code . + dbus-update-activation-environment --systemd DISPLAY XAUTHORITY + xhost +SI:localuser:$(whoami) + xhost +SI:localuser:microsoft-identity-broker + env: + DBUS_SESSION_BUS_ADDRESS: $(SetDbusSession.dbusSessionAddress) + +- task: UseDotNet@2 + displayName: 'Use the latest .NET 8' + inputs: + version: 8.x + +- task: CmdLine@2 + displayName: 'Clear local NuGet cache' + inputs: + script: 'nuget locals all -clear' + +- task: DotNetCoreCLI@2 + displayName: 'Wotnet workload restore' + inputs: + command: 'custom' + custom: 'workload' + arguments: 'restore .\src\client\Microsoft.Identity.Client\Microsoft.Identity.Client.csproj' + +- task: DotNetCoreCLI@2 + displayName: 'Build Integration Test' + inputs: + command: 'build' + projects: | + ./tests/Microsoft.Identity.Test.Integration.netcore/Microsoft.Identity.Test.Integration.NetCore.csproj + configuration: ${{ parameters.BuildConfiguration }} + +- script: | + dotnet test **/Microsoft.Identity.Test.Integration.netcore/Microsoft.Identity.Test.Integration.NetCore.csproj -l "console;verbosity=detailed" + displayName: 'Run Integration tests .NET' + env: + CERTIFICATE_LOCATION: $(generateLabCert.certDir) + CERTIFICATE_PASSWORD: $(generateLabCert.certPass) \ No newline at end of file diff --git a/src/client/Microsoft.Identity.Client.Broker/BrokerExtension.cs b/src/client/Microsoft.Identity.Client.Broker/BrokerExtension.cs index 256d3427c8..462f231cf6 100644 --- a/src/client/Microsoft.Identity.Client.Broker/BrokerExtension.cs +++ b/src/client/Microsoft.Identity.Client.Broker/BrokerExtension.cs @@ -71,15 +71,15 @@ public static PublicClientApplicationBuilder WithSsoPolicy(this PublicClientAppl private static void AddRuntimeSupport(PublicClientApplicationBuilder builder) { - if (DesktopOsHelper.IsWin10OrServerEquivalent()) + if (DesktopOsHelper.IsWin10OrServerEquivalent() || DesktopOsHelper.IsLinux()) { builder.Config.BrokerCreatorFunc = (uiParent, appConfig, logger) => { - logger.Info("[Runtime] WAM supported OS."); + logger.Info("[Runtime] Broker supported OS."); return new RuntimeBroker(uiParent, appConfig, logger); }; - } + } else { builder.Config.BrokerCreatorFunc = diff --git a/src/client/Microsoft.Identity.Client.Broker/RuntimeBroker.cs b/src/client/Microsoft.Identity.Client.Broker/RuntimeBroker.cs index ee9292f83b..bf455109f3 100644 --- a/src/client/Microsoft.Identity.Client.Broker/RuntimeBroker.cs +++ b/src/client/Microsoft.Identity.Client.Broker/RuntimeBroker.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Linq; using System.Diagnostics; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Identity.Client.ApiConfig.Parameters; using Microsoft.Identity.Client.Cache; @@ -29,6 +30,10 @@ internal class RuntimeBroker : IBroker private readonly BrokerOptions _wamOptions; private static Exception s_initException; + // Linux broker's username password flow is via interactive calls + [DllImport("libX11.so.6")] + private static extern IntPtr XOpenDisplay(string display); + private static Dictionary LogLevelMap = new Dictionary() { { NativeInterop.LogLevel.Trace, LogLevel.Verbose }, @@ -39,7 +44,10 @@ internal class RuntimeBroker : IBroker { NativeInterop.LogLevel.Fatal, LogLevel.Error }, }; - public bool IsPopSupported => true; + /// + /// Pop is supported on Windows only + /// + public bool IsPopSupported => DesktopOsHelper.IsWindows(); /// /// Being a C API, MSAL runtime uses a "global init" and "global shutdown" approach. @@ -94,7 +102,7 @@ public RuntimeBroker( ILoggerAdapter logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - + if (_logger.PiiLoggingEnabled) { s_lazyCore.Value.EnablePii(_logger.PiiLoggingEnabled); @@ -396,15 +404,29 @@ public async Task AcquireTokenByUsernamePasswordAsync( { authParams.Properties["MSALRuntime_Username"] = acquireTokenByUsernamePasswordParameters.Username; authParams.Properties["MSALRuntime_Password"] = acquireTokenByUsernamePasswordParameters.Password; - - using (NativeInterop.AuthResult result = await s_lazyCore.Value.SignInSilentlyAsync( + // For Linux broker, use the interactive flow with username password to get the token + if (Environment.GetEnvironmentVariable("TF_BUILD") != null && DesktopOsHelper.IsLinux()) { + using (NativeInterop.AuthResult result = await s_lazyCore.Value.SignInInteractivelyAsync( + XOpenDisplay(":1"), authParams, authenticationRequestParameters.CorrelationId.ToString("D"), + acquireTokenByUsernamePasswordParameters.Username, cancellationToken).ConfigureAwait(false)) - { - var errorMessage = "Could not acquire token with username and password."; - msalTokenResponse = WamAdapters.HandleResponse(result, authenticationRequestParameters, _logger, errorMessage); + { + var errorMessage = "Could not acquire token with username and password."; + msalTokenResponse = WamAdapters.HandleResponse(result, authenticationRequestParameters, _logger, errorMessage); + } + } else { + using (NativeInterop.AuthResult result = await s_lazyCore.Value.SignInSilentlyAsync( + authParams, + authenticationRequestParameters.CorrelationId.ToString("D"), + cancellationToken).ConfigureAwait(false)) + { + var errorMessage = "Could not acquire token with username and password."; + msalTokenResponse = WamAdapters.HandleResponse(result, authenticationRequestParameters, _logger, errorMessage); + } } + } return msalTokenResponse; @@ -586,7 +608,7 @@ public void HandleInstallUrl(string appLink) public bool IsBrokerInstalledAndInvokable(AuthorityType authorityType) { - if (!DesktopOsHelper.IsWin10OrServerEquivalent()) + if (!DesktopOsHelper.IsWin10OrServerEquivalent() && !DesktopOsHelper.IsLinux()) { _logger?.Warning("[RuntimeBroker] Not a supported operating system. WAM broker is not available. "); return false; diff --git a/src/client/Microsoft.Identity.Client/ApiConfig/BrokerOptions.cs b/src/client/Microsoft.Identity.Client/ApiConfig/BrokerOptions.cs index 871cacc8ad..1e28b942a7 100644 --- a/src/client/Microsoft.Identity.Client/ApiConfig/BrokerOptions.cs +++ b/src/client/Microsoft.Identity.Client/ApiConfig/BrokerOptions.cs @@ -29,6 +29,10 @@ public enum OperatingSystems /// Use broker on Windows OS /// Windows = 0b_0000_0001, // 1 + /// + /// Use broker on Linux + /// + Linux = 0b_0000_0010, // 2 } /// @@ -71,8 +75,9 @@ internal static BrokerOptions CreateFromWindowsOptions(WindowsBrokerOptions winO public bool MsaPassthrough { get; set; } = false; /// - /// Currently only supported on Windows + /// Currently only supported on Windows and Linux /// Allows the Windows broker to list Work and School accounts as part of the + /// Linux broker will discover accounts as part of the /// public bool ListOperatingSystemAccounts { get; set; } @@ -81,6 +86,8 @@ internal bool IsBrokerEnabledOnCurrentOs() if (EnabledOn.HasFlag(OperatingSystems.Windows) && DesktopOsHelper.IsWindows()) { return true; + } else if (EnabledOn.HasFlag(OperatingSystems.Linux) && DesktopOsHelper.IsLinux()) { + return true; } return false; diff --git a/src/client/Microsoft.Identity.Client/PlatformsCommon/Shared/DesktopOsHelper.cs b/src/client/Microsoft.Identity.Client/PlatformsCommon/Shared/DesktopOsHelper.cs index a5fc805a46..84b87cfb18 100644 --- a/src/client/Microsoft.Identity.Client/PlatformsCommon/Shared/DesktopOsHelper.cs +++ b/src/client/Microsoft.Identity.Client/PlatformsCommon/Shared/DesktopOsHelper.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using Microsoft.Identity.Client.Utils; @@ -19,6 +20,8 @@ internal static class DesktopOsHelper private static Lazy s_winVersionLazy = new Lazy( GetWindowsVersionStringInternal); + private static Lazy s_wslEnvLazy = new Lazy(IsWslEnv); + public static bool IsWindows() { @@ -55,6 +58,22 @@ public static bool IsMac() #endif } + private static bool IsWslEnv() + { + if (IsLinux()) { + try + { + var versionInfo = File.ReadAllText("/proc/version"); + return versionInfo.Contains("Microsoft") || versionInfo.Contains("WSL"); + } + catch + { + return false; // if we can't read the file, we can't determine if it's WSL + } + } + return false; + } + /// /// Checks if the OS supports WAM (Web Account Manager) /// WAM Supported OS's are Windows 10 and above for Client, Windows 2019 and above for Server @@ -95,6 +114,11 @@ private static string GetWindowsVersionStringInternal() #endif } + public static bool IsRunningOnWsl() + { + return s_wslEnvLazy.Value; + } + public static string GetWindowsVersionString() { return s_winVersionLazy.Value; diff --git a/src/client/Microsoft.Identity.Client/PublicApi/net462/PublicAPI.Unshipped.txt b/src/client/Microsoft.Identity.Client/PublicApi/net462/PublicAPI.Unshipped.txt index 49930d7c11..bb29330d16 100644 --- a/src/client/Microsoft.Identity.Client/PublicApi/net462/PublicAPI.Unshipped.txt +++ b/src/client/Microsoft.Identity.Client/PublicApi/net462/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ +Microsoft.Identity.Client.BrokerOptions.OperatingSystems.Linux = 2 -> Microsoft.Identity.Client.BrokerOptions.OperatingSystems Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.get -> System.Collections.Generic.IEnumerable Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.set -> void \ No newline at end of file diff --git a/src/client/Microsoft.Identity.Client/PublicApi/net472/PublicAPI.Unshipped.txt b/src/client/Microsoft.Identity.Client/PublicApi/net472/PublicAPI.Unshipped.txt index cc453616ba..bb29330d16 100644 --- a/src/client/Microsoft.Identity.Client/PublicApi/net472/PublicAPI.Unshipped.txt +++ b/src/client/Microsoft.Identity.Client/PublicApi/net472/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ +Microsoft.Identity.Client.BrokerOptions.OperatingSystems.Linux = 2 -> Microsoft.Identity.Client.BrokerOptions.OperatingSystems Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.get -> System.Collections.Generic.IEnumerable -Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.set -> void +Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.set -> void \ No newline at end of file diff --git a/src/client/Microsoft.Identity.Client/PublicApi/net8.0-android/PublicAPI.Unshipped.txt b/src/client/Microsoft.Identity.Client/PublicApi/net8.0-android/PublicAPI.Unshipped.txt index cc453616ba..5e303488d1 100644 --- a/src/client/Microsoft.Identity.Client/PublicApi/net8.0-android/PublicAPI.Unshipped.txt +++ b/src/client/Microsoft.Identity.Client/PublicApi/net8.0-android/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ +Microsoft.Identity.Client.BrokerOptions.OperatingSystems.Linux = 2 -> Microsoft.Identity.Client.BrokerOptions.OperatingSystems Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.get -> System.Collections.Generic.IEnumerable Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.set -> void diff --git a/src/client/Microsoft.Identity.Client/PublicApi/net8.0-ios/PublicAPI.Unshipped.txt b/src/client/Microsoft.Identity.Client/PublicApi/net8.0-ios/PublicAPI.Unshipped.txt index cc453616ba..5e303488d1 100644 --- a/src/client/Microsoft.Identity.Client/PublicApi/net8.0-ios/PublicAPI.Unshipped.txt +++ b/src/client/Microsoft.Identity.Client/PublicApi/net8.0-ios/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ +Microsoft.Identity.Client.BrokerOptions.OperatingSystems.Linux = 2 -> Microsoft.Identity.Client.BrokerOptions.OperatingSystems Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.get -> System.Collections.Generic.IEnumerable Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.set -> void diff --git a/src/client/Microsoft.Identity.Client/PublicApi/net8.0/PublicAPI.Unshipped.txt b/src/client/Microsoft.Identity.Client/PublicApi/net8.0/PublicAPI.Unshipped.txt index cc453616ba..5e303488d1 100644 --- a/src/client/Microsoft.Identity.Client/PublicApi/net8.0/PublicAPI.Unshipped.txt +++ b/src/client/Microsoft.Identity.Client/PublicApi/net8.0/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ +Microsoft.Identity.Client.BrokerOptions.OperatingSystems.Linux = 2 -> Microsoft.Identity.Client.BrokerOptions.OperatingSystems Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.get -> System.Collections.Generic.IEnumerable Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.set -> void diff --git a/src/client/Microsoft.Identity.Client/PublicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/client/Microsoft.Identity.Client/PublicApi/netstandard2.0/PublicAPI.Unshipped.txt index cc453616ba..5e303488d1 100644 --- a/src/client/Microsoft.Identity.Client/PublicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/client/Microsoft.Identity.Client/PublicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ +Microsoft.Identity.Client.BrokerOptions.OperatingSystems.Linux = 2 -> Microsoft.Identity.Client.BrokerOptions.OperatingSystems Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.get -> System.Collections.Generic.IEnumerable Microsoft.Identity.Client.AssertionRequestOptions.ClientCapabilities.set -> void diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/ClientCredentialsMtlsPopTests.cs b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/ClientCredentialsMtlsPopTests.cs index 55c924df51..0810388ff7 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/ClientCredentialsMtlsPopTests.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/ClientCredentialsMtlsPopTests.cs @@ -6,6 +6,7 @@ using Microsoft.Identity.Client; using Microsoft.Identity.Client.Internal; using Microsoft.Identity.Test.Common; +using Microsoft.Identity.Test.Common.Core.Helpers; using Microsoft.Identity.Test.Integration.Infrastructure; using Microsoft.Identity.Test.Integration.NetFx.Infrastructure; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -24,6 +25,7 @@ public void TestInitialize() TestCommon.ResetInternalStaticCaches(); } + [DoNotRunOnLinux] // POP is not supported on Linux [TestMethod] public async Task Sni_Gets_Pop_Token_Successfully_TestAsync() { diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/ClientCredentialsTests.NetFwk.cs b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/ClientCredentialsTests.NetFwk.cs index e3bee50609..d1c7b042a6 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/ClientCredentialsTests.NetFwk.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/ClientCredentialsTests.NetFwk.cs @@ -480,7 +480,8 @@ private static string GetSignedClientAssertionManual( { "sub", issuer } }; - RSACng rsa = certificate.GetRSAPrivateKey() as RSACng; + // cng is Windows specific, so we use RSA instead + RSA rsa = certificate.GetRSAPrivateKey(); // Works cross-platform Dictionary header; if (useSha2AndPss) @@ -505,7 +506,14 @@ private static string GetSignedClientAssertionManual( var headerBytes = JsonSerializer.SerializeToUtf8Bytes(header); var claimsBytes = JsonSerializer.SerializeToUtf8Bytes(claims); string token = Base64UrlHelpers.Encode(headerBytes) + "." + Base64UrlHelpers.Encode(claimsBytes); - + if (rsa is null) + { + throw new InvalidOperationException("RSA private key expected"); + } + if (string.IsNullOrEmpty(token)) + { + throw new InvalidOperationException("Token expected"); + } //codeql [SM03799] Backwards Compatibility: Requires accepting PKCS1 for supporting ADFS byte[] signatureBytes = rsa.SignData( Encoding.UTF8.GetBytes(token), diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/MsalCacheStorageIntegrationTests.cs b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/MsalCacheStorageIntegrationTests.cs index c309dbe284..3f2f7b9b8c 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/MsalCacheStorageIntegrationTests.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/MsalCacheStorageIntegrationTests.cs @@ -125,15 +125,12 @@ public void CacheStorageFactory_WithFallback_Linux() attribute2: new KeyValuePair("MsalClientVersion", "1.0.0.0")) .Build(); - // Tests run on machines without Libsecret Storage store = Storage.Create(storageWithKeyRing, logger: _logger); Assert.IsTrue(store.CacheAccessor is LinuxKeyringAccessor); - // ADO Linux test agents do not have libsecret installed by default - // If you run this test on a Linux box with UI / LibSecret, then this test will fail - // because the statement below will not throw. - AssertException.Throws( - () => store.VerifyPersistence()); + // Installed libsecret on ADO Linux test agents, please see build/linux-install-deps.sh + // and setup keyring on the agent, please see build/template-test-on-linux.yml + store.VerifyPersistence(); Storage unprotectedStore = Storage.Create(s_storageCreationProperties, _logger); Assert.IsTrue(unprotectedStore.CacheAccessor is FileAccessor); @@ -147,8 +144,7 @@ public void CacheStorageFactory_WithFallback_Linux() // Mimic another sdk client to check libsecret availability by calling // MsalCacheStorage.VerifyPeristence() -> LinuxKeyringAccessor.CreateForPersistenceValidation() - AssertException.Throws( - () => store.VerifyPersistence()); + store.VerifyPersistence(); // Verify above call doesn't delete existing cache file Assert.IsTrue(File.Exists(s_storageCreationProperties.CacheFilePath)); diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/PoPTests.NetFwk.cs b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/PoPTests.NetFwk.cs index 8df3f05b09..a2e2757708 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/PoPTests.NetFwk.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/PoPTests.NetFwk.cs @@ -16,6 +16,7 @@ using Microsoft.Identity.Client.AppConfig; using Microsoft.Identity.Client.AuthScheme.PoP; using Microsoft.Identity.Client.Extensibility; +using Microsoft.Identity.Client.Extensions.Msal; #if NET_CORE using Microsoft.Identity.Client.Broker; #endif @@ -61,6 +62,7 @@ public async Task PoP_MultipleKeys_Async() await MultipleKeys_Async().ConfigureAwait(false); } + [DoNotRunOnLinux] // POP is not supported on Linux [RunOn(TargetFrameworks.NetCore)] public async Task PoP_BearerAndPoP_CanCoexist_Async() { @@ -217,6 +219,7 @@ private async Task MultipleKeys_Async() result); } + [DoNotRunOnLinux] // POP is not supported on Linux [RunOn(TargetFrameworks.NetCore)] public async Task PopTestWithConfigObjectAsync() { @@ -254,6 +257,7 @@ public async Task PopTestWithConfigObjectAsync() Assert.AreEqual("RS256", alg, "The algorithm in the token header should be RS256"); } + [DoNotRunOnLinux] // POP is not supported on Linux [TestMethod] public async Task PopTestWithRSAAsync() { @@ -291,6 +295,7 @@ public async Task PopTestWithRSAAsync() Assert.AreEqual("RS256", alg, "The algorithm in the token header should be RS256"); } + [DoNotRunOnLinux] // POP is not supported on Linux [RunOn(TargetFrameworks.NetCore)] public async Task ROPC_PopTestWithRSAAsync() { @@ -323,6 +328,7 @@ public async Task ROPC_PopTestWithRSAAsync() } + [DoNotRunOnLinux] // POP is not supported on Linux [TestMethod] public async Task PopTest_ExternalWilsonSigning_Async() { @@ -388,7 +394,8 @@ public async Task PopTest_ExternalWilsonSigning_Async() TokenSource.Cache, result2.AuthenticationResultMetadata.TokenSource); } - + + [DoNotRunOnLinux] // POP is not supported on Linux [TestMethod] public async Task PopTestWithECDAsync() { @@ -427,6 +434,7 @@ public async Task PopTestWithECDAsync() result); } + [DoNotRunOnLinux] // POP is not supported on Linux [TestMethod] public async Task NewPOP_WithKeyIdOnly_Async() { @@ -520,6 +528,7 @@ public async Task NewPOP_WithKeyIdOnly_Async() result2.AuthenticationResultMetadata.TokenSource); } + [DoNotRunOnLinux] // POP is not supported on Linux [TestMethod] public async Task InMemoryCryptoProvider_AlgIsPS256() { @@ -662,6 +671,7 @@ public async Task InMemoryCryptoProvider_WithGraph() Assert.IsTrue(responseWithPopToken.IsSuccessStatusCode, "The response should be successful with the PoP token"); } + [DoNotRunOnLinux] // POP is not supported on Linux [TestMethod] public async Task PoPToken_ShouldHaveCorrectAlgorithm_PS256_Async() { @@ -700,6 +710,7 @@ public async Task PoPToken_ShouldHaveCorrectAlgorithm_PS256_Async() } #if NET_CORE + [DoNotRunOnLinux] // POP is not supported on Linux [IgnoreOnOneBranch] public async Task WamUsernamePasswordRequestWithPOPAsync() { @@ -740,31 +751,29 @@ public async Task WamUsernamePasswordRequestWithPOPAsync() public void CheckPopRuntimeBrokerSupportTest() { //Broker enabled - var pcaBuilder = PublicClientApplicationBuilder - .Create(TestConstants.ClientId); - - pcaBuilder = pcaBuilder.WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)); - - IPublicClientApplication app = pcaBuilder.Build(); - - Assert.IsTrue(app.IsProofOfPossessionSupportedByClient()); + if (SharedUtilities.IsWindowsPlatform()) { + CheckPopSupport(new BrokerOptions(BrokerOptions.OperatingSystems.Windows), true); + } //Broker disabled - pcaBuilder = PublicClientApplicationBuilder - .Create(TestConstants.ClientId); + CheckPopSupport(new BrokerOptions(BrokerOptions.OperatingSystems.None), false); - pcaBuilder.WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.None)); - - app = pcaBuilder.Build(); + // POP is not supported on Linux + if (SharedUtilities.IsLinuxPlatform()) { + CheckPopSupport(new BrokerOptions(BrokerOptions.OperatingSystems.Linux), false); + } + } + + private static void CheckPopSupport(BrokerOptions brokerOptions, bool isPopSupported) + { + var pcaBuilder = PublicClientApplicationBuilder + .Create(TestConstants.ClientId); - Assert.IsFalse(app.IsProofOfPossessionSupportedByClient()); + pcaBuilder = pcaBuilder.WithBroker(brokerOptions); - //Broker not configured - app = PublicClientApplicationBuilder - .Create(TestConstants.ClientId) - .Build(); + IPublicClientApplication app = pcaBuilder.Build(); - Assert.IsFalse(app.IsProofOfPossessionSupportedByClient()); + Assert.AreEqual(isPopSupported, app.IsProofOfPossessionSupportedByClient()); } #endif diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/RuntimeBrokerTests.cs b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/RuntimeBrokerTests.cs index 9a828527fd..455a047d4f 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/RuntimeBrokerTests.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/RuntimeBrokerTests.cs @@ -18,6 +18,7 @@ using Microsoft.Identity.Client.ApiConfig; using Microsoft.Identity.Client.Broker; using Microsoft.Identity.Client.Core; +using Microsoft.Identity.Client.Extensions.Msal; using Microsoft.Identity.Client.OAuth2; using Microsoft.Identity.Client.SSHCertificates; using Microsoft.Identity.Client.UI; @@ -26,6 +27,7 @@ using Microsoft.Identity.Test.Common.Core.Helpers; using Microsoft.Identity.Test.Common.Core.Mocks; using Microsoft.Identity.Test.Integration.Infrastructure; +using Microsoft.Identity.Test.Integration.Utils; using Microsoft.Identity.Test.LabInfrastructure; using Microsoft.VisualStudio.TestTools.UnitTesting; using NSubstitute; @@ -35,14 +37,13 @@ namespace Microsoft.Identity.Test.Integration.Broker [TestClass] public class RuntimeBrokerTests { - [DllImport("user32.dll")] - static extern IntPtr GetForegroundWindow(); - //This client id is for Azure CLI which is one of the only 2 clients that have PreAuth to use ssh cert feature string _SSH_ClientId = "04b07795-8ddb-461a-bbee-02f9e1bf7b46"; //SSH User impersonation scope required for this test private string[] _SSH_scopes = new[] { "https://pas.windows.net/CheckMyAccess/Linux/user_impersonation" }; + private BrokerOptions _brokerOptions = TestUtils.GetPlatformBroker(); + private string CreateJwk() { RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048); @@ -70,7 +71,7 @@ public async Task WamSilentAuthUserInteractionRequiredAsync() .WithAuthority("https://login.microsoftonline.com/organizations"); IPublicClientApplication pca = pcaBuilder - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithBroker(_brokerOptions) .Build(); // Act @@ -90,6 +91,7 @@ public async Task WamSilentAuthUserInteractionRequiredAsync() } } + [DoNotRunOnLinux] // POP is not supported on Linux [IgnoreOnOneBranch] [TestMethod] public async Task ExtractNonceWithAuthParserAndValidateShrAsync() @@ -104,7 +106,7 @@ public async Task ExtractNonceWithAuthParserAndValidateShrAsync() IPublicClientApplication pca = PublicClientApplicationBuilder .Create(labResponse.App.AppId) .WithAuthority(labResponse.Lab.Authority, "organizations") - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithBroker(_brokerOptions) .Build(); Assert.IsTrue(pca.IsProofOfPossessionSupportedByClient(), "Either the broker is not configured or it does not support POP."); @@ -135,7 +137,7 @@ public async Task ExtractNonceWithAuthParserAndValidateShrAsync() result); } - + [DoNotRunOnLinux] // Linux broker return different error code [IgnoreOnOneBranch] [TestMethod] public async Task WamInvalidROPC_ThrowsException_TestAsync() @@ -148,7 +150,7 @@ public async Task WamInvalidROPC_ThrowsException_TestAsync() .Create(labResponse.App.AppId) .WithAuthority(labResponse.Lab.Authority, "organizations") .WithLogging(wastestLogger, enablePiiLogging: true) // it's important that the PII is turned on, otherwise context is 'pii' - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithBroker(_brokerOptions) .Build(); MsalServiceException ex = await AssertException.TaskThrowsAsync(() => @@ -164,6 +166,7 @@ public async Task WamInvalidROPC_ThrowsException_TestAsync() Assert.AreEqual("ApiContractViolation", ex.AdditionalExceptionData[MsalException.BrokerErrorStatus]); Assert.AreEqual("3399811229", ex.AdditionalExceptionData[MsalException.BrokerErrorCode]); Assert.IsNotNull(ex.AdditionalExceptionData[MsalException.BrokerTelemetry]); + } [IgnoreOnOneBranch] @@ -180,7 +183,7 @@ public async Task WamSilentAuthLoginHintNoAccontInCacheAsync() .WithAuthority("https://login.microsoftonline.com/organizations"); IPublicClientApplication pca = pcaBuilder - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithBroker(_brokerOptions) .Build(); // Act @@ -203,7 +206,7 @@ public async Task WamUsernamePasswordRequestAsync() var labResponse = await LabUserHelper.GetDefaultUserAsync().ConfigureAwait(false); string[] scopes = { "User.Read" }; - IntPtr intPtr = GetForegroundWindow(); + IntPtr intPtr = TestUtils.GetWindowHandle(); Func windowHandleProvider = () => intPtr; @@ -211,17 +214,20 @@ public async Task WamUsernamePasswordRequestAsync() .Create(labResponse.App.AppId) .WithParentActivityOrWindow(windowHandleProvider) .WithAuthority(labResponse.Lab.Authority, "organizations") - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithLogging((x, y, z) => Debug.WriteLine($"{x} {y}"), LogLevel.Verbose, true) + .WithBroker(_brokerOptions) .Build(); + // Get Accounts + var accounts = await pca.GetAccountsAsync().ConfigureAwait(false); + // Acquire token using username password var result = await pca.AcquireTokenByUsernamePassword(scopes, labResponse.User.Upn, labResponse.User.GetOrFetchPassword()).ExecuteAsync().ConfigureAwait(false); - MsalAssert.AssertAuthResult(result, TokenSource.Broker, labResponse.Lab.TenantId, scopes); Assert.IsNotNull(result.AuthenticationResultMetadata.Telemetry); // Get Accounts - var accounts = await pca.GetAccountsAsync().ConfigureAwait(false); + accounts = await pca.GetAccountsAsync().ConfigureAwait(false); Assert.IsNotNull(accounts); var account = accounts.FirstOrDefault(); @@ -246,11 +252,12 @@ await AssertException.TaskThrowsAsync( .ConfigureAwait(false); } + [DoNotRunOnLinux] // SSH Certs are not supported on Linux [IgnoreOnOneBranch] [TestMethod] public async Task WamWithSSHCertificateAuthenticationSchemeAsync() { - IntPtr intPtr = GetForegroundWindow(); + IntPtr intPtr = TestUtils.GetWindowHandle(); Func windowHandleProvider = () => intPtr; var labResponse = await LabUserHelper.GetDefaultUserAsync().ConfigureAwait(false); @@ -259,7 +266,7 @@ public async Task WamWithSSHCertificateAuthenticationSchemeAsync() .WithTestLogging() .WithAuthority(labResponse.Lab.Authority, "organizations") .WithParentActivityOrWindow(windowHandleProvider) - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithBroker(_brokerOptions) .Build(); string jwk = CreateJwk(); @@ -292,14 +299,15 @@ public async Task WamUsernamePasswordWithForceRefreshAsync() var labResponse = await LabUserHelper.GetDefaultUserAsync().ConfigureAwait(false); string[] scopes = { "User.Read" }; - IntPtr intPtr = GetForegroundWindow(); + IntPtr intPtr = TestUtils.GetWindowHandle(); Func windowHandleProvider = () => intPtr; IPublicClientApplication pca = PublicClientApplicationBuilder .Create(labResponse.App.AppId) .WithParentActivityOrWindow(windowHandleProvider) .WithAuthority(labResponse.Lab.Authority, "organizations") - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithLogging((x, y, z) => Debug.WriteLine($"{x} {y}"), LogLevel.Verbose, true) + .WithBroker(_brokerOptions) .Build(); // Acquire token using username password @@ -342,7 +350,7 @@ public async Task WamUsernamePasswordRequestAsync_WithPiiAsync() var labResponse = await LabUserHelper.GetDefaultUserAsync().ConfigureAwait(false); string[] scopes = { "User.Read" }; - IntPtr intPtr = GetForegroundWindow(); + IntPtr intPtr = TestUtils.GetWindowHandle(); Func windowHandleProvider = () => intPtr; @@ -353,7 +361,7 @@ public async Task WamUsernamePasswordRequestAsync_WithPiiAsync() .WithParentActivityOrWindow(windowHandleProvider) .WithAuthority(labResponse.Lab.Authority, "organizations") .WithLogging(testLogger, enablePiiLogging: true) - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithBroker(_brokerOptions) .Build(); // Acquire token using username password @@ -387,6 +395,7 @@ public async Task WamUsernamePasswordRequestAsync_WithPiiAsync() result = await pca.AcquireTokenSilent(scopes, account).ExecuteAsync().ConfigureAwait(false); } + [DoNotRunOnLinux] // List Windows Work and School accounts is not supported on Linux [IgnoreOnOneBranch] [TestMethod] public async Task WamListWindowsWorkAndSchoolAccountsAsync() @@ -394,7 +403,7 @@ public async Task WamListWindowsWorkAndSchoolAccountsAsync() var labResponse = await LabUserHelper.GetDefaultUserAsync().ConfigureAwait(false); string[] scopes = { "User.Read" }; - IntPtr intPtr = GetForegroundWindow(); + IntPtr intPtr = TestUtils.GetWindowHandle(); Func windowHandleProvider = () => intPtr; @@ -430,7 +439,7 @@ public async Task WamListWindowsWorkAndSchoolAccountsAsync() [TestMethod] public async Task WamAddDefaultScopesWhenNoScopesArePassedAsync(string scopes) { - IntPtr intPtr = GetForegroundWindow(); + IntPtr intPtr = TestUtils.GetWindowHandle(); Func windowHandleProvider = () => intPtr; @@ -438,18 +447,25 @@ public async Task WamAddDefaultScopesWhenNoScopesArePassedAsync(string scopes) .Create("43dfbb29-3683-4673-a66f-baba91798bd2") .WithAuthority("https://login.microsoftonline.com/organizations") .WithParentActivityOrWindow(windowHandleProvider) - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithBroker(_brokerOptions) .Build(); - // Act - var ex = await AssertException.TaskThrowsAsync( + if (SharedUtilities.IsLinuxPlatform()) { + var exLinux = await AssertException.TaskThrowsAsync( () => pca.AcquireTokenSilent(new string[] { scopes }, PublicClientApplication.OperatingSystemAccount) .ExecuteAsync()) .ConfigureAwait(false); - - Assert.IsTrue(!string.IsNullOrEmpty(ex.ErrorCode)); + StringAssert.Contains(exLinux.AdditionalExceptionData[MsalException.BrokerErrorContext], "requestedScopes is NULL or EMPTY"); + } else { + var ex = await AssertException.TaskThrowsAsync( + () => pca.AcquireTokenSilent(new string[] { scopes }, PublicClientApplication.OperatingSystemAccount) + .ExecuteAsync()) + .ConfigureAwait(false); + Assert.IsTrue(!string.IsNullOrEmpty(ex.ErrorCode)); + } } + [DoNotRunOnLinux] // POP is not supported on Linux [IgnoreOnOneBranch] [TestMethod] public async Task WamUsernamePasswordPopTokenEnforcedWithCaOnValidResourceAsync() @@ -461,7 +477,7 @@ public async Task WamUsernamePasswordPopTokenEnforcedWithCaOnValidResourceAsync( string[] scopes = { "https://msidlab4.sharepoint.com/user.read" }; - IntPtr intPtr = GetForegroundWindow(); + IntPtr intPtr = TestUtils.GetWindowHandle(); Func windowHandleProvider = () => intPtr; @@ -469,7 +485,7 @@ public async Task WamUsernamePasswordPopTokenEnforcedWithCaOnValidResourceAsync( .Create(labResponse.App.AppId) .WithParentActivityOrWindow(windowHandleProvider) .WithAuthority(labResponse.Lab.Authority, "organizations") - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithBroker(_brokerOptions) .Build(); // Acquire token using username password with POP on a valid resource @@ -484,6 +500,7 @@ public async Task WamUsernamePasswordPopTokenEnforcedWithCaOnValidResourceAsync( Assert.AreEqual(popUser, result.Account.Username); } + [DoNotRunOnLinux] // POP are not supported on Linux [IgnoreOnOneBranch] [TestMethod] [ExpectedException(typeof(MsalUiRequiredException))] @@ -496,7 +513,7 @@ public async Task WamUsernamePasswordPopTokenEnforcedWithCaOnInValidResourceAsyn string[] scopes = { "user.read" }; - IntPtr intPtr = GetForegroundWindow(); + IntPtr intPtr = TestUtils.GetWindowHandle(); Func windowHandleProvider = () => intPtr; @@ -504,7 +521,7 @@ public async Task WamUsernamePasswordPopTokenEnforcedWithCaOnInValidResourceAsyn .Create(labResponse.App.AppId) .WithParentActivityOrWindow(windowHandleProvider) .WithAuthority(labResponse.Lab.Authority, "organizations") - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .WithBroker(_brokerOptions) .Build(); // Acquire token using username password with POP on a resource not in the CA policy diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs b/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs index cd341b3a9e..5bb6aaa179 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs @@ -9,6 +9,7 @@ using Microsoft.Identity.Test.Common; using Microsoft.Identity.Test.Common.Core.Helpers; using Microsoft.Identity.Test.Integration.Infrastructure; +using Microsoft.Identity.Test.Integration.Utils; using Microsoft.Identity.Test.LabInfrastructure; using Microsoft.Identity.Test.Unit; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -126,7 +127,7 @@ private async Task AcquireTokenWithDeviceCodeFlowAsync(LabResponse labResponse, private async Task AcquireTokenSilentAfterDeviceCodeFlowWithBrokerAsync(LabResponse labResponse, string userType) { Trace.WriteLine($"Calling AcquireTokenSilentAfterDeviceCodeFlowWithBrokerAsync with {0}", userType); - BrokerOptions options = new BrokerOptions(BrokerOptions.OperatingSystems.Windows); + BrokerOptions options = TestUtils.GetPlatformBroker(); var builder = PublicClientApplicationBuilder.Create(labResponse.App.AppId).WithTestLogging().WithBroker(options); switch (labResponse.User.AzureEnvironment) diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/Utils/TestUtils.cs b/tests/Microsoft.Identity.Test.Integration.netcore/Utils/TestUtils.cs new file mode 100644 index 0000000000..949b5b16a4 --- /dev/null +++ b/tests/Microsoft.Identity.Test.Integration.netcore/Utils/TestUtils.cs @@ -0,0 +1,79 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Identity.Client; + +namespace Microsoft.Identity.Test.Integration.Utils +{ + public static class TestUtils + { + /// + /// Get the handle of the foreground window for Windows + /// + [DllImport("user32.dll")] + static extern IntPtr GetForegroundWindow(); + + /// + /// Get the handle of the console window for Linux + /// + [DllImport("libX11.so.6")] + private static extern IntPtr XOpenDisplay(string display); + + [DllImport("libX11.so.6")] + private static extern IntPtr XRootWindow(IntPtr display, int screen); + + [DllImport("libX11.so.6")] + private static extern IntPtr XDefaultRootWindow(IntPtr display); + + /// + /// Get window handle on xplat + /// + public static IntPtr GetWindowHandle() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return GetForegroundWindow(); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + try { + IntPtr display = XOpenDisplay(":1"); + if (display == IntPtr.Zero) + { + Console.WriteLine("No X display available. Running in headless mode."); + } + else + { + Console.WriteLine("X display is available."); + } + return display; + } catch (System.Exception ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(ex.ToString()); + Console.ResetColor(); + } + return IntPtr.Zero; + } + else + { + throw new PlatformNotSupportedException("This platform is not supported."); + } + } + + public static BrokerOptions GetPlatformBroker() { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return new BrokerOptions(BrokerOptions.OperatingSystems.Windows); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return new BrokerOptions(BrokerOptions.OperatingSystems.Linux){ListOperatingSystemAccounts = true,}; + } + else + { + throw new PlatformNotSupportedException("This platform is not supported."); + } + } + + } +} \ No newline at end of file diff --git a/tests/Microsoft.Identity.Test.LabInfrastructure/CertificateHelper.cs b/tests/Microsoft.Identity.Test.LabInfrastructure/CertificateHelper.cs index 1c4519e621..1a2b3e2e43 100644 --- a/tests/Microsoft.Identity.Test.LabInfrastructure/CertificateHelper.cs +++ b/tests/Microsoft.Identity.Test.LabInfrastructure/CertificateHelper.cs @@ -3,6 +3,7 @@ using System; using System.Security.Cryptography.X509Certificates; +using Microsoft.Identity.Client.Extensions.Msal; namespace Microsoft.Identity.Test.LabInfrastructure { @@ -37,9 +38,16 @@ public static X509Certificate2 FindCertificateByName(string subjectName) /// with , or null if no matching certificate was found public static X509Certificate2 FindCertificateByName(string certName, StoreLocation location, StoreName name) { + // Unix LocalMachine X509Store is limited to the Root and CertificateAuthority stores + if (SharedUtilities.IsLinuxPlatform()) + { + var certPasswrod = Environment.GetEnvironmentVariable("CERTIFICATE_PASSWORD"); + var certLocation = Environment.GetEnvironmentVariable("CERTIFICATE_LOCATION"); + var cert = new X509Certificate2(certLocation, certPasswrod, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); + return cert; + } // Don't validate certs, since the test root isn't installed. const bool validateCerts = false; - using (var store = new X509Store(name, location)) { store.Open(OpenFlags.ReadOnly); diff --git a/tests/Microsoft.Identity.Test.LabInfrastructure/Microsoft.Identity.Test.LabInfrastructure.csproj b/tests/Microsoft.Identity.Test.LabInfrastructure/Microsoft.Identity.Test.LabInfrastructure.csproj index 7c8ed47cba..cb491f52d7 100644 --- a/tests/Microsoft.Identity.Test.LabInfrastructure/Microsoft.Identity.Test.LabInfrastructure.csproj +++ b/tests/Microsoft.Identity.Test.LabInfrastructure/Microsoft.Identity.Test.LabInfrastructure.csproj @@ -17,6 +17,7 @@ Microsoft.Identity.Client + diff --git a/tests/Microsoft.Identity.Test.Unit/Microsoft.Identity.Test.Unit.csproj b/tests/Microsoft.Identity.Test.Unit/Microsoft.Identity.Test.Unit.csproj index 275d5e892e..eb6a842e0f 100644 --- a/tests/Microsoft.Identity.Test.Unit/Microsoft.Identity.Test.Unit.csproj +++ b/tests/Microsoft.Identity.Test.Unit/Microsoft.Identity.Test.Unit.csproj @@ -10,7 +10,6 @@ Debug;Release;Debug + MobileApps AnyCPU;x64 - diff --git a/tests/devapps/WAM/NetWSLWam/Class1.cs b/tests/devapps/WAM/NetWSLWam/Class1.cs new file mode 100644 index 0000000000..826bddf419 --- /dev/null +++ b/tests/devapps/WAM/NetWSLWam/Class1.cs @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Identity.Client; +using Microsoft.Identity.Client.Broker; + +namespace WAMClassLibrary +{ + public class Authentication + { + /// + /// Get the handle of the console window for Linux + /// + [DllImport("libX11")] + private static extern IntPtr XOpenDisplay(string display); + + [DllImport("libX11")] + private static extern IntPtr XRootWindow(IntPtr display, int screen); + + [DllImport("libX11")] + private static extern IntPtr XDefaultRootWindow(IntPtr display); + + + public static async Task InvokeBrokerAsync() + { + IntPtr _parentHandle = XRootWindow(XOpenDisplay(null), 0);; + Func consoleWindowHandleProvider = () => _parentHandle; + + // 1. Configuration - read below about redirect URI + var pca = PublicClientApplicationBuilder.Create("4b0db8c2-9f26-4417-8bde-3f0e3656f8e0"/*Lab Public Multi-Tenant*/) + .WithAuthority("https://login.microsoftonline.com/common") + .WithDefaultRedirectUri() + .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Linux){ + ListOperatingSystemAccounts = true, + MsaPassthrough = true, + Title = "MSAL WSL Test App" + }) + .WithParentActivityOrWindow(consoleWindowHandleProvider) + .WithLogging((x, y, z) => Console.WriteLine($"{x} {y}"), LogLevel.Verbose, true) + .Build(); + + // Add a token cache, see https://learn.microsoft.com/entra/msal/dotnet/how-to/token-cache-serialization?tabs=desktop + + // 2. GetAccounts + var accounts = await pca.GetAccountsAsync().ConfigureAwait(false); + var accountToLogin = accounts.FirstOrDefault(); + + try + { + var authResult = await pca.AcquireTokenSilent(new[] { "user.read" }, accountToLogin) + .ExecuteAsync().ConfigureAwait(false); + } + catch (MsalUiRequiredException ex) + { + Console.WriteLine(ex.Message); + Console.WriteLine(ex.ErrorCode); + } + + try + { + var authResult = await pca.AcquireTokenInteractive(new[] { "user.read" }).WithLoginHint("idlab@msidlab4.onmicrosoft.com") + .ExecuteAsync().ConfigureAwait(false); + + Console.WriteLine(authResult.Account); + + Console.WriteLine("Acquired Token Successfully!!!"); + + } + catch (MsalClientException ex) + { + int errorCode = Marshal.GetHRForException(ex) & ((1 << 16) - 1); + Console.WriteLine("MsalClientException (ErrCode " + errorCode + "): " + ex.Message); + } + catch (MsalException ex) + { + Console.WriteLine($"MsalException Error signing-out user: {ex.Message}"); + } + catch (Exception ex) + { + int errorCode = Marshal.GetHRForException(ex) & ((1 << 16) - 1); + Console.WriteLine("Error Acquiring Token (ErrCode " + errorCode + "): " + ex); + } + Console.Read(); + } + + public static void Main(string[] args) + { + InvokeBrokerAsync().Wait(); + } + } +} diff --git a/tests/devapps/WAM/NetWSLWam/Properties/launchSettings.json b/tests/devapps/WAM/NetWSLWam/Properties/launchSettings.json new file mode 100644 index 0000000000..0411ab6b8c --- /dev/null +++ b/tests/devapps/WAM/NetWSLWam/Properties/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "test": { + "commandName": "Project" + }, + "WSL": { + "commandName": "WSL2", + "distributionName": "" + } + } +} \ No newline at end of file diff --git a/tests/devapps/WAM/NetWSLWam/test.csproj b/tests/devapps/WAM/NetWSLWam/test.csproj new file mode 100644 index 0000000000..ec3de2464c --- /dev/null +++ b/tests/devapps/WAM/NetWSLWam/test.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + Exe + latest + false + + + + {6839f934-45f0-4026-8af3-c3aefb7d48a9} + Microsoft.Identity.Client.Broker + + + {60117a9b-4bb8-472e-bfff-52cbf67ca95a} + Microsoft.Identity.Client + + + \ No newline at end of file