We have a winforms clickonce application in C# which is granted full trust and signed using a valid certificate.
The application runs fine and updates correctly on Windows XP, Windows 7. However, on a Windows 8 machine, it just fails to update. The application runs correctly though. However, the first update request to move up to a later version fails with: System.Deployment.Application.TrustNotGrantedException
The code failed after the call to ApplicationDeployment::CheckForDetailedUpdate() failed. Wondering why this could happen as the exact same code is running fine on all previous versions of Windows. Any help will be appreciated. Below is the relevant stack trace:
System.Deployment.Application.TrustNotGrantedException: User has refused to grant required permissions to the application.
at System.Deployment.Application.ApplicationTrust.RequestTrust(SubscriptionState subState, Boolean isShellVisible, Boolean isUpdate, ActivationContext actCtx, TrustManagerContext tmc)
at System.Deployment.Application.DeploymentManager.DetermineTrustCore(Boolean blocking, TrustParams tp)
at System.Deployment.Application.DeploymentManager.DetermineTrust(TrustParams trustParams)
at System.Deployment.Application.ApplicationDeployment.CheckForDetailedUpdate(Boolean persistUpdateCheckResult)
at System.Deployment.Application.ApplicationDeployment.CheckForDetailedUpdate()
The only time I'd seen this stack trace was when I tried calling CheckForDetailedUpdate() without setting up the explicit trust before hand. After adding the code below, the update check worked.
// Setup the trust level
var deployment = ApplicationDeployment.CurrentDeployment;
var appId = new ApplicationIdentity(deployment.UpdatedApplicationFullName);
var unrestrictedPerms = new PermissionSet(PermissionState.Unrestricted);
var appTrust = new ApplicationTrust(appId) {
DefaultGrantSet = new PolicyStatement(unrestrictedPerms),
IsApplicationTrustedToRun = true,
Persist = true
};
ApplicationSecurityManager.UserApplicationTrusts.Add(appTrust);
// Check for update
var info = deployment.CheckForDetailedUpdate();
From this MSDN page there are two causes. But it seems TrustNotGrantedException is usually raised when a new ClickOnce update has been deployed that uses more privileges than the previous version...
The application uses permission elevation and the user denies the request for elevated trust; or
The application uses Trusted Application Deployment and the digital certificate used to sign the application is not listed as a trusted publisher on the local machine. If you have deployed an update to an application, and the update uses more permissions than the previous version, and ClickOnce throws a TrustNotGrantedException, the new version will not install.
So it makes sense that it would fail to update, because the apps security level has changed since the user last installed it - so they will need to reinstall it.
We had the same problem and ended up using the InPlaceHostingManager class. It's made for installing or updating a ClickOnce deployment. GetManifestAsync() fires the GetManifestCompleted event, which gives you the version number. Then you can call DownloadApplicationAsync() and handle the DownloadApplicationCompleted event. So far this works and no TrustNotGrantedException is thrown.
Related
Right now i am using an web application with code to read from and write to the registry. While debugging in Visual studio everything went fine but on the online test server it didn't run. the error exception message i am getting is:
System.Security.SecurityException: Requested registry access is not
allowed.
This is the code i am using:
private RegistryKey GetWritableBaseRegistryKey(string extendedPath)
{
var path = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
return RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default).OpenSubKey($"{path}\\{extendedPath}", true);
}
The sollutions i found where:
Solution 1
you will not be able to set AppPoolIdentity to a specific group, but
you can
create a local user (compmgmt.msc)
add the user to the administrator group (compmgmt.msc)
Set the application pool to run under that user, under Advanced Settings.
Obviously you know this is a very bad idea from a security
perspective, and should never ever ever be performed on a forward
facing server.
source
Solution 2
Create a separate console application to run the service in admin
modus so you could access the registry. This solution was performance
heavy because you need to run 2 separate applications.
Solution 3
Use this code to allow access to the registry.
RegistryPermission perm1 = new RegistryPermission(RegistryPermissionAccess.AllAccess, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall");
perm1.Demand();
Or this code
RegistrySecurity rs = new RegistrySecurity();
string currentUserStr = Environment.UserDomainName + "\\" + Environment.UserName;
RegistryAccessRule accessRule = new RegistryAccessRule(currentUserStr, RegistryRights.WriteKey | RegistryRights.ReadKey | RegistryRights.Delete | RegistryRights.FullControl, AccessControlType.Allow);
rs.AddAccessRule(accessRule);
But these didn't work on the server however while debugging in visual studio the code ran fine.
In order for the web application to access the registry it must have sufficient permission. Consequently Solution 1 is the only one likely to work. It describes setting the web sites application pool to a user in the local administrators group. Its misses the steps about actually setting your IIS web site to use the newly created App Pool, which is why it might not work for you.
The technical process of reading a restricted registry, especially the application Uninstall registry key, inside a web server is really unlikely to be useful to you. Of what possible use is allowing a web server to access the servers own Application uninstall list going to be ?
I suspect you intend to open that registry key on the client's PC (my speculation) which is not going to be possible.
I upgrade my app which worked fine on Windows Server 2008(32 bit) from framework 3.5 to 4.5 for Windows Server 2012(64 bit). In the app, there is third party component runs on 32 bit. We cannot upgrade it because the supplier has no plans to update it. Therefore my app platform target is set for any CPU but Prefer 32-bit on my project property. All function is work except writing the event log. Would anyone provide suggestion to deal with this issue? Thank in advance.
There is my code to write the event log.
private static void RecordEventLog(string sMessage, EventLogEntryType ErrorType)
{
string source = "Testing App";
string logName = "Application";
string machineName = ".";
if (!EventLog.SourceExists(source, machineName))
{
EventSourceCreationData sourceData = new EventSourceCreationData(source, logName);
sourceData.MachineName = machineName;
EventLog.CreateEventSource(sourceData);
}
new EventLog(logName, machineName, source).WriteEntry(sMessage, ErrorType);
}
The problem may be the rights to create the event source - I can't see why 32 vs 64-bit would make a difference. You may have to run the app with admin privileges (at least the first time) to create the event source.
From MSDN:
To create an event source in Windows Vista and later or Windows Server
2003, you must have administrative privileges.
The reason for this requirement is that all event logs, including
security, must be searched to determine whether the event source is
unique. Starting with Windows Vista, users do not have permission to
access the security log; therefore, a SecurityException is thrown.
In Windows Vista and later, User Account Control (UAC) determines the
privileges of a user. If you are a member of the Built-in
Administrators group, you are assigned two run-time access tokens: a
standard user access token and an administrator access token. By
default, you are in the standard user role. To execute the code that
accesses the security log, you must first elevate your privileges from
standard user to administrator. You can do this when you start an
application by right-clicking the application icon and indicating that
you want to run as an administrator.
I work with emergency services and they have an application that uses map files to let them know where they need to go and it uses GPS to let them know where they are. We have to update the map files as things change and before I started here they were being done through VB scripts which started to fail. I decided to code my own app in C# to do this which works fine.
I created a package in SCCM 2012 that caches all of the files locally and then it compares the files in the cache to what is on the machine and then replaces any older files. This all works fine but the application they use called MobileCAD locks the files so I have to kill this process and then do the file copy and start the application again. We never know when an emergency happens so this update may start when they are on the road so it is important that it starts the application again as soon as possible. If it does not start the application then the emergency services people may try to do so manually but if core files are being updated then it may not start or cause issues.
I coded my application which uses an app manifest to force it to run as an administrator for the file copy. This application is run through SCCM which uses the local 'System' account to do all of the work and killing MobileCAD and copying files which works great. What I originally found was that it does start MobileCAD but it does so under the System account and the process would be there but it was not visible. I think this is the same problem they were originally having so the emergency services people would need to reboot the computer and wait for it to log back in and then start the wireless service so they could get back into MobileCAD.
To address this issue I did research and found that I could use the ProcessStartInfo in .NET and force it to use another account. As we use an automatic logon for these machines the users name, password, and domain are all in the registry so it was easy to pull it out and inject it into the code. Awesome, looks like it is easy enough so I code it up and sure enough it works perfectly when run under my admin account. In my basic testing everything worked perfectly until I try the same in SCCM, now it fails with the following error message.
System.ComponentModel.Win32Exception (0x80004005): Access is denied
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at UpdateFDM.Program.StartProcess(String processName)
I am sorry for all of the words but I believe it helps if you have a good understanding of the issue and what I am trying to do. I have also hard coded the user information into the code instead of pulling it from the registry but I get the same error. Again, this works fine under my admin account but fails when it is pushed through SCCM and it is only launching MobileCAD that fails.
This is the code I am using for launching MobleCAD, do you see where my issue may lie? I know SCCM confuses it but SCCM basically runs things just as you would from the command line but it uses the local System account.
Thanks for any help.
// Declares the new start instance
ProcessStartInfo process = new ProcessStartInfo();
// Gets the process to start
process.FileName = processName;
// Maximizes the process windows at start-up
process.WindowStyle = ProcessWindowStyle.Maximized;
// Gets the user name from the autologon information
process.UserName = GetDefaultUserInfo("DefaultUserName");
// Gets the domain for the user
process.Domain = GetDefaultUserInfo("DefaultDomainName");
// Holds the password for the default user
SecureString password = new SecureString();
// Gets the raw password from the registry
string rawPassword = GetDefaultUserInfo("DefaultPassword");
// Copies the password in a secure string
foreach (char ch in rawPassword)
{
password.AppendChar(ch);
}
// Sets the password
process.Password = password;
// Needed to launch the app as the logged on user
process.LoadUserProfile = true;
process.UseShellExecute = false;
// Starts the process
Process.Start(process);
// Process started, return true
return true;
I have an ASP.NET MVC 3 application which uses PowerShell to connect to Office 365 to retrieve some details about user licenses.
The code itself works in many cases:
The project in my local IIS works
A piece of code in LINQPad using the library works on my machine
A piece of code in LINQPad using the library works on the target server
And where it doesn't work is of course the only place it really should work: The IIS on the target server.
I always get an Exception when calling the Connect-MsolService cmdlet. The problem is that the Exception doesn't tell me anything.
The Exception type is
Microsoft.Online.Administration.Automation.MicrosoftOnlineException
and the message is
Exception of type 'Microsoft.Online.Administration.Automation.MicrosoftOnlineException' was thrown
which is pretty useless.
The Office 365 user account I use in my code is always the same. The user account used to start the IIS is always the same, too (Local System).
I wrapped the PowerShell code execution in a class named PowerShellInvoker. Its code can be found here.
And here is the code that connects to Office 365:
var cred = new PSCredential(upn, password);
_psi = new PowerShellInvoker("MSOnline");
_psi.ExecuteCommand("Connect-MsolService", new { Credential = cred });
There is no Exception actually thrown, the error is found in the Error property of the pipeline. (See lines 50ff. of the PowerShellInvoker class.)
The problem is that I don't know what could be wrong, especially because the same code works when I use LINQPad. The search results by Google couldn't help me either.
The server runs on Windows Server 2008 R2 Datacenter SP1 with IIS 7.5.
I found the solution!
I don't know the reason, but on the target server, the app pool's advanced settings for my app had set Load User Profile to False. I changed it back to True (which should be default) and voilĂ , it works!
Edit: The Load User Profile setting was apparently automatically set to False by default because the IIS 6.0 Manager was installed and False was the default behavior until IIS 6.0.
While I am trying to upload a registry in my registries using the C# code , the application is throwing the error "a required privilege is not held by the client". If I am using the same code on some other machine it is working fine but not particularly on my machine
I am using below mentioned code to upload the registry files
Process my_p = new Process();
my_p.StartInfo.FileName = "reg";
my_p.StartInfo.Arguments = "load HKLM\TEST C:\Documents and Settings\Administrator\NTUSER.DAT";
my_p.Start();
my_p.WaitForExit();
System.IO.StreamReader srOutPut = my_p.StandardOutput;
System.IO.StreamReader srError = my_p.StandardError;
my_p.Close();
results = srOutPut.ReadToEnd().Trim();
Errors = srError.ReadToEnd().Trim();
Moreover One thing I have noticed that the above code I am using in http based web site, but when I am using it in a File Syatem based web site it is working fine. Please help I am not getting the error.
Regards,
Vikram
You can load RegLoadKey function directly to load the hive as a subkey. Another API is RegLoadAppKey but it works only starting from Windows Vista. Different versions of Reg.exe use the API. How you can read in the description the RegLoadKey you need have SE_RESTORE_NAME and SE_BACKUP_NAME privileges and enable these (see http://msdn.microsoft.com/en-us/library/ms717797.aspx). If you are in the Group of Administrators or Backup Operators you have these privileges. One more problem can be if Reg.exe use RegLoadKey function and you have a local administrative rights, but you start on Vista or Windows 7 a command without admin rights because of UAC (User Account Control).