For my application, when a user login, I display a prompt and ask if the user wants to save the password to keychain. The code saves successfully and I'm able to query the keychain for the stored password completely fine.
My question is how come when I check my phone under Passwords & Acccounts - Website & App Passwords, nothing is displayed.
The bit of code I used to save the key
public static bool SaveValueToKeyChain(string entryKey, string entryValue)
{
SecRecord record = new SecRecord(SecKind.GenericPassword)
{
Account = entryKey,
Label = entryKey,
Service = _keyChainServiceName
};
SecStatusCode resultCode;
SecKeyChain.QueryAsRecord(record, out resultCode);
if (resultCode == SecStatusCode.Success)
{
if (SecKeyChain.Remove(record) != SecStatusCode.Success)
{
return false;
}
}
resultCode = SecKeyChain.Add(new SecRecord(SecKind.GenericPassword)
{
Label = entryKey,
Account = entryKey,
Service = _keyChainServiceName,
Accessible = SecAccessible.WhenUnlockedThisDeviceOnly,
Synchronizable = true,
ValueData = NSData.FromString(entryValue, NSStringEncoding.UTF8),
});
return resultCode == SecStatusCode.Success;
}
I've also followed the solution from here https://developer.xamarin.com/samples/monotouch/Keychain/ and no luck as well. May I get some assistance.
For each application, the keychain has two access zones, a private zone and a public zone (that is, a group mode).
Private area :is a closed storage area. Each application can only operate its own private area. Any data stored in this application is invisible to other programs, and other programs do not have permission to access this private area. (Can be understood as a sandbox with a keychain).
Public area: apple provides a data sharing module between multiple apps developed by the same developer account. It is now limited to data sharing between different apps under the same developer account. This area is another data storage space that is independent of the private area. Achieve common access to some data between multiple applications.
I guess here should be the private area.You can have a try with group mode. Sharing Access to Keychain Items Among a Collection of Apps
Related
I intend to create a manifest of Windows users and I need to hand-pick them from the valid users on an unknown computer.
There are lots of different types of environments:
single computer with local users only
domain computer with local and domain users
domain computer with local users and users from the various domains of the forest
So I don't want to implement a custom solution to handle all the various types and also there is a built-in solution in Windows:
Unfortunately, I couldn't find any code to access the Find users… dialog, but I guess, in the last 20 years someone has created a NuGet for that so there must be some code to rely on.
Can you point me in the right direction?
This is called the Directory Object Picker dialog.
Someone made a package that wraps the native calls for .NET: Active-Directory-Object-Picker
You can install it from NuGet: Tulpep.ActiveDirectoryObjectPicker
There is example code on the GitHub page:
DirectoryObjectPickerDialog picker = new DirectoryObjectPickerDialog()
{
AllowedObjectTypes = ObjectTypes.Computers,
DefaultObjectTypes = ObjectTypes.Computers,
AllowedLocations = Locations.All,
DefaultLocations = Locations.JoinedDomain,
MultiSelect = true,
ShowAdvancedView = true
};
if (picker.ShowDialog() == DialogResult.OK)
{
foreach (var sel in picker.SelectedObjects)
{
Console.WriteLine(sel.Name);
}
}
How can I get my app to open the last edited file after a click in the Windows 10 Timeline? Thanks for the help.
var activityId = Guid.NewGuid().ToString();
UserActivityChannel channel = UserActivityChannel.GetDefault();
UserActivity userActivity = await channel.GetOrCreateUserActivityAsync(activityId);
userActivity.VisualElements.DisplayText = PageTitle.Text;
if (File != null)
{
userActivity.VisualElements.Description = File.DisplayName;
}
userActivity.VisualElements.BackgroundColor = Colors.Black;
userActivity.VisualElements.Content = AdaptiveCardBuilder.CreateAdaptiveCardFromJson(cardText);
userActivity.ActivationUri = new Uri("my-app:navigate?page=" + _index);
await userActivity.SaveAsync();
_currentActivity?.Dispose();
_currentActivity = userActivity.CreateSession();
From the UserActivityChannel Class, there is a GetRecentUserActivitiesAsync method, but it only get the specified number of the most recently engaged user activities sorted by the time each user activity ended. Due to the privacy protecting policy of UWP app, your app can not get the user activities from system or other apps.
Currently, in your app, you can only operate the user activities which your app created. If the file is edited by the system or other app, you can not implement the effect you want. But if the file is operated by your app, you can try to create a user activity which is for opening the file then handle the protocol activated event in your app to open it. Maybe you should see the topic track recently used files.
For quite a few days now I have been trying to get some custom Active Directory based authentication to work. It all works in theory but apparently my theory is wrong. Users who are logged on to a domain write a string token (e.g. PIN code) to their own property field in Active Directory (doesn't really matter which one, but I used primaryInternationISDNNumber for this) upon logging on to the ASP.NET application This PIN is always generated and written programmatically.
To explain it roughly, the web browser loads a Java applet which then loads a native DLL written in C++, which generates and writes the PIN to current user's Active Directory field. That DLL then returns the generated PIN to the applet which then passes it to the browser, which performs an AJAX call with the data returned to initiate the authentication. The application, which has got access to the AD, reads this field value for the connecting user object and checks if it matches with the one the user supplied. If PIN codes match, the user is successfully authenticated.
This is the sample code the ASP.NET application used to read the AD:
using (var de = new DirectoryEntry("LDAP://" + domainName))
{
using (var adSearch = new DirectorySearcher(de))
{
// Get user from active directory.
adSearch.Filter = "(sAMAccountName=" + userName.Trim().ToLower(CultureInfo.CurrentCulture) + ")";
var adSearchResult = adSearch.FindOne();
var entry = adSearchResult.GetDirectoryEntry();
var pinCodeProp = entry.Properties["primaryInternationISDNNumber"];
return pinCodeProp != null ? pinCodeProp.Value : string.Empty;
}
}
This works fine, often. But often is not acceptable. It needs to always be working.
The trouble is that the ASP.NET application sometimes gets the value which was previously in that field, not the actual value. As if there is some kind of caching. I have tried to add de.UsePropertyCache = false but that yielded the same results.
I have created two Win32 console applications for test purposes. One writes the PIN code, the other reads the PIN code. They always work fine!
I thought, this gotta be some problem with IIS application pool. So I have created a native DLL which gets loaded by the ASP.NET application using Platform Invoke. This DLL creates a new thread, calls CoInitialize and reads the PIN code. This is the code:
pszFqdn = argv[1];
pszUserName = argv[2];
pszPassword = argv[3];
IADs *pObject = NULL;
HRESULT hr = S_OK;
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = ADsOpenObject(pszFqdn, pszUserName, pszPassword, ADS_SECURE_AUTHENTICATION, IID_IADs, (LPVOID*)&pObject);
if (SUCCEEDED(hr) && pObject)
{
VARIANT var;
VariantInit(&var);
hr = pObject->Get(CComBSTR("primaryInternationalISDNNumber"), &var);
if ((SUCCEEDED(hr) && var.bstrVal) || hr == 0x8000500d)
{
if (hr != 0x8000500d)
{
// convert the BSTR received to TCHAR array
std::wstring wsValue(var.bstrVal, SysStringLen(var.bstrVal));
// copy the received value to somewhere
// ... not relevant
}
VariantClear(&var);
}
pObject->Release();
}
}
CoUninitialize();
To my tremendous and unpleasant surprise, this code after a day of working properly, started returning the previous values, just like the managed code before!
So now I thought, alright, I wasn't able to escape the IIS application pool and since this gotta be a problem with IIS application pool, I will create a native Windows application which I will execute by using Process.Start method. I will return my PIN code by means of process exit code (since it's an integer anyway). The application uses the similar C++ code as the DLL above.
So I start my application, wait for it to finish, read the exit code. Returns the bad value!
But okay, I'd say, the process is started using the current user credentials, which is again IIS application pool. So I start the application under different credentials. And guess what..... it returns the old value again (?!?!?!).
And I thought Java was hell... Anyone has got any idea about what could possibly be going on here?
It was the replication indeed. As I didn't want to force the replication before reading the field (that would have been a time-expensive operation probably anyway), I came to an idea to read this field from each domain controller and check if any of them matches with the value supplied.
As it might prove helpful to someone, I did that using the following code.
var ctx = new DirectoryContext(
DirectoryContextType.DirectoryServer,
ipAddress,
userName, // in the form DOMAIN\UserName or else it would fail for a remote directory server
password);
var domain = Domain.GetDomain(ctx);
var values = new List<string>();
foreach (DomainController dc in domain.DomainControllers)
{
using (var entry =
new DirectoryEntry(
"LDAP://" + dc.IPAddress,
userName,
password))
{
using (var search = new DirectorySearcher(entry))
{
search.Filter = "(&(primaryInternationalISDNNumber=*)(sAMaccountName=" + userName + "))";
var result = search.FindOne();
var de = result.GetDirectoryEntry();
if (de.Properties["primaryInternationalISDNNumber"].Value != null)
{
values.Add(de.Properties["primaryInternationalISDNNumber"].Value.ToString());
}
}
}
}
Is there any API for writing a C# program that could interface with Windows update, and use it to selectively install certain updates?
I'm thinking somewhere along the lines of storing a list in a central repository of approved updates. Then the client side applications (which would have to be installed once) would interface with Windows Update to determine what updates are available, then install the ones that are on the approved list. That way the updates are still applied automatically from a client-side perspective, but I can select which updates are being applied.
This is not my role in the company by the way, I was really just wondering if there is an API for windows update and how to use it.
Add a Reference to WUApiLib to your C# project.
using WUApiLib;
protected override void OnLoad(EventArgs e){
base.OnLoad(e);
UpdateSession uSession = new UpdateSession();
IUpdateSearcher uSearcher = uSession.CreateUpdateSearcher();
uSearcher.Online = false;
try {
ISearchResult sResult = uSearcher.Search("IsInstalled=1 And IsHidden=0");
textBox1.Text = "Found " + sResult.Updates.Count + " updates" + Environment.NewLine;
foreach (IUpdate update in sResult.Updates) {
textBox1.AppendText(update.Title + Environment.NewLine);
}
}
catch (Exception ex) {
Console.WriteLine("Something went wrong: " + ex.Message);
}
}
Given you have a form with a TextBox this will give you a list of the currently installed updates. See http://msdn.microsoft.com/en-us/library/aa387102(VS.85).aspx for more documentation.
This will, however, not allow you to find KB hotfixes which are not distributed via Windows Update.
The easiest way to do what you want is using WSUS. It's free and basically lets you setup your own local windows update server where you decide which updates are "approved" for your computers. Neither the WSUS server nor the clients need to be in a domain, though it makes it easier to configure the clients if they are. If you have different sets of machines that need different sets of updates approved, that's also supported.
Not only does this accomplish your stated goal, it saves your overall network bandwidth as well by only downloading the updates once from the WSUS server.
If in your context you're allowed to use Windows Server Update Service (WSUS), it will give you access to the Microsoft.UpdateServices.Administration Namespace.
From there, you should be able to do some nice things :)
P-L right. I tried first the Christoph Grimmer-Die method, and in some case, it was not working. I guess it was due to different version of .net or OS architecture (32 or 64 bits).
Then, to be sure that my program get always the Windows Update waiting list of each of my computer domain, I did the following :
Install a serveur with WSUS (may save some internet bandwith) : http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=5216
Add all your workstations & servers to your WSUS server
Get SimpleImpersonation Lib to run this program with different admin right (optional)
Install only the administration console component on your dev workstation and run the following program :
It will print in the console all Windows updates with UpdateInstallationStates.Downloaded
using System;
using Microsoft.UpdateServices.Administration;
using SimpleImpersonation;
namespace MAJSRS_CalendarChecker
{
class WSUS
{
public WSUS()
{
// I use impersonation to use other logon than mine. Remove the following "using" if not needed
using (Impersonation.LogonUser("mydomain.local", "admin_account_wsus", "Password", LogonType.Batch))
{
ComputerTargetScope scope = new ComputerTargetScope();
IUpdateServer server = AdminProxy.GetUpdateServer("wsus_server.mydomain.local", false, 80);
ComputerTargetCollection targets = server.GetComputerTargets(scope);
// Search
targets = server.SearchComputerTargets("any_server_name_or_ip");
// To get only on server FindTarget method
IComputerTarget target = FindTarget(targets, "any_server_name_or_ip");
Console.WriteLine(target.FullDomainName);
IUpdateSummary summary = target.GetUpdateInstallationSummary();
UpdateScope _updateScope = new UpdateScope();
// See in UpdateInstallationStates all other properties criteria
_updateScope.IncludedInstallationStates = UpdateInstallationStates.Downloaded;
UpdateInstallationInfoCollection updatesInfo = target.GetUpdateInstallationInfoPerUpdate(_updateScope);
int updateCount = updatesInfo.Count;
foreach (IUpdateInstallationInfo updateInfo in updatesInfo)
{
Console.WriteLine(updateInfo.GetUpdate().Title);
}
}
}
public IComputerTarget FindTarget(ComputerTargetCollection coll, string computername)
{
foreach (IComputerTarget target in coll)
{
if (target.FullDomainName.Contains(computername.ToLower()))
return target;
}
return null;
}
}
}
In my current C# code I'm able to lock a Windows user session programmatically (same as Windows + L).
Since the app would still be running, is there any way to unlock the session from that C# program. User credentials are known. The app is running on Windows 7.
You'll need a custom windows credential provider to log in for you. Also, you'll need to save the user's credentials somewhere to log in. There are some samples in Windows SDK 7 https://www.microsoft.com/en-us/download/details.aspx?id=8279
There's a bunch of projects to get you started under Samples\security\credentialproviders.
To unlock the screen:
set the username / password in CSampleCredential::Initialize
set autologin to true in CSampleCredential::SetSelected
search the hardware provider sample for WM_TOGGLE_CONNECTED_STATUS message to see how to trigger the login
build some way to communicate with your app to trigger the unlock (local tcp server for example)
It's a pain in the ass, but it works.
Here is some hackery to do that: http://www.codeproject.com/Articles/16197/Remotely-Unlock-a-Windows-Workstation
Didn't test it myself though.
Not for .NET part, but you could also make your own custom Logon UI and inject some mechanism there. It can easily become security problem though.
var path = new ManagementPath();
path.NamespacePath = "\\ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption"; path.ClassName = "Win32_EncryptableVolume";
var scope = new ManagementScope(path, new ConnectionOptions() { Impersonation = ImpersonationLevel.Impersonate });
var management = new ManagementClass(scope, path, new ObjectGetOptions());
foreach (ManagementObject vol in management.GetInstances())
{
Console.WriteLine("----" + vol["DriveLetter"]);
switch ((uint)vol["ProtectionStatus"])
{
case 0:
Console.WriteLine("not protected by bitlocker");
break;
case 1:
Console.WriteLine("unlocked");
break;
case 2:
Console.WriteLine("locked");
break;
}
if ((uint)vol["ProtectionStatus"] == 2)
{
Console.WriteLine("unlock this driver ...");
vol.InvokeMethod("UnlockWithPassphrase", new object[] { "here your pwd" });
Console.WriteLine("unlock done.");
}
}
Note: this only works if you run Visual Studio as an administrator.
No, there is no way to do this, by design. What's your scenario and why do you need to lock/unlock the workstation?
Of course you can't unlock it. Unlocking a session requires the user physically be there to enter their account credentials. Allowing software to do this, even with saved credentials, would be a security issue for many of the other situations where workstation locking is used.