Windows用户获得"拒绝访问"从Exchange Server [英] Windows User getting "access denied" from exchange server

查看:249
本文介绍了Windows用户获得"拒绝访问"从Exchange Server的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个MVC Web应用程序利用Windows身份验证和Exchange Web服务。虽然在发展,这一伟大的工作,因为在IIS应用程序池我的开发机器上被设置为在我的Windows用户运行,Exchange服务器是同一个域。

在Web服务器,不过,我们所有的应用程序都设置为可以访问所有的数据库服务器等数据库连接使用集​​成安全系统用户下运行,所以我无法模拟在应用程序级别的用户。

我一直在试图通过code冒充当前Windows用户如下:

 公共抽象类ExchangeServiceImpersonator
{
    私有静态WindowsImpersonationContext _ctx;    公共任务<串GT; CreateMeetingAsync(从,列表与LT字符串,字符串>至,串主题,绳体,字符串位置,日期开始,日期时间结束)
    {
        VAR TCS =新TaskCompletionSource<串GT;();
        EnableImpersonation();        尝试
        {
            tcs.TrySetResult(CreateMeetingImpersonated(从,到,主题,正文,位置,开始,结束));
        }
        赶上(例外五)
        {
            tcs.TrySetException(E);
        }
        最后
        {
            DisableImpersonation();
        }        返回tcs.Task;
    }    公共抽象的字符串CreateMeetingImpersonated(从,列表与LT字符串,字符串>至,串主题,绳体,字符串位置,日期开始,结束日期时间);    私有静态无效EnableImpersonation()
    {
        的WindowsIdentity winId =(的WindowsIdentity)HttpContext.Current.User.Identity;
        _ctx = winId.Impersonate();
    }    私有静态无效DisableImpersonation()
    {
        如果(_ctx!= NULL)
            _ctx.Undo();
    }
}

然后,实现抽象方法的类:

 公共类ExchangeServiceExtensionsBase:ExchangeServiceImpersonator
{
    私人ExchangeService _Service;    公共服务ExchangeService
    {
        得到
        {
            如果(this._service == NULL)
            {
                this._service =新ExchangeService(ExchangeVersion.Exchange2013);
                this._service.Url =新的URI(WebConfigurationManager.AppSettings [的ExchangeServer]);
                this._service.UseDefaultCredentials = TRUE;
            }            返回this._service;
        }
        集合{返回; }
    }    公众覆盖字符串CreateMeetingImpersonated(从,列表与LT字符串,字符串>至,串主题,绳体,字符串位置,日期开始,日期时间结束)
    {
        //this.Service.ImpersonatedUserId =新ImpersonatedUserId(ConnectingIdType.SmtpAddress,来自);        预约会议=新的任命(服务);
        。字符串meetingID = Guid.NewGuid()的ToString();        meeting.Subject =主体;
        meeting.Body =<跨度风格= \\FONT-FAMILY:'世纪的哥特式'\\>中+ body.Replace(Environment.NewLine,&所述峰; br />中)+&所述峰; br />&所述峰; br />中+
            <跨度风格= \\颜色:白色; \\>会议标识符:+ meetingID +< / SPAN>< / SPAN>< BR />< BR />中;
        meeting.Body.BodyType = BodyType.HTML;
        meeting.Start =开始;
        meeting.End =结束;
        meeting.Location =位置;
        meeting.ReminderMinutesBeforeStart = 60;        的foreach(在字符串与会者)
        {
            meeting.RequiredAttendees.Add(与会者);
        }
        meeting.Save(SendInvitationsMode.SendToAllAndSaveCopy);        返回meetingID;
    }
}

然后,该方法在访问如下:

 公共静态类ExchangeServiceExtensions
{
    公共静态异步任务<串GT; CreateMeetingAsync(从,列表与LT字符串,字符串>至,串主题,绳体,字符串位置,日期开始,日期时间结束)
    {
        ExchangeServiceImpersonator serviceImpersonator =新ExchangeServiceExtensionsBase();
        返回等待serviceImpersonator.CreateMeetingAsync(从,到,主题,正文,位置,开始,结束);
    }
}

这仍然工作在我的本地开发计算机上,但无论我做什么,从服务器访问用户状态越来越从Exchange服务器拒绝访问:


  

请求失败。远程服务器返回错误:(401)未经授权


我试着离开它的默认凭据:

  this._service.UseDefaultCredentials = TRUE;

和尝试手动设置凭据当前(假想模拟)用户:

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

另外,我使用Exchange试图 ImpersonatedUserId 使用的电子邮件地址的对象:

  this._service.ImpersonatedUserId =新ImpersonatedUserId(ConnectingIdType.SmtpAddress,来自);

返回以下异常:


  

该帐户没有权限来模拟的用户。



解决方案

默认情况下,并作为一种安全措施,Windows将prevent您从Web服务器委派凭据到Exchange。这意味着你无法模拟用户访问你的网站。

这是被称为服务器双跃的情景。第一个跳是从用户的机器到Web服务器,而第二个一跳是从Web服务器到Exchange服务器(谷歌会给你很多的点击服务器双跳)。

这是一件好事,因为它会prevent来自全球服务器移动任何黑客的攻击。<​​/ P>

这是工作在开发机器上的原因是,只有一个从您的本地W​​eb服务器到Exchange服务器的一跳。

要解决这个问题,你需要允许Web服务器委派凭据到Exchange服务器。这就是所谓的Kerberos委派,必须由系统管理员在Active Directory(这是超出了我的知识)以某种方式成立。

I have a MVC Web Application makes use of Windows Authentication and Exchange Web Services. While in development, this worked great, since the application pool in IIS on my development machine is set to run under my windows user and the Exchange Server is on the same domain.

On the web server, though, all our applications are set to run under a system user that has access to all the database servers etc. The database connection uses Integrated Security, so I cannot impersonate a user over an application level.

I've been trying to impersonate the current windows user through the code as follows:

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();
    }
}

Then, the class that implements the abstract methods:

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;
    }
}

Then, the methods are accessed as follows:

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);
    }
}

This still works on my local dev machine, but no matter what I do, the user accessing from the server keeps getting an access denied from the exchange server:

The request failed. The remote server returned an error: (401) Unauthorized.

I've tried leaving it on default credentials:

this._service.UseDefaultCredentials = true;

And attempting to manually set the credentials to the current (supposedly impersonated) user:

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

Also, I've tried using the Exchange ImpersonatedUserId object using the email address:

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

which returns the following exception:

The account does not have permission to impersonate the requested user.

解决方案

By default and as a security measure, Windows will prevent you from delegating your credentials from the web server to Exchange. This means you cannot impersonate the user accessing your web site.

This is known as the "server double hop" scenario. The first "hop" is from the user's machine to the web server, and the second "hop" is from the web server to the Exchange server (Google will give you lots of hits on server double hop).

This is a good thing because it will prevent any hackers from moving around your servers.

The reason it is working on your development machine is that there is only one "hop" from your local web server to the Exchange server.

To solve it you need to allow the web server to delegate the credentials to the Exchange server. This is called Kerberos delegation and must be set up by your system administrator somehow in the Active Directory (which is beyond my knowledge).

这篇关于Windows用户获得&QUOT;拒绝访问&QUOT;从Exchange Server的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆