【问题标题】:Windows User getting "access denied" from exchange serverWindows 用户从 Exchange 服务器获得“拒绝访问”
【发布时间】:2016-03-22 12:42:11
【问题描述】:

我有一个使用 Windows 身份验证和 Exchange Web 服务的 MVC Web 应用程序。在开发过程中,这很好用,因为我的开发机器上的 IIS 中的应用程序池设置为在我的 windows 用户下运行,而 Exchange Server 位于同一个域中。

但是,在 Web 服务器上,我们所有的应用程序都设置为在有权访问所有数据库服务器等的系统用户下运行。数据库连接使用集成安全性,因此我无法在应用程序级别上模拟用户。

我一直在尝试通过如下代码来冒充当前windows用户:

public abstract class ExchangeServiceImpersonator
{
    private static WindowsImpersonationContext _ctx;

    public Task<string> CreateMeetingAsync(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end)
    {
        var tcs = new TaskCompletionSource<string>();
        EnableImpersonation();

        try
        {
            tcs.TrySetResult(CreateMeetingImpersonated(from, to, subject, body, location, begin, end));
        }
        catch(Exception e)
        {
            tcs.TrySetException(e);
        }
        finally
        {
            DisableImpersonation();
        }

        return tcs.Task;
    }

    public abstract string CreateMeetingImpersonated(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end);

    private static void EnableImpersonation()
    {
        WindowsIdentity winId = (WindowsIdentity)HttpContext.Current.User.Identity;
        _ctx = winId.Impersonate();
    }

    private static void DisableImpersonation()
    {
        if (_ctx != null)
            _ctx.Undo();
    }
}

那么,实现抽象方法的类:

public class ExchangeServiceExtensionsBase : ExchangeServiceImpersonator
{
    private ExchangeService _service;

    public ExchangeService Service
    {
        get
        {
            if (this._service == null)
            {
                this._service = new ExchangeService(ExchangeVersion.Exchange2013);
                this._service.Url = new Uri(WebConfigurationManager.AppSettings["ExchangeServer"]);
                this._service.UseDefaultCredentials = true;
            }

            return this._service;
        }
        set { return; }
    }

    public override string CreateMeetingImpersonated(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end)
    {
        //this.Service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, from);

        Appointment meeting = new Appointment(Service);
        string meetingID = Guid.NewGuid().ToString();

        meeting.Subject = subject;
        meeting.Body = "<span style=\"font-family:'Century Gothic'\" >" + body.Replace(Environment.NewLine, "<br/>") + "<br/><br/>" +
            "<span style=\"color: white;\">Meeting Identifier: " + meetingID + "</span></span><br/><br/>";
        meeting.Body.BodyType = BodyType.HTML;
        meeting.Start = begin;
        meeting.End = end;
        meeting.Location = location;
        meeting.ReminderMinutesBeforeStart = 60;

        foreach (string attendee in to)
        {
            meeting.RequiredAttendees.Add(attendee);
        }
        meeting.Save(SendInvitationsMode.SendToAllAndSaveCopy);

        return meetingID;
    }
}

然后,访问方法如下:

public static class ExchangeServiceExtensions
{
    public static async Task<string> CreateMeetingAsync(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end)
    {
        ExchangeServiceImpersonator serviceImpersonator = new ExchangeServiceExtensionsBase();
        return await serviceImpersonator.CreateMeetingAsync(from, to, subject, body, location, begin, end);
    }
}

这在我的本地开发机器上仍然有效,但无论我做什么,从服务器访问的用户都会不断收到来自交换服务器的访问被拒绝:

请求失败。远程服务器返回错误:(401) Unauthorized.

我已尝试将其保留为默认凭据:

this._service.UseDefaultCredentials = true;

并尝试手动将凭据设置为当前(假设是模拟的)用户:

this._service.Credentials = new WebCredentials(CredentialCache.DefaultNetworkCredentials);

另外,我尝试通过电子邮件地址使用 Exchange ImpersonatedUserId 对象:

this._service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, from);

返回以下异常:

该帐户无权模拟请求的用户。

【问题讨论】:

标签: asp.net exchangewebservices credentials ews-managed-api


【解决方案1】:

默认情况下,作为一项安全措施,Windows 会阻止您将凭据从 Web 服务器委托给 Exchange。这意味着您不能冒充访问您网站的用户。

这被称为“服务器双跳”场景。第一个“跃点”是从用户的机器到 Web 服务器,第二个“跃点”是从 Web 服务器到 Exchange 服务器(Google 会给你很多关于服务器双跃点的命中)。

这是一件好事,因为它可以防止任何黑客在您的服务器周围移动。

它在您的开发机器上运行的原因是从您的本地 Web 服务器到 Exchange 服务器只有一个“跃点”。

要解决此问题,您需要允许 Web 服务器将凭据委托给 Exchange 服务器。这称为 Kerberos 委派,必须由系统管理员在 Active Directory 中以某种方式设置(我不知道)。

【讨论】:

  • 向服务器管理员转发了有关设置 Kerberos 委派的查询。需要等着看他们怎么说。
【解决方案2】:

我尝试将 AD 对象设置更改为 Trust this computer for delegation..(您需要 AD 管理员权限),但这并没有解决问题。

我的突破是将应用程序池的标识(高级设置...)设置为 NetworkService。它也适用于 LocalServiceLocalSystem,但要小心,因为它们具有更高的权限。 令我惊讶的是,当我输入实际上拥有交换系统所有权限的 AD 管理员帐户时,它不适用于 自定义帐户

关于我的申请的一般信息:

  • ASP.CORE 2.1 网络服务
  • Windows Server 2016
  • IIS 10.0.x
  • 内部公司网络

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多