שיתוף קבצים, תיקיות ואחסון

לכל קובץ, תיקייה ואחסון שיתופי ב-Google Drive משויכים משאבי Permissions. כל משאב מזהה את ההרשאה של type (משתמש, קבוצה, דומיין, מישהו) ו-role מסוימים, כמו "הרשאת תגובה" או "קוראת". לדוגמה, יכול להיות שלקובץ יש הרשאה שמעניקה למשתמש מסוים (type=user) הרשאת קריאה בלבד (role=reader) ואילו הרשאה אחרת מעניקה לחברים בקבוצה מסוימת (type=group) את היכולת להוסיף תגובות לקובץ (role=commenter).

במאמר תפקידים מפורטת רשימה מלאה של התפקידים והפעולות המותרות על ידי כל אחד מהם.

תרחישים לשיתוף משאבים ב-Drive

יש 5 סוגים שונים של תרחישים של שיתוף:

  1. כדי לשתף קובץ בתיקייה 'האחסון שלי', צריך להיות למשתמש role=writer ומעלה.

    • אם הערך הבוליאני writersCanShare מוגדר ל-False בקובץ, למשתמש חייב להיות role=owner.

    • אם למשתמש עם role=writer יש גישה זמנית בהתאם לתאריך ולשעת תפוגה, הוא לא יכול לשתף את הקובץ.

    מידע נוסף זמין במאמר הוספת תאריך תפוגה.

  2. כדי לשתף תיקייה מ'האחסון שלי', למשתמש צריך להיות role=writer או יותר.

    • אם הערך הבוליאני writersCanShare מוגדר ל-False בקובץ, למשתמש חייב להיות ה-role=owner המתיר יותר.

    • אי אפשר להשתמש בגישה זמנית (שהיא בתוקף לפי תאריך ושעה) בתיקיות 'האחסון שלי' יחד עם role=writer.

  3. כדי לשתף קובץ באחסון שיתופי, צריך להיות למשתמשים role=writer ומעלה.

    • ההגדרה writersCanShare לא חלה על פריטים בתיקיות אחסון שיתופי. לכן, המערכת מתייחסת תמיד לערך True.
  4. כדי לשתף תיקייה באחסון שיתופי, למשתמש צריך להיות role=organizer.

    • אם ההגבלה sharingFoldersRequiresOrganizerPermission באחסון שיתופי מוגדרת לערך False, משתמשים עם ההרשאה role=fileOrganizer יכולים לשתף תיקיות מאותו אחסון שיתופי.
  5. כדי לנהל את החברות באחסון השיתופי, למשתמש צריך להיות role=organizer. רק משתמשים וקבוצות יכולים להיות חברים באחסון שיתופי.

הפצת הרשאות

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

לעומת זאת, אם קובץ יורש את הערך role=writer מתיקייה, ומועבר לתיקייה אחרת שמספקת את התפקיד 'קורא', הקובץ יורש עכשיו את הערך role=reader.

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

לחלופין, אפשר לבטל הרשאות שעברו בירושה בקובץ או בתיקייה בתיקיית 'האחסון שלי'. כך, אם קובץ יורש את הערך role=writer מתיקייה 'האחסון שלי', אפשר להגדיר בקובץ role=reader את רמת ההרשאה שלו.

יכולות

בסופו של דבר, המשאב Permissions לא קובע את היכולת של המשתמש הנוכחי לבצע פעולות בקובץ או בתיקייה. במקום זאת, משאב Files מכיל אוסף של capabilities שדות בוליאניים שמשמשים כדי לציין אם אפשר לבצע פעולה בקובץ או בתיקייה. ה-API של Google Drive מגדיר את השדות האלה על סמך משאב ההרשאות של המשתמש הנוכחי שמשויך לקובץ או לתיקייה.

לדוגמה, כאשר אלכס מתחבר לאפליקציה ומנסה לשתף קובץ, התפקיד של אלכס נבדק תוך שימוש בהרשאות של הקובץ. אם התפקיד מאפשר להם לשתף קובץ, השדה capabilities שקשור לקובץ, כמו canShare, ימולא גם הוא ביחס לתפקיד. אם אלכס רוצה לשתף את הקובץ, האפליקציה שלך בודקת את capabilities כדי לוודא שהקובץ canShare מוגדר לערך true.

יצירת הרשאה

חובה למלא את שני השדות הבאים בעת יצירת הרשאה:

  • type – ה-type מזהה את היקף ההרשאה (user, group, domain או anyone). הרשאה עם type=user חלה על משתמש ספציפי, ואילו הרשאה עם type=domain חלה על כל המשתמשים בדומיין ספציפי.

  • role – השדה role מציין את הפעולות שאפשר לבצע בשדה type. לדוגמה, הרשאה ל-type=user ול-role=reader מעניקה למשתמש הרשאת קריאה בלבד בקובץ או בתיקייה. או הרשאה עם type=domain ועם role=commenter מאפשרת לכל המשתמשים בדומיין להוסיף תגובות לקובץ. במאמר תפקידים מפורטת רשימה מלאה של התפקידים והפעולות המותרות על ידי כל אחד מהם.

כשיוצרים הרשאה ב-type=user או ב-type=group, צריך גם לספק emailAddress כדי לקשר את המשתמש או הקבוצה הספציפיים להרשאה.

כשיוצרים הרשאה type=domain, צריך גם לציין domainכדי לקשר דומיין ספציפי להרשאה.

כדי ליצור הרשאה:

  1. משתמשים ב-method permissions.create עם fileId לקובץ או לתיקייה המשויכים.
  2. בגוף הבקשה, מזהים את type ואת role.
  3. אם הערך הוא type=user או type=group, יש לציין emailAddress. אם הערך הוא type=domain, יש לציין את domain.

שימוש בקהלים לטירגוט

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

כדי להשתמש בקהלי יעד:

  1. נכנסים למסוף Google Admin.

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

  2. נכנסים לתפריט > ספרייה > קהלי יעד.

  3. ברשימת קהלי היעד, לוחצים על השם של קהל היעד. במאמר יצירת קהל יעד מוסבר איך יוצרים קהל יעד.

  4. מעתיקים את המזהה הייחודי מכתובת ה-URL של קהל היעד: https://admin.google.com/ac/targetaudiences/ID.

  5. יוצרים הרשאה עם type=domain ומגדירים את השדה domain כ-ID.audience.googledomains.com.

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

אחזור כל ההרשאות של קובץ, תיקייה או אחסון שיתופי

משתמשים ב-method permissions.list כדי לאחזר את כל ההרשאות לקובץ, לתיקייה או לאחסון שיתופי.

אימות הרשאות המשתמשים

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

כדי לבדוק את היכולות, צריך לקרוא לפונקציה files.get כשהפרמטר fileId והפרמטר fields מוגדרים לשדה capabilities.

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

קביעת מקור התפקיד של קבצים ותיקיות מאחסון שיתופי

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

כדי לקבוע את מקור התפקיד של אחסון שיתופי, או פריטים בתוך האחסון, צריך לבצע קריאה ל-permissions.get כשהפרמטר fileId ו-permissionId מוגדרים ל-fields בשדה permissionDetails. כדי למצוא את permissionId, יש להשתמש ב-permissions.list עם fileId.

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

שינוי ההרשאות

כדי לשנות הרשאות בקובץ או בתיקייה, אפשר לשנות את התפקיד שהוקצה:

  1. קוראים ל-permissions.update עם permissionId של ההרשאה לשנות, ול-fileId את הקובץ, התיקייה או האחסון השיתופי המשויך. כדי למצוא את permissionId, יש להשתמש ב-permissions.list עם fileId.

  2. בבקשה מציינים את role החדש.

אתם יכולים לתת הרשאות לקבצים או לתיקיות באחסון שיתופי, גם אם המשתמש או הקבוצה כבר חברים בו. לדוגמה, אלכס שייך ל-role=commenter כחלק מהמינוי שלו לאחסון שיתופי. עם זאת, האפליקציה שלכם יכולה לתת לאלכס role=writer קובץ באחסון שיתופי. במקרה כזה, מכיוון שלתפקיד החדש יש יותר הרשאה מהתפקיד שניתן לחברי הקבוצה, ההרשאה החדשה הופכת לתפקיד בפועל בקובץ או בתיקייה.

ביטול גישה לקובץ או לתיקייה

כדי לבטל גישה לקובץ או לתיקייה, צריך להתקשר אל delete באמצעות fileId ול-permissionId כדי למחוק את ההרשאה.

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

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

הפעולה delete משמשת גם למחיקה של הרשאות שהוחלו ישירות על קובץ או תיקייה באחסון שיתופי.

העברת בעלות על קובץ לחשבון Google Workspace אחר באותו ארגון

אפשר להעביר את הבעלות על הקבצים הקיימים בתיקייה 'האחסון שלי' מחשבון Google Workspace אחד לחשבון אחר באותו ארגון. ארגון שבבעלותו אחסון שיתופי הוא הבעלים של הקבצים שכלולים בו. לכן אין תמיכה בהעברות בעלות בקבצים ובתיקיות בתיקיות אחסון שיתופי. המארגנים של האחסון השיתופי יכולים להעביר אליו פריטים.

כדי להעביר בעלות על קובץ ב'אחסון שלי', מבצעים אחת מהפעולות הבאות:

  • יוצרים הרשאת קובץ שמעניקה למשתמש מסוים (type=user) הרשאת גישה (role=owner).

  • עדכון ההרשאה של קובץ קיים באמצעות role=owner והעברת הבעלות למשתמש שצוין (transferOwnership=true).

העברת בעלות על קובץ מחשבון צרכן אחד לאחר

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

  1. הבעלים הנוכחי יוזם העברת בעלות על ידי יצירה או עדכון של הרשאת הקובץ של הבעלים החדש הפוטנציאלי. ההרשאה חייבת לכלול את ההגדרות הבאות: role=writer, type=user וגם pendingOwner=true. אם הבעלים החדשים יוצרים הרשאה לבעלים הפוטנציאליים, תישלח התראה באימייל לבעלים החדשים שמצוין בהם שהם מתבקשים לתבוע בעלות על הקובץ.

  2. הבעלים החדש יאשר את הבקשה להעברת בעלות על ידי יצירה או עדכון של הרשאת הקובץ. ההרשאה צריכה לכלול את ההגדרות הבאות: role=owner וגם transferOwnership=true. אם הבעלים החדשים ייצרו הרשאה חדשה, באימייל הקודם תישלח התראה באימייל על כך שהבעלות הועברה.

כשקובץ מועבר, התפקיד של הבעלים הקודמים משודרג לאחור ל-writer.

שינוי מספר הרשאות עם בקשות באצווה

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

הדוגמה הבאה היא דוגמה לשינוי של הרשאת אצווה בספריית לקוח.

Java

drive/snippets/drive_v3/src/main/java/ShareFile.java
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.Permission;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/* Class to demonstrate use-case of modify permissions. */
public class ShareFile {

  /**
   * Batch permission modification.
   * realFileId file Id.
   * realUser User Id.
   * realDomain Domain of the user ID.
   *
   * @return list of modified permissions if successful, {@code null} otherwise.
   * @throws IOException if service account credentials file not found.
   */
  public static List<String> shareFile(String realFileId, String realUser, String realDomain)
      throws IOException {
        /* Load pre-authorized user credentials from the environment.
         TODO(developer) - See https://developers.google.com/identity for
         guides on implementing OAuth2 for your application.application*/
    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault()
        .createScoped(Arrays.asList(DriveScopes.DRIVE_FILE));
    HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(
        credentials);

    // Build a new authorized API client service.
    Drive service = new Drive.Builder(new NetHttpTransport(),
        GsonFactory.getDefaultInstance(),
        requestInitializer)
        .setApplicationName("Drive samples")
        .build();

    final List<String> ids = new ArrayList<String>();


    JsonBatchCallback<Permission> callback = new JsonBatchCallback<Permission>() {
      @Override
      public void onFailure(GoogleJsonError e,
                            HttpHeaders responseHeaders)
          throws IOException {
        // Handle error
        System.err.println(e.getMessage());
      }

      @Override
      public void onSuccess(Permission permission,
                            HttpHeaders responseHeaders)
          throws IOException {
        System.out.println("Permission ID: " + permission.getId());

        ids.add(permission.getId());

      }
    };
    BatchRequest batch = service.batch();
    Permission userPermission = new Permission()
        .setType("user")
        .setRole("writer");

    userPermission.setEmailAddress(realUser);
    try {
      service.permissions().create(realFileId, userPermission)
          .setFields("id")
          .queue(batch, callback);

      Permission domainPermission = new Permission()
          .setType("domain")
          .setRole("reader");

      domainPermission.setDomain(realDomain);

      service.permissions().create(realFileId, domainPermission)
          .setFields("id")
          .queue(batch, callback);

      batch.execute();

      return ids;
    } catch (GoogleJsonResponseException e) {
      // TODO(developer) - handle error appropriately
      System.err.println("Unable to modify permission: " + e.getDetails());
      throw e;
    }
  }
}

Python

drive/snippets/drive-v3/file_snippet/share_file.py
from __future__ import print_function

import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


def share_file(real_file_id, real_user, real_domain):
    """Batch permission modification.
    Args:
        real_file_id: file Id
        real_user: User ID
        real_domain: Domain of the user ID
    Prints modified permissions

    Load pre-authorized user credentials from the environment.
    TODO(developer) - See https://developers.google.com/identity
    for guides on implementing OAuth2 for the application.
    """
    creds, _ = google.auth.default()

    try:
        # create drive api client
        service = build('drive', 'v3', credentials=creds)
        ids = []
        file_id = real_file_id

        def callback(request_id, response, exception):
            if exception:
                # Handle error
                print(exception)
            else:
                print(f'Request_Id: {request_id}')
                print(F'Permission Id: {response.get("id")}')
                ids.append(response.get('id'))

        # pylint: disable=maybe-no-member
        batch = service.new_batch_http_request(callback=callback)
        user_permission = {
            'type': 'user',
            'role': 'writer',
            'emailAddress': 'user@example.com'
        }
        batch.add(service.permissions().create(fileId=file_id,
                                               body=user_permission,
                                               fields='id',))
        domain_permission = {
            'type': 'domain',
            'role': 'reader',
            'domain': 'example.com'
        }
        domain_permission['domain'] = real_domain
        batch.add(service.permissions().create(fileId=file_id,
                                               body=domain_permission,
                                               fields='id',))
        batch.execute()

    except HttpError as error:
        print(F'An error occurred: {error}')
        ids = None

    return ids


if __name__ == '__main__':
    share_file(real_file_id='1dUiRSoAQKkM3a4nTPeNQWgiuau1KdQ_l',
               real_user='gduser1@workspacesamples.dev',
               real_domain='workspacesamples.dev')

Node.js

drive/snippets/drive_v3/file_snippets/share_file.js
/**
 * Batch permission modification
 * @param{string} fileId file ID
 * @param{string} targetUserEmail username
 * @param{string} targetDomainName domain
 * @return{list} permission id
 * */
async function shareFile(fileId, targetUserEmail, targetDomainName) {
  const {GoogleAuth} = require('google-auth-library');
  const {google} = require('googleapis');

  // Get credentials and build service
  // TODO (developer) - Use appropriate auth mechanism for your app
  const auth = new GoogleAuth({
    scopes: 'https://www.googleapis.com/auth/drive',
  });
  const service = google.drive({version: 'v3', auth});
  const permissionIds = [];

  const permissions = [
    {
      type: 'user',
      role: 'writer',
      emailAddress: targetUserEmail, // 'user@partner.com',
    },
    {
      type: 'domain',
      role: 'writer',
      domain: targetDomainName, // 'example.com',
    },
  ];
  // Note: Client library does not currently support HTTP batch
  // requests. When possible, use batched requests when inserting
  // multiple permissions on the same item. For this sample,
  // permissions are inserted serially.
  for (const permission of permissions) {
    try {
      const result = await service.permissions.create({
        resource: permission,
        fileId: fileId,
        fields: 'id',
      });
      permissionIds.push(result.data.id);
      console.log(`Inserted permission id: ${result.data.id}`);
    } catch (err) {
      // TODO(developer): Handle failed permissions
      console.error(err);
    }
  }
  return permissionIds;
}

PHP‏

drive/snippets/drive_v3/src/DriveShareFile.php
use Google\Client;
use Google\Service\Drive;
function shareFile()
{
    try {
        $client = new Client();
        $client->useApplicationDefaultCredentials();
        $client->addScope(Drive::DRIVE);
        $driveService = new Drive($client);
        $realFileId = readline("Enter File Id: ");
        $realUser = readline("Enter user email address: ");
        $realDomain = readline("Enter domain name: ");
        $ids = array();
            $fileId = '1sTWaJ_j7PkjzaBWtNc3IzovK5hQf21FbOw9yLeeLPNQ';
            $fileId = $realFileId;
            $driveService->getClient()->setUseBatch(true);
            try {
                $batch = $driveService->createBatch();

                $userPermission = new Drive\Permission(array(
                    'type' => 'user',
                    'role' => 'writer',
                    'emailAddress' => 'user@example.com'
                ));
                $userPermission['emailAddress'] = $realUser;
                $request = $driveService->permissions->create(
                    $fileId, $userPermission, array('fields' => 'id'));
                $batch->add($request, 'user');
                $domainPermission = new Drive\Permission(array(
                    'type' => 'domain',
                    'role' => 'reader',
                    'domain' => 'example.com'
                ));
                $userPermission['domain'] = $realDomain;
                $request = $driveService->permissions->create(
                    $fileId, $domainPermission, array('fields' => 'id'));
                $batch->add($request, 'domain');
                $results = $batch->execute();

                foreach ($results as $result) {
                    if ($result instanceof Google_Service_Exception) {
                        // Handle error
                        printf($result);
                    } else {
                        printf("Permission ID: %s\n", $result->id);
                        array_push($ids, $result->id);
                    }
                }
            } finally {
                $driveService->getClient()->setUseBatch(false);
            }
            return $ids;
    } catch(Exception $e) {
        echo "Error Message: ".$e;
    }

}

‎.NET

drive/snippets/drive_v3/DriveV3קטעי טקסט/ShareFile.cs
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data;
using Google.Apis.Requests;
using Google.Apis.Services;

namespace DriveV3Snippets
{
    // Class to demonstrate use-case of Drive modify permissions.
    public class ShareFile
    {
        /// <summary>
        /// Batch permission modification.
        /// </summary>
        /// <param name="realFileId">File id.</param>
        /// <param name="realUser">User id.</param>
        /// <param name="realDomain">Domain id.</param>
        /// <returns>list of modified permissions, null otherwise.</returns>
        public static IList<String> DriveShareFile(string realFileId, string realUser, string realDomain)
        {
            try
            {
                /* Load pre-authorized user credentials from the environment.
                 TODO(developer) - See https://developers.google.com/identity for
                 guides on implementing OAuth2 for your application. */
                GoogleCredential credential = GoogleCredential.GetApplicationDefault()
                    .CreateScoped(DriveService.Scope.Drive);

                // Create Drive API service.
                var service = new DriveService(new BaseClientService.Initializer
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Drive API Snippets"
                });

                var ids = new List<String>();
                var batch = new BatchRequest(service);
                BatchRequest.OnResponse<Permission> callback = delegate(
                    Permission permission,
                    RequestError error,
                    int index,
                    HttpResponseMessage message)
                {
                    if (error != null)
                    {
                        // Handle error
                        Console.WriteLine(error.Message);
                    }
                    else
                    {
                        Console.WriteLine("Permission ID: " + permission.Id);
                    }
                };
                Permission userPermission = new Permission()
                {
                    Type = "user",
                    Role = "writer",
                    EmailAddress = realUser
                };

                var request = service.Permissions.Create(userPermission, realFileId);
                request.Fields = "id";
                batch.Queue(request, callback);

                Permission domainPermission = new Permission()
                {
                    Type = "domain",
                    Role = "reader",
                    Domain = realDomain
                };
                request = service.Permissions.Create(domainPermission, realFileId);
                request.Fields = "id";
                batch.Queue(request, callback);
                var task = batch.ExecuteAsync();
                task.Wait();
                return ids;
            }
            catch (Exception e)
            {
                // TODO(developer) - handle error appropriately
                if (e is AggregateException)
                {
                    Console.WriteLine("Credential Not found");
                }
                else
                {
                    throw;
                }
            }
            return null;
        }
    }
}