Delphi XE5:使用WDSL-Import创建的接口调用EWS而不进行模拟

时间:2013-11-07 15:23:43

标签: delphi impersonation exchangewebservices

我目前正致力于将我们的应用程序中的日历约会同步到Win Server 2008上的Exchange Server 2007 SP1。它应该处理删除和添加多个用户帐户的约会。该接口是使用Delphi XE5的WDSL-Import组件创建的。它生成一个类型'ExchangeServicePortType',使用如下:

var
  ws: ExchangeServicePortType;
  exCreate: CreateItem;
  exItemResp: CreateItemResponse;
  exImper: ExchangeImpersonation;
  secContext: SerializedSecurityContext;
  exMailboxCult: MailboxCulture;
  exReqServerVersion: RequestServerVersion;
  exServerVersion: ServerVersionInfo;
....
ws := GetExchangeServicePortType(false);
...
exImper.ConnectingSID.SID := <useraccount>; 
...
ws.CreateItem(exCreate, exImper, secContext, exMailboxCult, exReqServerVersion,  
    exCreateItemResponse, exServerVersion);

问题: 在以下情况下,它只适用于“假冒”:

  • 'syncuser'正在客户端上运行sync-programm。
  • 服务器上的“syncuser”帐户具有针对所有用户帐户的特殊权限ms-Exch-EPI-Impersonation,ms-Exch-EPI-May-Impersonate。
  • 在服务器上为所有人调用cmdlet'Add-MailboxPermission -Identity“user-account”-User -AccessRights FullAccess -InheritanceType All'。
  • EWS身份验证= windows-authentication

问题:在Delphi XE中是否有可能在没有“假冒”的情况下调用EWS,它是如何工作的?

在托管API中,可以调用:

ExchangeServiceBinding ws = new ExchangeServiceBinding();
ws.Credentials = new NetworkCredential("user", "password", "domain");

任何帮助/想法/解释/建议都非常感谢。


感谢David Heffernan。 我尝试了使用C#-dll(Visual Studio 2010)和R. Giesecke的.DllExport扩展以及EWS托管api 1.2的建议方法。代码如下:

EWSTerminSync.cs
...
using System.Runtime.InteropServices;
using RGiesecke.DllExport;
...

public class  EWSSync
{      
   public static ExchangeService service;

    private static bool CertificateValidationCallBack(
       object sender,
       System.Security.Cryptography.X509Certificates.X509Certificate certificate,
       System.Security.Cryptography.X509Certificates.X509Chain chain,
       System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
        ...
    }   

   [DllExport]
    public static int InitEWS()
    {           
       (0)ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;               

      (1) service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
       service.Credentials = new WebCredentials("name", "pwd", "domain");
       service.Url = new Uri("https://myServer/EWS/Exchange.asmx");
       ...
    }   
    [DllExport]
    public static int DoSomething()
    {
    ...
    }
}

C#-dll加载到Delphi7应用程序中,如下所示:

type
TCreateInstance = function(): integer; stdcall;

FDLLHandle: THandle;
...
procedure Execute()
var
    res: integer;
begin
FDLLHandle := LoadLibrary(pansichar('EWSTerminSync.dll'));
if FDLLHandle >= 32 then
begin
    @FCreateInstance := GetProcAddress(FDLLHandle, 'InitEWS');

    res := FCreateInstance;
    ...
end;
...
end;

如果它作为delphi应用程序执行,一切正常。我可以创建/删除约会和日历等内容。 但我必须在作为Windows服务运行的delphi应用程序中使用它。相同的代码产生错误“EXCEPTION:EExternalException / Externe Exception E0434352”。 在函数InitEWS()中运行第(1)行。如果不调用任何ews托管的api函数,只需在函数InitEWS()中执行一些字符串操作,一切都可以在服务中正常工作。 应用程序和服务在相同的用户凭据下运行。

在Windows服务中使用ews托管api有任何限制吗? 为了在服务中调用ews托管api函数,必须执行哪些设置?

1 个答案:

答案 0 :(得分:0)

你可以在没有模仿的情况下使用Ews,问题就是Delphi添加了一个xml节点,即使是nil参数(无论soDontSendEmptyNodes选项如何)。我找不到更好的方法来消除这个,而不是创建一个新的TOPToSoapDomConvert类,它只是跳过nil参数。

unit SoapHelpers;

interface

uses
  System.Classes, Soap.IntfInfo, Soap.InvokeRegistry, Soap.OPToSOAPDomConv;

type

  TOPToSoapDomConvert2 = class(TOPToSoapDomConvert)
  public
    function InvContextToMsg(const IntfMD: TIntfMetaData;
                              MethNum: Integer;
                              Con: TInvContext;
                              Headers: THeaderList): TStream; override;
  end;

implementation

uses
  System.SysUtils, System.TypInfo;

type
  TInvContextTmp = class(TInvContext)
  public
    procedure CopyPointers(Cont: TInvContext);
    procedure RemovePointer(Index: Integer);
  end;

const
  IS_OUT  = $0200;

{ TOPToSoapDomConvert2 }

// Skip null parameters they are always being sent regardless of sendemptynodes settings
function TOPToSoapDomConvert2.InvContextToMsg(const IntfMD: TIntfMetaData;
  MethNum: Integer; Con: TInvContext; Headers: THeaderList): TStream;
var
  MethMD: TIntfMethEntry;
  Params, ParamsSave: TIntfParamEntryArray;
  Con2: TInvContextTmp;
  P: Pointer;
  I, K, XmlOptions, ParamCountSave, ParamCount: Integer;
  ExtParamName, ParamNamespace: string;
begin
  MethMD := IntfMD.MDA[MethNum];

  ParamsSave := MethMD.Params;
  ParamCountSave := MethMD.ParamCount;
  ParamCount := MethMD.ParamCount;

  SetLength(Params, Length(MethMD.Params));
  for I := Low(Params) to High(Params) do
    Params[I] := MethMD.Params[I];

  Con2 := TInvContextTmp.Create;
  Con2.CopyPointers(Con);

  for I := High(Params) downto Low(Params) do
  begin
    InvRegistry.GetParamInfo(IntfMD.Info, MethMD.Name, Params[I].Name,
                             ExtParamName, ParamNamespace, XMLOptions);

    if not ((pfOut in Params[I].Flags) or ((XMLOptions and IS_OUT) = IS_OUT)) then
    begin
      P := Con.GetParamPointer(I);
      if (Params[I].Info <> nil) and (Params[I].Info.Kind = tkClass) and (Pointer(P^) = nil) then
      begin
        for K := I + 1 to High(Params) do
          Params[K-1] := Params[K];
        SetLength(Params, Length(Params)-1);

        Dec(ParamCount);
        Con2.RemovePointer(I);
      end;
    end;
  end;

  if Length(MethMD.Params) <> Length(Params) then
  begin
    MethMD.ParamCount := ParamCount;
    MethMD.Params := Params;
    IntfMD.MDA[MethNum] := MethMD;
  end;

  try
    Result := inherited InvContextToMsg(IntfMD, MethNum, Con2, Headers);
  finally
    if Length(MethMD.Params) <> Length(ParamsSave) then
    begin
      MethMD.ParamCount := ParamCountSave;
      MethMD.Params := ParamsSave;
      IntfMD.MDA[MethNum] := MethMD;
    end;
    Con2.Free;
  end;
end;

{ TInvContextTmp }

procedure TInvContextTmp.CopyPointers(Cont: TInvContext);
var
  k: Integer;
begin
  SetLength(DataP, Length(TInvContextTmp(Cont).DataP));
  for k := Low(TInvContextTmp(Cont).DataP) to High(TInvContextTmp(Cont).DataP) do
    DataP[k] := TInvContextTmp(Cont).DataP[k];
end;

procedure TInvContextTmp.RemovePointer(Index: Integer);
var
  k: Integer;
begin
  for k := Index+1 to High(DataP) do
    DataP[k-1] := DataP[k];
end;

end.

何时,你可以像这样使用它:

...
    lRIO := THTTPRio.Create(nil);

    lRIO.Converter := TOPToSoapDomConvert2.Create(lRIO);
    lRIO.Converter.WSDLView := nil;
...