-
-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Usage Question] impersonation for kerberos authenticated users #117
Comments
I think I have to call ImpersonateLoggedOnUser with the with Will try (if I find an example for node.js: this package export appears to be a good fit, I'm going to install it) and close the issue, if it works. |
I'm getting
for this code const { impersonateLoggedOnUser, revertToSelf} = require('F:\\Apps\\ng\\angular-sso-example\\back\\build\\Release\\users.node');
const accessToken = req?.session?.sso?.user?.accessToken;
impersonateLoggedOnUser(accessToken); |
The two libraries have different ways to treat the handles. edit Ehm.... this is what you use to retrieve a HANDLE from a string, I'll try to modify the other lib users.cc accordingly... |
Now the access token is correctly transformed into a napi value and viceversa (code below), but still ImpersonateLoggedOnUser throws invalid handle.
|
I have recompiled the library to have access to the private server context handle. const getServerHandle = (req : any) => req?.session?.sso?.serverContextHandle
const input = getServerHandle(req);
sspi.ImpersonateSecurityContext(input);
const new_access_token = sspi.OpenThreadToken();
impersonateLoggedOnUser(new_access_token); and in this case I'm getting a different error: 'Access is denied.' asked on SO, but it has been closed. In conclusion, the results of my tests of reusing serverContextHandle and OpenThreadToken are
|
Unfortunately also MS SQL windows authentication fails because it sees the process owner user and not the impersonated SSPI token. |
I doubt that other debug details are needed. All this boils down to saying that Kerberos ticket is only valid to authenticate Alice to Bob but can't be used for Bob to impersonate Alice (typically for windows authentication on ms sql server). I only see 2 possible answers: either 1) yes, it's by design (hopefully that is true IMO) or 2) no, one could be able to use Kerberos ticket to |
Solved with this code! In the context of SSPI Kerberos access token (typically from single sign on), the access denied from Will post a PR #include "../../misc.h"
#include <fstream>
namespace myAddon {
// Proof of concept as Kerberos SSPI impersonated user
void testImpersponation(HANDLE userToken) {
// Create and open a text file
std::ofstream MyFile("test_SSPI.bat");
// Write to the file
MyFile << "whoami > whoami.txt";
// Close the file
MyFile.close(); // check if file owner is the impersonated user
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = {0};
wchar_t wszCommand[]=L"cmd.exe /C test_SSPI.bat";
/* Unicode version of CreateProcess modifies its command parameter... Ansi doesn't.
Apparently this is not classed as a bug ???? */
if(!CreateProcessAsUser(userToken,NULL,wszCommand,NULL,NULL,FALSE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
{
//CloseHandle(hToken);
fprintf(stderr,"CreateProcess returned error %d\n",GetLastError());
return;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread)
}
void e_ImpersonateSecurityContext(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
if (info.Length() < 1) {
throw Napi::Error::New(
env,
"ImpersonateSecurityContext: Wrong number of arguments. "
"ImpersonateSecurityContext(serverContextHandle: string)");
}
Napi::String serverContextHandleString = info[0].As<Napi::String>();
CtxtHandle serverContextHandle =
SecHandleUtil::deserialize(serverContextHandleString.Utf8Value());
SECURITY_STATUS secStatus = ImpersonateSecurityContext(&serverContextHandle);
if (secStatus != SEC_E_OK) {
throw Napi::Error::New(env,
"Cannot ImpersonateSecurityContext: secStatus = " +
plf::error_msg(secStatus));
}
HANDLE userToken;
DWORD flags = MAXIMUM_ALLOWED; // TOKEN_QUERY | TOKEN_QUERY_SOURCE;
BOOL status = OpenThreadToken(GetCurrentThread(), flags, TRUE, &userToken);
if (status == FALSE) {
throw Napi::Error::New(env, "OpenThreadToken: error. " + plf::error_msg());
}
HANDLE duplicatedToken;
BOOL statusDupl = DuplicateTokenEx(userToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &duplicatedToken);
if (statusDupl == FALSE) {
throw Napi::Error::New(env, "DuplicateTokenEx: error. " + plf::error_msg());
}
if (!ImpersonateLoggedOnUser(duplicatedToken)) {
throw Napi::Error::New(env, "C++ ImpersonateLoggedOnUser: error. " + plf::error_msg());
}
testImpersponation(duplicatedToken);
RevertToSelf();
CloseHandle(duplicatedToken);
}
} // namespace myAddon The above proof of concept and impersonation test has been moved now to the other library as written below. |
now the impersonation test has been moved to the other library native-users-node PR by passing the server handle to the session: |
Only a support/help question.
Let say I have a user authenticated via kerberos SSO.
Now my node backend is running under system user and it has no access to a certain network folder.
The authenticated user instead has access to such network folder, so I want to impersonate the user; question: how to do that?
Should I use the access token from sso? I can't find an example, a tutorial or more instructions.
I've tried to look at the source code here.
The point is that I see that SSO.ts is doing
sspi.ImpersonateSecurityContext(this.serverContextHandle);
but to do that it is using a serverContextHandle that is kept private(*)! I would be tempted to fork and modify the code at that point (here, conceptually, I should be able to open the shared folder as the impersonated user, correct?), but it seems complex and before doing that, I would rather gather a better overall understanding. Also because I see alsosspi.OpenThreadToken()
immediately after the impersonation: is that needed for the impersonation (maybe not, I guess the user is already impersonated here, correct?) or just to save the access token? I guess it is for the latter goal, but, again, as I said before, I miss the usage of this access token.(*) Well, it is passed via contructor from the auth.ts that in turn is gathering the
serverSecurityContext.contextHandle
, basically fromsspi.AcceptSecurityContext(input)
where the input is more or less the Kerberos authorization token... ok, but I believe I'm not supposed to repeat all that procedure (starting from Kerberos token and passing it to AcceptSecurityContext) again in my usage code: that would mean that saving the access token is useless, so I'm not considering this option.The text was updated successfully, but these errors were encountered: