Я работаю над приложением на сервере Java (работающем под Windows в качестве службы) и хочу реализовать следующий сценарий:
- Пользователь отправляет POST-запрос на сервер.Пользователь проходит проверку подлинности с помощью Kerberos (SPNEGO, SSO в корпоративной среде).
- Служба создает новый процесс Java.Процесс должен выполняться как аутентифицированный пользователь, а , а не пользователь сервиса (олицетворение / делегирование).
- Новый процесс должен выполняться в контексте безопасности пользователя.Он должен взаимодействовать с другими удаленными системами, требующими аутентификации Kerberos (например, общие папки, другие веб-службы, ...).
Рабочее подтверждение концепции:
- Приложение Spring Boot с Waffle для аутентификации Kerberos.
- Создайте новый процесс для аутентифицированного пользователя.Я использую JNA и встроенную функцию Windows CreateProcessAsUser .
- Процесс создается как аутентифицированный пользователь.Я могу проверить это с помощью утилиты Process Explorer.
Что отсутствует и не работает :
- Процесс не может запрашивать другие билеты Kerberos (например,вызывая InitializeSecurityContext ())
- Процесс не может получить доступ к сетевым ресурсам.
- Процесс не может обмениваться данными с другими веб-службами, для которых требуется проверка подлинности Kerberos.
Мои вопросы:
- Что мне не хватает или что возможно не так с моим кодом?
- Возможно ли вообще реализовать то, чего я хочу достичь?
Сервер - Аутентификация (сокращена, извлечена из Waffle):
final byte[] tokenBuffer = authorizationHeader.getTokenBytes();
CredHandle serverCredHandle = new CredHandle();
TimeStamp clientLifetime = new TimeStamp();
int rc = Secur32.INSTANCE.AcquireCredentialsHandle(
null,
"Negotiate",
Sspi.SECPKG_CRED_INBOUND,
null,
null,
null,
null,
serverCredHandle,
clientLifetime);
SecBufferDesc pbClientToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, tokenBuffer);
CtxtHandle phNewServerContext = new CtxtHandle();
SecBufferDesc pbServerToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, Sspi.MAX_TOKEN_SIZE);
IntByReference pfClientContextAttr = new IntByReference();
rc = Secur32.INSTANCE.AcceptSecurityContext(
serverCredHandle,
null,
pbClientToken,
Sspi.ISC_REQ_CONNECTION,
Sspi.SECURITY_NATIVE_DREP,
phNewServerContext,
pbServerToken,
pfClientContextAttr,
null);
rc = Advapi32.INSTANCE.ImpersonateLoggedOnUser(/* provide the security context token */)
Сервер - CreateProcessAsUser:
// get impersonation token of user
WinNT.HANDLEByReference threadToken = new WinNT.HANDLEByReference();
WinNT.HANDLE threadHandle = Kernel32.INSTANCE.GetCurrentThread();
boolean threadTokenResult = Advapi32.INSTANCE.OpenThreadToken(
threadHandle,
WinNT.TOKEN_QUERY | WinNT.TOKEN_DUPLICATE | WinNT.TOKEN_ASSIGN_PRIMARY,
false, /* TRUE if the access check is to be made against the process-level security context. FALSE if the access check is to be made against the current security context of the thread calling the OpenThreadToken function. */
threadToken);
// create primary token by duplicating impersonation token
WinNT.HANDLEByReference primaryToken = new WinNT.HANDLEByReference();
boolean primaryTokenResult = Advapi32.INSTANCE.DuplicateTokenEx(
threadToken.getValue(), /* hExistingToken */
WinNT.TOKEN_DUPLICATE | WinNT.TOKEN_QUERY | WinNT.TOKEN_ASSIGN_PRIMARY, /* dwDesiredAccess */
null, /* lpTokenAttributes */
WinNT.SECURITY_IMPERSONATION_LEVEL.SecurityDelegation, /* ImpersonationLevel */
WinNT.TOKEN_TYPE.TokenPrimary, /* TokenType */
primaryToken); /* phNewToken */
String environment = createEnvironment(primaryToken);
WinBase.STARTUPINFO startupInfo = new WinBase.STARTUPINFO();
WinBase.PROCESS_INFORMATION processInfo = new WinBase.PROCESS_INFORMATION();
boolean createProcessResult = Advapi32.INSTANCE.CreateProcessAsUser(
primaryToken.getValue(), /* hToken */
null, /* lpApplicationName */
command, /* lpCommandLine */
null, /* lpProcessAttributes */
null, /* lpThreadAttributes */
false, /* bInheritHandles */
WinNT.CREATE_NEW_CONSOLE | WinNT.CREATE_UNICODE_ENVIRONMENT, /* dwCreationFlags */
environment, /* lpEnvironment */
processDirectory, /* lpCurrentDirectory */
startupInfo, /* lpStartupInfo */
processInfo); /* lpProcessInformation */