เรียก Web API จากแอปพลิเคชัน MVC พร้อมการตรวจสอบสิทธิ์ Windows แบบรวม

ฉันมีแอปพลิเคชัน MVC และโครงการ Web API ที่เกี่ยวข้องซึ่งทั้งคู่โฮสต์บนเซิร์ฟเวอร์ระยะไกลบน IIS พวกเขาแชร์กลุ่มแอปพลิเคชันเดียวกัน เมื่อใดก็ตามที่ฉันพยายามโทรไปยัง Web API จากแอปพลิเคชัน MVC ฉันได้รับข้อผิดพลาด 403 ซึ่งดูเหมือนว่าจะมาจากข้อมูลรับรองที่ไม่ถูกต้องที่ถูกส่งผ่านโดย HttpClientHandler ฉันมี

UseDefaultCredentials = true 

และฉันได้ลองตั้งค่าแล้ว

Credentials = CredentialCache.DefaultNetworkCredentials

แต่สิ่งเหล่านี้ไม่อนุญาตให้คำขอ API ผ่านไปได้

การตั้งค่ากลุ่มแอปพลิเคชันให้ใช้ชื่อผู้ใช้/รหัสผ่าน AD ของฉันทำให้คำขอ API ทั้งหมดผ่านไปได้ และยังเรียก API โดยตรงจากบุรุษไปรษณีย์เพื่อส่งคืนข้อมูลอย่างถูกต้อง

สมมติฐานของฉันคือ IIS AppPool[ชื่อพูล] ได้รับการส่งต่อในคำขอ และข้อมูลประจำตัวที่เหมาะสมจะไม่ถูกส่งผ่าน มีวิธีแก้ไขปัญหานี้โดยไม่ทำให้ API ไม่ปลอดภัยหรือไม่ (เช่น มีกลุ่มโดเมนเพียงไม่กี่กลุ่มเท่านั้นที่สามารถเข้าถึงได้)

ตัวอย่างการโทรที่ฉันทำกับ API จากแอปพลิเคชัน MVC

    public async Task<HttpResponseMessage> CreateIncident(Incident model)
    {
        using (var client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true }))
        {
            var newIncident = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json");
            var response = await client.PostAsync(hostUri, newIncident);
            return response;
        }
    }

person Robert McCoy    schedule 27.02.2017    source แหล่งที่มา
comment
คุณจะผ่านพร็อกซีเลยหรือไม่?   -  person joshmcode    schedule 28.02.2017
comment
ไม่ ทั้งหมดนี้โฮสต์อยู่บนเซิร์ฟเวอร์ภายใน และการโทรทั้งหมดจะดำเนินการผ่านเซิร์ฟเวอร์นั้นโดยเฉพาะ ไม่มีพร็อกซี อย่างที่ฉันบอกไปว่าบุรุษไปรษณีย์และการโทรโดยตรงไปยัง API จากคอมพิวเตอร์ของฉันผ่านไปได้ แต่ดูเหมือนว่า .NET Core ไม่สามารถปลอมแปลงคำขอได้ และฉันก็หวังว่าจะมีคนอื่นทำสิ่งนี้เมื่อเร็ว ๆ นี้ซึ่งสามารถให้ข้อมูลอัปเดตที่มากกว่านี้ได้ วิธีแก้ปัญหามากกว่าบางอันที่มีอายุ 6+ เดือนที่ล้าสมัยไปเล็กน้อยใน .NET Core   -  person Robert McCoy    schedule 28.02.2017


คำตอบ (3)


หากไม่มีข้อมูลเพิ่มเติมก็ยากที่จะพูดได้อย่างแน่นอน แต่ปัญหาน่าจะเกิดจากการรับรองความถูกต้องแบบ double-hop ที่คุณกำลังพยายาม

  1. แอปพลิเคชันไคลเอ็นต์ (เบราว์เซอร์ในกรณีของเว็บไซต์) จะตรวจสอบสิทธิ์ผู้ใช้ที่ไคลเอ็นต์ส่ง
  2. การรับรองความถูกต้องไปยังเซิร์ฟเวอร์ (แอปพลิเคชัน MVC)
  3. แอปพลิเคชัน MVC จะพยายามส่งผ่านการรับรองความถูกต้องไปยังบริการเว็บ

เมื่อฉันต้องการทำงานที่คล้ายกัน ฉันไม่สามารถทำให้ HttpClient ทำงานได้ ฉันลองใช้วิธีแก้ปัญหาที่แนะนำจำนวนหนึ่งจากคำถามนี้ จะทำให้ HttpClient ส่งข้อมูลรับรองไปพร้อมกับคำขอได้อย่างไร แม้ว่าจะให้ข้อมูล -- โดยเฉพาะคำตอบของ BlackSpy ส่วนนี้อธิบายว่าทำไม:

สิ่งที่คุณพยายามทำคือให้ NTLM ส่งต่อข้อมูลระบุตัวตนไปยังเซิร์ฟเวอร์ถัดไป ซึ่งมันไม่สามารถทำได้ - ทำได้เพียงเลียนแบบซึ่งจะให้คุณเข้าถึงทรัพยากรในเครื่องเท่านั้น

ฉันลงเอยด้วยการใช้ WebClient (โดยต้องมีการกำหนดเป้าหมาย. NET framework) กับสิ่งนี้ในแอปพลิเคชัน MVC (ดาวน์โหลดไฟล์จาก web api ในกรณีนี้):

private async Task GetFileAsync(Identity identity, string serviceAddress, Stream stream)
{
    var windowsIdentity = Identity as WindowsIdentity;

    if (windowsIdentity == null)
    {
        throw new InvalidOperationException("Identity not a valid windows identity.");
    }

    using (windowsIdentity.Impersonate())
    {
        using (var client = new WebClient { UseDefaultCredentials = true })
        {
            var fileData = await client.DownloadDataTaskAsync(serviceAddress);
            await stream.WriteAsync(fileData, 0, fileData.Length);
            stream.Seek(0, SeekOrigin.Begin);
        }
    }
}

แม้ว่าข้อกำหนดในการกำหนดเป้าหมายเฟรมเวิร์กแบบเต็มจะป้องกันไม่ให้สิ่งนี้เป็นโซลูชัน .NET Core แต่ดูเหมือนว่าจะมีการเพิ่มเข้ามาตั้งแต่นั้นมา

เพิ่ม WebClient ในสัญญา System.Net.WebClient ใหม่

PR นี้พอร์ต System.Net.WebClient ไปยัง corefx โค้ดส่วนใหญ่นำมาจากเดสก์ท็อปแล้วจึงทำความสะอาดเล็กน้อยตามสไตล์ การเขียนโค้ดหลักเพียงอย่างเดียวคือการลบโค้ดที่ใช้การเรียกกลับ APM ที่ซับซ้อนหลายร้อยบรรทัดออก และแทนที่ด้วยวิธีอะซิงก์หลักสองสามวิธี ยังมีการล้างข้อมูลอีกมากมายที่สามารถทำได้ แต่ในทางปฏิบัติก็เพียงพอแล้ว

person David Culp    schedule 28.02.2017
comment
ฉันเห็นวิธีแก้ปัญหานี้ (และอ่านหลายสิ่งมากเกินไปเกี่ยวกับ double hop) แต่ฉันไม่คิดว่า Web Client อยู่ใน Core พวกเขารวมมันเข้ากับที่เก็บ แต่เท่าที่ฉันสามารถบอกได้ว่ามันไม่เคยรวมอยู่ใน RC หรือการแสดงตัวอย่างใด ๆ และฉันไม่สามารถอ้างอิงได้ใน Visual Studio ฉันหวังว่าจะมีคนมีการใช้งานที่ทันสมัยกว่านี้สำหรับการแอบอ้างบุคคลอื่น เนื่องจากเธรด Stack Overflow อื่นที่ฉันอ่านมีวิธีแก้ปัญหาที่ล้าสมัยซึ่งใช้งานไม่ได้อีกต่อไป ฉันไม่อยากชี้กลับไปที่ .NET Framework แต่นั่นคือสิ่งที่อาจเกิดขึ้นได้เช่นกัน ขอบคุณ! - person Robert McCoy; 28.02.2017
comment
สวัสดี เดวิด ในที่สุดฉันก็พบวิธีแก้ปัญหาที่ตามหาอยู่ (ใช่แล้ว...ใช้เวลาสักหน่อย) คุณสามารถดูการอภิปรายเกี่ยวกับปัญหา GitHub ได้ที่นี่ และผู้ใช้ ilanc ได้โพสต์ลิงก์ไปยังตัวอย่างวิธีการซื้อคืนที่ด้านล่างของการสนทนา github.com/aspnet/Home/issues/1805 - person Robert McCoy; 02.03.2017

หากไม่เห็นรหัสก็ยากที่จะพูด คุณได้ลองโดยไม่ตั้งค่าพารามิเตอร์ Credentials แล้วหรือยัง? ฉันจะเรียกใช้พู้ทำเล่นและเปรียบเทียบคำขอที่ส่งโดยแอปพลิเคชัน MVC และบุรุษไปรษณีย์

person Shane Ray    schedule 27.02.2017
comment
ฉันดูผลลัพธ์จากพู้ทำเล่น บุรุษไปรษณีย์ไม่ได้ทำการเจรจาใด ๆ เนื่องจาก Integrated Windows Authentication เซิร์ฟเวอร์จึงกำหนดข้อมูลรับรองการเข้าสู่ระบบของฉันโดยอัตโนมัติ สำหรับแอปพลิเคชัน MVC นั้นกำลังส่งการอนุญาตการเจรจาต่อรองพร้อมกับคำขอ และนั่นกำลังส่งคืน 401 นั่นเป็นสาเหตุที่ฉันคิดว่า API กำลังรับข้อมูล IIS AppPool และส่งสิ่งนั้นเป็นข้อมูลรับรอง ฉันยังโยนโค้ดตัวอย่างเล็กน้อยในคำถามด้วย - person Robert McCoy; 28.02.2017
comment
คุณได้ลองลบ UseDefaultCredentials = true แล้วหรือยัง - person Shane Ray; 28.02.2017
comment
ใช่ ดูเหมือนจะไม่มีผลกระทบใดๆ เลย ลองทำ PreAuth = false และ Credentials ตั้งค่าเป็นบางอย่างด้วย อาจใช้วิธีแก้ปัญหาของ David และให้แอปไม่ใช่ Core ที่สมบูรณ์ - person Robert McCoy; 28.02.2017

คุณสามารถดูวิธีปลอมตัวเป็นผู้ใช้ที่ผ่านการรับรองความถูกต้องแล้ว (windows) ได้ที่หน้าสนทนา GitHub นี้: https://github.com/aspnet/Home/issues/1805

ilanc มีการสาธิตที่ดีจริงๆ โดยมีลิงก์อยู่ด้านล่าง

person Robert McCoy    schedule 01.03.2017