2

How do you open a document as another user?

The document type is unkown (could be pdf, .xls, .doc, images etc). Document is on a network share, username, domain and password are all known.

I have thoroughly researched this question and I do not beleive the question has been answered here. Please prove me wrong.

This question gets close Open a shared file under another user and domain?

But unfortunately it opens the file to a filestream, I need to open the file in its associated application.

Community
  • 1
  • 1
Reafidy
  • 8,240
  • 5
  • 51
  • 83
  • Do you mean you want to open it from within your program? Or else what are the tags for? – Karl Knechtel Jun 24 '11 at 02:00
  • Hi Karl - I want my winforms application to allow the user to select a document using openfiledialog and then open the file. However the file will be on a network share. I can show the openfiledialog using impersonation. But once the user selects the file I am unsure how to open it as start process does not run under the impersonated account. – Reafidy Jun 24 '11 at 02:18
  • @Reafidy : Is your WinForms app written in C#? Why did you tag this question `c++`? – ildjarn Jun 24 '11 at 02:36
  • @ildjarn I assumed than someone with C++ experince may be able to offer a solution. I am happy to remove it, if you take issue to it. – Reafidy Jun 24 '11 at 02:42
  • @Reafidy : The problem is that I couldn't just post an answer using C++ and have that be acceptable here, since C# and C++ have very different idioms. With C++ you would use `LogonUserEx` + `ShellExecuteEx` (and I can tell you -- writing the P/Invoke code for `LogonUserEx` is not fun) while with C# you would use `WindowsIdentity.Impersonate` + `Process.Start` (with `UseShellExecute=true`). In this particular case, I really don't think the `c++` tag is appropriate. – ildjarn Jun 24 '11 at 02:48
  • Okay thanks I will remove it. When using impersonation process.start does not run under the impersonated users account so that will not work. – Reafidy Jun 24 '11 at 03:07
  • @Reafidy : Well, it definitely works (speaking from experience) if you P/Invoke `LogonUser` or `LogonUserEx` and use the returned handle as the impersonation token. See [here](http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.windowsforms/topic62740.aspx) for some relevant pre-written code to accomplish exactly this (although, at a glance, the `FormatMessage` P/Invoke code looks wrong). – ildjarn Jun 24 '11 at 03:34
  • I used the code you suggested and checked the impersonation was running correctly using WindowsIdentity.GetCurrent().Name. However I still get an "access denied" message when using process.start. Process.start does not seem to use the impersonated user. – Reafidy Jun 24 '11 at 04:41

3 Answers3

1

Check out Runas

runas /user:somedomain\someuser "cmd /c start c:\somedocument.pdf"

It is located at C:\Windows\System32\runas.exe

To open this from a C# application, you could use Process.Start, with the appropriate flags.

Edit

Well, you can skip the use of Runas entirely, since Process.Start can do the same job, and still allow you to specify the password however you like (hard-coded internally, or via the UI).

Simply use cmd.exe /c start <pathToFile> to launch the file via the shell with the associated program:

string cmdPath = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.System),
    "cmd.exe");
string workingDirectory = @"C:\users\public";
string pathToFile = Path.Combine(workingDirectory, "somefile.png");
string arguments = string.Format("/c start {0}", pathToFile);
var password = new SecureString();
foreach (char c in "usersPassword")
    password.AppendChar(c);

var processStartInfo = new ProcessStartInfo()
{
    FileName = cmdPath,
    Arguments = arguments,
    WorkingDirectory = workingDirectory,
    UserName = "TestUser",
    Domain = Environment.MachineName, // Could use domain
    Password = password,
    UseShellExecute = false,
};
Process.Start(processStartInfo);
Merlyn Morgan-Graham
  • 58,163
  • 16
  • 128
  • 183
  • To use process start with a username and password I have to set UseShellExecute to false and then doing so only allows you to then run .exe's. I need to open document typs ie PDF's. – Reafidy Jun 24 '11 at 02:26
  • @Reafidy: runas.exe is an exe, and it can in turn run cmd.exe. Cmd.exe has a `start` command that will open it in the shell. I'm thinking that if you run cmd.exe as a different user, then `start` will use that same user, but I could be wrong. – Merlyn Morgan-Graham Jun 24 '11 at 02:34
  • Runas does not allow a password to be entered and I do not want to prompt the user for it as they will not have it anyway. – Reafidy Jun 24 '11 at 03:02
  • @Reafidy: Well, you don't really need run-as if you run cmd.exe directly with alternate credentials. I'll edit my answer to demonstrate how. – Merlyn Morgan-Graham Jun 24 '11 at 08:26
  • Marvelous piece of code. Thank you. ALthough I had to remove the start command and add "" around the filepath. The only things is that the cmd window breifly appears. I tried both: startinfo.CreateNoWindow = True startinfo.WindowStyle = ProcessWindowStyle.Hidden – Reafidy Jun 24 '11 at 22:56
  • 1
    @Reafidy: I looked around quite a bit on SO and elsewhere, and found its kind of a pain without using a shim. You can write your own windows app that simply calls `Process.Start`, with `UseShellExecute = true` to replace cmd.exe. Or you can live with the window popping up :) The rest of the options involve a lot of p/Invoke, and are really painful, and I'd personally be nervous about getting the security details wrong. See http://stackoverflow.com/questions/33594/createprocessasuser-vs-shellexecute for one. – Merlyn Morgan-Graham Jun 25 '11 at 04:39
  • Thanks Merlyn, useshellexecute = true means you cannot add a username/password. I think I will take your advice and live with it. However judging by what @Alexei has stated below I may be going about this all wrong. Thanks for your help. – Reafidy Jun 27 '11 at 00:18
  • 1
    @Reafidy: You'd do the l/p in your main app, and the shim wouldn't need the l/p, since you'd already be running as that user. The shim would just replace cmd.exe in my answer's sample code, to avoid popping up a window. You'd do `Process.Start` twice, in two different programs :) – Merlyn Morgan-Graham Jun 27 '11 at 02:53
  • Ahh I see what you mean, I should have read it more thoroughly. Thanks - thats definately a solution to the orginal question. Alexei's comments below have put the breaks on for me though. – Reafidy Jun 27 '11 at 03:34
1

Have you considered simply copying the file locally and opening it as current user?

Reasoning:

  • I don't know any document editng application that natively allow opening documents as another user. As result you'd better start the application to view document as another user.
  • Not all applications behave properly when executed on the same desktop* under different user (i.e. with "run as" or CreateProcessWithLogonW) and most applications dealing with interaction with documents are not tested to be used in "run as" context.
  • Some applications will simple ignore the fact that it tried to start under different user if another copy is already running on the same desktop.

*Desktop is used in Win32 sense.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • Where in the op was there a mention of "Run as" functionality? If this answer refers to another answer, it's much more appropriate to post a comment on that answer rather then another answer. – Neowizard Jun 24 '11 at 06:10
  • Good point. It looks like all forms of "run as" is the only solution for OP requirements... so marking post as community wiki to allow better formatting and more comments about "run as" scenario to be posted without reputation accumulation. – Alexei Levenkov Jun 24 '11 at 07:03
  • I had considered your first point - I dismissed it because I then have to write code for the user to upload it again once they have saved their changes. Thinking about it some more though I think you have a good point. As you have guessed I am creating a document manager, are your thoughts that instead of openening as another user I should allow the user to save to a temp directory or instead request that they specify a directory to save to? Following their changes they then have to reupload the document to the server... is that what you would expect to see? – Reafidy Jun 24 '11 at 23:05
  • 1
    I would not expect users to upload files under someone elses credentials - this is just plain wrong. Obviously it's your call, but please consider how you will track who made what change... Anyway if you want to go the route of storing all documenents on share under one user - copy locally as special user , open as current user, monitor for changes and upload under special user when file changed. (Please check out exisitng document management systems before rolling out your own unless you doing it for educational purposes.) – Alexei Levenkov Jun 25 '11 at 00:36
  • thanks, point taken. My intentions were to set up a special user account for the application. So only the application could work with the share, updating an sql database as users copy, edit and change documents. Thus preventing users from manually changing the files which would leave inconsistencies with the database. I take it that is incorrect, how would you expect to see this done? – Reafidy Jun 27 '11 at 00:15
1

you could some server side web service which has full permission and you can try to call that web service to check if passed user is allowed to edit the document, if it is, then webservice can retrieve that doc and send it over.

that way you have put permissioning layer/tier in between and dont have to deal it on yr client app. client app simply sends username and webservice handles the rest

Bek Raupov
  • 3,782
  • 3
  • 24
  • 42
  • Another good answer. The webservice will require extra IT work in regard to setting up the webservice. I would like to see if I can handle it through the file system first. THis is a good option though - thanks. – Reafidy Jun 24 '11 at 23:08