メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2009年6月27日土曜日

[Apache Shindig][お勉強][OpenSocial] メモ37 SecurityToken 5

securityTokenをsecureにして、iframeでGadgetを表示後、しばらくほっておいて、
再表示しようとすると、


Caused by: org.apache.shindig.common.crypto.BlobExpiredException: Blob expired, was valid from Sat Jun 27 20:23:10 JST 2009 to Sat Jun 27 21:29:10 JST 2009, attempted use at Sat Jun 27 21:43:12 JST 2009
at org.apache.shindig.common.crypto.BasicBlobCrypter.checkTimestamp(BasicBlobCrypter.java:228)
at org.apache.shindig.common.crypto.BasicBlobCrypter.unwrap(BasicBlobCrypter.java:190)
at org.apache.shindig.auth.BlobCrypterSecurityToken.decrypt(BlobCrypterSecurityToken.java:83)
at org.apache.shindig.auth.BlobCrypterSecurityTokenDecoder.createToken(BlobCrypterSecurityTokenDecoder.java:114)
 

とexpiredだといわれる。

ほほぅ。


./java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java
 

を見ると、

/**
* We allow a few minutes on either side of the validity window to account
* for clock skew.
*/
private void checkTimestamp(Map out, int maxAge)
throws BlobExpiredException {
long origin = Long.parseLong(out.get(TIMESTAMP_KEY));
long minTime = origin - CLOCK_SKEW_ALLOWANCE;
long maxTime = origin + maxAge + CLOCK_SKEW_ALLOWANCE;
long now = timeSource.currentTimeMillis()/1000;
if (!(minTime < now && now < maxTime)) {
throw new BlobExpiredException(minTime, now, maxTime);
}
}
 

となっている。
呼び出し元を見ると、maxAgeは3600。
で、CLOCK_SKEW_ALLOWANCEは180。
(秒単位)

なので、securityTokenが発行された時の3分前から63分後までは、securityTokenは有効で、
そのほかはExpiredとなる。

さて、この値を変更したい人はどうすればよいか。

BlobCrypterSecurityTokenで定義されているんだけど、
”いじるな”という感じ。
OpenSocialの仕様なんですかね。

.

[Apache Shindig][お勉強][OpenSocial] メモ36 SecurityToken4

サーバ側でApache Shindigのモジュールを使用し、securityTokenを作成してみた。
正しいかどうかは知らない。


String viewerId = "viewer";
String ownerId = "owner";
String domain = "shindig";
String container = "default";
long moduleId = 0;
String appId = "http://www.labpixies.com/campaigns/todo/todo.xml";

String securityToken = null;
try {
String keyFile = containerConfig.getString(container, "gadgets.securityTokenKeyFile");
if (keyFile != null) {
BlobCrypterSecurityToken token = new BlobCrypterSecurityToken(new BasicBlobCrypter(new java.io.File(keyFile)), container, domain);
token.setOwnerId(ownerId);
token.setViewerId(viewerId);
token.setAppUrl(appId);
token.setModuleId(moduleId);
token.setActiveUrl(request.getRequestURL().toString());
securityToken = token.encrypt();
}
else {
BasicSecurityToken token = new BasicSecurityToken(
ownerId,
viewerId,
appId,
domain,
appId,
"" + moduleId,
container,
request.getRequestURL().toString());
securityToken = token.toSerialForm();
}
}
catch (Exception ex) {
AnonymousSecurityToken token = new AnonymousSecurityToken();
securityToken = token.toSerialForm();
}

securityToken = URLEncoder.encode(securityToken, "UTF-8");
 


もっとちゃんと実装しなきゃならないけど、
おおまかな流れ的には、こんな感じでよい気がする。
activeUrlには何を指定するか、まだ知らないんで、とりあえずリクエストURLを指定した。

で、とりあえず動いた。
AuthenticationServletFilterもちゃんと通過。
iframeには意味不明な文字列が指定されている。

securityTokenには'+'とかが入るので、処理の最後でURLEncoder.encodeしてやらないと
だめ。(ちろっとはまった)

iframeのsecurityTokenをでたらめな文字列を指定すると、ちゃんと403になる。

うーん。
AuthenticationServletFilterでやっている処理は、
FilterじゃなくてHandlerでやった方がいじりやすい気もする。

--

というか、SecurityTokenDecoderはShindigにあるのに、SecurityTokenEncoderはShindigには
用意されていない。BlobCrypterがあるので、いらない、ということかな?

SecurityTokenDecoderも含めて、Shindigはサンプルだから自分で実装しろ、ということか。。
.

[Apache Shindig][お勉強][OpenSocial] メモ35 UnauthenticationMode

stパラメータでsecureTokenなる文字列をサーブレットに渡すんだけど、
Shindigのサンプル実装だと、stパラメータが渡されない場合、


AnonymousAuthenticationHandler
 

という名のハンドラが効いて、空のsecureTokenを作成してサーブレットに渡してくれる。
多分、OpenSocialコンテナを組み込もうと思っている人で、Secureな感じにしたい人は、
このAnonymousAuthenticationHandlerをはずすか、サーブレット側で認証エラーにするか
するんじゃないかなー。ぜんぜんちがうかもしれないけど。(JSecurityFilterはまだ知らない)

で、このAnonymousAuthenticationHandlerは、allowUnauthenticatedというプロパティを
もっていて、この値がTRUEだと、空のsecureTokenを作成する。

TRUEかFALSEかを設定している箇所は、

./java/social-api/src/main/java/org/apache/shindig/social/core/config/SocialApiGuiceModule.java
 

の中の

bind(Boolean.class)
.annotatedWith(Names.named(AnonymousAuthenticationHandler.ALLOW_UNAUTHENTICATED))
.toInstance(Boolean.TRUE);
 

のところ。この最後のBoolean.TRUEをBoolean.FALSEに書き換えればOKっと。

で?

--
insecureなSecurityTokenは"テストの時に使えるよ"とコメントに書いてある。
.

2009年6月25日木曜日

[OpenSSO][お勉強] OpenSSOを勉強する

OpenSSOはちょっとだけ触ってみた、というレベルなので、
ちょっと、ちゃんと勉強してみようかと。(というか、必要に迫られて・・)

興味はあるので、いやいやというわけではないけど。

さて、本でもあれば、それを買うところ。

とりあえずは、sunのサイトにいって、
OpenSSO Early Access Free Training
でもやってみるか。

初心者向けらしい。が、結構なボリュームとのこと。

.

[Apache Shindig][お勉強][OpenSocial] メモ34 SecureToken 3(gadgets.securityTokenKeyFile)

securityTokenを暗号化する場合には、
container.jsの


//"gadgets.securityTokenType" : "secure",
//"gadgets.securityTokenKeyFile" : "/path/to/key/file.txt",
 

のコメントをはずすっぽいんだけど、
gadgets.securityTokenKeyFileには何を指定するんだろう・・。



./java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java
 

を見ると、

/**
* Creates a crypter based on a key in a file. The key is the first line
* in the file, whitespace trimmed from either end, as UTF-8 bytes.
*
* The following *nix command line will create an excellent key:
* <pre>
* dd if=/dev/random bs=32 count=1 | openssl base64 > /tmp/key.txt
* </pre>
*
* @throws IOException if the file can't be read.
*/
 

などというありがたいコメント発見。
なるほど。ということで、さっそくやってみた。

まずは、container.jsを以下のように書き換えて・・

"gadgets.securityTokenType" : "secure",
"gadgets.securityTokenKeyFile" : "/tmp/key.txt",
 

んで、元の
"gadgets.securityTokenType" : "insecure"
の行をコメントにする。

次は、

$ dd if=/dev/random bs=32 count=1 | openssl base64 > /tmp/key.txt
 

を実行と。

で、Shindig起動。

・・起動できたけど、試せない。。


とりあえず、securityToken作るときにBlobCrypterSecurityTokenのencryptを使えば良さそう
だけど、どうでしょう。

.

[Apache Shindig][お勉強][OpenSocial] メモ33 SecureToken 2

全然違った。


./java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenDecoder.java
 

を見ると、


public DefaultSecurityTokenDecoder(ContainerConfig config) {
String tokenType = config.getString(ContainerConfig.DEFAULT_CONTAINER, SECURITY_TOKEN_TYPE);
if ("insecure".equals(tokenType)) {
decoder = new BasicSecurityTokenDecoder();
} else if ("secure".equals(tokenType)) {
decoder = new BlobCrypterSecurityTokenDecoder(config);
} else {
throw new RuntimeException("Unknown security token type specified in " +
ContainerConfig.DEFAULT_CONTAINER + " container configuration. " +
SECURITY_TOKEN_TYPE + ": " + tokenType);
}
}

 

とあるんで、"insecure"を"secure"に変更するといい感じっぽい。

insecureをsecureにする場所は、

config/container.js
 



gadgets.securityTokenType
 

のところ。

最初は


// Use an insecure security token by default
"gadgets.securityTokenType" : "insecure",
 

という感じになっているので、

"gadgets.securityTokenType" : "secure",
 

とすれば良いっぽい。

さて、ここだけ変更すればよいのかは、今のところ不明。
--
と思ったけど、
container.jsのコメントに書いてあるねー。

// Uncomment these to switch to a secure version
//
//"gadgets.securityTokenType" : "secure",
//"gadgets.securityTokenKeyFile" : "/path/to/key/file.txt",
 

って。
さて、このキーファイルというのはなんじゃらほい。

.

[Apache Shindig][お勉強][OpenSocial] メモ32 SecureToken

GadgetRenderingServletへガジェットの描画をリクエストする際など、
stというパラメータ名でsecurityTokenなるものを渡さないといけない。

だけど、これサンプルを見ると、全然secureじゃない。

でも、mixiとかだとsecurityTokenは意味不明な文字列になっている。

サーバ側で適当に暗号化するのかなぁ、などと思っていたら、
Shindigに、


org.apache.shindig.auth.BlobCrypterSecurityToken
 

というクラスを発見。

これ使って暗号化するっぽい。

ので、さっそく使ってみることにした。

つづく。
.

2009年6月24日水曜日

[Apache Shindig][お勉強][OpenSocial] メモ31 おや?

Apache Shindig 1.1って

OpenSocial 0.9

ですか。そうですか。


--
OpenSocial 0.8かと思ってた。。

.

2009年6月23日火曜日

[Apache Shindig][お勉強][OpenSocial] メモ30 iframeの外でrequestNavigateTo

iframeを使って、その中にgadgetを表示しているんだけど、
iframeの外からrequestNavigateToをする方法がいまいち分からない。。


てっきりgadgets.GadgetService.requestNavigateToとかをコールすればよいのかと
思いきや、自分がどのガジェットかどうか判断できなさそう。

とりあえず、


$('<a href="#" class="navigate">View</a>').mousedown(function (e) {
e.stopPropagation();
}).click(function () {
var elementUrl = $('#remote_iframe_0').attr("src");
var newElementUrl = '';
if (currentView === 'profile') {
currentView = 'canvas';
}
else {
currentView = 'profile';
}
newElementUrl = elementUrl.replace(/[&]?view=[^&]*/,"").replace(/[?]/,"?view=" + currentView + "&");
$('#remote_iframe_0').attr('src',newElementUrl);
return false;
}).appendTo($('#remote_iframe_0').parent().parent().find('.widget-head'));
 

な感じに、iframeのsrcを書き換えることでViewを遷移させることができた。

なんとなく気持ち悪い。


--
この辺はLayoutManagerがやるのかも。

.

[Apache Shindig][お勉強][OpenSocial] メモ29 requestNavigateTo

基本的には自力で実装しなきゃいけないっぽい。

が、

https://issues.apache.org/jira/browse/SHINDIG-515

のパッチのとおり、gadgets.jsのgadgets.IfrGadgetService.prototype.requestNavigateTo
を変更すれば、とりあえずはrequestNavigateToできる。


gadgets.IfrGadgetService.prototype.requestNavigateTo = function(view,
opt_params) {
var element = document.getElementById(this.f); // the calling frame
if (!element) {
return;
}

var elementUrl = element.src;
var newElementUrl = elementUrl.replace(/[&]?view=[^&]*/,"").replace(/[?]/,"?view="+view+"&");

if (opt_params) {
var paramStr = gadgets.json.stringify(opt_params);
if (paramStr.length > 0) {
newElementUrl += '&appParams=' + encodeURIComponent(paramStr);
}
}

element.src = newElementUrl;
};
 

な感じに。

ちなみに、元のrequestNavigateToでは、gadgets.IfrGadgetService.prototype.getUrlForView
をコールしてurlを決定しているんだけど、こちらは、

This is a silly implementation
 

だそうで。

.

[Apache Shindig][お勉強][OpenSocial] メモ28 /social/rpcと/gadget/api/rpc

Shindig付属のGadgetRenderingServletを動かすと、

サービス一覧を取得するために、


/social/rpc
 

と、

/gadget/api/rpc
 

に対してサーブレット内からmethod=system.listMethodsリクエストが投げられる。

が、

securityCodeを付けないでリクエストを投げているので、
必ず毎回エラーになる。

/social/rpcと/gadget/api/rpcも実装せよ、ということ・・?
まだコードの読みが甘いのか。。

--
追記:2009/7/11
やっぱりコードの読みが甘かった。
AuthenticationServletFilterを通しておけば、
AnonymousSecurityTokenがセットされるので、404にはならない。

.

[Apache Shindig][お勉強][OpenSocial] メモ27 DBBasedUserPrefStore

CookieBaseduserPrefStoreを参考にDBBasedUserPrefStoreを作ってみた。


gadgets.DBBasedUserPrefStore = function() {
gadgets.UserPrefStore.call(this);
};

gadgets.DBBasedUserPrefStore.inherits(gadgets.UserPrefStore);

gadgets.DBBasedUserPrefStore.prototype.USER_PREFS_PREFIX =
'gadgetUserPrefs-';

gadgets.DBBasedUserPrefStore.prototype.saveUserPrefUrl_ = "saveUserPref.json";
gadgets.DBBasedUserPrefStore.prototype.loadUserPrefUrl_ = "loadUserPref.json";
gadgets.DBBasedUserPrefStore.prototype.serverBase_ = "serverBase";

gadgets.DBBasedUserPrefStore.prototype.getPrefs = function(gadget) {
var userPrefs = {};
var keyName = this.USER_PREFS_PREFIX + gadget.id;
var data = this._loadUserPref(keyName);
if (data) {
for (var aa in data) {
userPrefs[decodeURIComponent(aa)] = decodeURIComponent(data[aa]).replace(/^'/,"").replace(/'$/,"");
}
}

return userPrefs;
};

gadgets.DBBasedUserPrefStore.prototype.savePrefs = function(gadget) {
var pairs = [];
for (var name in gadget.getUserPrefs()) {
var value = gadget.getUserPref(name);
var pair = encodeURIComponent(name) + '=\'' + encodeURIComponent(value) + '\'';
pairs.push(pair);
}

var name = this.USER_PREFS_PREFIX + gadget.id;
var pair = encodeURIComponent("__gadgetId__") + '=' + encodeURIComponent(name);
pairs.push(pair);
var value = pairs.join('&');

this._saveUserPref(value);
};

gadgets.DBBasedUserPrefStore.prototype._saveUserPref = function(data) {
var userPref = '';
$.ajax({
type: "POST",
url: this.serverBase_ + this.saveUserPrefUrl_ ,
data: data,
success: function(json) {
userPref = $(json).find('UserPref').text();
}
});
return userPref;
};

gadgets.DBBasedUserPrefStore.prototype._loadUserPref = function(name) {
var data = '';
$.ajax({
type: "GET",
cache: false,
async: false,
dataType: 'string',
url: this.serverBase_ + this.loadUserPrefUrl_ + "?__gadgetId__=" + name,
success: function(str) {
data = str;
}
});
return eval("(" + data + ")");
};

gadgets.DBBasedUserPrefStore.prototype.setServerBase = function(base) {
this.serverBase_ = base;
};

gadgets.Container.prototype.userPrefStore =
new gadgets.DBBasedUserPrefStore();
 

な感じに、cookiebaseduserprefstore.jsをまんま変更し、
setPrefsとgetPrefsでサーバ側へリクエストを投げると。

サーバ側は、送られてきたリクエストを適当に処理し、DBへ保存。

使うときは、

<script type="text/javascript" src="../../js/rpc.js?c=1&debug=1"></script>
<script type="text/javascript" src="cookies.js"></script>
<script type="text/javascript" src="util.js"></script>
<script type="text/javascript" src="gadgets.js"></script>
<script type="text/javascript" src="dbbaseduserprefstore.js"></script>
 

な感じに読み込んで、、

<script type="text/javascript">
//<![CDATA[
var gadget = gadgets.container.createGadget({id: "0",specUrl: "http://www.labpixies.com/campaigns/todo/todo.xml", secureToken: "${secureToken}"});
gadget.setServerBase("${contextPath}/gadgets/");
gadgets.container.userPrefStore.setServerBase("${contextPath}/");
gadgets.container.addGadget(gadget);
$("#remote_iframe_0").attr("src", gadget.getIframeUrl());
//]]>
</script>
 

な感じでiframeのurlをセット。
${contextPath}はローカルな事情からアプリケーションサーバのcontextPathをセットと。

とりあえずは、これで、labpixies.comのtodoガジェットはちゃんと動くっぽい。

さて、次はrequestNavigateToをなんとかする。



--
つーか、javascriptはこんな感じでよいのかしらん。
.

2009年6月21日日曜日

[Apache Shindig][お勉強][OpenSocial] メモ26 CookieBasedUserPrefStore4

なるほど。。

Shindig付属のサンプルのままで、いけたのね。。


<link rel="stylesheet" href="gadgets.css">
<script type="text/javascript" src="../../js/rpc.js?c=1&debug=1"></script>
<script type="text/javascript" src="cookies.js"></script>
<script type="text/javascript" src="util.js"></script>
<script type="text/javascript" src="gadgets.js"></script>
<script type="text/javascript" src="cookiebaseduserprefstore.js"></script>
<script type="text/javascript">
var specUrl0 = 'http://www.google.com/ig/modules/test_setprefs_multiple_ifpc.xml';

function init() {
gadgets.container.layoutManager =
new gadgets.FloatLeftLayoutManager('gadget-parent');

gadgets.container.addGadget(
gadgets.container.createGadget({specUrl: specUrl0}));
};

function renderGadgets() {
gadgets.container.renderGadgets();
};
</script>
</head>
<body onLoad="init();renderGadgets();">
<h2>Sample: set-pref support</h2>
<div id="gadget-parent" class="gadgets-gadget-parent"></div>
</body>
 


で何も考えずにCookie保存は無事できると。

.