WebView2 Not Respecting Windows Account (allowSingleSignOnUsingOSPrimaryAccount) - c#

I have a .NET 5.0 WinForms app that uses WebView2 with the evergreen runtime. I create my own environment with allowSingleSIgnOnUsingOSPrimaryAccount set to true (see snippet below). This results in the user opening up the app viewing our AzureAD fronted web app and authenticating against our app reg without the need to type in a user/pass or go through MFA.
var _cacheFolderPath = Path.Combine(Application.UserAppDataPath, "Myappname.exe.WebView2");
CoreWebView2EnvironmentOptions webViewEnvironmentOptions = new CoreWebView2EnvironmentOptions(allowSingleSignOnUsingOSPrimaryAccount: _config.UseWindowsAuth);
var webView2Environment = CoreWebView2Environment.CreateAsync(browserExecutableFolder: null, userDataFolder: _cacheFolderPath, options: webViewEnvironmentOptions).Result;
webView.EnsureCoreWebView2Async(webView2Environment);
On most machines, this works as expected, but there are a few machines where users are prompted for password. So a user that seamlessly logs in to our web app when logged into Windows on their primary machine may go to one of these particular machines and get prompted for an email/pass and MFA. I'm not seeing errors, event logs, etc....it just seems as though setting this value to true in code is simply being ignored or overridden.
I've tried to look for documentation related to Group Policy settings possibly being the cause, but there is not a lot I found regarding this for WebView2. Is there anything that is/can be set explicitly through GP, or some other mechanism that may be having some effect WebView2's behavior regarding allowSingleSignOnUsingOSPrimaryAccount?

Maybe try to go with something like this:
var options = new CoreWebView2EnvironmentOptions
{
AllowSingleSignOnUsingOSPrimaryAccount = true,
AdditionalBrowserArguments = "--auth-server-whitelist=_"
};
var userdatafolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Incognito", new Random().Next().ToString());
var environment = await CoreWebView2Environment.CreateAsync(null, userdatafolder, options: options);
Debug.WriteLine("InitializeAsync");
await WebView21.EnsureCoreWebView2Async(environment);
Debug.WriteLine($"WebView2 Runtime version: {WebView21.CoreWebView2.Environment.BrowserVersionString}");

Related

How to get a MSAL access token for SharePoint Online in a federated environment the non-interactive way in a non-interactive .Net console app?

The task as simple as to have a scheduled .NET console app which will download a file from SharePoint Online on a regular basis using AD domain user account.
If I use recommended way
var token = publicApplication.AcquireTokenByIntegratedWindowsAuth(scopes).ExecuteAsync().Result;
I'm getting
UriFormatException: Invalid URI: The hostname could not be parsed.
What does it mean? Which URI, hostname? Should I override something somewhere or add some special parameter?
I've googled thru this stuff a lot, and I have no idea where to look further, any advice will be appreciated.
P.S. I have no permissions to do anything on SharePoint side, I'm not a SP admin. I just have access to specific folder on the site from which I'm downloading the file. And also I have a code which works interactively:
WebRequest.DefaultWebProxy = WebRequest.GetSystemWebProxy();
WebRequest.DefaultWebProxy.Credentials = CredentialCache.DefaultNetworkCredentials;
var scopes = new string[] { "https://tenant.sharepoint.com/.default" };
var options = new PublicClientApplicationOptions()
{
TenantId = "tenant.com",
ClientId = "{872cd9fa-d31f-45e0-9eab-6e460a02d1f1}",//known Visual Studio Id
};
var publicApplication = PublicClientApplicationBuilder.CreateWithApplicationOptions(options).Build();
var token = publicApplication.AcquireTokenInteractive(scopes).WithLoginHint("name.surname#tenant.com").ExecuteAsync().Result;
But it shows a browser window
No questions asked, pop-up disappear, and I get the token which is used further to download a file from SPOnline using /_api/web/GetFileByServerRelativeUrl(' stuff.
So just run the app, see the popup, get the file downloaded. No interaction needed.
But this approach doesn't work if I put this routine really non-interactive:
Showing a modal dialog box or form when the application is not running in UserInteractive mode is not a valid operation. Specify the ServiceNotification or DefaultDesktopOnly style to display a notification from a service application.
Turns out the non-interactive way is only possible using tenant-side registered application. Implemented using certificate authentication.
But surprisingly the token obtained by ConfidentialClientApplicationBuilder doesn't work the way I wanted/expected (scopes/user impersonation issues). So now we use Graph client approach.
This is the only way which works for me (.NetFramework 4.7.2):
using Azure.Identity;
using Microsoft.Graph;
//...
static async Task GetFile(GraphServiceClient graphClient, string fileName2get)
{
var fileitem = graphClient
.Sites["SiteGuidYouMayGetBy /sites/[your site name]/_api/site/id"]
.Drives["CrazyLongDriveIdYouMayGetByEnumeratingDrivesHere"]
.Root
.ItemWithPath($"/Path To The File starting from Drive Root/{fileName2get}")
.Content
.Request().GetResponseAsync();
var stream = fileitem.GetAwaiter().GetResult();
using (var fileStream = System.IO.File.Create($"C:/Temp/{fileName2get}"))
{
await stream.Content.CopyToAsync(fileStream);
}
}

AWS Cognito - User pool xxxx does not exist

var client = new AmazonCognitoIdentityProviderClient("MYKEY", "MYSECRET", RegionEndpoint.USEast1);
var request = new AdminGetUserRequest();
request.Username = "USERNAME";
request.UserPoolId = "POOLID";
var user = client.AdminGetUserAsync(request).Result;
The key/secret are authenticating as a user with Administrator Access. For good measure, I've also given it the AmazonCognitoPowerUser policy.
The region endpoint is correct and the same as the one my user pool is in. The user pool Id is correct. The first part of the user pool ID matches the region.
I'm at a loss for where else this could possibly be going wrong. Any ideas?
Update 8/2/19
Manual CLI command:
PM> aws cognito-idp list-user-pools --region us-east-1 --max-results 10
{
"UserPools": []
}
The region is correct, so there must be some issue with permissions. Is there anything I could try tweaking on the pool, or other policies I may need to add to the user?
So, it looks like this is some sort of AWS glitch with the existing IAM user.
Having created a new user with exactly the same permissions, access works as intended both from CLI and the code in the original question.
Actually your configuration can be wrong , you downloaded awsconfiguration.json and it looks like same I know.. but this configuration can be wrong. When you examine the json you will see a field.. "CognitoUserPool": {PoolId, appclient id ..}
You need to open your user pool and create new client or control existing client information. Check your awsconfiguration.json again with this webpage's pool id, appclient id etc. Update your json... it will solve the problem.
I ran into this problem with the AWS CLI and it puzzled me too, but I learned that I needed to provide the profile name in the parameter list to get it to work. So it looked like this:
aws cognito-idp admin-get-user --profile dev-account ....
My profiles are stored on my Mac at cat ~/.aws/config| grep profile
The config file is created by an in-house custom script. This is the contents of what that file looks like.
[profile dev-account]
sso_start_url = https://yourcompanyname.awsapps.com/start#/
sso_region = us-east-1
sso_account_id = 1234567890
sso_role_name = PowerUserAccess
region = us-east-1
output = json
Also, in this folder is a "credentials" file that has some JSON for these variables: profile name, aws_access_key_id, aws_secret_access_key, aws_session_token, aws_expiration

UWP create VPN connection

Currently I'm trying to figure out, how to add a VPN profile and connect to it from my universal app. I can connect to existing VPN connections with the Windows.Networking.Vpn namespace. I can also add a profile, but can not find a way to set all the required information (PSK for example). There is no documentation about this namespace in the MS docs. I also saw that there are two different profile namespaces available: VpnNativeProfile and VpnPlugInProfile. What is the difference between them? Currently I'm not at home, so I can't provide my current code, but it would be very helpful if someone can give me some hints. Is there a documentation available somewhere else?
Edit 1//
Here is my sample Code
Creating a profile
VpnManagementAgent mgr = new VpnManagementAgent();
VpnNativeProfile profile = new VpnNativeProfile()
{
AlwaysOn = false,
NativeProtocolType = VpnNativeProtocolType.L2tp,
ProfileName = "MyConnection",
RememberCredentials = true,
RequireVpnClientAppUI = true,
RoutingPolicyType = VpnRoutingPolicyType.SplitRouting,
TunnelAuthenticationMethod = VpnAuthenticationMethod.PresharedKey,
UserAuthenticationMethod = VpnAuthenticationMethod.Mschapv2,
};
profile.Servers.Add("vpn.example.com");
VpnManagementErrorStatus profileStatus = await mgr.AddProfileFromObjectAsync(profile);
Connecting to the VPN
PasswordCredential credentials = new PasswordCredential
{
UserName = "username",
Password = "password",
};
VpnManagementErrorStatus connectStatus = await mgr.ConnectProfileWithPasswordCredentialAsync(profile, credentials);
This works, but i don't know where or how to set the PSK.
VPN Native Profile : This refers to a Windows Inbox / Built-In VPN profile and can be used for L2TP, PPTP or IKEv2 based VPN
VPN Plugin Profile : Refers to a Windows 10 UWP based VPN Plugin. This is a VPN app written using the Windows.networking.VPN namespace.
I also took a peek at the code and can see that there seems to be a very obvious miss where there isnt really a way to set the PSK via the code. The only real workaround would be to set it in the Settings UI for now.
I will go ahead and report to the VPN team for Windows about this being missing.
Documentation Link : https://learn.microsoft.com/en-us/uwp/api/windows.networking.vpn

LDAP search fails on server, not in Visual Studio

I'm creating a service to search for users in LDAP. This should be fairly straightforward and probably done a thousand times, but I cannot seem to break through properly. I thought I had it, but then I deployed this to IIS and it all fell apart.
The following is setup as environment variables:
ldapController
ldapPort
adminUsername 🡒 Definitely a different user than the error reports
adminPassword
baseDn
And read in through my Startup.Configure method.
EDIT I know they are available to IIS, because I returned them in a REST endpoint.
This is my code:
// Connect to LDAP
LdapConnection conn = new LdapConnection();
conn.Connect(ldapController, ldapPort);
conn.Bind(adminUsername, adminPassword);
// Run search
LdapSearchResults lsc = conn.Search(
baseDn,
LdapConnection.SCOPE_SUB,
lFilter,
new string[] { /* lots of attributes to fetch */ },
false
);
// List out entries
var entries = new List<UserDto>();
while (lsc.hasMore() && entries.Count < 10) {
LdapEntry ent = lsc.next(); // <--- THIS FAILS!
// ...
}
return entries;
As I said, when debugging this in visual studio, it all works fine. When deployed to IIS, the error is;
Login failed for user 'DOMAIN\IIS_SERVER$'
Why? The user specified in adminUsername should be the user used to login (through conn.Bind(adminUsername, adminPassword);), right? So why does it explode stating that the IIS user is the one doing the login?
EDIT I'm using Novell.Directory.Ldap.NETStandard
EDIT The 'user' specified in the error above, is actually NOT a user at all. It is the AD registered name of the computer running IIS... If that makes any difference at all.
UPDATE After consulting with colleagues, I set up a new application pool on IIS, and tried to run the application as a specified user instead of the default passthrough. Exactly the same error message regardless of which user I set.
Try going via Network credentials that allows you to specify domain:
var networkCredential = new NetworkCredential(userName, password, domain);
conn.Bind(networkCredential);
If that does not work, specify auth type basic (not sure that the default is) before the call to bind.
conn.AuthType = AuthType.Basic;

Unable to get some user account information in UWP app - In-premise active directory (Not Azure AD)

In a UWP app, I have enabled the User Account Information capability.
I need to get the username and the domain name (each of them separately) of the currently logged on user (The users are logged on with an in-premise Active Directory account - Not Azure AD).
For example, the user would log in to the Active Directory domain domain1 using the username user1. i.e. domain1\user1.
I am using the following code to try to get the required details:
IReadOnlyList<User> users = await User.FindAllAsync();
var user = users.FirstOrDefault();
// get domain
var data1 = await user.GetPropertyAsync(KnownUserProperties.DomainName);
string strDomainName = (string)data1;
// get username
var data2 = await user.GetPropertyAsync(KnownUserProperties.AccountName);
string strUserName = (string)data2;
Issues:
strDomainName returns domain1.com\user1. Why does this include the .com part for all our domains? On c# winforms applications we can easily get domain1\user1 without any issue.
strUserName returns an empty string. i.e. "". Why does this not return any value?
I also checked the following:
KnownUserProperties.FirstName returns an empty string. i.e. ""
KnownUserProperties.LastName returns an empty string. i.e. ""
KnownUserProperties.PrincipalName returns an empty string. i.e. ""
KnownUserProperties.ProviderName returns an empty string. i.e. ""
KnownUserProperties.GuestHost returns an empty string. i.e. ""
Is there anything else I need to enable similar to the User Account Information capability? Or are there any other permissions that need to be granted to the app to get this information?
I understand that I can get the value of strDomainName and perform string functions to get what I need. But I want to know if there is any way to get this information directly. Also curious why KnownUserProperties.AccountName and other properties listed above such as FirstName, LastName etc. just returns an empty string.
I am running the following version of Windows:
I have the following set as the Target version and Min Version:
To verify, I also tested with the UserInfo sample project by Microsoft from GitHub and I got the following output:
The following was automatically enabled in Settings > Privacy > Account Info.
TestApp is the app I tried with and User Info C# Sample is the sample app from GitHub:
Update:
After also enabling the Enterprise Authentication capability, KnownUserProperties.PrincipalName does return the expected value. i.e. user1#domain1.com.
However, other properties listed above such as FirstName, LastName etc. just returns an empty string and I am still unable to find any property that returns domain1\user1 (without the .com part)
The Information you are trying to access are not reliable, as they (as you mentioned) do not have to be set and also they can be restricted access to via privacy settings in general.
I had a similar problem and would advise you to use the UWP OneDrive API
using Microsoft.OneDrive.Sdk;
and then request wl.basic scope. This scope contains at least a reliable username.
public static async Task<bool> GetAuthenticatedClient()
{
string oneDriveConsumerBaseUrl = "https://api.onedrive.com/v1.0";
var scopes = new List<string>
{
"wl.signin",
"wl.basic",
};
Task authTask;
var onlineIdAuthProvider = new OnlineIdAuthenticationProvider(scopes.ToArray());
authTask = onlineIdAuthProvider.RestoreMostRecentFromCacheOrAuthenticateUserAsync();
oneDriveClient = new OneDriveClient(oneDriveConsumerBaseUrl, onlineIdAuthProvider);
AuthProvider = onlineIdAuthProvider;
try
{
await authTask;
if (!AuthProvider.IsAuthenticated)
{
return false;
}
}
catch (ServiceException exception)
{
// Swallow the auth exception but write message for debugging.
//Debug.WriteLine(exception.Error.Message);
return false;
}
return true;
}
As for the domain, I'm not sure, but you could try to access it via Environment.UserDomainName like described on MSDN or with Windows.Networking.Connectivity.NetworkInformation.GetHostNames() like described here.
I found another possible solution to this. If you are still debugging this locally or the app was already installed on the target machine, I could enable the capabality User Account Information but this was not propagated to the actual installed app:
when your search for your app name in the start menu and then right click the entry and select App settings you get something like this:
As soon as I enabled the highlighted option (basically it says 'Account information') it worked.

Categories