見出し画像

(Okta x GAS)ユーザーとグループ一覧を取得する

この記事はcorp-engr 情シスSlack(コーポレートエンジニア x 情シス)#1 Advent Calendar 2023のアドベントカレンダー6日目です。今回は最近Oktaを使い始めたのでAPIを使ってユーザーとグループリストを出力するGASを作ってみました。

もしかしたらOkta Workflowsを使えば簡単に出力出来るかもしれませんが、まだ勉強不足なので今回は慣れたGASでやってみました。
(早くOkta完全に理解したい・・・)


使用するAPI

  • 今回はOktaで提供されている以下APIを利用しました。

手順

実際の作成方法は以下の通りです。

1.Okta APIキー発行

1)Okta Admin Consoleにログイン
2)左メニューにて[Security] > [API]クリック
3) [Create token]をクリックして説明文を入力して[Create token]クリック

4)トークンが払い出されるのでコピーしておく。

補足:公式手順は以下になります。

2.スプレットシート準備

 1)スプレットシートを新規作成
 2)シートを2つ作成してそれぞれ以下にシート名に変更しておく
  ・Users
  ・Groups

3.スクリプト作成

1)メニューから[拡張機能] > [Apps Script] クリック
2)プロジェクト名を入力(名前は任意)
3)コードに以下スクリプトをコピーして貼り付け(コピペでOK)

function main() {
  const okta_domain = PropertiesService.getScriptProperties().getProperty('okta_domain');
  const api_token = PropertiesService.getScriptProperties().getProperty('api_token');
  
//スプレットシート情報
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const sheet1 = spreadsheet.getSheetByName("Users");   // 事前にシートを作成"Users"
  const sheet2 = spreadsheet.getSheetByName("Groups");  // 事前にシートを作成"Groups"

  const headers = {
    "Accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "SSWS " + api_token
  };

//STEP1-1 ユーザーリスト出力
  users_list(okta_domain,headers,sheet1)

//STEP2-1 グループのリスト出力
  groups_list(okta_domain,headers,sheet2)

//STEP2-2 グループIDからメンバー出力
  groups_userlist(okta_domain,headers,sheet2)
}


//STEP1-1 ユーザーリスト出力
function users_list(okta_domain, headers, sheet1) {
  // ユーザー情報取得API実行
    const users_url = "https://" + okta_domain + "/api/v1/users?limit=200";
    let users_response = UrlFetchApp.fetch(users_url, {
      headers: headers,
      muteHttpExceptions: true
    });

  // グループ情報を配列に格納
  const UsersArr = [];
  let users = JSON.parse(users_response.getContentText());

  // 200より多い場合は繰り返しリクエストを行う
  while (users_response.getResponseCode() === 200) {
    let nextPage = users_response.getHeaders(); // 次のページのURLを取得
    let nextPageUrl = nextPage.Link.split(";")[0].slice(1, -1)
    let nextPageChk = nextPage.Link.split(";")[1].slice(6, -1)
    let nextPageResponse = UrlFetchApp.fetch(nextPageUrl, {
      headers: headers,
      muteHttpExceptions: true
    });
    let nextusers = JSON.parse(nextPageResponse.getContentText());
    
    if (nextPageChk == "next") {
      users.push(...nextusers);           // ユーザー情報を配列に追加
      users_response = nextPageResponse;  // 次のページのレスポンスをセット
    } else {
      break; // ページがない場合はループを抜ける
    }
  }
  if (users_response.getResponseCode() === 200) {
    for (let i = 0; i < users.length; i++) {
      const user = users[i];
      const userId = user.id;
      const status = user.status;
      const firstName = user.profile.firstName;
      const lastName = user.profile.lastName;
      const email = user.profile.email;
      const created = user.created;
      const lastLogin = user.lastLogin;

      UsersArr[i] = [userId, status, firstName, lastName, email, created, lastLogin];
    }

    // スプレッドシートに書き出し
      sheet1.clear(); // シートの内容をクリア
      sheet1.appendRow(['UserID', 'Status', 'FirstName', 'LastName', 'Email', 'Created', 'LastLogin']);
      sheet1.getRange(sheet1.getLastRow() + 1, 1, UsersArr.length, UsersArr[0].length).setValues(UsersArr);

      console.log("UserList added to the spreadsheet successfully");
  } else {
    console.log("Failed to get Users from Okta API");
    exit;
  }
}

//STEP2-1 グループのリスト出力 
function groups_list(okta_domain,headers,sheet2) {
// グループ情報取得(※フィルターでOKTA_GROUPとBUILT_INのみ取得)
  const groups_url = "https://" + okta_domain + "/api/v1/groups" + "?filter=type+eq+%22OKTA_GROUP%22%20or%20type+eq+%22BUILT_IN%22&limit=10"; 
  let groups_response = UrlFetchApp.fetch(groups_url, {
    headers: headers,
    muteHttpExceptions: true
  });

// グループ情報を配列に格納
  const GroupsArr = []; 
  const groups = JSON.parse(groups_response.getContentText()); // 取得したグループ情報をパースして配列に格納

  // 200より多い場合は繰り返しリクエストを行う
  while (groups_response.getResponseCode() === 200) {
    let nextPage = groups_response.getHeaders(); // 次のページのURLを取得
    let nextPageUrl = nextPage.Link.split(";")[0].slice(1, -1)
    let nextPageChk = nextPage.Link.split(";")[1].slice(6, -1)
      
    let nextPageResponse = UrlFetchApp.fetch(nextPageUrl, {
      headers: headers,
      muteHttpExceptions: true
    });
    let nextgroups = JSON.parse(nextPageResponse.getContentText());
    
    if (nextPageChk == "next") {
      groups.push(...nextgroups);          // ユーザー情報を配列に追加 
      groups_response = nextPageResponse;  // 次のページのレスポンスをセット
    } else {
      break; // ページがない場合はループを抜ける
    }
  }

  if (groups_response.getResponseCode() === 200) {
    for (let i = 0; i < groups.length; i++) {
      const group = groups[i];
      const groupId = group.id
      const groupName = group.profile.name; 
      const groupdescription = group.profile.description; 
      const grouptype = group.type;  
      const groupCreated = group.created
      const groupLastUpdated = group.lastUpdated
      const groupLastMembershipUpdated = group.lastMembershipUpdated

      GroupsArr.push([groupId,groupName,groupdescription,grouptype,groupCreated,groupLastUpdated,groupLastMembershipUpdated]);

    }
    // スプレッドシートに書き出し
      sheet2.clear(); //シートの内容をクリア
      sheet2.appendRow(['GroupID','GroupName','GroupDescription','GroupType','CreatedDate','LastUpdate','LastMemberUpdate','MemberList']); 
      sheet2.getRange( sheet2.getLastRow()+1,1, GroupsArr.length, GroupsArr[0].length).setValues(GroupsArr);

    console.log("Group members added to the spreadsheet successfully");

  } else {
    console.log("Failed to get groups from Okta API");
    exit;
  }
}

//STEP2-2 グループIDからメンバー出力
function groups_userlist(okta_domain,headers,sheet2) {
  const lastRow1 = sheet2.getLastRow();

  for (let j = 2; j < lastRow1+1; j++){
    const groupID = sheet2.getRange('A'+ j).getValue();
    const members_url = "https://" + okta_domain + "/api/v1/groups/" + groupID + "/users"; // 各グループのメンバー情報を取得するAPIのURL
    const members_response = UrlFetchApp.fetch(members_url, {
      headers: headers,
      muteHttpExceptions: true
    });

    if (members_response.getResponseCode() === 200) {
      const members = JSON.parse(members_response.getContentText()); // 取得したメンバー情報をパースして配列に格納
      const memberNames = members.map(function (member) {
        return member.profile.email;
      }).join(", "); // メンバー名をコンマ区切りの文字列に変換
      sheet2.getRange('H'+ j).setValue(memberNames);
    }
  }
}

6)左メニューの歯車アイコン(プロジェクトの設定)を開く
7)スクリプト プロパティに以下登録して保存

  • プロパティ / 値

    • api_token / 作成したOktaのAPIキー

    • okta_domain / テナントURL

8)スクリプト[main]を実行して動作することを確認。

補足

APIのLimit

  • UsersとGroupsのAPIは共に一度に取得できる最大数が200となってます。そのため200を超える場合は繰り返しリクエストを行いすべて取得出来るようにしています。

最後に

昨年もこのアドベントカレンダーに参加させていただきました。去年の投稿は以下リンク先にあるので興味ある方がいれば見てみて下さい。


この記事が気に入ったらサポートをしてみませんか?