تغییر هویت در شیرپوینت : RunWithElevatedPrivileges

 یکی از مسائلی که اکثرا توسعه دهندگان شیرپوینت با آن مواجه هستند بحث Impersonation در شیرپوینت می
باشد ، اما گاهی این مسئله مشکلات بسیاری همراه خود دارد و در صورتی که به درستی
استفاده نشود خواسته های شما را برآورده نخواهد کرد.

امروز میخوام این مسئله رو به صورت کامل برای شما باز کنم ، اما قبل از اینکه
به سراغ موارد استفاده بریم شرح کوتاهی در مورد
Impersonation خواهیم داد :

Impersonation به نحوه پردازش کد یا بخشی از کد با هویت یک
شخص دیگر در
Context گفته می شود.

در برخی موارد ممکن است شما بخواهید از هویت شخصی دیگر ، هویت Application
Pool
، مدیر سایت یا مجموعه سایت ( System Account ) و یا حتی از
هویت کاربران ویندوز به خاطر مجوزهایی که هر یکی از این افراد دارند استفاده کنید
، اما قبل از اینکه تصمیم بگیرید که از برای
Impersonation  از چه هویتی استفاده کنید این نکته بسیار مهم
است که تفاوت بین
SharePoint Security Context و Windows
Security Context
را خوب درک کنید .

در محیط شیرپوینت و برنامه هایی که برای آن نوشته می شود (مثل یک وب پارت )
شما علاوه بر اینکه نیاز دارید به منابع داخلی دسترسی داشته باشید ( مانند لیست ها
، مخازن اسناد ، فایل ها و … ) ممکن است نیاز به دسترسی به منابع خارجی پیدا
کنید ( مانند جداولی در
SQL Server  یا
یک سیستم خارجی و یا حتی
Shared Folders ) که دسترسی به این منابع خارج از کنترل
شیرپوینت می باشد ، پس زمانی که میخواهید از
Impersonation  استفاده کنید حتما باید این نکات را در نظر
داشته باشید تا تمام نیازهای شما برطرف گردد .

خوب حالا اجازه بدید ببینیم چطور میتونیم از روش های مختلف برای Impersonation
 استفاده کنیم :

 استفاده از SPSecurity.RunWithElevatedPrivileges

اجرای کدها توسط RunWithElevatedPrivileges یکی از محبوب
ترین روش ها برای اجرای کد با هویتی که دارای مجوزهای لازم است می باشد :

 

SPSecurity.RunWithElevatedPrivileges(delegate()

{

   using (SPSite elevatedSite = new
SPSite(SPContext.Current.Site.Id))

   {

      using (SPWeb elevatedWeb =
elevatedSite.OpenWeb(SPContext.Current.Web.Id))

      {

          // codes …

      }

   }

});

 

اما با اجرای کدهایی که داخل این بلاک قرار میگیرند تغییراتی بدین صورت اعمال
خواهد شد :

هر دوی Windows Security Context و SharePoint
Security Context
تغییر خواهند کرد .

elevatedWeb.CurrentUser.LoginName برابر SharePointSystem خواهد بود .

WindowsIdentity.getCurrent().Name برابر هویت Application Pool
 خواهد بود.

با توجه به تغییراتی که صورت میگیرد کدهای داخل این بلاک بر مبنای هویت Application
Pool
اجرا می شوند ( Windows Account ) که در واقع این هویت اجرا کننده Web
Application
شماست و همچنین وظیفه پیکربندی تنظیمات دیتابیس را نیز بر عهده
دارد ، بنابراین با اجرای این کد شما به تمام منابع خارجی شامل
Local
file System
و جداول SQL Server  دسترسی دارید .

همچنین با توجه به اینکه در حوزه SharePoint Security Context این کد با هویت
SHAREPOINTSYSTEM اجرا میشود ، هرگونه تغییری که بر روی آبجکت
ها اعمال شوند (
SPFile ، SPListItem ، SPWeb و … )
تغییرات با هویت
SHAREPOINTSYSTEM ثبت می شوند ( Created
By
و Modified By ) .

اما نکات مهمی در مورد RunWithElevatedPrivileges هستند که باید
در مورد آنها اطلاعات کافی داشته باشیم :

۱ – RunWithElevatedPrivileges تنها زمانی اجرا می شود که آبجکت SPSite داخل این بلاک
ایجاد شود

شما می بایست برای اجرای کدها حتما آبکجت های SPSite  و SPWeb را داخل بلاک
ایجاد نمایید ( با استفاده از
Url ، ID سایت  و یا حتی با استفاده از SPContext ) در غیر
اینصورت با خطای
Access Denied  مواجه خواهید شد ، به مثال زیر توجه کنید :

SPSecurity.RunWithElevatedPrivileges(delegate()

{

      SPSite elevatedSite =
SPContext.Current.Site;

      using (SPWeb elevatedWeb =
elevatedSite.OpenWeb())

      {

         // Performing administrative
actions here will give Access Denied exception.

      }

   }

});

فراموش نکنید که پس از استفاده از این آبجکت ها حتما آن ها را Dispose کنید .

۲- استفاده نادرست از آبجکت ها ممکن
است ریسک های امنیتی دربر داشته باشد

آبجکت هایی که در داخل این بلاک استفاده می شوند ( مانند SPFile ، SPList و … )
مجوزهای خود را حتی خارج از این بلاک نیز حفظ میکنند ! بنابراین شما نباید این
آبجکت ها را به خارج از بلاک ارسال کنید وگرنه ممکن است با مشکلات امنیتی مواجه
شوید . مثال زیر را در نظر بگیرید :

SPList taskList=null;

SPSecurity.RunWithElevatedPrivileges(delegate()

{

      SPSite elevatedSite = SPContext.Current.Site;

 

      using (SPWeb elevatedWeb =
elevatedSite.OpenWeb())

      {

           taskList =
elevatedWeb.Lists["Tasks"]

      }

   }

});

//This code will succeed even outside the block as it is accessed via
elevated SPWeb. Hence Security Risk.

taskList.Delete();

در واقع زمانی که شما یک آبجکت SPSite ایجاد میکنید ، این آّبجکت با زیر ساخت SPRequest ادامه پیدا
میکند و
SPRequest کاربری که این آبجکت را ایجاد کرده به خاطر
میسپارد ، بنابراین تمام اشیایی که از
SPSite  مورد دسترسی قرار میگیرند SPRequest را مورد اشتراک
قرار می دهند .

در مثال بالا وقتی SPSite در این بلاک ایجاد میشود SPRequest کاربری
که این آبجکت را ایجاد کرده ثبت میکند که در مثال بالا
SHAREPOINTSystem
 می باشد . بنابراین زمانی
که آبجکتی مثل
SPList را از این SPSite فراخوانی کنید
( مثل
Site.RootWeb.Lists[ “Tasks”] ) ، این آبجکت حتی در خارج از بلاک نیز از
هویت
SHAREPOINTSystem برای تغییرات بهره خواهد برد .

 

۳ – RunWithElevatedPrivileges تغییرات Windows Security Context را نیز به خوبی تشخیص می دهد .

به طور مثال اگر هویت Application Pool  یک Web Application را از SPAdmin1 به SPAdmin2 تغییر دهید و
سپس از این بلاک استفاده کنید :

·        
در داخل شیرپوینت
هویت همچنان
SHAREPOINTSYSTEM خواهد بود ( SharePoint
Security Context
)

·        
تغییرات خارج از
شیرپوینت با هویت کاربر تغییر یافته
 ( SPAdmin2) اعمال خواهد
شد (
Windows Security Context )

بنابراین تمام درخواست هایی که به سیستم های خارجی صورت پذیرد ( مثل وب سرویس
یا دیتابیس ) بر اساس هویت
Windows Account  خواهد بود که با توجه به مجوزهای کاربر ممکن است
با موفقیت انجام شده و یا با خطا به پایان برسد.

 

۴- RunWithElevatedPrivileges زمانی که HTTPContext برابر Null باشد اجرا
نخواهد شد !

شما نمیتوانید از این بلاک زمانی که HTTPContext یا درواقع SPContext برابر Null باشد استفاده
کنید و کدهای داخل بلاک بدون توجه به
RunWithElevatedPrivileges اجرا خواهند شد
، بنابراین شما نمیتوانید از این بلاک در پروژه های
Console
Application
 ، Timer Job و حتی Event
Handlers
که HTTPContext برابر Null  می باشد ( به دلیل اینکه درخواستی از سمت مرورگر
ارسال نمیشود ) استفاده کنید .

۵ – RunWithElevatedPrivileges در پروژه های Sandbox solution  اجرا نمیشود .

شما نمیتوانید از این بلاک در پروژه های sandbox solution استفاده کنید و
می بایست پروژه های شما حتما از نوع
Farm Solution  باشند . ( برای اطلاعات بیشتر در مورد محدودیت
های
sandbox solution به این
لینک
مراجعه کنید )

۶- اعمال تغییرات با هویت کاربر فعلی ( شخصی که عملیات را انجام میدهد )

همانطور که در بالا ذکر شد زمانی که شما از این بلاک
استفاده میکنید تمام تغییرات مانند
Created
by
و Modified by با هویت SHAREPOINTSYSTEM  ذخیره خواهند شد ، ولی
مشکلی که اکثر توسعه دهندگان دارند در این است که میخواهند تغییرات با هویت شخص
جاری که در حال اجرای عملیات است ذخیره شود ( به عنوان مثل
user1 ) .

برای این کار کافیست کاربر جاری را قبل از انجام عملیات در
بلاک در متغیری ذخیره کرده و سپس تغییرات را به اسم وی ثبت کنید ، به مثال زیر
توجه کنید :

private void UpdateItem(SPList
RestrictedList, bool IsAnonymous)

{

SPUser
user =SPContext.CurrentWeb.CurrentUser;

Guid
siteID = RestrictedList.ParentWeb.Site.ID;

Guid
webID = RestrictedList.ParentWeb.ID;

Guid
listID = RestrictedList.ID;

SPSecurity.RunWithElevatedPrivileges(()
=>

{

using
(SPSite site = new SPSite(siteID))

{

using (SPWeb web = site.OpenWeb(webID))

{

web.AllowUnsafeUpdates = true;

SPList elevatedList = web.Lists[listID];

SPListItem item = elevatedList.Items.Add();

SPUser systemUser =
web.AllUsers[@"SHAREPOINT\system"];

SPFieldUserValue
currentUser = new SPFieldUserValue( item.ParentList.ParentWeb, user.ID,
user.Name);

if (!IsAnonymous)

{

item["Author"] = currentUser;

item["Editor"] = currentUser;

} else {

item["Author"] = systemUser;

item["Editor"] = systemUser;

}

item.Update();

}

}

}

);

}

}

 

در این مثال فیلدهای Author و Editor مشخص کننده
ایجاد کننده و ویرایش کننده آیتم هستند .

امیدوارم که این مقاله مفید بوده باشه ، در قسمت بعد مقاله
در مورد
SPUserToken و Win32 API صحبت
خواهیم کرد.

موفق و پیروز باشید 

پاسخ دهید