I need to get the current logged on username? I need this to work properly when I call the code from ASP.NET which is working in Windows Authentication mode. i.e. I do not want to get the ASPNET user in that circumstance, but the impersonated user. This is related to my earlier question. Everything I try returns ASPNET.
In your other question you wrote that you configured ASP.NET to use Windows authentication with impersonation:
<system.web>
...
<authentication mode="Windows"/>
<identity impersonate="true"/>
...
</system.web>
Does the ASP.NET application show the correct credentials (user and domain)?
Are you invoking the Delphi function using the correct Identity context, like
WindowsIdentity winId = (WindowsIdentity)HttpContext.Current.User.Identity;
try
{
ctx = winId.Impersonate();
// call Delphi function, passing the identity context
}
catch
{
}
finally
{
if (ctx != null)
ctx.Undo();
}
Update:
If the COM abject is called from the code behind for a web form page, you can try to set ASPCOMPAT property of the web form page to true.
See:
- http://www.ureader.com/msg/110628.aspx
- http://dotnetdebug.net/2006/06/13/aspnet-web-application-and-sta-com-objects-security-issues/
The "identity" tag makes sure that the thread executing the request (the MTA thread) will impersonate its security context to the user specified in the tag but our STA COM object eventually was created on the default STA thread which was not impersonate, causing it to get the security context of the process (which was IUSR_XXX – the least powerful user of all).
Perhaps your IADsWinNTSystemInfo
approach (from the linked previous question) returns current process' account information, but ASP.NET is impersonating on a thread level?
Try this:
type
PTokenUser = ^TTokenUser;
TTokenUser = packed record
User: SID_AND_ATTRIBUTES;
end;
function GetCurrentUserName(out DomainName, UserName: string): Boolean;
var
Token: THandle;
InfoSize, UserNameSize, DomainNameSize: Cardinal;
User: PTokenUser;
Use: SID_NAME_USE;
_DomainName, _UserName: array[0..255] of Char;
begin
Result := False;
DomainName := '';
UserName := '';
Token := 0;
if not OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, Token) then
begin
if GetLastError = ERROR_NO_TOKEN then // current thread is not impersonating, try process token
begin
if not OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token) then
Exit;
end
else
Exit;
end;
try
GetTokenInformation(Token, TokenUser, nil, 0, InfoSize);
User := AllocMem(InfoSize * 2);
try
if GetTokenInformation(Token, TokenUser, User, InfoSize * 2, InfoSize) then
begin
DomainNameSize := SizeOf(_DomainName);
UserNameSize := SizeOf(_UserName);
Result := LookupAccountSid(nil, User^.User.Sid, _UserName, UserNameSize, _DomainName, DomainNameSize, Use);
if Result then
begin
SetString(DomainName, _DomainName, StrLen(_DomainName));
SetString(UserName, _UserName, StrLen(_UserName));
end;
end;
finally
FreeMem(User);
end;
finally
CloseHandle(Token);
end;
end;
Example usage:
var
DomainName, UserName: string;
begin
if not GetCurrentUserName(DomainName, UserName) then
RaiseLastOSError;
Writeln(Format('%s\%s', [DomainName, UserName]));
end;
Hope this helps.
This is a part of the code of my LoadProfile tool, it works well in Delphi 2010:
const
UNLEN = 256; // Maximum user name length
var
TokenHandle: THandle; // Handle to the Processes' Acces Token
cbTokenInfo: DWORD; // Size of TokenInfo in Bytes
pTokenUser: PTOKEN_USER; // Pointer to a TOKEN_USER record
cchName: DWORD; // Count of characters (length) of the Username array
cchDomain: DWORD; // Count of characters (length) of the Domainname array
peUse: DWORD; // Account type for LookupAccountSid
UserName: array[0..UNLEN] of Char; // Holds the Username
DomainName: array[0..UNLEN] of Char; // Holds the Domainname
ComputerName: array[0..UNLEN] of Char; // Hold the Computername
// Open the Current Process' Token
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY or
TOKEN_IMPERSONATE or TOKEN_DUPLICATE, TokenHandle);
// Check if we have a valid handle
if TokenHandle = 0 then
Exit;
{ We will use GetTokenInformation to get the user's SID, the first call
to GetTokenInformation is used to determine how much memory we need to
allocate }
GetTokenInformation(TokenHandle, TokenUser, nil, 0, cbTokenInfo);
// as documented the call should fail with ERROR_INSUFFICIENT_BUFFER
if (GetLastError() <> ERROR_INSUFFICIENT_BUFFER) then
Exit;
// Allocate Memory
pTokenUser := HeapAlloc(GetProcessHeap(), 0, cbTokenInfo);
if (pTokenUser = nil) then
Exit;
// Retrieve the user information from the token.
if ( not GetTokenInformation(TokenHandle, TokenUser, pTokenUser,
cbTokenInfo, cbTokenInfo)) then
Exit;
cchName := Length(UserName);
cchDomain := Length(DomainName);
peUse:= SidTypeUser;
// Use the SID to find User and Domain Name
Write('LookupAccountSid... ');
if not LookupAccountSid(nil, pTokenUser^.User.Sid, UserName, cchName,
DomainName, cchDomain, peUse) then
Exit;
// Cleanup
if (pTokenUser <> nil) then
HeapFree(GetProcessHeap(), 0, pTokenUser);
WriteLn('CloseHandle... OK');
CloseHandle(TokenHandle);