我最近也在为 Indy 和我的 Exchange 服务器而苦恼。 SaslNtlm 组件不在 Delphi XE5 附带的 Indy10 版本中。它甚至不在 Indy Protocols 文件夹的源文件中。
幸运的是,使用 SMTP 客户端进行 NTLM 身份验证所需的许多东西都可用。有一个名为 IdAuthenticationSSPI 的单元实现了整个 NTLM 交换。剩下要做的就是实现 TIdSASL 的自定义后代,它与 TIndySSPINTLMClient 对象交互。
TSaslNtlm = class(TIdSASL)
public
constructor Create(AOwner: TComponent);
destructor Destroy; override;
function StartAuthenticate(const AChallenge, AHost, AProtocolName : string): string; override;
function ContinueAuthenticate(const ALastResponse, AHost, AProtocolName : string): string; override;
function IsReadyToStart: Boolean; override;
class function ServiceName: TIdSASLServiceName; override;
private
FSSPIClient: TIndySSPINTLMClient;
end;
类的实现如下:
constructor TSaslNtlm.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FSSPIClient := TIndySSPINTLMClient.Create;
end;
destructor TSaslNtlm.Destroy;
begin
FSSPIClient.Free;
inherited;
end;
function TSaslNtlm.StartAuthenticate(const AChallenge, AHost,
AProtocolName: string): string;
begin
FSSPIClient.SetCredentials(AHost, '', '');
Result := BytesToStringRaw(FSSPIClient.InitAndBuildType1Message);
end;
function TSaslNtlm.ContinueAuthenticate(const ALastResponse, AHost,
AProtocolName: string): string;
var LastMsg: TIdBytes;
begin
LastMsg := ToBytes(ALastResponse, Indy8BitEncoding
{$IFDEF STRING_IS_ANSI}, Indy8BitEncoding{$ENDIF});
Result := BytesToStringRaw(FSSPIClient.UpdateAndBuildType3Message(LastMsg));
end;
function TSaslNtlm.IsReadyToStart: Boolean;
begin
Result := True;
end;
class function TSaslNtlm.ServiceName: TIdSASLServiceName;
begin
Result := 'NTLM';
end;
然后只需将这种 SASL 机制添加到 SMTP 客户端即可:
smtp.AuthType := satSASL;
ntml := TSaslNtlm.Create(smtp);
with smtp.SASLMechanisms.Add do begin
DisplayName := ntlm.ServiceName;
SASL := ntlm;
end;