پیش از نصب و راه اندازی IdentityServer، نیاز است با یک سری از مفاهیم اساسی پروتکل OpenID Connect، مانند Identity token ،Client types ،Flow و Endpoints، آشنا شویم تا بتوانیم از امکانات این IDP ویژه استفاده و آنها را تنظیم کنیم. بدون آشنایی با این مفاهیم، اتصال برنامهای که در
قسمت قبل تدارک دیدیم به IdentityServer میسر نیست.
پروتکل OpenID Connect چگونه کار میکند؟
در انتهای
قسمت اول این سری، پروتکل OpenID Connect معرفی شد. در ادامه جزئیات بیشتری از این پروتکل را بررسی میکنیم.
هر برنامهی کلاینت متصل به WebAPI
مثال قسمت قبل، نیاز به دانستن هویت کاربر وارد شدهی به آنرا دارد. در اینجا به این برنامهی کلاینت، اصطلاحا relying party هم گفته میشود؛ از این جهت که این برنامهی کلاینت، به برنامهی Identity provider و یا به اختصار IDP، جهت دریافت نتیجهی اعتبارسنجی کاربر، وابستهاست. برنامهی کلاینت یک درخواست Authentication را به سمت IDP ارسال میکند. به این ترتیب کاربر به صورت موقت از برنامهی جاری خارج شده و به برنامهی IDP منتقل میشود. در برنامهی IDP است که کاربر مشخص میکند کیست؛ برای مثال با ارائهی نام کاربری و کلمهی عبور. پس از این مرحله، در صورت تائید هویت کاربر، برنامهی IDP یک Identity Token را تولید و امضاء میکند. سپس برنامهی IDP کاربر را مجددا به برنامهی کلاینت اصلی هدایت میکند و Identity Token را در اختیار آن کلاینت قرار میدهد. در اینجا برنامهی کلاینت، این توکن هویت را دریافت و اعتبارسنجی میکند. اگر این اعتبارسنجی با موفقیت انجام شود، اکنون کاربر تعیین اعتبار شده و هویت او جهت استفادهی از قسمتهای مختلف برنامه مشخص میشود. در برنامههای ASP.NET Core، این توکن هویت، پردازش و بر اساس آن یکسری Claims تولید میشوند که در اغلب موارد به صورت یک کوکی رمزنگاری شده در سمت کلاینت ذخیره میشوند.
به این ترتیب مرورگر با هر درخواستی از سمت کاربر، این کوکی را به صورت خودکار به سمت برنامهی کلاینت ارسال میکند و از طریق آن، هویت کاربر بدون نیاز به مراجعهی مجدد به IDP، استخراج و استفاده میشود.
مراحل انتقال کاربر به IDP، صدور توکن هویت، بازگشت مجدد به برنامهی کلاینت، اعتبارسنجی، استخراج Claims و ذخیرهی آن به صورت یک کوکی رمزنگاری شده را در تصویر فوق ملاحظه میکنید. بنابراین در حین کار با یک IDP، مرحلهی لاگین به سیستم، دیگر در برنامه یا برنامههای کلاینت قرار ندارد. در اینجا دو فلش به سمت IDP و سپس به سمت کلاینت را بخاطر بسپارید. در ادامه از آنها برای توضیح Flow و Endpoints استفاده خواهیم کرد.
البته OpenID Connect برای کار همزمان با انواع و اقسام برنامههای کلاینت طراحی شدهاست؛ مانند برنامهی سمت سرور MVC، برنامههای سمت کلاینت جاوا اسکریپتی مانند Angular و برنامههای موبایل. برای این منظور باید در IDP نوع کلاینت و یکسری از تنظیمات مرتبط با آنرا مشخص کرد.
کلاینتهای عمومی و محرمانه
زمانیکه قرار است با یک IDP کار کنیم، این IDP باید بتواند بین یک برنامهی حسابداری و یک برنامهی پرسنلی که از آن برای احراز هویت استفاده میکنند، تفاوت قائل شود و آنها را شناسایی کند.
- کلاینت محرمانه (Confidential Client)
هر کلاینت با یک client-id و یک client-secret شناخته میشود. کلاینتی که بتواند محرمانگی این اطلاعات را حفظ کند، کلاینت محرمانه نامیده میشود.
در اینجا هر کاربر، اطلاعات هویت خود را در IDP وارد میکند. اما اطلاعات تعیین هویت کلاینتها در سمت کلاینتها ذخیره میشوند. برای مثال برنامههای وب ASP.NET Core میتوانند هویت کلاینت خود را به نحو امنی در سمت سرور ذخیره کنند و این اطلاعات، قابل دسترسی توسط کاربران آن برنامه نیستند.
- کلاینت عمومی (Public Client)
این نوع کلاینتها نمیتوانند محرمانگی هویت خود را حفظ و تضمین کنند؛ مانند برنامههای جاوا اسکریپتی Angular و یا برنامههای موبایل که بر روی وسایل الکترونیکی کاربران اجرا میشوند. در این حالت هرچقدر هم سعی کنیم، چون کاربران به اصل این برنامهها دسترسی دارند، نمیتوان محرمانگی اطلاعات ذخیره شدهی در آنها را تضمین کرد.
مفهوم OpenID Connect Endpoints
در تصویر ابتدای بحث، دو فلش را مشاهده میکنید؛ برای مثال چگونه میتوان به Identity token دسترسی یافت (Authentication) و همچنین زمانیکه صحبت از Authorization میشود، چگونه میتوان Access tokens را دریافت کرد. اینکه این مراحله چگونه کار میکنند، توسط Flow مشخص میشود. Flow مشخص میکند که چگونه باید توکنها از سمت IDP به سمت کلاینت بازگشت داده شوند. بسته به نوع کلاینتها که در مورد آنها بحث شد و نیازمندیهای برنامه، باید از Flow مناسبی استفاده کرد.
هر Flow با Endpoint متفاوتی ارتباط برقرار میکند. این Endpointها در حقیقت جایگزین راهحلهای خانگی تولید برنامههای IDP هستند.
- در ابتدا یک Authorization Endpoint وجود دارد که در سطح IDP عمل میکند. این مورد همان انتهای فلش اول ارسال درخواست به سمت IDP است؛ در تصویر ابتدای بحث. کار این Endpoint، بازگشت Identity token جهت انجام عملیات Authentication و بازگشت Access token برای تکمیل عملیات Authorization است. این عملیات نیز توسط Redirection کلاینت انجام میشود (هدایت کاربر به سمت برنامهی IDP، دریافت توکنها و سپس هدایت مجدد به سمت برنامهی کلاینت اصلی).
نکتهی مهم: استفادهی از TLS و یا همان پروتکل HTTPS برای کار با OpenID Connect Endpoints اجباری است و بدون آن نمیتوانید با این سیستم کار کنید. به عبارتی در اینجا ترافیک بین کلاینت و IDP، همواره باید رمزنگاری شده باشد.
البته مزیت کار با ASP.NET Core 2.1، یکپارچگی بهتر و پیشفرض آن با پروتکل HTTPS است؛ تا حدی که مثال پیشفرض local آن
به همراه یک مجوز موقتی SSL نصب شدهی توسط SDK آن کار میکند.
- پس از Authorization Endpoint که در مورد آن توضیح داده شد، یک Redirection Endpoint وجود دارد. در ابتدای کار، کلاینت با یک Redirect به سمت IDP هدایت میشود و پس از احراز هویت، مجددا کاربر به سمت کلاینت Redirect خواهد شد. به آدرسی که IDP کاربر را به سمت کلاینت Redirect میکند، Redirection Endpoint میگویند و در سطح کلاینت تعریف میشود. برنامهی IDP، اطلاعات تولیدی خود را مانند انواع توکنها، به سمت این Endpoint که در سمت کلاینت قرار دارد، ارسال میکند.
- پس از آن یک Token Endpoint نیز وجود دارد که در سطح IDP تعریف میشود. این Endpoint، آدرسی است در سمت IDP، که برنامهی کلاینت میتواند با برنامه نویسی، توکنهایی را از آن درخواست کند. این درخواست عموما از نوع HTTP Post بدون Redirection است.
مفهوم OpenID Connect Flow
- اولین Flow موجود، Authorization Code Flow است. کار آن بازگشت کدهای Authorization از Authorization Endpoint و همچنین توکنها از طریق Token Endpoint میباشد. در ایجا منظور از «کدهای Authorization»، اطلاعات دسترسی با طول عمر کوتاه است. هدف Authorization Code این است که مشخص کند، کاربری که به IDP لاگین کردهاست، همانی است که Flow را از طریق برنامهی وب کلاینت، شروع کردهاست. انتخاب این نوع Flow، برای کلاینتهای محرمانه مناسب است. در این حالت میتوان مباحث Refresh token و داشتن توکنهایی با طول عمر بالا را نیز پیاده سازی کرد.
- Implicit Flow، تنها توکنهای تولیدی را توسط Authorization Endpoint بازگشت میدهد و در اینجا خبری از بازگشت «کدهای Authorization» نیست. بنابراین از Token Endpoint استفاده نمیکند. این نوع Flow، برای کلاینتهای عمومی مناسب است. در اینجا کار client authentication انجام نمیشود؛ از این جهت که کلاینتهای عمومی، مناسب ذخیره سازی client-secret نیستند. به همین جهت در اینجا امکان دسترسی به Refresh token و توکنهایی با طول عمر بالا میسر نیست. این نوع از Flow، ممکن است توسط کلاینتهای محرمانه نیز استفاده شود.
- Hybrid Flow، تعدادی از توکنها را توسط Authorization Endpoint و تعدادی دیگر را توسط Token Endpoint بازگشت میدهد؛ بنابراین ترکیبی از دو Flow قبلی است. انتخاب این نوع Flow، برای کلاینتهای محرمانه مناسب است. در این حالت میتوان مباحث Refresh token و داشتن توکنهایی با طول عمر بالا را نیز پیاده سازی کرد. از این نوع Flow ممکن است برای native mobile apps نیز استفاده شود.
آگاهی از انواع Flowها، انتخاب نوع صحیح آنها را میسر میکند که در نتیجه منتهی به مشکلات امنیتی نخواهند شد. برای مثال Hybrid Flow توسط پشتیبانی از Refresh token امکان تمدید توکن جاری و بالا بردن طول عمر آنرا دارد و این طول عمر بالا بهتر است به کلاینتهای اعتبارسنجی شده ارائه شود. برای اعتبارسنجی یک کلاینت، نیاز به client-secret داریم و برای مثال برنامههای جاوا اسکریپتی نمیتوانند محل مناسبی برای ذخیره سازی client-secret باشند؛ چون از نوع کلاینتهای عمومی محسوب میشوند. بنابراین نباید از Hybrid Flow برای برنامههای Angular استفاده کرد. هرچند انتخاب این مساله صرفا به شما بر میگردد و چیزی نمیتواند مانع آن شود. برای مثال میتوان Hybrid Flow را با برنامههای Angular هم بکار برد؛ هرچند ایدهی خوبی نیست.
انتخاب OpenID Connect Flow مناسب برای یک برنامهی کلاینت از نوع ASP.NET Core
برنامههای ASP.NET Core، از نوع کلاینتهای محرمانه بهشمار میروند. بنابراین در اینجا میتوان تمام Flowهای یاد شده را انتخاب کرد. در برنامههای سمت سرور وب، به ویژگی به روز رسانی توکن نیاز است. بنابراین باید دسترسی به Refresh token را نیز داشت که توسط Implicit Flow پشتیبانی نمیشود. به همین جهت از Implicit Flow در اینجا استفاده نمیکنیم. پیش از ارائهی OpenID Connect، تنها Flow مورد استفادهی در برنامههای سمت سرور وب، همان Authorization Code Flow بود. در این Flow تمام توکنها توسط Token Endpoint بازگشت داده میشوند. اما Hybrid Flow نسبت به آن این مزیتها را دارد:
- ابتدا اجازه میدهد تا Identity token را از IDP دریافت کنیم. سپس میتوان آنرا بدون دریافت توکن دسترسی، تعیین اعتبار کرد.
- در ادامه OpenID Connect این Identity token را به یک توکن دسترسی، متصل میکند.
به همین جهت OpenID Connect نسبت به OAuth 2 ارجحیت بیشتری پیدا میکند.
پس از آشنایی با این مقدمات، در قسمت بعدی، کار نصب و راه اندازی IdentityServer را انجام خواهیم داد.