تغییر هویت در شیرپوینت : SPUserToken ، Win32 API

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

استفاده از User Token

یکی دیگر از راه های تغییر هویت در شیرپوینت استفاده از آبجکت SPUserToken می باشد .

با استفاده از این آبجکت کافیست شخص مورد نظر که میخواهیم عملیات با هویت او
اجرا شود را بدانیم و با به دست آوردن
Token عملیات را اجرا
کنیم . با استفاده از مشخصه
UserToken  از کلاس
SPUser میتوانیم Token  یک
شخص را بدست بیاوریم و سپس در
Constructor  کلاس
SPSite از آن استفاده کرده تا بتوانیم کدهای مورد نظر را اجرا کنیم .

این روش بهترین روش برای تغییر هویت می باشد ولی باید در هنگام استفاده از این
روش مطمئن باشید که کاربری که قصد انجام عملیات با هویت وی را دارید در سایت وجود
داشته باشد و همچنین مطمئن باشید که وی تمام دسترسی های لازم برای انجام عملیات
شما را دارد .

به مثال زیر توجه کنید :

SPWeb oWeb = SPContext.Current.Web;

SPUserToken token = oWeb.AllUsers[@"RaminAhmadi"].UserToken;

using (SPSite elevatedSite = new SPSite(oWeb.Site.ID, token))

 {

    using (SPWeb elevatedweb =
site.OpenWeb())

     {

      // codes

     }

 }

 در این مثال زمانی که کاربری درخواستی را صادر میکند ، کدها با هویت RaminAhmadi اجرا می شوند ،
در واقع پس از ایجاد کلاس
SPSite کلاس SPUser و SPUserTokenنیز
ایجاد می گردد و تمام منابعی که در داخل شیرپوینت فراخوانی شوند با دسترسی های این
کاربر خواهد بود .

اما نکاتی که در مورد این روش باید به آن توجه کنید :

Windows Security Context تغییر نمیکند !

 

در مثال بالا مقدار WindowsIdentity.GetCurrent().Name برابر SPContext.Current.Web.CurrentUser خواهد بود ، در
واقع هویت
Windows Security Context تغییری نخواهد
کرد و برابر کاربری است که در شیرپوینت لاگین کرده است و درخواست را صادر نموده .

پس تمام دسترسی هایی که به منایع خارجی از جمله وب سرویس یا دیتابیس انجام شود
برابر هویت ویندوز کاربر جاری خواهد بود !

Token  ها
محدودیت زمانی دارند !

 

شما فقط ۲۴ ساعت مهلت دارید تا از یک Token  استفاده کنید ، حتما میپرسید خوب معمولا اکثر
عملیات در زمان های کوتاهی انجام می شود . باید خدمت شما عرض کنم که همیشه اینطور
نیست ، در صورتی که
Workflow یا Event Receiver ( از نوع asynchronous ) داشته باشید
ممکن است زمان زیادی تا انجام گام بعدی وقفه وجود داشته باشد و در صورتی که
Token در این مدت
انقضا شده باشد کد شما با هویت کاربر جاری اجرا خواهد شد .

اما نگران نباشید ، این مورد قابل تغییر است ، شما میتوانید با یک خط دستور در
PowerShell این موضوع را حل کنید :

   stsadm -o setproperty
-propertyname token-timeout -propertyvalue 720

در مثال بالا ما زمان انقضا Token  را
از ۲۴ ساعت به ۷۲ ساعت تغییر دادیم .

استفاده از Win32 API

 

همانطور که در روش های قبلی متوجه شده اید ما در هیچ یک از روش های قبلی نمیتوانیم
خارج از شیرپوینت هویت را تغییر دهیم ( مثل
Console
Application
) .

اگر شما از پروژه های Console Application یا Windows
Application
استفاده کنید و نیاز به تغییر هویت برای فراخوانی وب سرویس و یا
آبجکت مدل داشته باشید ، می بایست یک آبجکت از نوع
WindowsIdentity ایجاد کنید :

class Program

    {

        //
Declare signatures for Win32 LogonUser and CloseHandle APIs

        [DllImport("advapi32.dll", SetLastError = true)]

        static extern bool LogonUser(

        string principal,

        string authority,

        string password,

        LogonSessionType logonType,

        LogonProvider logonProvider,

        out IntPtr token);

        [DllImport("kernel32.dll", SetLastError = true)]

        static extern bool CloseHandle(IntPtr handle);

        enum LogonSessionType : uint

        {

            Interactive = 2,

            Network,

            Batch,

            Service,

            NetworkCleartext = 8,

            NewCredentials

        }

        enum LogonProvider : uint

        {

            Default = 0, // default for platform (use this!)

            WinNT35, // sends smoke signals to authority

            WinNT40, // uses NTLM

            WinNT50 // negotiates Kerb or NTLM

        }

 

        static void Main(string[] args)

        {

            string username;

            string password;

            string domain;

            Console.Write("Enter
username:"
);

            username = Console.ReadLine();

            Console.Write("Enter
domain:"
);

            domain = Console.ReadLine();

            Console.Write("Enter
password: "
);

            password = Console.ReadLine();

            IntPtr token = IntPtr.Zero;

            WindowsImpersonationContext impersonatedUser = null;

            try

            {

                bool result = LogonUser(username, domain, password, LogonSessionType.Network,
LogonProvider.Default, out token);

                if (result)

                {

                    WindowsIdentity id = new WindowsIdentity(token);

                    // Begin impersonation

                    impersonatedUser =
id.Impersonate();

                    Console.WriteLine("Identity after impersonation : " + WindowsIdentity.GetCurrent().Name);

                    // Call to Sharepoint Web services or object model

                }

                else

                {

                    Console.WriteLine("LogonUser failed: " + Marshal.GetLastWin32Error().ToString());

                }

            }

            catch

            {

            }

            finally

            {

                //
Stop impersonation and revert to the process identity

                if (impersonatedUser != null)

                    impersonatedUser.Undo();

                //
Free the token

                if (token != IntPtr.Zero)

                    CloseHandle(token);

            }

            //
Verify the old process identity

            Console.WriteLine(String.Format("Identity
after Undo: "
+ WindowsIdentity.GetCurrent().Name));

            Console.Read();

 

        }

 

    }

 

روش های دیگری هم برای این کار وجود دارد مثل RevertToSelf (به
این
لینک
مراجعه نمایید ) و
Impersonate(intPtr) ( مثال زیر ) :

private void ImpersonateCodeExecution()
{
            WindowsImpersonationContext ctx = null;
            try
            {
                if (!WindowsIdentity.GetCurrent().IsSystem)
                {
                    ctx = WindowsIdentity.Impersonate(System.IntPtr.Zero);
                    //execute your code here
                }
            }
            catch { }
            finally
            {
                if (ctx != null)
                {
                    ctx.Undo();
                }         
            }
 }

 

نکات مهم در مورد Impersonation در شیرپوینت :

·        
سعی کنید به جای
استفاده از
SPSecurity.RunWithElevatedPrivileges از SPUserToken در کدهای خود
استفاده کنید ، تنها در صورتی که نیاز به فراخوانی های خارج از شیرپوینت دارید که
می بایست تحت اکانت
Application Pool Identity اجرا شوند یا SPUser معتبر و یا
شناخته شده ای برای انجام عملیات خود ندارید از
SPSecurity.RunWithElevatedPrivileges استفاده کنید .

·        
در صورتی که از SPSecurity.RunWithElevatedPrivileges استفاده می
کنید همیشه تمام آبجکت های داخل بلاک را
Dispose نمایید و آن ها
را به خارج از بلاک منتقل نکنید .

·        
در صورتی که در
خارج از شیرپوینت نیاز به تغییر هویت دارید از
Win32 API و یا WindowsIdentity.Impersonate(token) استفاده نمایید
.

 

و اما در پایان لینک های مفید درباره Impersonation در شیرپوینت :

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

پاسخ دهید