עבודה עם היקפי הרשאות OAuth2

אתם צופים במסמכי התיעוד של Apigee Edge.
כדאי לעיין במסמכי התיעוד של Apigee X.
מידע

במאמר הזה נסביר איך להשתמש בהיקפי הרשאות של OAuth 2.0 ב-Apigee Edge.

מהו היקף הרשאות OAuth2?

היקפי OAuth 2.0 מאפשרים להגביל את רמת הגישה שניתנת לאסימון גישה. לדוגמה, יכול להיות שאסימון גישה שהונפק לאפליקציית לקוח יקבל הרשאת קריאה וכתיבה למשאבים מוגנים, או רק הרשאת קריאה. אתם יכולים להטמיע את ממשקי ה-API כדי לאכוף כל היקף או שילוב של היקפים שתרצו. לכן, אם לקוח מקבל טוקן עם היקף קריאה (READ) ומנסה לקרוא לנקודת קצה ל-API שנדרשת לה גישת כתיבה (WRITE), הקריאה תיכשל.

בנושא הזה נסביר איך מוקצים היקפי הרשאות לאסימוני גישה ואיך Apigee Edge אוכף היקפי הרשאות של OAuth 2.0. אחרי שתקראו את הנושא הזה, תוכלו להשתמש בהיקפים בביטחון.

איך מוקצים היקפים לאסימוני גישה?

כש-Edge יוצר אסימון גישה, הוא עשוי להקצות לו היקף. כדי להבין איך זה קורה, צריך קודם להכיר את הישויות הבאות ב-Apigee Edge: מוצרי API, מפתחים ואפליקציות למפתחים. למבוא, ראו מבוא לפרסום. מומלץ לעיין בחומר הזה לפני שממשיכים.

אסימון גישה הוא מחרוזת ארוכה של תווים שנראים אקראיים, שמאפשרת ל-Edge לאמת בקשות API נכנסות (אפשר לחשוב עליו כעל תחליף לפרטי כניסה רגילים של שם משתמש וסיסמה). מבחינה טכנית, האסימון הוא מפתח שמפנה לאוסף של מטא-נתונים שנראה כך:

{
  "issued_at" : "1416962591727",
  "application_name" : "0d3e1d41-a59f-4d74-957e-d4e3275d4781",
  "scope" : "A",
  "status" : "approved",
  "api_product_list" : "[scopecheck1-bs0cSuqS9y]",
  "expires_in" : "1799", //--in seconds
  "developer.email" : "scopecheck1-AdBmANhsag@apigee.com",
  "organization_id" : "0",
  "token_type" : "BearerToken",
  "client_id" : "eTtB7w5lvk3DnOZNGReBlvGvIAeAywun",
  "access_token" : "ODm47ris5AlEty8TDc1itwYPe5MW",
  "organization_name" : "wwitman",
  "refresh_token_expires_in" : "0", //--in seconds
  "refresh_count" : "0"
}

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

איך הטוקן מקבל את ההיקף שלו?

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

כשיוצרים אפליקציית מפתחים ומוסיפים לה מוצרים, Edge בודק את כל המוצרים באפליקציית המפתחים ויוצר רשימה של כל ההיקפים של המוצרים האלה (רשימת ההיקפים הראשית או הגלובלית של האפליקציה – איחוד של כל ההיקפים המוכרים).

כשלקוח אפליקציה מבקש אסימון גישה מ-Apigee Edge, הוא יכול לציין אילו היקפי הרשאות הוא רוצה לשייך לאסימון הזה. לדוגמה, בבקשה הבאה מוגדר היקף ההרשאה 'A'. כלומר, הלקוח מבקש משרת ההרשאות (Edge) ליצור אסימון גישה עם היקף הרשאות A (שנותן לאפליקציה הרשאה להפעיל ממשקי API עם היקף הרשאות A). האפליקציה שולחת בקשת POST כזו:

curl -i -X POST -H Authorization: Basic Mg12YTk2UkEIyIBCrtro1QpIG -H content-type:application/x-www-form-urlencoded http://myorg-test.apigee.net/oauth/token?grant_type=client_credentials&scope=A

מה קורה

כש-Edge מקבל את הבקשה הזו, הוא יודע איזו אפליקציה שולחת את הבקשה ואיזו אפליקציית פיתוח הלקוח רשם (מזהה הלקוח ומפתחות הסוד של הלקוח מקודדים בכותרת של אימות בסיסי). מכיוון שפרמטר השאילתה scope נכלל, Edge צריך להחליט אם לאחד ממוצרי ה-API שמשויכים לאפליקציית המפתח יש היקף 'A'. אם כן, נוצר אסימון גישה עם ההיקף 'A'. דרך נוספת להסתכל על זה היא שפרמטר השאילתה scope הוא סוג של מסנן. אם אפליקציית המפתחים מזהה את ההיקפים A,‏ B ו-X, ופרמטר השאילתה מציין scope=X Y Z, רק ההיקף X יוקצה לאסימון.

מה קורה אם הלקוח לא מצרף פרמטר של היקף? במקרה הזה, Edge יוצר טוקן שכולל את כל ההיקפים שהאפליקציה של המפתח מזהה. חשוב להבין שההתנהגות שמוגדרת כברירת מחדל היא להחזיר טוקן גישה שמכיל את האיחוד של כל ההיקפים של כל המוצרים שנכללים באפליקציה של המפתח.

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

נניח שאפליקציית מפתח מזהה את היקפי ההרשאות הבאים: A B C D. זו רשימת ההיקפים הראשית של האפליקציה. יכול להיות שלמוצר אחד באפליקציה יש היקף A ו-B, ולמוצר שני יש היקף C ו-D, או כל שילוב אחר. אם הלקוח לא מציין פרמטר scope (או אם הוא מציין פרמטר היקף ללא ערך), יינתן לטוקן כל ארבעת ההיקפים: A, ‏ B,‏ C ו-D. שוב, האסימון מקבל קבוצה של היקפי הרשאות שהיא איחוד של כל היקפי ההרשאות שהאפליקציה של המפתח מזהה.

יש עוד מקרה שבו התנהגות ברירת המחדל היא להחזיר אסימון גישה עם כל ההיקפים המוכרים, וזה קורה כשבמדיניות GenerateAccessToken (המדיניות של Apigee Edge שמפיקה אסימוני גישה) לא מצוין רכיב <Scope>. לדוגמה, הנה מדיניות GenerateAccessToken שבה מצוין <Scope> is. אם רכיב <Scope> חסר (או אם הוא קיים אבל ריק), תתבצע ההתנהגות שמוגדרת כברירת מחדל.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-GenerateAccessToken">
    <DisplayName>OAuthV2 - Generate Access Token</DisplayName>
    <Attributes>
      <Attribute name='hello' ref='system.time' display='false'>value1</Attribute>
    </Attributes>
    <Scope>request.queryparam.scope</Scope> 
    <GrantType>request.formparam.grant_type</GrantType>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>GenerateAccessToken</Operation>
    <SupportedGrantTypes>
      <GrantType>client_credentials</GrantType>
    </SupportedGrantTypes>
  <GenerateResponse enabled="true"/>
</OAuthV2>

איך נאכפים טווחי ההרשאות?

קודם כל, חשוב לזכור שב-Apigee Edge, אסימוני גישה מאומתים באמצעות מדיניות OAuthV2 (בדרך כלל ממוקמת בתחילת זרימת הנתונים של שרת proxy). במדיניות צריך לציין את הפעולה VerifyAccessToken. בואו נבחן את המדיניות הזו:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope> <!-- Optional: space-separated list of scope names. -->
    <GenerateResponse enabled="true"/>
</OAuthV2>

שימו לב לרכיב <Scope>. הוא משמש לציון ההיקפים שהמדיניות תקבל.

בדוגמה הזו, המדיניות תצליח רק אם אסימון הגישה כולל את ההיקף A. אם הרכיב <Scope> הזה מושמט או אם אין לו ערך, המדיניות מתעלמת מההיקף של אסימון הגישה.

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

נניח של-API שלכם מוגדר תהליך לנקודת הקצה /resourceA:

<Flow name="resourceA">
            <Condition>(proxy.pathsuffix MatchesPath "/resourceA") and (request.verb = "GET")</Condition>
            <Description>Get a resource A</Description>
            <Request>
                <Step>
                    <Name>OAuthV2-VerifyAccessTokenA</Name>
                </Step>
            </Request>
            <Response>
                <Step>
                    <Name>AssignMessage-CreateResponse</Name>
                </Step>
            </Response>
        </Flow>

כשתהליך העבודה הזה מופעל (מתקבלת בקשה עם /resourceA בסיומת של נתיב), המדיניות OAuthV2-VerifyAccessTokenA נקראת באופן מיידי. המדיניות הזו בודקת שאסימון הגישה תקף, ומחפשת את ההיקפים שהאסימון תומך בהם. אם המדיניות מוגדרת כמו בדוגמה שלמטה, עם <Scope>A</Scope>, המדיניות תפעל רק אם לטוקן הגישה יש היקף 'A'. אחרת, תוחזר שגיאה.

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

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

דוגמאות לקוד

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

מקרה ברירת מחדל

נניח שיש לכם אפליקציית מפתחים עם מוצרים, ואיחוד ההיקפים של המוצרים האלה הוא: A,‏ B ו-C. קריאה ל-API זו מבקשת אסימון גישה, אבל לא מציינת פרמטר של שאילתת היקף.

curl -X POST -H content-type:application/x-www-form-urlencoded http://wwitman-test.apigee.net/scopecheck1/token?grant_type=client_credentials

במקרה כזה, לטוקן שנוצר יוקצו ההיקפים A,‏ B ו-C (התנהגות ברירת המחדל). המטא-נתונים של האסימון ייראו בערך כך:

{
  "issued_at" : "1417016208588",
  "application_name" : "eb1a0333-5775-4116-9eb2-c36075ddc360",
  "scope" : "A B C",
  "status" : "approved",
  "api_product_list" : "[scopecheck1-yEgQbQqjRR]",
  "expires_in" : "1799", //--in seconds
  "developer.email" : "scopecheck1-yxiuHuZcDW@apigee.com",
  "organization_id" : "0",
  "token_type" : "BearerToken",
  "client_id" : "atGFvl3jgA0pJd05rXKHeNAC69naDmpW",
  "access_token" : "MveXpj4UYXol38thNoJYIa8fBGlI",
  "organization_name" : "wwitman",
  "refresh_token_expires_in" : "0", //--in seconds
  "refresh_count" : "0"
}

נניח שיש לכם נקודת קצה ל-API עם היקף הרשאות 'A' (כלומר, הפונקציה VerifyAccessToken דורשת את היקף ההרשאות 'A'). זו המדיניות VerifyAccessToken:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

הנה דוגמה לקריאה לנקודת קצה שמחילה את היקף A:

curl -X GET -H Authorization: Bearer MveXpj4UYXol38thNoJYIa8fBGlI http://wwitman-test.apigee.net/scopecheck1/resourceA 

קריאת ה-GET הזו מסתיימת בהצלחה:

 {
   "hello" : "Tue, 25 Nov 2014 01:35:53 UTC"
 }

הפעולה מצליחה כי מדיניות VerifyAccessToken שמופעלת כשקוראים לנקודת הקצה דורשת הרשאה A, ואסימון הגישה קיבל הרשאות A,‏ B ו-C – התנהגות ברירת המחדל.

סינון בקשות תמיכה

נניח שיש לכם אפליקציה למפתחים עם מוצרים בהיקפים A,‏ B,‏ C ו-X. שולחים בקשה לאסימון גישה וכוללים את פרמטר השאילתה scope, כך:

curl -i -X POST -H content-type:application/x-www-form-urlencoded 'http://myorg-test.apigee.net/oauth/token?grant_type=client_credentials&scope=A X'

במקרה הזה, הטוקן שנוצר יקבל את ההיקפים A ו-X, כי שניהם היקפים תקפים. חשוב לזכור שאפליקציית המפתח מזהה את ההיקפים A,‏ B,‏ C ו-X. במקרה כזה, אתם מסננים את רשימת מוצרי ה-API על סמך ההיקפים האלה. אם למוצר יש היקף A או X, אפשר להגדיר נקודות קצה של API שיאכפו את ההיקפים האלה. אם למוצר אין היקף A או X (נניח שיש לו היקפים B,‏ C ו-Z), אי אפשר לבצע קריאות ל-API שדורש היקפים A או X באמצעות הטוקן.

כשמפעילים את ה-API עם הטוקן החדש:

curl -X GET -H Authorization: Bearer Rkmqo2UkEIyIBCrtro1QpIG http://wwitman-test.apigee.net/scopecheck1/resourceX

אסימון הגישה מאומת על ידי proxy ל-API. לדוגמה:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenX">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A X</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

הפעלת ה-GET מצליחה ומוחזרת תשובה. לדוגמה:

 {
   "hello" : "Tue, 25 Nov 2014 01:35:53 UTC"
 }
 

הבקשה מצליחה כי מדיניות VerifyAccessToken דורשת את ההרשאות A או X, ואסימון הגישה כולל את ההרשאות A ו-X. כמובן, אם הרכיב <Scope> היה מוגדר לערך B, הקריאה הזו הייתה נכשלת.

סיכום

חשוב להבין איך Apigee Edge מטפל בהיקפי הרשאות של OAuth 2.0. הנה כמה נקודות מרכזיות:

  • אפליקציית מפתח 'מזהה' את האיחוד של כל ההיקפים שהוגדרו לכל המוצרים שלה.
  • כשאפליקציה מבקשת אסימון גישה, היא יכולה לציין את היקפי ההרשאות שהיא רוצה לקבל. מערכת Apigee Edge (שרת ההרשאות) קובעת אילו היקפי הרשאות יוקצו בפועל לאסימון הגישה, על סמך (א) היקפי ההרשאות המבוקשים ו-(ב) היקפי ההרשאות שמזוהים על ידי אפליקציית המפתחים.
  • אם Apigee Edge לא מוגדר לבדיקת היקף (האלמנט <Scope> חסר במדיניות VerifyAccessToken או שהוא ריק), הקריאה ל-API תצליח כל עוד ההיקף שמוטמע באסימון הגישה תואם לאחד מההיקפים שמזוהים על ידי אפליקציית המפתחים הרשומה (אחד מההיקפים ברשימת ההיקפים 'הראשית' של האפליקציה).
  • אם לטוקן גישה לא משויכים היקפי הרשאות, הוא יצליח רק במקרים שבהם Edge לא מתייחס להיקף ההרשאות (הרכיב <Scope> חסר במדיניות VerifyAccessToken או שהוא ריק).