人事データベース HRMOS Coreチームの doyaaaaaken です。

最近は Kotlin でサーバサイドをメインに開発しています。
なお、本日が最終出社日です!(新手の退職エントリですw)

今回、日本語・英語どちらの資料も少ない、珍しい規格を用いた開発を行ったので、それについて簡単に紹介します。

何をやったか

弊社では、現在 HRMOS Core と呼ばれる人事データベースを開発しています。

そこで、Slack や Salesforce などメジャーなクラウドサービスも採用している SCIM(System for Cross-domain Identity Managementの略) と呼ばれる規格に準拠した、汎用的なユーザ情報連携のための API 群を開発しました。

開発した背景

HRMOS Core は人事データベースであるという特性上、社員情報を一元管理し、入社、退社、人事異動などの社員情報のライフサイクルの管理も行ないます。

そして、クラウドサービス全盛の今、一元管理された社員情報を Slack、Salesforce などの各種クラウドサービスとどの様に連携するかという課題があります。
これらをシステム的に処理するには、他のクラウドサービスが社員情報を取得できるようにするための API や、社員情報の変更を他サービスにプッシュするユーザープロビジョニング/デプロビジョニング機能が必要です。

この一連の仕組みを汎用的に実現するために SCIM の規格を検討、採用しました。

機能概要図

SCIM とは?

クラウドベースのアプリケーション間でアイデンティティ情報を連携するための仕様です。

ここでいうアイデンティティ情報とは、ユーザー情報と、ユーザーを包含するグループ情報を指しています。これらの情報はどの様なサービスでも必要になる情報だと思います。

SCIM では、連携のための共通仕様を定義することで、他のサービスとの連携を簡易にすることを目標としています。1

SCIM が必要とされる背景

背景でも軽く触れましたが、エンタープライズ向けサービスにもクラウドが普及したことで以下の様な問題が生まれました。

ユーザアカウントの運用部門にとっての問題

クラウド製品の開発者にとっての問題

他サービスとのユーザ情報連携を実現する上で、サービスごとの固有仕様に沿って実装する必要があり、工数が増えてしまう

これはほんの一例ですが、こういった問題を解決するため、アイデンティティ情報連携のための共通仕様を策定しようという話が SCIM です。

SCIM の仕様

仕様概要

詳細に関しては公式のページを参照頂くとして、概要だけ紹介します。

SCIM は、ユーザ情報やそれを包括するグループ情報などのアイデンティティ情報を連携するために JSON・HTTP を利用したプロトコルです。

REST API ベースで、以下のような仕様が定められています。

定義されているリソース

ユーザー情報を表す User リソース、ユーザーを包含するグループを表す Group リソースなどが RFC7643 として定義されています。
各リソースの属性は独自の項目を拡張することが可能です。

URL の命名パターン

リソースごとに URL のパターンが決まっており、User であれば https://example.com/**/User といった URL になります。

エンドポイントの HTTP メソッドおよびその挙動

POST は新規作成処理, PUT は置換処理, PATCH は部分更新処理として定義されています。

レスポンスの HTTP ステータス

作成リクエストの場合は 201、削除の場合は 204 など、リソースと操作毎に推奨されるステータスコードが定義されています。

リクエストパラメータ・リクエストボディー・レスポンスボディー

例えば、検索リクエストにおける検索条件は filter=title pr and userType eq “Employee” といった形式で条件を指定します。 PUT, POST リクエストボディーについても、先程の RFC7643 である程度定められています。

連携方法

SCIM の処理を行う主体は、リクエストを送信する側であるクライアント、リクエストを受け付ける側であるサーバーいずれにもなりえます。

HRMOS Core では、クライアントとして他サービスへユーザ情報をプッシュ連携する User Provisioning 機能、サーバーとして他サービスからユーザ情報の参照・編集を受け付ける API をサポートしています。

SCIM に沿ったリクエストの例

具体的なリクエスト・レスポンスを見れば内容をより想像できると思うので、以下に掲載します。
各項目に入るべき値の意味、型、制約については、先程紹介した RFC7643 で定められています。

※ 例:「userName は一意かつユーザフレンドリーな文字列」、「emails は配列型で primary=true のものが必ず1つある」等

例1) ユーザ取得リクエスト

リクエスト

1
2
3
4
GET /v2/Users/2819c223-7f76-453a-919d-413861904646 HTTP/1.1
Host: example.com
Accept: application/scim+json
Authorization: Bearer h480djs93hd8

レスポンス

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
HTTP/1.1 200 OK
Content-Type: application/scim+json

{
  "schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id":"2819c223-7f76-453a-919d-413861904646",
  "externalId":"doyaaaaaken",
  "meta":{
    "resourceType":"User",
    "created":"2011-08-01T21:32:44.882Z",
    "lastModified":"2011-08-01T21:32:44.882Z",
    "location": "https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646",
    "version":"W\/\"e180ee84f0671b1\""
  },
  "userName":"doyaaaaaken",
  "userType": "Employee",
  "name":{
    "familyName":"Tanaka",
    "givenName":"Taro"
  },
  "phoneNumbers":[
    {
      "value":"555-555-8377",
      "type":"work"
    }
  ],
  "emails":[
    {
      "value":"taro.tanaka@example.com",
      "type":"work",
      "primary": true
    }
  ],
  "addresses": [
    {
      "type": "work",
      "streetAddress": "100 Universal City Plaza",
      "locality": "Hollywood",
      "region": "CA",
      "postalCode": "91608",
      "country": "USA",
      "formatted": "100 Universal City Plaza\nHollywood, CA 91608 USA",
      "primary": true
    }
  ],
  "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
    "employeeNumber": "701984",
    "costCenter": "4130",
    "organization": "Universal Studios",
    "division": "Theme Park",
    "department": "Tour Operations",
    "manager": {
      "value": "26118915-6090-4610-87e4-49d8ca9f808d",
      "$ref": "../Users/26118915-6090-4610-87e4-49d8ca9f808d",
      "displayName": "John Smith"
    }
  }
}

例2) ユーザ作成リクエスト

リクエスト

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
POST /v2/Users  HTTP/1.1
Accept: application/json
Authorization: Bearer h480djs93hd8
Host: example.com
Content-Length: ...
Content-Type: application/json

{
  "schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
  "externalId":"doyaaaaaken",
  "userName":"doyaaaaaken",
  "name":{
    "familyName":"Taro",
    "givenName":"Tanaka"
  }
}

レスポンス

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
HTTP/1.1 201 Created
Content-Type: application/scim+json
Location: https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646
ETag: W/"e180ee84f0671b1"

{
  "schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id":"2819c223-7f76-453a-919d-413861904646",
  "externalId":"doyaaaaaken",
  "meta":{
    "resourceType":"User",
    "created":"2011-08-01T21:32:44.882Z",
    "lastModified":"2011-08-01T21:32:44.882Z",
    "location": "https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646",
    "version":"W\/\"e180ee84f0671b1\""
  },
  "name":{
    "familyName":"Taro",
    "givenName":"Tanaka"
  },
  "userName":"doyaaaaaken"
}

普及度合いについて

採用するかどうか検討する上で、実際に普及しているかどうかは気になると思います。

利用しているサービス

GSuite、Slack、Salesforce、 Azure Active Directory、 Trello などで利用されています。
他にも公式ページに対応しているサービス例が掲載されています。

RFC のステータス

SCIM の最新バージョンである 2.0 の内容は、2015年9月に RFC7642, RFC7643, RFC7644 に定義されています。

このうち Standard Track(標準化過程)に分類され、具体的な仕様について定義されているのは RFC7643, RFC7644 ですが、これらのステータスは Proposed Standard(標準化への提唱)の段階にあります。

この段階は、仕様として成熟しきってはいないが(将来仕様が変化する可能性がある)、インターネットコミュニティにおいて十分検討され、設計上の方針が確定しており、安定している段階だと定義されています。2 3

これらのことから SCIM の採用を検討しても良い段階に来ているのがわかると思います。

まとめ

エンタープライズの分野においてもクラウドサービスが増えてきたことで、サービス間の連携機能の重要性は増してきています。

まだまだ事例、資料等は少ないのですが、REST API ベースで簡単に理解できる仕様ではあるので、皆さんのサービスでも SCIM の採用を検討してみてはいかがでしょうか?

それでは良い Identity Provisioning Life を!

参考

小山健太(doyaaaaaken)
小山健太(doyaaaaaken)

ずっと新規事業開発畑のサーバサイドがメインのエンジニア。KotlinやScalaを使っているがJavaを使ったことがなくたまに話しについていけないのが悩み。