Chapters ▾ 2nd Edition

7.14 ابزارهای گیت (Git Tools) - ذخیره‌سازی اطلاعات ورود (Credential Storage)

ذخیره‌سازی اطلاعات ورود (Credential Storage)

اگر از پروتکل SSH برای اتصال به مخازن راه دور استفاده می‌کنید، ممکن است کلیدی بدون عبارت رمز داشته باشید که به شما اجازه می‌دهد بدون وارد کردن نام کاربری و رمز عبور، به‌صورت امن داده‌ها را منتقل کنید. با این حال، این امکان در پروتکل‌های HTTP وجود ندارد — هر اتصال نیازمند نام کاربری و رمز عبور است. این موضوع برای سیستم‌هایی که از احراز هویت دو مرحله‌ای استفاده می‌کنند، دشوارتر می‌شود؛ جایی که توکنی که به‌عنوان رمز عبور استفاده می‌کنید به‌صورت تصادفی تولید شده و غیرقابل تلفظ است.

خوشبختانه، گیت یک سیستم مدیریت اطلاعات ورود دارد که می‌تواند در این زمینه کمک کند. گیت چند گزینه پیش‌فرض ارائه می‌دهد:

  • حالت پیش‌فرض، عدم کش کردن است. در این حالت هر بار اتصال، از شما نام کاربری و رمز عبور درخواست می‌شود.

  • حالت “cache” اطلاعات ورود را به‌صورت موقت در حافظه نگه می‌دارد. هیچ رمز عبوری روی دیسک ذخیره نمی‌شود و پس از ۱۵ دقیقه از حافظه پاک می‌شوند.

  • حالت “store” اطلاعات ورود را در فایلی به‌صورت متن ساده روی دیسک ذخیره می‌کند و هیچ‌گاه منقضی نمی‌شوند. این بدان معناست که تا زمانی که رمز عبور خود را در میزبان گیت تغییر ندهید، دیگر نیازی به وارد کردن دوباره اطلاعات ورود نخواهید داشت. نقطه ضعف این روش این است که رمزهای عبور به‌صورت متن ساده در فایلی در پوشه خانگی شما ذخیره می‌شوند.

  • اگر از macOS استفاده می‌کنید، گیت دارای حالت “osxkeychain” است که اطلاعات ورود را در زنجیره کلید ایمن سیستم شما ذخیره می‌کند. این روش اطلاعات را روی دیسک ذخیره می‌کند و هیچ‌گاه منقضی نمی‌شوند، اما با همان سیستمی رمزگذاری می‌شوند که گواهی‌های HTTPS و پرکردن خودکار سافاری را نگه می‌دارد.

  • اگر از ویندوز استفاده می‌کنید، می‌توانید هنگام نصب https://gitforwindows.org/ [گیت برای ویندوز] قابلیت Git Credential Manager را فعال کنید یا به‌صورت جداگانه جدیدترین نسخه https://github.com/git-ecosystem/git-credential-manager/releases/latest [GCM] را به‌عنوان سرویس مستقل نصب نمایید. این سیستم مشابه کمک‌یار “osxkeychain” است ولی از فروشگاه اعتبار ویندوز برای مدیریت اطلاعات حساس استفاده می‌کند. همچنین می‌تواند اطلاعات ورود را به WSL1 یا WSL2 ارائه دهد. برای اطلاعات بیشتر به https://github.com/git-ecosystem/git-credential-manager#readme [دستورالعمل نصب GCM] مراجعه کنید.

شما می‌توانید یکی از این روش‌ها را با تنظیم مقدار پیکربندی گیت انتخاب کنید:

$ git config --global credential.helper cache

برخی از این کمک‌یارها گزینه‌هایی دارند. کمک‌یار “store” می‌تواند آرگومان --file <مسیر> را دریافت کند که محل ذخیره‌سازی فایل متن ساده را تعیین می‌کند (به‌صورت پیش‌فرض ~/.git-credentials است). کمک‌یار “cache” گزینه --timeout <ثانیه> را می‌پذیرد که مدت زمان فعال بودن سرویس را تغییر می‌دهد (پیش‌فرض “900” ثانیه یا ۱۵ دقیقه است). در اینجا نمونه‌ای از چگونگی پیکربندی کمک‌یار “store” با نام فایل سفارشی آمده است:

$ git config --global credential.helper 'store --file ~/.my-credentials'

گیت حتی اجازه می‌دهد چندین کمک‌یار را پیکربندی کنید. هنگام جستجوی اطلاعات ورود برای یک میزبان خاص، گیت به ترتیب از آنها می‌پرسد و بعد از دریافت اولین پاسخ متوقف می‌شود. هنگام ذخیره‌سازی اطلاعات، گیت نام کاربری و رمز عبور را به تمام کمک‌یارهای فهرست ارسال می‌کند و هر کدام می‌توانند تصمیم بگیرند چه کاری انجام دهند. در اینجا نمونه‌ای از فایل .gitconfig است که فایل اطلاعات ورود روی یک درایو فلش ذخیره شده اما می‌خواهید از کش حافظه برای کاهش تایپ در صورت عدم اتصال درایو استفاده کنید:

[credential]
    helper = store --file /mnt/thumbdrive/.git-credentials
    helper = cache --timeout 30000

پشت صحنه (Under the Hood)

این سیستم چگونه کار می‌کند؟ فرمان اصلی گیت برای سیستم کمک‌یار اطلاعات ورود، git credential است که یک فرمان را به‌عنوان آرگومان می‌گیرد و سپس ورودی بیشتری از طریق stdin دریافت می‌کند.

این موضوع با یک مثال آسان‌تر درک می‌شود. فرض کنید کمک‌یار اطلاعات ورود پیکربندی شده و اطلاعات ورود برای mygithost ذخیره شده است. در اینجا جلسه‌ای است که از فرمان “fill” استفاده می‌کند، فرمانی که هنگام تلاش گیت برای یافتن اطلاعات ورود برای یک میزبان فراخوانی می‌شود:

$ git credential fill (1)
protocol=https (2)
host=mygithost
(3)
protocol=https (4)
host=mygithost
username=bob
password=s3cre7
$ git credential fill (5)
protocol=https
host=unknownhost

Username for 'https://unknownhost': bob
Password for 'https://bob@unknownhost':
protocol=https
host=unknownhost
username=bob
password=s3cre7
  1. این خط فرمان است که تعامل را آغاز می‌کند.

  2. سپس git-credential منتظر ورودی روی stdin می‌ماند. اطلاعاتی که می‌دانیم را می‌دهیم: پروتکل و نام میزبان.

  3. یک خط خالی نشان می‌دهد که ورودی کامل است و سیستم اطلاعات ورود باید پاسخ دهد.

  4. سپس git-credential کنترل را به دست می‌گیرد و اطلاعاتی که یافته را روی stdout می‌نویسد.

  5. اگر اطلاعات ورود یافت نشود، گیت از کاربر نام کاربری و رمز عبور را می‌پرسد و آنها را به خروجی می‌فرستد (که در اینجا به همان کنسول متصل است).

سیستم اطلاعات ورود در واقع برنامه‌ای جدا از خود گیت را اجرا می‌کند؛ اینکه کدام برنامه و چگونه بستگی به مقدار پیکربندی credential.helper دارد. این برنامه‌ها اشکال مختلفی دارند:

Configuration Value Behavior

foo

Runs git-credential-foo

foo -a --opt=bcd

Runs git-credential-foo -a --opt=bcd

/absolute/path/foo -xyz

Runs /absolute/path/foo -xyz

!f() { echo "password=s3cre7"; }; f

Code after ! evaluated in shell

پس کمک‌یارهای بالا در واقع برنامه‌های git-credential-cache، git-credential-store و غیره هستند و می‌توانیم آنها را با آرگومان‌های خط فرمان پیکربندی کنیم. شکل کلی این است: “git-credential-foo [آرگومان‌ها] <عمل>.” پروتکل stdin/stdout همان git-credential است اما مجموعه‌ای کمی متفاوت از اعمال را به کار می‌برند:

  • get درخواست جفت نام کاربری/رمز عبور است.

  • store درخواست ذخیره یک مجموعه اطلاعات ورود در حافظه این کمک‌یار است.

  • erase پاک کردن اطلاعات ورود مربوط به مشخصات داده شده از حافظه این کمک‌یار است.

برای اعمال store و erase پاسخی لازم نیست (گیت آن را نادیده می‌گیرد). اما برای get گیت بسیار علاقه‌مند است به آنچه کمک‌یار می‌گوید. اگر کمک‌یار اطلاعات مفیدی نداشته باشد، می‌تواند بدون خروجی خارج شود، اما اگر داشته باشد، باید اطلاعات ارائه شده را با داده‌های ذخیره شده خودش تکمیل کند. خروجی مانند یک سری دستورات انتساب تلقی می‌شود؛ هر چیزی که ارائه شود جایگزین آنچه گیت قبلاً می‌دانسته می‌شود.

در اینجا همان مثال بالا آمده است، اما به جای git-credential مستقیم به git-credential-store می‌رویم:

$ git credential-store --file ~/git.store store (1)
protocol=https
host=mygithost
username=bob
password=s3cre7
$ git credential-store --file ~/git.store get (2)
protocol=https
host=mygithost

username=bob (3)
password=s3cre7
  1. اینجا به git-credential-store می‌گوییم که اطلاعات ورود را ذخیره کند: نام کاربری “bob” و رمز عبور “s3cre7” برای دسترسی به https://mygithost.

  2. حالا می‌خواهیم این اطلاعات را بازیابی کنیم. اجزای ارتباطی که می‌دانیم (https://mygithost) را می‌دهیم و سپس یک خط خالی.

  3. git-credential-store با نام کاربری و رمز عبوری که ذخیره کرده بودیم پاسخ می‌دهد.

فایل ~/git.store به این شکل است:

https://bob:s3cre7@mygithost

فقط یک سری خطوط است که هر کدام شامل یک آدرس URL همراه با اطلاعات ورود است. کمک‌یارهای osxkeychain و wincred از فرمت بومی فروشگاه‌های پشتیبان خود استفاده می‌کنند، در حالی که cache از فرمت حافظه داخلی خود استفاده می‌کند (که هیچ فرآیند دیگری نمی‌تواند بخواند).

کش اعتبارنامهٔ سفارشی (A Custom Credential Cache)

با توجه به اینکه git-credential-store و دوستان برنامه‌هایی جدا از گیت هستند، به‌راحتی می‌توان فهمید که هر برنامه‌ای می‌تواند کمک‌یار اطلاعات ورود گیت باشد. کمک‌یارهای ارائه شده توسط گیت بسیاری از موارد رایج را پوشش می‌دهند، اما همه را نه. مثلاً فرض کنید تیم شما اطلاعات ورود مشترکی دارد که بین همه اعضا به اشتراک گذاشته شده، مثلاً برای استقرار. این اطلاعات در پوشه مشترکی ذخیره شده اما نمی‌خواهید آن‌ها را در فروشگاه اطلاعات ورود خود کپی کنید چون مرتباً تغییر می‌کنند. هیچ‌کدام از کمک‌یارهای موجود این حالت را پوشش نمی‌دهند؛ بیایید ببینیم برای نوشتن یکی از آنها چه باید کرد. ویژگی‌های کلیدی که این برنامه باید داشته باشد:

  1. تنها عملی که باید به آن توجه کنیم get است؛ store و erase عملیات نوشتن هستند، پس هنگام دریافت آن‌ها به‌سادگی به‌خوبی خارج می‌شویم.

  2. فرمت فایل اطلاعات ورود مشترک همان فرمت استفاده شده توسط git-credential-store است.

  3. محل آن فایل نسبتاً استاندارد است، اما باید اجازه داد کاربر مسیر دلخواهش را نیز وارد کند.

دوباره این افزونه را با زبان روبی می‌نویسیم، اما هر زبان دیگری هم مناسب است مادامی که گیت بتواند آن را اجرا کند. در اینجا کد کامل منبع کمک‌یار جدید ما آمده است:

#!/usr/bin/env ruby

require 'optparse'

path = File.expand_path '~/.git-credentials' # (1)
OptionParser.new do |opts|
    opts.banner = 'USAGE: git-credential-read-only [options] <action>'
    opts.on('-f', '--file PATH', 'Specify path for backing store') do |argpath|
        path = File.expand_path argpath
    end
end.parse!

exit(0) unless ARGV[0].downcase == 'get' # (2)
exit(0) unless File.exist? path

known = {} # (3)
while line = STDIN.gets
    break if line.strip == ''
    k,v = line.strip.split '=', 2
    known[k] = v
end

File.readlines(path).each do |fileline| # (4)
    prot,user,pass,host = fileline.scan(/^(.*?):\/\/(.*?):(.*?)@(.*)$/).first
    if prot == known['protocol'] and host == known['host'] and user == known['username'] then
        puts "protocol=#{prot}"
        puts "host=#{host}"
        puts "username=#{user}"
        puts "password=#{pass}"
        exit(0)
    end
end
  1. اینجا گزینه‌های خط فرمان را تجزیه می‌کنیم و اجازه می‌دهیم کاربر مسیر فایل ورودی را مشخص کند. پیش‌فرض ~/.git-credentials است.

  2. این برنامه تنها وقتی پاسخ می‌دهد که عمل get باشد و فایل ذخیره‌سازی موجود باشد.

  3. این حلقه از stdin می‌خواند تا خط خالی اول برسد. ورودی‌ها در هش known برای مراجعه بعدی ذخیره می‌شوند.

  4. این حلقه محتوای فایل ذخیره‌سازی را می‌خواند و به دنبال تطابق می‌گردد. اگر پروتکل، میزبان و نام کاربری در known با این خط تطابق داشت، برنامه نتایج را به stdout چاپ می‌کند و خارج می‌شود.

کمک‌یار خود را به نام git-credential-read-only ذخیره کنید، آن را در جایی از مسیر سیستم قرار دهید و اجرایی کنید. در اینجا نمونه جلسه تعاملی آمده است:

$ git credential-read-only --file=/mnt/shared/creds get
protocol=https
host=mygithost
username=bob

protocol=https
host=mygithost
username=bob
password=s3cre7

از آنجا که نام آن با «git-» شروع می‌شود، می‌توانیم از دستور ساده برای مقدار پیکربندی استفاده کنیم:

$ git config --global credential.helper 'read-only --file /mnt/shared/creds'

همان‌طور که می‌بینید، گسترش این سیستم بسیار ساده است و می‌تواند برخی مشکلات رایج شما و تیم‌تان را حل کند.

scroll-to-top