על Federated Identity

האינטרנט פורח – וזה דבר נהדר. במקום אתרים סטטיים יש לנו עכשיו \"אפליקציות\" שעושות דברים נפלאים. לעתים הולכות וקרבות אפליקציות משתפות פעולה זו-עם-זו בכדי לעשות משהו נפלא חדש.
בכדי לעשות את כל הדברים הנפלאים הללו, בצורה שתתאים לנו, האפליקציות שומרות פרטים עלינו. פרטים אישיים. פרטים חשובים.

בכדי להגן על הפרטים האישיים של המשתמשים, העולם משתמש במנגנוני-אבטחה, שאחד מיסודותיהם הוא מנגנון הAuthentication (זיהוי). כשמדברים על האינטרנט ואפליקציות המדברות זו-עם-זו, אנו מדברים לרוב על Authentication בעזרת Federated Identity (= זהות בקבוצה מבוזרת).

בפוסט זה נסקור את עקרונות הבסיס של פרוטוקולי Federated Identity ונספק כמה מילים על הפרוטוקולים הנפוצים.

זהות

אם אנו מדברים על Federated Identity (בפוסט זה אשתמש מעתה בקיצור FI), אולי כדאי להתחיל בכמה מילים על המושג \"זהות\".
אני מניח שכולם יודעים מהי \"זהות\" של אדם ביום-יום (כל עוד לא נגרר למישור הפילוסופי): המסמך שמתאר את הזהות שלנו יכול להיות ת\"ז, דרכון או רשומה במשרד הפנים, אבל גם נתונים פיזיים: מראה, טביעת אצבע או אופן ההליכה (מסתבר שהוא דיי ייחודי) – כל אלו מתארים את הזהות שלנו.
מרכיב חשוב בזיהוי \"יום-יומית\" היא שהיא מבוססת על אמון (Trust): מישהו מאמין למדינת ישראל וסומך על תעודת הזהות שהיא הנפיקה (על אף שהיא עלולה להיות שקרית או מזויפת). אתם יכולים להאמין למישהו (למשל חבר לעבודה) שאומר \"אני מכיר אותו, זהו משה!\". האמון יפחת אם החבר לא מכיר היטב את האיש השלישי, או אם אתם לא מכירים היטב את החבר. למשל: אדם זר שניגש ברחוב ומספר לכם שאיש שלישי הוא משה, הוא לא מצב מעורר אמון (אפשר לפתוח ולומר: \"מה בכלל רוצה ממני הבחור הזה?!\")

אמון יכול להיות טרנזיטיבי: החבר ראה ת\"ז של אדם שלישי. אתם סומכים על החבר שסומך על תעודת הזהות שראה.
זהות דיגיטלית, או זהות אינטרנט היא דומה – אך קצת שונה:
  • בעולם הדיגיטלי אין באופן טבעי מאפיינים ייחודיים (מראה, קול, או אפילו דרך הליכה) המזהים אדם שלישי – כולם נראים \"אותו הדבר\" מלבד כמה פרטים שהצהירו על עצמם.
    • מעניין לציין שיש עיקרון שנקרא \"risk-based authentication\" בו מאמתים זהות של משתמש (ליתר דיוק: מחשבים סיכון לגניבת זהות) ע\"י איסוף ופענוח \"ההתנהגות הדיגיטלית\" הטיפוסית של המשתמש, למשל: מספר השניות שהוא מבלה בכל דף באתר וסדר הדפים שהוא ניגש אליהם. אם תתחברו לאתר הבנק ותנהגו בצורה שונה מאוד מבד\"כ – יש סיכוי שתחסמו ותתבקשו לגשת לסניף להוציא ססמה חדשה. 
  • מיקום גאוגרפי הוא קל ל\"זיוף\": כיצד אני יודע שהבחורה הנחמדה מאשדוד שמופיעה בפייסבוק היא לא האקר רוסי שנמצא 2000 קילומטר משם?
  • קל למדי לפורץ \"לאמץ\" מספר זהויות דיגיטליות, אפילו באותו האתר – דבר הרבה יותר מסובך בעולם הפיסי.
  • כמות הישויות (חברות / אפליקציות) שאוספות עלינו מידע הוא רב יותר, והמידע מפורט יותר. קשה להאמין שביה\"ס שלמדתם בו במשך שנים שמר מידע שווה ערך למה שאתר אינטרנט שומר עליכם בתוך מספר ימים של שימוש.
    מספיק שרק אתר אחד ייפרץ – בכדי שפרטים אישיים כלשהם שלכם יהיו נגישים לאישיות לא רצויה.
  • אתרי אינטרנט יכולים לייצר בקלות יחסית חזות אמינה, או לפחות אנו נוהגים בפחות זהירות כלפיהם: לכמה אתרים נתתם את כתובת הדוא\"ל שלכם והשתמשתם שם באותה הסיסמה כמו חשבון הדוא\"ל? לכמה בתי עסק נתתם את הכתובת שלכם בבית, ומפתח?

Federated Identity

עקרונות ה FI אינם תקן או דרך-יחידה לבצע את הדברים, אולם אם נתבונן במנגנונים הנפוצים:
  • (Kerberos)
  • SAML 2.0
  • OAuth
  • OpenID
  • Claims-Based Authentication
נראה שיש בניהם המון דמיון. במשך שנים לארגונים ומערכות שונות היו מימושים פרטיים לאותם עקרונות. כל זה השתנה בשנות האלפיים שאפליקציות החלו יותר ויותר לדבר זו עם זו. עברו עוד מספר שנים עד שהארגונים הגדולים הצליחו להסכים על תקן (תקנים) אחידים ולהתיישר לפיהם. שלושת התקנים החשובים (SAML, OAuth ו OpenID) מציגים שוני עקרוני בפונקציונלית שלהם שמצדיק קיום 3 פרוטוקולים שונים.
Kerberos ו CBA הם פתרונות מוצלחים, שנפוצים כיום כמעט ורק בעולם של מייקרוסופט. מכיוון שההגמוניה של מייקרוסופט בסביבת המחשוב נפגעה מאוד במעבר לענן – ניתן להתייחס כיום ל2 תקנים אלו כתקנים בעלי חשיבות משנית.

תהליך אפשור גישה למשאב. אנו נתמקד בפוסט זה בשלב ה Verification

ניתן לקרוא עוד על שלב ה Authorization בפוסט קודם בנושא.
תהליך ה FI מנצל את העובדה שאימות (Authentication) וניהול הרשאות (Authorization) הם, מאז-ומעולם וע\"פ תכנון, שלבים נפרדים בתהליך הגישה למשאב – בכדי להפוך את תהליך האימות לתהליך מבוזר שמתרחש בכלל על שרת אחר.

בשפה של FI מגדירים את המונחים הבאים:

  • Service Provider – את הישות נותנת את השירות, למשל שרת פייסבוק.
  • Identity Provider (בקיצור: IdP) – את הישות שמאמתת את זהות המשתמש (שלב Verification). ייתכן וה IdP הוא לא המערכת בה מנהלים את המשתמשים (קרי LDAP / Active Directory) אלא שירות חיצוני שנמצא ביחסי אמון עם ה User Repository.
  • Credential Store (לחלופין Authentication Store) – היכן ששומרים את ההרשאות מה משתמש מורשה לעשות (שלב ה Permission Check), לרוב זהו נותן השירות (למשל: פייסבוק), אך תאורטית זו יכולה להיות מערכת צד-שלישי שנותן השרות סומך עליה. פיזית, נתונים אלו נשמרים לרוב ב Directory Service או בסיס-נתונים.
בדומה לעולם הפיסי, המפתח לFI הוא אמון (Trust) בין השרתים השונים. אמון זה נוצר פעמים רבות תוך כדי החלפת מפתחות-הצפנה בין 2 השרתים. ברגע שיש אמון, האמון הוא \"מוחלט\"[א]: אין וידוא נוסף מעברת לאימות זהות השרת עליו סומכים (על בסיס הצפנה) ווידוא שמה שנשלח מהשרת המרוחק לא שונה (modified) בדרך.

הנה תרשים שמתאר בקירוב את האופן בו פרוטוקולים של FI עובדים:

תרשים A

הנחה מקדימה: ה SP מכיר וסומך על ה IdP (נעשה בעזרת קונפיגורציה ידנית).

  1. המשתמש פותח דף בדפדפן ומנווט ל SP.
  2. ה SP לא מזהה את המשתמש ומפנה אותו ל IdP. אופן ההפניה שונה מפרוטוקול לפרוטוקול, וכן זהות ה IdP.
  3. ה IdP מאמת את זהות המשתמש בדרכים שעומדות לפניו: הוא מכיר את המשתמש וצריך להיות מסוגל לאמת אותו.
  4. ה IdP מפנה את הדפדפן חזרה לדף המקור (פרטים הופיעו בבקשת האימות, בד\"כ) ומייצר \"מסמך\" (token או ticket) המתאר פרטים שהוא יודע על המשתמש: id, מיקום, קבוצות שהוא שייך אליהן וכו\'. פרטים אלו נקראים לרוב Assertions או Claims וה\"מסמך\" שמכיל אותם הוא מין וריאציה דיגיטלית של דרכון או ת\"ז.
    ה\"מסמך\" נחתם ב חתימה דיגיטלית כדי לוודא שצד שלישי לא יוכל לעשות בו שינויים.
  5. ה SP מקבל את המסמך – הוא מאמת, לרוב בעזרת החתימה הדיגיטלית, את זהות ה IdP ואת שלמות/תקינות (integrity) המסמך. 
  6. במידה והמסמך נמצא תקין, הוא מבצע log in למשתמש ע\"פ הפרטים שבמסמך, כלומר: בד\"כ יוצר session שמתאר את המשתמש.

בסיכום מהיר ניתן לציין ל FI את היתרונות והחסרונות הבאים:

יתרונות

  1. משתמש: כאשר משתמשים באותה סיסמה על ריבוי מערכות, ברגע שמערכת אחת נפרצת הפורץ יכול לנסות את הסיסמה ב 100 האתרים הנפוצים – אולי יתמזל מזלו. בעזרת FI אין צורך לנהל מספר-רב של ססמאות: אם מערכת (Service Provider) נפרצה – אין עליה את הסיסמה שלי. 
  2. משתמש: חוויית משתמש טובה. מעבר לכמה שניות המתנה בזמן ה login, המשתמש לא מודע ש FI היה בכלל מעורב. 
  3. מפתח ה SP: לא צריך להתעסק עם הנושא המורכב שקרוי Authentication. אנשי שיווק היו כבר ממציאים: \"Authentication as a Service\".
  4. מפתח, Admin ומשתמש: היכולת לספק (SSO (Single Sign-On בצורה אלגנטית (למשל: פרוטוקול SAML 2.0), הרבה יותר אלגנטיים ממשפחה נפוצה אחרת של פתרונות SSO שנקראת \"Credential Storage\" בה שרתים שונים / מכונת המשתמש שומרת שם וסיסמה לשרתים השונים. SSO הוא טוב כי:
    1. המשתמש – לא צריך לזכור הרבה ססמאות / לבצע Login שוב כאשר הוא מופנה למערכת אחרת.
    2. ה Administrator – לא צריך לנהל מנגנוני Authentication כפולים
    3. המפתח (של SP) – חוסך לעצמו התעסקות עם Authentication. שהמפתח של ה IdP – יעשה את זה!
  5. מפתח SP: מקבל אינטגרציה קלה בין מערכות, שכעת רק צריכות להסכים על פרוטוקול ה FI.
  6. מפתח, Admin: מנגנוני FI לרוב גמישים למדי, ומאפשרים ל IdP לספק כל סט של נתונים שהאפליקציה דורשת, למשל: מקום גאוגרפי של המשתמש, שפה מועדפת וכו\'. זהו תחליף חלקי לשמירת מידע personalized על המשתמש, ויותר מזה – ניהול כפול שלו במספר מערכות (אני רוצה לכוון את השפה עברית במערכת אחת ולא בעשרה).

חסרונות

  1. החשש שפריצה ל IdP תספק לפורץ גישה לכל האפליקציות של המשתמש/ים על ה IdP, מה שנקרא \"מפתח יחיד לממלכה\".
    הסיכון קיים, אבל מכיוון שניהול של 20 ססמאות מוביל לרוב לסיסמה אחת על 20 שרתים שפחות מאובטחים מה IdP הממוצע – אין אלטרנטיבה טובה יותר לסיכון הזה, עדיין.
  2. פתרון מורכב להקמה. למרות שהרעיון אינו חדש, יש מחסור בבסיס ידע / חומר כתוב [ב] / מומחים בתחום ה FI, במיוחד כאשר מדובר בdeployments שאינם בסיסיים. לאחרונה צצים פתרונות של \"IdP as a Service\" (לדוגמה Azure ACS) – לא אתפלא לגלות שהם מצליחים לפשט רבות את מלאכת ההגדרה.
  3. אין סטנדרט יחיד ל FI (בעצם יש 3-4 נפוצים), מה שמחייב מערכות לתמוך בכמה תקנים / לא לתמוך ב FI עבור כל המשתמשים.

הפרוטוקולים

כמה מילים על ההבדלים בין הפרוטוקולים הנפוצים:

OpenID
מקצר / מפשט את תהליך ה Trust בין ה SP ל IdP. בעזרת OpenID, אתר (SP) יכול לסמוך על IdP מבלי שה IdP יכיר אותו. כלומר: אין צורך בהחלפת מפתחות / certificates. מתאים לאתרי אינטרנט שפתוחים לכולם, ושבעיקר רוצים לזהות את המשתמש מבלי להכביד עליו. לרוב חיבור של OpenID נראה למשתמש הקצה ככפתור \"התחבר באמצעות… \"
IdPs של OpenID כוללים את: Facebook, Google, Yahoo ועוד.

OpenId מאפשר שתי דרכים שונות לבצע Authentication:

  1. המשתמש נרשם ל IdP ומקבל OpenId. כשהוא מתחבר ל SP עליו להזין את ה OpenId שבתוכו מקודד URL ל IdP וכך ה SP יודע להיכן להפנות את הדפדפן לצורך Authentication (שלב 2 בתרשים A)
  2. (כנראה יותר נפוצה) כשהמשתמש ניגש ל SP, ניתן לו ב UI מבחר של IdP והוא בוחר אחד מבניהם אליו ה SP יפנה את הדפדפן לביצוע תהליך ה Authentication.
OAuth

הייחוד ב OAuth הוא שהוא כולל גם Authorization, Authorization שעושה משתמש הקצה לאתר מסוים – לגשת לפרטים שלו (קריאה ו/או כתיבה).
נגדיר את \"אתר המקור\", כאתר שמנהל פרטים אישיים של המשתמש ואתר ה Service Provider כנותן שירות מסוים נוסף.
התצוגה למשתמש הקצה תהיה הפנייה לאתר המקור ושאלה: \"אתר SP מבקש לגשת ל… שלך, האם אתה מאשר?\" האישור הוא כן/לא, לעתים עם יכולת לאשר רק חלק מהפעולות. לעתים השאלה מופיעה בתוך iFrame (יכולת שנחסמה בגרסה 2.0 של הפרוטוקול) בכדי לא לגרום למשתמש לאבד אוריינטציה (אבל מאפשר התקפות clickjacking).

כשהמשתמש נותן אישור ל SP לגשת למידע, ה token שמותיר את הגישה מקודד בפירוש את שם ה SP כך שאם ה token נחטף – אתר אחר לא יוכל לעשות בו שימוש.
בנוסף, OAuth token ניתן לזמן מוגבל ולאחר שיפוג – יהיה צריך האתר לבקש את אישור המשתמש פעם נוספת.

SAML
פרוטוקול SAML (בעצם SAML 2.0, אף אחד לא משתמש בגרסה 1 בימנו…) הוא פרוטוקול FI \"קלאסי\".
על ה IdP וה SP לייצר trust ע\"י החלפת מפתחות ומשתמש בעיקר תסריטים של Enterprise בהם חשוב להגביל גישה ל SP ממשתמשים לא רצויים. SAML 2.0 גם תומך ב SSO.
SAML, כדרך אגב, מתבסס על XML/SOAP (טכנולוגיות כמעט \"מוקצות\" בימנו) כבסיס.

שיהיה בהצלחה!

[א] בניגוד לעולם האמיתי בו יש לנו דרגות של ספק, גם באלו שאנו \"מאמינים\".

[ב] דוגמה פשוטה: התיעוד הכי מקיף שמצאתי לאחר חיפוש על SAML 2.0 (פרוטוקול נפוץ מאוד, במיוחד בעולם ה Enterprise) – הוא וויקיפדיה.

קישורים:

מיתוסים והבהרות לגבי SAML (מ 2003)

סדנת פיתוח ווב ב Expert Days 2013

עוד כחודש, אעביר סדנה של יום (6 שעות) תחת הכותרת:

המטרה שלי היא לתת יסודות עמוקים ואיתנים לפיתוח ווב, לאלו שהגיעו לעולם הווב לאחרונה מבלי ללמוד את היסודות בצורה מסודרת. אני לא מדבר על HTML5 / CSS3, שאפשר ללמוד אותם בקלות מהאינטרנט, אלא על:
  • קורס מזורז ברשתות – עבור פיתוח ווב
    • אדבר בקצרה על פרוטוקולים: הבדלים בין Ethernet ו 3G, על TCP/IP ו DNS.
    • אדבר על רכיבי רשת וכיצד (בקצרה) הם עובדים: Proxy, Reverse Proxy, CDN, Load Balancer וכו\'.
  • סקירה יסודית של HTTP
    • מחזור בקשה-תשובה, ומבנה הבקשה / התשובה.
    • Methods/Verbs ו Status Codes מרכזיים – וכיצד להשתמש בהם כדי לכתוב שירותי REST בצורה נכונה.
    • Headers חשובים שכדאי להכיר.
    • Caching ו Cookies.
  • מבנה הדפדפן וביצועים של אפליקציות ווב
    • כיצד ניתן לנצל בצורה טובה יותר את הרשת בכדי לכתוב אפליקציות ווב מהירות יותר.
    • כיצד להשתלב בצורה חכמה יותר עם pipeline הרינדור של הדפדפן.
  • אבטחה וה Same-Origin Policy
    • כיצד לתקשר עם domains אחרים, ולעשות זאת בצורה מאובטחת.
כל הדברים שהייתם מצפים ללמוד באוניברסיטה, אבל ללא 10 שנות האיחור ; )
הכנס אמנם במקור מיועד לטכנולוגיות מייקרוסופט, אך הסדנא ניטרלית ונכונה לכל טכנולוגיה (כמו עוד כמה סדנאות ב Track הווב).

אם מעניין אתכם, או אתם מכירים אנשים שסנדה כזו עשוייה להועיל להם, אנא שלחו להם את הפוסט.

הסדנא תתקיים ביום ראשון, ה 8 בדצמבר 2013, בכפר המכבייה (רמת גן).

תודה,
ליאור

    Enterprise Architecture: Authorization

    קשה להגדיר מהי Enterprise Architecture, לרוב זוהי ארכיטקטורה של / ועבור ארגונים גדולים.

    אחד מנושאי-הליבה שחוזר על עצמו ב Enterprise Architecture הם נושאי ה Authentication ו Authorization (בקיצור: A&A):

    • Authentication – אימות הזהות של משתמש (\"האם הוא מי שהוא טוען שהוא?\")
    • Authorization – כיצד שולטים בהרשאות מה המשתמש, לאחר שאימתנו את זהותו, יכול לעשות.
    ישנם מעט Enterprise שלא כוללים A&A, למשל כמעט כל הגישות בווב יהיו על גבי HTTPS (הדורשת הזדהות) ולא HTTP.

    אינני יודע לומר כיצד לומדים את נושאי ה A&A, יש מעט חומר יעיל שאני מכיר. אני למדתי מכמה ותיקים ממני, וממספר לא מבוטל של התמודדויות אישיות.

    בפוסט זה אני רוצה להתמקד בתחום ה Authorization ולהציג עקרון מעניין, שאני מניח שלא מוכר בקרב רבים, הנקרא Role-Based Authorization (בקיצור: RBA, נקרא גם Role-Based Access Control קרי RBAC).

    הקדמה: המודל הנאיבי

    ניהול המשתמשים הפשוט (והנאיבי) ביותר כולל טבלה בבסיס הנתונים של המשתמשים וססמותיהם. כשהמשתמש מתחבר למערכת עליו להקליד שם משתמש (כלומר: user id) וסיסמה ואז משווים את הפרטים למידע בטבלה. אם המידע נכון – שומרים את זהות המשתמש על ה session (באם זה server-side session, cookie וכו\').
    כמובן שכדאי שהססמאות יהיו \"מגובבות\" (hashed) ואולי גם \"מטושטשות\" (מה שנקרא salted [א]). נושא זה הוא תחום ה Authentication, אימות זהות המשתמש, נושא שאנני מתכוון לעסוק בו בפוסט זה.

    עבור ה authorization, ניהול ההרשאות של כל משתמש, יוצרים טבלה נוספת \"הרשאות\" הכוללת user id, resource id, permission type (להזכיר: מימוש נאיבי לחלוטין). כל פעם שמשתמש ייגש למשאב, נבדוק בטבלה אם יש לו הרשאה לפעולה (למשל: read, write וכו\') ואז נאפשר לו / נמנע ממנו את הפעולה.

    ניתן לתאר את המודל הנאיבי באופן הבא:

    מודל נאבי זה אינו scalable לניהול כאשר יש הרבה מאוד אובייקטים ו/או משתמשים. כדי שמודל Authorization \"יעבוד כראוי\" חשוב מאוד שיהיה נהיל (maintainable) ופשוט. מבחן בסיסי הוא לענות על שתי שאלות:

    1. \"האם ניתן להבין בקלות מה בדיוק משתמש x מורשה לעשות?\" במקרה שלנו – ממש לא. הוא יכול לקבל הרשאות לעשרות, מאות, אולי אלפי אובייקטים. גם אם יש לנו את רשימה של האובייקטים זמינה בקלות – יכול לקחת זמן מה לפענח ולהבין מה הוא בדיוק כל אובייקט. לדוגמה: אם אלו מסמכים – מה מכילים המסמכים השונים שיש למשתמש הרשאות.
    2. \"כאשר אני מספק למישהו הרשאה, האם קל להבין למה בדיוק אני מספק לו הרשאה?\" במקרה הזה – כן, זהו אובייקט ספציפי.

    היכן משתמשים במודל זה?
    אני מקווה שרק ב textbooks של קורסי \"מבוא לאבטחה\", אם כי סביר שיש לא מעט מערכות שמנוהלות בערך כך. בפועל – אם מספר האובייקטים והמשתמשים מצומצם (נאמר, עשרה מכל אחד) – מודל זה יכול להיות פשוט ויעיל.

    עוד בעיה של המודל הוא software scalability. הטבלה בבסיס הנתונים עלולה לצמוח במהירות. למשל: חשבו על שרת קבצים המאכסן כמיליון קבצים עבור כמה מאות משתמשים (תסריט סביר של חברה בינונית). אם עבור כל גישה לכל אובייקט נצטרך לסרוק טבלה של מיליוני שורות (אובייקטים x משתמשים) – אנחנו בבעיה.

    יתרון של המודל שהוא בהחלט פשוט וקל להבנה – זוהי תכונת מפתח של המצופה ממודל Authorization.
    למה אני חוזר ומדגיש נקודה זו? כי בסוף את ניהול ההרשאות עושים בני-אדם. מודל \"מעולה מתמטית\" שהמשתמשים לא מבינים  – שקול למודל גרוע. הנה 2 דוגמאות אופייניות:

    1. משתמש א\' מנסה להגדיר הרשאות למשתמש ב\' – אך לא מצליח לעשות זאת. אחרי כמה ניסיונות הוא נשבר, בוחר את הקבוצה \"Everyone\" ומסמן כל checkbox שהוא רואה ב UI בכדי לאפשר למשתמש ב\' את הגישה המיוחלת.
      התוצאה: המידע חשוף לכולם ואיננו מאובטח.
    2. מנהל האבטחה / איש IT שאחראי על ההרשאות לא מצליח לעקוב למי יש גישה למה. עובדים עוברים תפקידים, עוזבים, מידע נוסף – אבל אין יכולת לעקוב אחרי מה שמתרחש. אין יכולת לאכוף חוקים אבטחה ארגוניים. מערכת האבטחה מסתמכת בעיקר על עובדים ללא הבנה בענייני אבטחה, שאבטחה היא בעיקר מעצור בשבילם \"to get the job done\".
      התוצאה: חוסר שליטה. לעתים מוסיפים מערכת אבטחה חיצונית שמגבילה את צעדי המשתמשים באופן דרקוני – בניסיונות להחזיר את השליטה.
    מה הוא רואה: הכל, או כלום? 

    מודל: Access Control List

    בואו נתקדם מהמודל הנאיבי 2 צעדים קדימה:

    1. ננהל את המשתמשים בקבוצות (בעזרת מערכת x.509/LDAP/Active Directory וכו\') וננהל הרשאות לקבוצות, לא בודדים. התוצאה: הרבה פחות הרשאות לנהל.
    2. נקבע היררכיה בין המשאבים, כך שאם נתנו הרשאה למודל אב – האובייקטים הבנים יורשים אותה (אלא אם הוגדר אחרת במפורש) – שוב: פחות משאבים לנהל עליהם הרשאות.
    המודל יראה בערך כך:

    מודל זה פישט משמעותית את כמות הרשומות ב\"טבלת ההרשאות\" ושיפר את ה scalability של הניהול: במקום עשרות משאבים / משתמשים, אנו יכולים כעת לנהל מאות. במידה ויש אחידות גבוהה של המשתמשים / משאבים – אולי אפילו אלפים.
    מודל ה Access Control Lists (בקיצור: ACL) – מפשט את יכולת הניהול אפילו קצת יותר: הוא מאגד את ה Permissions לאובייקט אחד שנקרא ACL. נובעים מכך כמה יתרונות:
    1. ה ACL הוא חלק מהמשאב. אם מזיזים את המשאב – ה ACL זז איתו, ואין צורך לנהל (ברמת הקוד) מעקב ושינויים בטבלת ההרשאות.
    2. בגלל שה ACL הוא אובייקט יחיד, יש פחות רשומות לנהל (יותר software scalability) / ניתן לנהל cache יותר יעיל.
    יתרונות אלו נראים קטנים – אך הם, בסופו של דבר, חשובים.

    לאחר התוספות, המודל יראה כך:

    היכן משתמשים במודל זה?
    • מערכות קבצים כמו Windows NT או Unix
    • IBM Tivoli, Cisco Network Infrastructure ומערכות Enterprise אחרות
    כמובן שיש וריאציות מעט-שונות של המודל.

    עקרון מוסכם כיום הוא שהרשאות חייבות להיות חיוביות (positive) בלבד – כלומר: \"מה המשתמש יכול לעשות\" ולא \"מה המשתמש לא יכול לעשות\". זאת, בכדי למנוע סיבוכיות / דו-משמעות של ההרשאות שניתנו. במערכת הקבצים של \"חלונות\" עברו על כלל זה – מה שמסבך מאוד את ניהול ההרשאות.

    1. \"האם ניתן להבין בקלות מה בדיוק משתמש x מורשה לעשות?\" – לא. מודל ה ACL שיפר את ה scalability של המודל הנאיבי, אך הוא עדיין נחשב מודל מאותגר-scalability מבחינת ניהול.
      ארגונים גדולים נוהגים לרכוש כלי ניתוח שסורקים את ה ACLs במערכות הקבצים, ומייצרות דוחות המקלים על ההבנה מה כל משתמש יכול לעשות.
    2. \"כאשר אני מספק למישהו הרשאה, האם קל להבין למה בדיוק אני מספק לו הרשאה?\" – פחות או יותר כן, כל עוד המשאבים מנוהלים היררכית בצורה הגיונית (מה שלעתים קרובות קורה).
    חולשה של מודל ה ACL הוא טיפול בהסרה של הרשאות – מה שעלול לדרוש עדכון של ACLs רבים והלוגיקה מאחוריו עלולה להיות בלתי-מובנת לחלק מהמשתמשים.

    מודל: Policy-Based Authorization

    במשך השנים ניסו ליצור מודל קל יותר לניהול, שיתאר יותר את צורכי האבטחה של הארגון ופחות ייצמד למבנה המשאבים הטכני במערכת. זהו מודל ה Policy-Based Authorization (בקיצור: PBA או PBAC).
    הרעיון הוא שהארגון יקבע סט של כללי-אבטחה / מדיניות אבטחה (Policies), יכיל אותם על משאבים, והמערכת תאכוף אותם.
    למשל: \"לחשבוניות שנוצרו בשבוע האחרון יש הרשאות קריאה למשתמשים מסוג x, המתחברים מתוך הרשת הארגונית\".
    בהפשטה, המודל יכול להראות משהו כזה:
    במודל זה יש וריאציות רבות יותר ממודלים אחרים.
    היכן משתמשים במודל זה?
    מודל זה מקובל בעולם ה Enterprise במערכות רבות, נפוץ גם בעולם אבטחה (דוגמה מאוד פשוטה: Firewall)
    1. \"האם ניתן להבין בקלות מה בדיוק משתמש x מורשה לעשות?\" – !Hell No: למרות שיש הרבה פחות חוקים (policies) מ Permission במודלים הקודמים – הם עכשיו מורכבים הרבה יותר ומסובכים למעקב. ליתר דיוק ניתן לומר שמודל זה עשוי להיות מוצלח במקרים מסוימים, במיוחד כאשר כללים בסיסיים יכולים לתאר אוסף גדול מאוד של מקרים, משאבים או משתמשים (למשל: \"אסור לגשת ל port 1433 בלי רשות של רגע ודודלי\").
      קל במודל להגדיר Policies באופנים שונים, ברמות הפשטה שונות, ובסגנון שונה שיקשה על ההבנה שלהן.
    2. \"כאשר אני מספק למישהו הרשאה, האם קל להבין למה בדיוק אני מספק לו הרשאה?\" – שוב, מאוד תלוי.
    סה\"כ, מודל ה PBA הוא שנוי במחלוקת לגבי היכולת שלו לפשט את ניהול ההרשאות במערכת ה Enterprise Scale.
    כיצד אם כן מערכות אבטחה רבות משתמשות במודל זה? התשובה שלי היא שאנשי אבטחה רבים סובלים ממודל מסובך שקשה לנהל ולעקוב אחריו. עבור כמה מקרים – המודל היה מוצלח, ועבור רבים אחרים – הוא נבחר מ\"סיבות היסטוריות\".

    מודל ה PBA יכול גם לסבול מבעיות software scalability קשות, כאשר מספר ה policies עולה. בחלק מהמערכות, \"מקמפלים\" את ה policies לאוטומט שיוכל לבצע את אימות ה policies בצורה יעילה יותר.

    מודל ה Role-Based Authorization

    האמת, שהפוסט הזה היה אמור להיות פוסט קצרצר שמתחיל מנקודה זו בדיוק. חששתי שיהיה חסר לרבים מהקוראים רקע – והוספתי הקדמה מקיפה.

    מודל ה Role-Based Authorization (בקיצור: RBA) הוא מודל נוסף שמנסה לתאר את הארגון וצרכיו, ולא רק להיצמד למבנה המשאבים הטכני.

    במודל ה RBA ממדלים Role (\"תפקיד\") כסט של מטלות (Tasks) לביצוע. אנשים שאמורים לבצע מטלות דומות, לרוב יהיו בתפקידים זהים או דומים. לאותם בעלי תפקידים דומים נותנים סט של הרשאות על משאבים.

    בצורה הפשוטה ביותר ניתן לבטא את מודל ה RBA באופן הבא:

    על פניו נראה שאין פה תחכום גדול: Role נראה כ Group בשינוי אדרת. זוהי אכן הסיבה שרבים מתבלבלים / לא מבינים את מודל ה RBA כראוי. בעצם, יש למודל מספר תכונות שלא ניתן להסיק מהתרשים בלבד:

    סמנטיקה: עצם כך שהקבוצה נקראת \"Role\" מעודדת את המשתמשים לייצר קבוצות ע\"פ התפקידים הקיימים בארגון: { רופאים, אחיות, אחיות בכירות } או { קניין, קניין חוץ, מנהל חשבונות }. צורה זו עוזרת לארגן את המשתמשים בשפה/סמנטיקה מרכזית בארגון – שכולם מכירים ומבינים.

    ריכוזיות: לעתים רבות משייכים את המשאבים ל Role ולא להיפך, כך שאובייקט ה Role הוא בעצם זה ש\"מחזיק\" את ההרשאות. גישה ריכוזית זו עוזרת לעקוב בקלות אחר ההרשאות – במיוחד במערכות מבוזרות בהן המשאבים נמצאים במערכות שונות.

    אחידות: מכיוון שמספר התפקידים בארגון הוא לא מאוד גדול (לא יותר מכמה עשרות, ברוב הארגונים), יחידת ההרשאות (שהן ה Role) הן Coarse-Grained, כלומר: מעט קבוצות המכילות הרבה משאבים.
    לגישה זו יש מספר תוצרים:
    1. למשתמשים תהיה גישה למשאבים שהם לא זקוקים להם (כי עמיתים מקבילים להם היו זקוקים להם לעבודתם). כלומר: ההרשאות הן לא \"מינימליות\".
    2. הרבה יותר קל ופשוט לנהל את ההרשאות:
      1. אם ל\"רופא\" אחר יש הרשאה למשאב, מספיק שאוסיף אותך ל Role \"רופא\", כדי שתקבל \"אותן הרשאות. \"שכפול הרשאות\" הוא פעולה דיי מסובכת עד בלתי-אפשרית במערכת שמנהלת הרשאות כ ACLs. 
      2. כשעובדים מבצעים מעברי פרויקטים / תת-תפקיד, סיכוי גבוה שההרשאות שמוגדרות להם עכשיו – מספיקות. ==> תחזוקה קלה.
      3. מכיוון שיש מעט קבוצות, והן מתמפות ל\"שפה הטבעית של הארגון\", למי שמגדיר את ההרשאות ברור הרבה יותר טוב למי הן מיועדות.
      4. כאשר רוצים לבצע סקירה של המשאבים שזמינים לרופאים, קל מאוד לבדוק את ה Role של הרופאים ולראות מה זמין להם.

    בואו נבחן את המודל:

    1. \"האם ניתן להבין בקלות מה בדיוק משתמש x מורשה לעשות?\" – כן. ה Role מוכר בארגון ויש הרבה נקודות התייחסות.
    2. \"כאשר אני מספק למישהו הרשאה, האם קל להבין למה בדיוק אני מספק לו הרשאה?\" – כן, ניתן לסקור את ה Role בקלות ולמצוא את כל המשאבים. סביר שהמשתמש מכיר את המשאבים כי הוא בעצמו חבר ב Role.
    היכן ניתן למצוא את המודל?
    שרתי ווב, JEE, Windows, .NET, מערכות שונות של SAP, Oracle, IBM ועוד.
    סה\"כ מודל ה RBA נחשב כ \"Best Practice\" בתעשיית ה Enterprise וכמודל מוצלח במיוחד. הוא מספק פשטות ניהול שהיא הדרך הכמעט-יחידה של ארגון לשלוט ולהבין אילו הרשאות יש לעובדים, מבלי לטרטר אותם יותר מדי. 
    הנה גרסה מעט יותר מורכבת של המודל (בכדי לסבר את העין):

    כמובן שלמודל ה RBA יש גם כמה חסרונות:
    1. המודל לא מספק שליטה במידע רגיש שאמור להיות זמין לקבוצה קטנה של אנשים. במקרים אלו מספקים מודל הרשאות נוסף (למשל: ACL למשאבים רבים – כמו קבצים, PBA למקרים רוחביים / מופשטים כמו Ethical Wall [ב]) על גבי קבוצה מסוימת של משאבים ב Role, כלומר: מגבילים חלק מהמשאבים המשויכים ל Role לתת קבוצה של ה Role.
    2. מה קורה בארגון שבו אין בעלי תפקידים ברורים? ארגונים בהם מידע מוגש על בסיס \"need to know\"? – מודל ה RBA פשוט לא מתאים.

    סיכום

    הפוסט הזה הוא מעין ניסוי עבורי: לגעת בנושא לא שגרתי, לא-טרנדי ולא קל-סקסי אך בהחלט רלוונטי לארכיטקטורה ושעשוי להיות שימושי בעת תכנון מערכות.
    סקרנו את המודלים הנפוצים של ניהול ההרשאות וניסינו להבין את החוקות / חולשות של כל אחד ומתי הוא מתאים.
    לפני שאתם ממציאים מודל הרשאות חדש למערכת שלכם – כדאי לחזור ולהיזכר במודלים הסטנדרטיים / המקובלים.

    שיהיה בהצלחה!

    ליאור

    [א] הנה הסבר מוצלח בנושא: https://crackstation.net/hashing-security.htm

    [ב] המקרה בו 2 בעלי תפקידים לא מורשים לגשת למידע אחד של השני מסיבות אתיות. לדוגמא: משרד עו\"ד שמייצג שתי חברות מתחרות בתיקים שונים. עדיין, אסור לעו\"ד שמייצג את חברה א\' למצוא מידע על החברה המתחרה ב\'.

    שלום, אנגולר! (Angular.js)

    לפני כשנה, כתבתי סדרת הפוסטים על MVC בצד הלקוח, והתמקדתי ב 3 ספריות:

    • Backbone
    • Knockout
    • Ember
    הזכרתי, כדרך אגב, את Angular.js של גוגל, שנראתה לי אז עוד אחת מיני רבות.
    במהלך השנה האחרונה, Angular הפכה לסופר-פופולרית: שנייה לאחר Backbone ע\"פ Github, וכנראה ראשונה בקצב הצמיחה והחשיפה התקשורתית. ייתכן והיא הייתה מספיק משמעותית גם לפני שנה – ופספסתי זאת.

    במשך זמן רב, הייתי שרוי תחת מסתורין: שמעתי חצאי-אמירות לגבי אנגולר, אך לא הצלחתי להרכיב מהן תמונה מציאותית / יציבה: מהי בעצם אנגולר ומה היא עושה. 

    בפוסט זה אני רוצה לבצע הכרות זריזה עם אנגולר (Angular), הספרייה שכולם מדברים עליה, ולהציג תמונה מציאותית (אפילו אם חלקית) על אופייה.
    משמעות המילה Angular = בעל פינות או זוויות חדות. אולי השם בא לבטא של Angular יש תפיסות חד-משמעיות?!

    אז מה היא אנגולר (AngularJS)?

    בכדי לענות על השאלה לעומק, נדרשים כנראה 3-4 פוסטים, אבל הנה כמה נקודות מעניינות:
    • אנגולר היא ספריית MVC בצד הלקוח. היא כוללת מודל, View, Controller ו Services.
    • בניגוד ל Backbone וכמו אמבר – זוהי ספרייה בעלת דעה ברורה, שלקחה החלטות עבור המשתמש. המשמעות: פחות שורות קוד שיש להקליד – אך גם פחות גמישות.
    • בניגוד לספריות אחרות, ובצורה דיי ייחודית, אנגולר משתלבת בצורה \"טבעית\" למדי בתוך ה HTML, במקום לייצר (כמו ספריות אחרות) הפשטות מעל ה HTML.
    • אנגולר נכתבה בראייה מרכזית של בדיקתיות (Testability). ניתן לכתוב לה בקלות בדיקות יחידה[א], ניתן לכתוב לה בקלות בדיקות אינטגרציה/מערכת. זו לא טענה שקל לטעון בעד אמבר (EmberJS) – למשל.
      אנגולר היא ספריית-האם של Karma (כלי מצוין להרצת בדיקות בג\'אווהסקריפט, שאנו משתמשים בו בלי-קשר).
      בכדי לתמוך בבדיקות יחידה, אנגולר כוללת מנגנון Dependency Injection [ב] מובנה.
      כל אלה = כבר סיבה טובה להעריך את אנגולר!
    • אנגולר אינה תלויה בשום ספריה אחרת, והקהילה שלה בעצם מעודדת אי-שימוש ב jQuery. היא כוללת תת-ספריה שנקראת jQuery Light המספקת כמה יכולות בסיסיות מקבליות ליכולותיה של jQuery ובתחביר דומה מאוד.
    • אנגולר תואמת AMD, אם כי לא ל require.js.
    • לאנגולר יש אינטגרציה עם ספרייה \"לוהטת\" אחרת: Twitter Bootstrap.
      אנגולר לא מייצרת UI עשיר ויפה (אלא רק Markup – ממש כמו ספריות MVC אחרות). Bootstrap משלימה גם את היופי וגם מתאימה לפילוסופיה של אנגולר. השלמה זו צריכה לעבוד יפה גם עם אלטרנטיבות ל Bootstrap כמו Foundation, Neat, Pure או Semantic.
    • לאנגולר מנגנון Two-Way Data-Binding יעיל (פרטים בהמשך).
    • לאנגולר יש מנגנון Templating ייחודי משלה (פרטים בהמשך).
    • ה \"Sweet Spot\" של אנגולר היא אפליקציות עסקיות, ואפליקציות CRUD בפרט (הזנת ושליפת נתונים). אנגולר לא מתאימה, למשל, למשחקים או ל UI לא-שגרתי.
    • אנגולר פופולרית: אנגולר היא ה \"A\" ב \"MEAN\" – סט טכנולוגיות פופולרי שמתתעד להיות התחליף המודרני ל LAMP.
    • אנגולר איננה פשוטה כמו Backbone, לוקח זמן ללמוד אותה ולהתמצא בפרטים.
    • אנגולר טוענת שהיא \"Forward Looking\" ומיישמת היום תקני ווב עתידיים / נראית כמו שהווב יראה עוד כמה שנים.
      יש דיבורים על כך שספרייה חדשנית אחרת של גוגל, Polymer, תשתלב לבסוף באנגולר.
      אני לא מתייחס לטיעונים האלו ברצינות, אנו יודעים למי ניתנה הנבואה…
    • אנגולר היא מבית גוגל, מה שאומר שיש מאחוריה מפתחי ווב מוכשרים אבל גם מנגנון יחסי-ציבור חסר-תקדים. פרויקטים של גוגל נוטים לעשות המון באזז עוד לפני שהם באמת הצליחו, מה שמותיר ספק אם לאנגולר צפוי מחזור חיים דומה לזה שהיה ל GWT.
    הנה דוגמה המשבחת את אנגולר ומראה כיצד מעבר מ BB לאנגולר צמצם בצורה משמעותית את כמות הקוד. הגיוני.

    שלום עולם!

    בואו נראה דוגמת קוד קטנה באנגולר:

    1. שימו לב שדף ה HTML באנגולר הוא משמעותי. ראשית הוספנו סקריפטים – כמו כל דף HTML.
      נכון, היה יעיל יותר להוסיף את תגיות ה script לאחר ה , דילגתי על שיפורי ביצועים לצורך פשטות הקוד.
    2. בתוך ה body הוספתי H1 והגדרתי את HelloWorldCtrl כקונטרולר האחראי על אזור זה (תג ה H1). הסיומת Ctrl מקובלת באנגולר לסימון קונטרולרים. צירוף האותיות ng משמש לכל ה properties / תגיות שאנגולר מוסיף ל HTML.
      אנגולר, במקום לבצע הפשטה של ה DOM/HTML – מרחיב אותו. קידומת ה data היא רשות אם אתם רוצים לשמור את קובץ ה HTML שלכם תקני. ניתן (ומקובל) להשתמש פשוט בקיצור, כגון ng-controller, וכך לחסוך קצת הקלדה [ג].
    3. בתוך תגית ה HTML הכנסנו ביטוי בשם message. אם עבדתם פעם עם mustache – אתם מכירים את השפה: סוגריים מסולסלים כפולים עוטפים ביטוי שיחושב.
    4.  באופן דומה למדי, גם הביטוי {{1 + 1}} יחושב. הבדל קטן: הוא לא דורש context (באנגולר נקרא: scope) בעוד הביטוי {{ message }} דורש context – והוא יקבל אותו מה controller האחראי על האזור.
    5. קוד הג\'אווהסקריפט שלנו פשוט למדי: הגדרנו קונטרולר (התאמה ע\"פ שם) שברגע ההפעלה שלו רושם על ה context/scope ערך בשם message. קידומת $ למשתנים (קרי scope$) מסמלת שאלו משתנים מיוחדים של אנגולר.
    6. כשספריית אנגולר נטענת, אנגולר מפענח את ה DOM ומחפש אחר תוית data-ng-app/ng-app. תוית זו מסמנת את אזור האפליקציה של אנגולר. אפליקציות אנגולר יכולות להתארח או לחיות זו לצד זו.
      לאחר מכן אנגולר ימשיך לפענח את ה DOM וימצא את data-ng-controller.
      בשלב הבא הוא יאתחל את ה controller ואז בעזרתו יחליף את {{ message }} בביטוי הרצוי.
    הנה התוצאה המדהימה של האפליקציה שלנו:
    כפי שאתם רואים, אנגולר \"התעסקה\" לנו ב HTML markup:

    זו חלק מהשיטה.

    סיכום ביניים:

    • ה HTML הוא מרכזי בפתרון. לא כמו Backbone שמעדיפה HTML עם DIV אחד ריק.
    • Controller הוא מעין \"מנהל אזורי\"
    • חלק משמעותי מהכתיבה באנגולר (ה View / HTML) – הוא דקלרטיבי.

    שלום עולם 2: Data-Binding דו-כיווני

    קשה להגדיר את הדוגמה הקודמת כדוגמה מייצגת אפליקציית אנגולר – רק בגלל שאנגולר היא מקיפה ולה כלים רבים. הדוגמה הבאה תשלים אזור חשוב מאוד באנגולר: ה 2WDB (קיצור של Two-Way Data Binding).

    2WDB אומר בקיצור:

    • ברגע שמעדכנים את המודל – ה View מתעדכן אוטומטית.
    • ברגע שמעדכנים את ה View – המודל מתעדכן אוטומטית.
    • (אין מה לדאוג: אין לופ אינסופי)
    מנגנון זה הוא אחד מ\"חוסכי הקלדת ה boilerplate code\" הגדולים של אנגולר באפליקציות CRUD: רישום לאירועים ועדכון מודלים או Views – קוד טכני שאין בו הרבה חוכמה.

    בואו נתבונן בדוגמה הבאה:

    1. קישרנו את שדה ה input ל מודל בשם message. היכן \"מחלקת המודל\" בקוד ג\'אווהסקריפט? – לא קיימת, במקרה זה היא implicit.
    2.  הביטוי {{message}} נמצא בתחום השיפוט של השליט האזורי – הרי הוא ה HelloWorldCtrl. המודל שהגדרנו בשלב 1, מתיישב על ה scope$ של הקונרטולר כפרמטר ובו הערך של שדה ה input. הגדרת HTML זו בלבד (ללא קוד הג\'אווהסקריפט) מספיקה בכדי לייצר databinding עובד. הנה לינק לדוגמה עובדת, ללא כל קוד ג\'אווהסקריפט.
      כאשר לא מוגדר controller, אזי ה binding ייעשה על ה scope$ הגלובאלי.
    3. ביצעו אתחול של הטקסט לערך התחלתי.
    4. הוספנו האזנה (watch$) על המודל של ה message. כל פעם שיש שינוי נמיר מופעים של האות e ל UpperCase. שימו לב שבעקבות ה 2WDB, הערך ההתחלתי שקבענו (\"!Hello World\") כבר עובר טרנספורמציה. הנה דוגמת קוד חיה. נסו להקליד e קטנה בתיבת הטקסט ותראו מה קורה.

    כל שינוי שנעשה ב View (תיבת הטקסט) משפיע על המודל (אובייקט ג\'אווהסקריפט בזיכרון, במקרה שלנו הוא בלתי-מפורש). בקונטרולר אנו מנטרים את השינוי במודל (watch$) ומבצעים בו שינוי נוסף – שחוזר ומעדכן את ה View (תיבת הטקסט). זהו ה 2WDB של אנגולר.

    ה Directive

    אחד המרכיבים המסתוריים של אנגולר הם ה Directives, בואו נציץ בהם ונראה במה מדובר.
    בוודאי שמתם לב שהשתמשנו בתגיות HTML ו Properties שאינם קיימים ב HTML5, כל ה *-ng.
    אנגולר מרחיבה את שפת ה HTML [ד] בשפה משלה, ובעצם מעניקה למפתח את היכולת להמשיך ולהרחיב את שפת ה HTML.

    איך בדיוק זה עובד? – מעקב אחר ה LifeCycle המלא הוא מעבר להיקף של פוסט זה [ה], אך אספק הסבר קצר, ואני מניח שרוב הקוראים יצליחו להרכיב תמונה מהירה ולא רחוקה מהמציאות של מה שמתרחש.

    לאנגולר יש Compiler (רכיב מרכזי) שסורק את ה HTML (הקיים והמתעדכן) ומבצע בו שינויים. אם הוא מזהה תגית לא סטנדרטית, למשל \"lb-superlink\", הוא יחפש רכיב (מעין \"plugin\" לקומפיילר) שמתאר את האלנמט הזה ויאמר לו מה לעשות. רכיב כזה נקרא Directive.

    מספר directives מסופקים, מהקופסא, עם אנגולר: למשל ng-repeat – רכיב שיכפיל קטע markup לכל רכיב ברשימה שמופיעה במודל (למשל: lineItems).

    מתכנתים יכולים להרחיב ולכתוב directives בעצמם. הנה קוד של directive פשוט למדי, ה (Superlink (tm – תגית המספקת טקסט אסתטי שניתן ללחוץ עליו :

    1. lb-superlink הוא הדירקטיב (directive) שמיד נגדיר. בעת לחיצה על הלינק – תופעל הפונקציה ()foo.
      כפי שניתן לראות, ה IDE מזהיר אותי שזה אלמנט לא סטנדרטי ב HTML.
    2. כפי שציינו בהקדמה, אנגולר תואמת למערכת המודולים של AMD. בחרתי בדוגמה זו להראות קוד קצת יותר \"מציאותי\", אשר מארגון את הקוד סביב המודול myModule.
    3. על דירקטיב (directive) להיות מוגדר עם שם camelCase, כאשר אנגולר מפרק את השם ליחידות ותאפשר מספר צורות של תחביר ב HTML לגשת לדירקטיב שהוגדר. למשל, שמו של ng-repeat הוא בעצם \"ngRepeat\" (בצורת camelCase) וניתן גם לקרוא לו בצורות כגון ng_repeat, ng:repeat או data-ng-repeat.
      באופן דומה יהיה ניתן להפעיל את הדירקטיב שלנו בצורת lb-superlink, lb_superlink וכו\'.
    4. התחביר ליצירת אובייקטים שהם instantiated באנגולר הם ע\"י פונקציה המחזירה אובייקט Prototype (כלומר: תבנית העיצוב בשם Prototype), המוגדר בתוך ה return. זהו תחביר קיים (אם כי לא מאוד נפוץ) להגדרת מחלקות בג\'אווהסקריפט.
    5. restrict מגדיר כיצד יהיה ניתן להשתמש בתוך ה HTML בדירקטיב שלנו. \"E\" הוא קיצור של אלמנט, קרי . אם היינו כותבים \"AE\" היה ניתן להגדיר את הדירקטיב גם כ attribute על אלמנט קיים קרי .
    6. ה template מתאר את ה markup שהדרקטיב שלנו ייצר. בחרנו ב div פשוט עם label עבור accessibility. עוד פרטים – בהמשך.
    7. כאשר replace הוא אמת – התג המקורי יוסר מתוך ה HTML ע\"י הקומפיילר. ניתן להשאיר את התג הקיים או להחליף אותו.
    8. transclude אומר שאנו רוצים לקחת ערכים מתוך התג המקורי ולהציב אותם בתוך התג כ ng-transclude ב template. במקרה שלנו: תג ה label.
    9. link הוא ערך חשוב. הוא בעצם פונקציית ה processing שתופעל בנוסף לפעולות הסטנדרטיות שהוגדרו ע\"י ה properties הנ\"ל. כאן אנו יכולים לכתוב קוד ג\'אווהסקריפט חופשי משלנו. במקרה שלנו אנו מבצעים bind לארוע לחיצה על האלמנט שנוצר. השתמשנו כאן ב jQuery Light שמגיע עם אנגולר (\"bind\"). כפי שניתן לראות – התחביר דומה מאוד.
    10. קוד זה (eval=evil) נראה קצת פחות אסתטי, אך הוא מקובל באנגולר. אנו קוראים את ערך ה attribute בשם click (במקרה שלנו: \"()foo\"), ומבצעים לו eval, במסגרת ה scope הרלוונטי לאלמנט. בת\'כלס אנו מפעילים את פונקציית foo שהוגדרה על ה scope$ של הקונטרולר.
    הנה ה markup שנוצר (כפי שאתם זוכרים, אנגולר \"מעשיר\" את ה markup בביטויים כגון ng-scope):

    סיכום

    עשינו סקירה + צלילה-מהירה לתוך אנגולר, ספרייה שתופסת לאחרונה תשומת לב וקהל מעריצים רב. ברור שנותר רב נסתר על הגלוי, אל אני מקווה שהצלחתי בקריאה של 5 עד 10 דקות להסיר חלק מהמסתורין מסביב לאנגולר לאלו שאינם מכירים. נראה לי חשוב ומעניין להכיר, אפילו במעט, ספרייה שמשפיעה במידה לא-מבוטלת על עולם ה FrontEnd.
    שיהיה בהצלחה!

    —-

    [א] אם אתם רוצים לקרוא מעט יותר על בדיקות יחידה: על בדיקות יחידה.

    [ב] אם אתם רוצים לקרוא מעט יותר על Dependency Injection: להבין Dependency Injection.

    [ג] בעצם, אנגולר הפרה את תקן ה HTML5 לאורך זמן, ורק לאחרונה הוסיפה את האופציה להוסיף קידומת -data ולציית לתקן.

    [ד] אנגולר מתבססת תקן עתידי של Custom Elements, שאם יתוקנן כמתוכנן – יהפוך את התחביר של אנגולר ל HTML5 תקני.

    [ה] תוכלו להתעמק בנושא לא-פשוט זה בעזרת מדריך ה Directives של אנגולר: http://docs.angularjs.org/guide/directive

    לינקים אחרים

    הרבה תוכן מעמיק על אנגולר, גם בעברית, בבלוג של אייל ורדי

    סיכום של שנתיים עבודה עם אנגולר, ע\"י Alexey Migutsky

    Weekly על אנגולר, שכולל בערך אינסוף לינקים (לא סתמיים) בנושא: http://syntaxspectrum.com/

    להבין גיט (Git)

    Git הוא כלי לניהול גרסאות (Version Control System) הפופולרי למדי בימים אלו.
    בניגוד ל (Subversion (SVN או Perforce שהם כלים בעלי ניהול מרכזי, ל Git יש ניהול מבוזר.משמעות אחת היא שבמקום שיהיה איש Operations מאחורי הקלעים שינהל את שרת ה SVN ויחסוך חשיבה למתכנתים ברוב הסוגיות הקשורות ל Source Control – כעת על המפתחים לדאוג לנושא זה בעצמם (לפחות במידה מסוימת).

    משמעות אחרת היא שיש למפתחים יותר כוח לנהל את הקוד בצורה הטובה להם, לבצע פיתוחים ו merges הדרגתיים ובסה"כ להתנהל בצורה יותר יעילה.

    היעילות ב Git לא מגיעה מייד. החוויה הראשונה היא כנראה שלילית לרבים המפתחים: מפתח שלא היה טרוד בענייני ה Source Control צריך לפתע פתאום ללמוד נושא חדש ולהגיע בו לרמה סבירה. השימוש ב Git הוא מורכב יותר ודורש לא-מעט אימון והעמקה. כל התהליך יכול לקחת כמה חודשים טובים.

    בסה"כ Git (וכלי ניהול גרסאות מבוזרים בכלל) נחשב לתומך בפיתוח Agile המאפשר גמישות לנהל releases שתוכנם נקבע בשלב מאוחר, לעבוד בשיתוף עם מפתחים אחרים – מבלי להפריע לשאר המפתחים, לבצע שינויים משמעותיים בבסיס הקוד, ועוד. במקרים רבים ארגונים מאמצים Git בעיקר בכדי "לזרז את ה Agile".

    בפוסט זה אנסה להסביר את המבנה / התנהגות של גיט קצת יותר לעומק – באופן שייסע להגיע לשלב הפרודקטיביות בכלי.

    גיט הוא פשוט להיט!
    מקור: סקר המפתחים של אקליפס 2013

    קצת הגדרות

    כשלומדים גרמנית (ניסיתי), מהר מאוד מזהים את הדמיון שלה לאנגלית:
    Ich bin Lior, משמעו: I am Lior.
    Das ist gut, משמעו:  This is good.

    מצד שני הדמיון גם מטעה, וגורם לנו להניח הנחות שגויות – שיבלבלו אותנו (אדלג על הדוגמאות 🙂 ). גיט היא אותו הדבר. אם אתם מגיעים מ SVN, Perforce או כלי דומה – כמה מהמונחים ישמעו לכם מוכרים מייד. היזהרו מהנחות אלו ונסו לא לקפוץ מהר למסקנות.

    תיקיית גיט על המחשב בה יש עותק של פרויקט נקראת "Git Repository". כל Repository (כלומר: בכל מכונת פיתוח) כולל את ההיסטוריה, של כל הקבצים מאז שהפרויקט נוצר. אל דאגה: גיט דוחס את המידע ומאכסן אותו בצורה יעילה כך שהוא לא תופס הרבה מקום. בשל העבודה שה Repository הוא מקומי על הדיסק שלכם – תגלו שגיט מהיר באופן מורגש מ Repository מרכזיים שעבדתם איתם בעבר.

    ה Commit Graph בגיט, מורכב מה commits השונים (ריבועים בציור למעלה) – כל אחד כולל snapshot של כל הפרויקט ברגע מסוים, וחצים – המייצגים קשר בין commits. למשל: B הוא בן של A: מישהו עבד על A, שינה אותו ואז ביצע commit ל B.

    Branch בגיט מוגדר כשרשרת כל parent commits של ה tip (קצה) של ה Branch. כלומר:

    • ה release Branch מכיל את A, B, C, E, G, H.
    • ה master Branch מכיל את A, B, C, D, F, I, J, K. כן, commits יכולים להיות חברים ביותר מ Branch אחד.
    • ה topic Branch מכיל את A, B, F, I, L, M.

    בד"כ נעבוד על ה Tip של ה Branch ולא על commits שנמצאים בהיסטוריה שלו.
    ה Branch הראשון שנוצר ב Git Repository נקרא master, אולם הוא לא שונה במאומה מכל מכל branch אחר שתיצרו מאוחר יותר – זה רק שם ברירת-מחדל.

    גיט מקומי וגיט מרוחק

    יש טעם לעבוד על גיט מקומי-בלבד, נאמר: כאשר שאר הצוות שלכם עובד על SVN ואתם רוצים Repository שלכם שישמור את השינויים שעשיתם כל 5 עד 30 דקות של עבודה.
    אם אתם לא רגילים לגיט, לבצע commit כל כמה דקות נשמע מוזר – אבל זה עניין שמתרגלים אליו :).

    כמובן, שהייעוד העיקרי של גיט הוא עבודה בצוות. גיט מאפשר לשתף עבודה בין Repositories:

    פעולת ה "clone" תשכפל את ה Repository המרוחק ותייצר Repository מקומי זהה על המחשב שלכם. זהה = מכיל את כל הקבצים, כל ה Branches וכל ההיסטוריה מרגע יצירת הפרויקט.

    פעולת Push דוחפת (commit(s מה Repository שלכם למרוחק ו Pull מביאה (commit(s מה Repository המרוחק אליכם.

    ניתן לעבוד עם גיט בצורה מבוזרת לגמרי, אולם כל המימושים שאני ראיתי עד היום (דיסקליימר: מפתחים שהגיעו לגיט מ SVN או Perforce) כללו Repository מרכזי עליו כל המפתחים מסנכרנים את הקוד. לא שונה משרת המרכזי של Perforce, למשל.

    לגיט יש עקומת למידה לא-קלה

    שכבת ה Persistence של גיט

    שכבת אכסון הנתונים של גיט ידועה בשם The Object Store או Object Database. את התוכן שלה ניתן למצוא בפועל תחת הספרייה git/objects.(בעקבות פעולת git clone נוצרת תיקייה נסתרת בשם "git." ב path בו התבצעה הפעולה).
    ה Object Store מאכסן 4 סוגים של אובייקטים. הנה הקשרים הלוגיים ביניהם:

    האובייקט הבולט ביותר הוא כמובן אובייקט ה Commit, המשמש כ Aggregator לתת העץ של כל הספריות והקבצים באותו ה Commit.
    ה Commit מצביע לעץ (Tree) אחד, שהוא ה Root Directory של תתי-הספריות (עצים) וקבצים (BLOBs) שהם חלק מה Commit.

    הערת צד: בוודאי מטרידה אתכם השאלה כיצד ענף (Branch) יכול להכיל משהו (Commit) שמצדו מכיל הרבה עצים (Trees) – הרי "ענף" הוא חלק מה"עץ". יש לכך 2 תשובות:

    1. Branch הוא ענף של ה "Commit Graph"', בעוד עץ (Tree) הוא ספרייה במערכת הקבצים של ה Commit הנוכחי.
    2. זו אכן טרמינולוגיה מבלבלת – היה עדיף לקרוא ל Tree פשוט Directory או Folder, על אף הקונוטציה הלא-רצויה למערכת ההפעלה חלונות (רחמנא ליצלן).

    כל BLOB ב Object Store מייצג קובץ, יהיה זה קובץ קוד (למשל java.) או קובץ נתונים אחר (למשל תמונה בפורמט png.). תוכן הקובץ עובר פונקציית Hash בשם SHA-1 המייצרת מספר בן 160bit המתאר את תוכן הקובץ. פונקציית SHA-1 היא פונקציית hash בעלת פיזור אחיד למדי (מקורה בעולם האבטחה) – ואנו מניחים שהיא מזהה תוכן של קובץ באופן ייחודי. ב UI של גיט נראה את ה hash בייצוג הקסדצימלי, למשל:

    12cfb1862b23356523d88127fa5d5aeb333950

    לעתים נראה קיצור של ה hash בצורת 7 הספרות הראשונות שלו – לרוב זהו ייצוג ייחודי דיו בכדי לזהות אובייקט בצורה אמינה (וגם: קל הרבה יותר להקלדה).
    גיט מזהה כל קובץ ע"פ התוכן שלו (לא ע"פ שם הקובץ, סיומת או תאריך) – כלומר, ע"פ ה hash שלו. זאת אומרת ש Tree בעצם מכיל רשימת hashes של קבצים, המתארת את הקבצים בספרייה, ומייצא בעצמו hash של ערכים אלו. ה Commit מקבל ה hash המחושב מה hash של תיקיית ה root של הפרויקט + כמה שדות.

    אם הקובץ(כלומר התוכן, בפנים) לא השתנה, אזי ה hash שלו יישאר זהה, וגיט לא תאכסן עותק חדש שלו ב Object Store. מספיק שביט אחד בקובץ השתנה (למשל: ריווחים בקוד) בכדי שעבור גיט זה יהיה אובייקט BLOB חדש לגמרי, בעל hash שונה לחלוטין שמאוחסן בשלמותו (ולא deltas).

    הערת צד: שמירת עותקים שלמים של קבצים היא החלטת Design של גיט הכוללת Tradeoff בין נפח אכסון ליעילות. כלי ניהול גרסאות רבים אחרים בחרו את האופציה השנייה. שווה לציין שהיתירות (redundancy) במקרה זה מגבירה את האמינות. אם היינו מחזיקים רק diffs, ו diff מסוים בשרשרת היה נפגם – היינו מאבדים את כל המשך השרשרת מאותו הרגע. באופן לא-מפתיע למדי, ניתן לראות דמיון רב בין החלטות התכנון של גיט ל פילוסופיית התכנון של יוניקס.

    באופן דומה, העצים הם hash של כל ה hashes של העצים / קבצים שהם מכילים. אם כל הקבצים בתת-עץ לא השתנו, אזי אובייקט ה Tree שמייצג אותם יישאר עם אותו ה hash וכן הלאה.
    זיהוי אובייקטים ע"פ hash מאפשר לגיט לבצע השוואות מהירות בין אובייקטים ובין תתי-עצים של אובייקטים: פשוט יש להשוות בין שני hashes.

    כמה properties חשובים על אובייקט ה Commit:


    commit message

    הערת טקסט המסבירה מה כולל ה commit.
    parents
    מצביעים ל commits אחרים, קשר המגדיר את ה Commit Graph.
    • אם ל commit יש יותר מהורה אחד (ניתן 3 או יותר) – אזי זהו merge בין ענפים (branches).
    • אם ל commit אין parents, אזי ה commit הזה הוא ה Root Commit (ראשית ה Repository) או orphan commit – מין אופציה מתקדמת בגיט לייצר branch חדש עם קוד שלא קשור לענפים הקיימים ב Repository.


    committer vs. author

    לרוב ה committer וה author יהיה אותו אדם, מלבד כמה מקרים בהם מישהו מבצע commit מחודש לקוד שמישהו אחר עשה לו commit בעבר.
    דוגמה אחת לכך היא cherry-pick, היכולת לקחת שינויים של commit ולהעתיק רק אותם (כלומר: את השינויים) ל branch אחר. יכולת זו היא רבת-עוצמה כאשר רוצים להעביר בין ענפים תיקוני-באגים. יכולות אחרות הן filter-branch ("שכתוב היסטוריה") ו rebase (חיתוך ענף, והדבקה שלו במקום אחר). במקרים אלו יהיה ניתן להבחין בין האדם שביצע את הפעולה (committer) לבין ה committer של הקוד המקורי (author).

    ה Index

    תהליך העדכון קבצים ל Git Repository מתבצע בשני שלבים:

    1. עדכון ה Index (נקרא גם "Staging Area" או "Directory Cache") בעדכון.
    2. ביצוע העדכונים מתוך ה Index ל Repository.
    תהליך דו-שלבי זה נוצר בכדי לאפשר למתכנת לבצע Review על השינויים שלו ולשלוט מה בדיוק נכנס ל Repository.

    האינדקס יכול להיות מבלבל לפעמים: רבים מדמיינים אותו כ snapshot הנוכחי של הפרויקט – אבל זה לא המצב. ה snapshot הנוכחי של הפרויקט לא מנוהל ע"י גיט – גיט סורק את תיקיות הפרויקט ברגע שהוא צריך (למשל: בעת הפעלת פקודת git status) כדי לדעת מה השתנה.

    האינדקס הוא מבנה נתונים נוסף של גיט, שמנותק ממצב הקבצים במערכת הקבצים (נקרא בעולם הגיט "Working tree)" ו/או מה Commit האחרון. הוא פשוט מילון של pathnames ו hashes של אובייקטים ב Object Store, כלומר .

    כאשר אנו מבצעים פעולת git status (או git status –short), או רואים השוואה בין התיקייה המקומית והאינדקס.
    בשלב הראשון גיט יציג לנו קבצים שהשתנו במערכת הקבצים, אבל לא מנוהלים ("tracking") ע"י האינדקס:

    הערה: git stat הוא alias שיצרתי לפקודה git status –short. לא נראה לי הגיוני שהגרסה הקצרה של הפקודה, ארוכה יותר להקלדה מהגרסה הארוכה של הפקודה. לכן יצרתי ה alias באופן הבא:

    git config –global alias.stat "status –short"

    ברגע שנבצע פעולת git add לקבצים – הם ייווספו לאינדקס:

    • ה pathname יזכור איזה קובץ במעקב.
    • תוכן הקובץ, כפי שהוא באותו הרגע, ישמר כ BLOB ב Object Store וה hash של אותו BLOB יישמר באינדקס.
    הנה:

    כעת אני רואה שהקובץ התווסף לאינדקס (עמודה ירוקה, A הוא קיצור של Add).
    כדי לראות אלו קבצים נמצאים באינדקס – פשוט הקלידו git ls-files.

    כמה דקות לאחר מכן אני מבצע git stat ומקבל את המצב הבא:

    מה זה המצב הדו-פרצופי הזה – מישהו יודע?
    הקובץ השתנה או התווסף? מדוע אדום וירוק יחדיו?

    מה שקרה הוא שגיט השווה בין תוכן הקובץ (ה hash שנוצר) במערכת הקבצים, לזה שמתואר ע"י האינדקס ושמור אצלו ב Object Store. הקובץ השתנה. גיט מדווח בצבע ירוק את המצב ב Object Store (הקובץ נוסף) ובאדום את המצב בדיסק (הקובץ השתנה, יחסית ל Object Store).

    אם נבצע git commit בשלב זה, העותק שהוספנו קודם לכן לאינדקס (ונשמר ב Object Store) יכנס ל Repository, בעוד השינויים שביצעו לאחר מכן – יישארו במערכת הקבצים.
    לאחר ה commit, פעולת Git Stat תראה רק את השינוי שבדיסק (הקובץ יוותר במעקב):

    עוד טיפ קטן:

    • פעולת <git rm <filename מסירה קובץ מהאינדקס (כלומר – הוא לא יהיה במעקב) ומהדיסק: זו הדרך להעיף קובץ שאינכם מעוניינים בו מהפרויקט. במילים אחרות: הוסף קובץ להסרה – לאינדקס. בכלל ש rm נשמע ההיפך מ add – זו דרך מצוינת להתבלבל.
    • לצורך הגנה, אם ניסיתם לבצע git rm על קובץ שנעשו בו שינויים – גיט יסרב ויציע לכם להוסיף cached– .לא פעם הקשבתי לעצתו בשמחה – ומחקתי לעצמי כמה שינויים.
    • פעולת <git reset <filename רק מסירה את הקובץ מהאינדקס – זו בעצם הפעולה ההופכית ל git add.
    פתרון אפשרי לבלבול, יכול להיות להגדיר alias בשם remove, שיהיה ההופכי ל add:
    git config –global alias.remove "reset"

    לי זה עזר.

    אם אתם רוצים לבצע היפוך ("revert" בשפת perforce) לשינוי בקובץ, עליכם פשוט לבצע <git checkout <filename. כפי שהזהרתי בהקדמה על השפה הגרמנית – פעולת git revert עושה משהו לגמרי אחר (והרסני).

    ענפים

    הפוסט מתארך, ולכן אסיים בנושא אחרון חשוב לפוסט זה: Branches.

    מהו Branch?
    כבר אמרנו ש Branch מוגדר כאוסף ה commits שניתן להגיע אליהם מה tip (הקצה) של ה Branch.
    הגדרה נוספת ומשלימה הוא ש Branch הוא מצביע ל commit, ומנקודה זו מוגדר ה branch.

    גיט מחזיק במבנה נתונים נוסף: refs (קיצור של References, נקרא גם Pointer לפעמים). יש בגיט 2 סוגי מצביעים:

    • מצביע ישיר, המצביע לאובייקט ב Object Store (לרוב זה יהיה commit או tag).
    • מצביע סימבולי (symbolic ref) המצביע למצביע אחר. משהו כמו symbolic link במערכת ההפעלה.
    גיט משתמש במצביעים כדי לתת שמות / לסמן דברים, ובמקרה שלנו – branches. כל אחד מה branches הוא פשוט מצביע שכזה.
    לעתים יווצר מצב בו ה Repository המרוחק ("origin") יכיל branches שלא קיימים אצלנו. פקודת git pull מייבאת את ה commits – אך לא את המצביעים. פקודת git fetch מייבאת את המצביעים מה Repository המרוחק, מה שיראה אצלנו כ branches ו tags.
    מצביע מיוחד הוא מצביע ה HEAD המסמן את המיקום הנוכחי שלנו ב Commit Graph. כאשר אנו מחליפים branch לעבודה ע"י פקודת <git checkout <branch name אנו מחליפים את HEAD להצביע על commit ו/או branch אחר.
    ייתכן מצב בו HEAD לא יצביע על tip של branch אלא על commit אחר בגרף. מצב זה יתרחש, למשל, בעקבות ביצוע פקודת <git checkout <commit's hash. לאחר פעולה זו גיט יספק הזהרה שאתם במצב של detached HEAD – כלומר HEAD לא מצביע על ה tip commit – ולכן אינו מצביע על branch.
    מצב זה, למרות שנראה מוזר, הוא תקין וניתן לבצע בו commits – מה שיוביל אותנו למצב הבא:

    commit E הוא לא חלק מה branch. ניתן לפתור מצב זה ע"י יצירת branch חדש מהנקודה הנוכחית ע"י
    פקודת <git checkout -b <new branch name ואולי אח"כ לבצע merge בין ה branch החדש ל dev. אם לאחר זמן ממושך לא "תטפלו" ב commits שאינם שייכים ל branch כלשהו – גיט ינקה אותם בתהליך "ניקוי הזבל" שלו.

    סיכום

    יש בערך אינסוף חומר על גיט ברשת. במקום לחזור פעם נוספת על סט של הפקודות של גיט ומשמעותן, ניסיתי להביא מבט קצת יותר טכני על ה internals של גיט ולהסביר כמה מההתנהגויות של גיט בעזרתן. לי נקודת-מבט זו הייתה חסרה – וסייעה רבות ברגע שקיבלתי אותה. נראה שגיט הוא קצת יותר מבאזז רגעי – והוא יישאר עמנו כמה שנים. אני מאמין ששווה להשקיע ולהבין אותו.

    שיהיה בהצלחה!

    —–

    קישורים רלוונטיים

    GitGuys – מקור טוב להבנת המבנה של גיט:
    http://www.gitguys.com/topics/

    Git cheat sheet – רפרנס ויזואלי של הפקודות הנפוצות וההשפעות שלהן:
    http://www.ndpsoftware.com/git-cheatsheet.html#loc=remote_repo;

    UnGit – כלי ויזואלי שעוזר ללמוד גיט:
    https://github.com/FredrikNoren/ungit

    Learn Git Branching – אתר טוב שמציע "משחק" שיסייע לכם לעקוב אחר branching מתקדם בגיט – נחמד מאוד.
    http://pcottle.github.io/learnGitBranching/

    כלי UI טוב מהרגיל לגיט (שומר על השפה של גיט) – SourceTree:

    "A shout out to developers of SourceTree – a nice GUI for git and hg. Useful even for a command-line fan like me. " — Martin Fowler

    לינק מעניין: לינוס מציג את גיט ב 2007.

    אוסף נחמד של מדריכי וידאו לגיט: http://training.github.com/resources/videos/