Sodele, ich würde das hier gerne weiterspinnen. Meine Recherchen im Netz führen mich zu der Erkenntnis, daß es niemanden gibt, der bereits erfolgreich mit Delphi in
OS ein Kerberos Ticket angefordert hat. Alle verweisen auf die üblichen Verdächtigen, die bei SO, oder eben der
msdn verlinkt sind. Knackpunkt ist folgendes:
Es ist eben nicht damit getan ein paar
API-Funktionen aufzurufen. Ein Kerberos-Ticket muss man sich auch per UDP-Kommunikation mit dem Kerberos-Server verdienen. Das führt dazu, daß selbst die zahlreichen voneinander abgeschrieben Beispile in den C-Dialekten an der Stelle äusserst schwammig werden. Ich halte Kerberos mittlerweile für eine Art weissen Wal, den jeder angeblich mal gesehen hat
Die
API-Aufrufe bekommt man mit Hilfe von ein bis zwei
Indy-Units einigermaßen zusammengeklöppelt. Aber selbst dann muss der korrekte SPN von Aussen gesetzt werden, Es gibt keine
API, die einem das abnimmt. Hier die Source meines kleinen Testprojekts:
Delphi-Quellcode:
uses IdSSPI, IdAuthenticationSSPI
procedure TForm2.Button1Click(Sender: TObject);
var
secfunc: SecurityFunctionTableA;
sec_Entry: SECURITY_STATUS;
pszTargetName: PSEC_CHAR;
hCredential: SecHandle;
tsExpiry: TimeStamp;
hNewContext: CtxtHandle;
Output: SecBufferDesc;
token: SecBuffer;
fContextAttr: ULONG;
pPkgInfo: PSecPkgInfoA;
TokenPointer: PByteArray;
InitSecurityInterfaceA: function: PSecurityFunctionTableA; stdcall;
begin
try
TokenPointer := nil;
InitSecurityInterfaceA := GetProcAddress(GetModuleHandle('secur32.dll'), 'InitSecurityInterfaceA');
if Assigned(InitSecurityInterfaceA) then
secfunc := InitSecurityInterfaceA^;
sec_State:= secfunc.QuerySecurityPackageInfoA(
PAnsiChar('Kerberos'),
@pPkgInfo
);
if sec_State = SEC_E_OK then
sec_State := secfunc.AcquireCredentialsHandleA(
nil,
pPkgInfo^.Name,
SECPKG_CRED_OUTBOUND,
nil,
nil,
nil,
nil,
@hCredential,
@tsExpiry
);
Output.ulVersion := SECBUFFER_VERSION;
Output.cBuffers := 1;
Output.pBuffers := @token;
GetMem(TokenPointer, ppkginfo^.cbMaxToken);
token.cbBuffer := ppkginfo^.cbMaxToken;
token.BufferType := SECBUFFER_TOKEN;
token.pvBuffer := tokenpointer;
if sec_State = SEC_E_OK then
sec_State := secfunc.InitializeSecurityContextA(
@hCredential,
nil,
PAnsiChar('RestrictedKrbHost/FM-DC01.mydomain.int'), // Muss man eben irgendwie selbst herausfinden
ISC_REQ_DELEGATE + ISC_REQ_MUTUAL_AUTH,
0,
SECURITY_NATIVE_DREP,
nil,
0,
@hNewContext,
@Output,
@fContextAttr,
@tsExpiry
);
if sec_State = SEC_I_CONTINUE_NEEDED then // Derzeit ist genau das der Status
begin
// Output irgendwie an den Kerberos-Server senden und die Anwort mit erneutem Aufruf von
// InitializeSecurityContextA verwursten
end;
if sec_State = SEC_E_OK then
begin
ShowMessage('YAY!');
end
else
case sec_State of
SEC_E_OK: ShowMessage('YAY!');
SEC_I_COMPLETE_AND_CONTINUE: ShowMessage('SEC_I_COMPLETE_AND_CONTINUE');
SEC_I_COMPLETE_NEEDED: ShowMessage('SEC_I_COMPLETE_NEEDED');
SEC_I_CONTINUE_NEEDED: ShowMessage('SEC_I_CONTINUE_NEEDED');
SEC_I_INCOMPLETE_CREDENTIALS: ShowMessage('SEC_I_INCOMPLETE_CREDENTIALS');
SEC_E_INSUFFICIENT_MEMORY: ShowMessage('SEC_E_INSUFFICIENT_MEMORY');
SEC_E_INTERNAL_ERROR: ShowMessage('SEC_E_INTERNAL_ERROR');
SEC_E_INVALID_HANDLE: ShowMessage('SEC_E_INVALID_HANDLE');
SEC_E_INVALID_TOKEN: ShowMessage('SEC_E_INVALID_TOKEN');
SEC_E_LOGON_DENIED: ShowMessage('SEC_E_LOGON_DENIED');
SEC_E_NO_AUTHENTICATING_AUTHORITY: ShowMessage('SEC_E_NO_AUTHENTICATING_AUTHORITY');
SEC_E_NO_CREDENTIALS: ShowMessage('SEC_E_NO_CREDENTIALS');
SEC_E_TARGET_UNKNOWN: ShowMessage('SEC_E_TARGET_UNKNOWN');
SEC_E_UNSUPPORTED_FUNCTION: ShowMessage('SEC_E_UNSUPPORTED_FUNCTION');
SEC_E_WRONG_PRINCIPAL: ShowMessage('SEC_E_WRONG_PRINCIPAL');
else
ShowMessage('UNKNOWN ERROR Code. Last Error:' + IntToStr(GetLastError));
end;
finally
secfunc.FreeCredentialsHandle(@hCredential);
secfunc.FreeContextBuffer(pPkgInfo);
FreeMem(TokenPointer);
end;
end;
Wer hat sowas mal wirklich vollumfänglich implementiert? (Der
SOAP-Teil aus meinem Startpost kann erstmal getrost vergessen werden)
Sherlock