2014-04-20

GoInstant触ってみる【ACL編】

これまで、GoInstantのデータの取り扱いについて説明してきましたが、実際のアプリケーションでは

”このルームにはこのユーザしか入れない”とか

”この時間になったら、このルームへの入出を許そう”とか

”このデータを取得できるのはadminユーザだけ”とか

そういったアクセスコントロール要件が出てきます。

 

もちろんこういったアクセスコントロールにもGoInstantは対応しています。

ということで、今回はACLについて。

 

基本的にGoInstantではAccess ControlというJSONの設定とユーザのJWT(ユーザ名とかグループ名)によって

制御することができます。

 

例えば、RoomにJoinできるユーザを絞り込みたいときは

{
  "$room": {
    "#join": { "users": ["localhost:tzm%40freedom-man.com"] },
 ...
}

こんな感じにやると、localhostで発行されたtzm@freedom-man.comっていうユーザがJoinできる設定になります。

(@を%40にしないとエラーになったので、ちゃんとURLエンコードしないとダメみたい…。)

 

グループだとこんな感じ。

{
  "$room": {
    "#join": {"groups": ["freedom-man"]},
    ...
}

freedom-manっていうグループに属するユーザはJoinできるっていう設定になります。

 

一つ一つ特定のユーザ名やグループ名を設定するのは正直しんどいので、

ルームの名前が付いたグループとかユーザ名を一括で許可する設定ができます。

{
  "$room": {
    "#join": {
      "groups": [
        "$room-grp"
      ]
    },
   ...
}

こうすると、ルームの名前 + "-grp"の名前(lobbyだったら"lobby-grp")のグループに対して

一括でJoinの権限を付与することができます。

 

あるキーの読み取りを制限したい場合は以下のように書きます。

{
  "$room": {
    ...
    "test": {
      "#get": {
        "users": [
          "localhost:tzm%40freedom-man.com"
        ]
      },
...
}

これで、localhostから発行されたtzm@freedom-man.comユーザのみtestキーの値を取得することが出来ます。

 

onメソッドのイベントも制御することができます。

{
  "$room": {
    ...
    "test": {
      "#onSet": {
        "users": [
          "localhost:tzm%40freedom-man.com"
        ]
      },
...
}

こうすると、on("set", ... と記述してもlocalhost:tzm@freedom-man.comユーザ以外では

コールバック関数が実行されることはありません。

 

これらのACLを設定して、あとはグループとユーザ名の制御をJWTで行ってあげればOKです。

python + flaskだとこんな感じ。※スクリプトタグでのJS呼び出しで対応しているのでFlaskのResponseがJSです。

## jwt_test.py ##
import base64
import json
import hmac
import hashlib
import Crypto
from Crypto.PublicKey import RSA 

def base64url_decode(input):
    input += '=' * (4 - (len(input) % 4)) 
    return base64.urlsafe_b64decode(input)

def base64url_encode(input):
    return base64.urlsafe_b64encode(input).replace('=', '') 

def createJWT(groups, username, displayname):
    key = base64url_decode("Input Your Secret Key")

    header = { 
        'typ':'JWT',
        'alg':'HS256'
    }   

    payload = { 
        'iss':'localhost',
        'sub': username,
        'dn': displayname,
        'g' : groups
    }   

    data = base64url_encode(json.dumps(header)) + "." + base64url_encode(json.dumps(payload))

    sig = base64url_encode(hmac.new(key, data, hashlib.sha256).digest())
    return "var token = \"" + data+ "." + sig + "\";"


## flask_jwt.py ##
from flask import Flask
from jwt_test import createJWT
app = Flask(__name__)

@app.route("/jwt")
def jwt():
    return createJWT([{'id':'lobby-grp', 'dn':'lobby'}], 'tzm@freedom-man.com', 'display')

if __name__ == "__main__":
    app.run()

 

JWTの生成にはGoInstantと共有している秘密鍵が必要で、ユーザが自分自身で生成することは不可能です。

つまりJWT生成を行うサーバサイドで、「この時間帯でこのユーザであればRoomへのJoinは禁止しよう」等の

細かい制御をすることになります。

※expire的なパラメータが無いので、使い回しはできちゃいそうですが…。

 

パーミッションでエラーになったときはこんな感じのエラーが出ます。

goinstant-permissionerror

このエントリーをはてなブックマークに追加