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

כרגע מוצג התיעוד של Apigee Edge.
כניסה למסמכי התיעוד של Apigee X.
מידע

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

מהו היקף OAuth2?

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

בנושא הזה נסביר איך היקפים מוקצים לאסימוני גישה ואיך אפליקציית 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"
}

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

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

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

כשיוצרים אפליקציה למפתחים ומוסיפים לה מוצרים, 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". דרך נוספת לבחון את העניין היא שהפרמטר של שאילתת ההיקף הוא סוג של מסנן. אם אפליקציית המפתחים מזהה את ההיקפים A, B, X, ופרמטר השאילתה מציין " scope=X Y Z", אז רק ההיקף "X" יוקצה לאסימון.

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

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

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

יש מקרה נוסף שבו התנהגות ברירת המחדל היא החזרת אסימון גישה עם כל ההיקפים המוכרים, והוא כאשר המדיניות GenerateAccessToken (מדיניות Apigee Edge שיוצרת אסימוני גישה) לא מציינת רכיב <Scope>. לדוגמה, זו מדיניות GenerateAccessToken שבה מצוין <Scope>. אם רכיב <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). חובה לציין במדיניות את הפעולה ValidAccessToken. נבחן את המדיניות הזו:

<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 כך לאכוף היקפים ספציפיים. כדי לעשות את זה, צריך לתכנן תהליכי עבודה מותאמים אישית שמצורפים אליהם כללי מדיניות ValidAccessToken שמצייתים להיקף.

נניח שב-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 שלהם. לשם כך הם יוצרים תהליכי עבודה מותאמים אישית לטיפול בהיקפים ספציפיים, ומצרפים כללי מדיניות של ValidAccessToken כדי לאכוף את ההיקפים האלה.

דוגמאות לקוד

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

ברירת מחדל של אותיות רישיות

נניח שיש לך אפליקציה למפתחים עם מוצרים, והאיחוד בין ההיקפים של המוצרים האלה הוא: א', ב' וג'. הקריאה הזו ל-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"
 }

הפעולה מצליחה כי למדיניות ValidAccessToken שמופעלת כשנקודת הקצה מופעלת נדרשת היקף A, ואסימון הגישה קיבל את ההיקפים 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 ו-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"
 }
 

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

סיכום

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

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