概要
mosquittoで実装されているACLのチェック機構がC言語で実装されていたのでJavaで書きなおしてみました
ソースファイル全体ではなくACLをチェックする一部のメソッドだけ書きなおしています
環境
- mosquitto 1.4
- Java 1.8.0_25
ソースコード
package test;
public class Test {
public static void main(String[] args) {
Test t = new Test();
String acl, topic;
acl = "aaa"; topic = "aaa"; // -> true
System.out.println(t.checkMatchingACLWithTopic(acl, topic));
acl = "#"; topic = "test"; // -> true
System.out.println(t.checkMatchingACLWithTopic(acl, topic));
acl = "+/aaa"; topic = "aaa/aaa"; // -> true
System.out.println(t.checkMatchingACLWithTopic(acl, topic));
acl = ""; topic = "test"; // -> false
System.out.println(t.checkMatchingACLWithTopic(acl, topic));
acl = "test"; topic = "test2"; // -> false
System.out.println(t.checkMatchingACLWithTopic(acl, topic));
acl = "+"; topic = "test"; // -> true
System.out.println(t.checkMatchingACLWithTopic(acl, topic));
acl = "a/+/c"; topic = "a/b/c"; // -> true
System.out.println(t.checkMatchingACLWithTopic(acl, topic));
acl = "a/+/+"; topic = "a/b"; // -> false
System.out.println(t.checkMatchingACLWithTopic(acl, topic));
}
/**
* ACL とアクセスしたいトピックがマッチするかチェックする
* これは mosquitto/lib/util_mosq.c の mosquitto_topic_matches_sub を Java に 書き換えたものである
*
* @param sub トピックに対するユーザのACL情報
* @param topic アクセスしたいトピック
* @return trueならばACLの中にアクセスしたトピックのパターンが含まれている
*/
public boolean checkMatchingACLWithTopic(String sub, String topic) {
int slen, tlen;
int spos, tpos;
boolean multiLevelWildCard = false;
if (sub == null && topic == null) {
return false;
}
slen = sub.length();
tlen = topic.length();
if (slen >= 0 && tlen >= 0) {
if ((sub.startsWith("$") && !topic.startsWith("$")) || (!sub.startsWith("$") && topic.startsWith("$"))) {
// $始まりだった場合
return false;
}
}
spos = 0;
tpos = 0;
// sub, topic ともに全文字列をチェックする
while (spos < slen && tpos < tlen) {
if(sub.charAt(spos) == topic.charAt(tpos)) {
if (tpos == tlen -1) {
if (spos == slen - 3 && sub.charAt(spos + 1) == '/' && sub.charAt(spos + 2) == '#') {
// # で 終わる sub だから true を返却
return true;
}
}
spos++;
tpos++;
if (spos == slen && tpos == tlen) {
// お互い最後の文字だった場合
return true;
} else if (tpos == tlen && spos == slen - 1 && sub.charAt(spos) == '+') {
// topic が最後の文字で sub もあと2文字で今の文字が「+」だった場合
return true;
}
} else {
if (sub.charAt(spos) == '+') {
spos++;
// sub が「+」の場合
while (tpos < tlen && topic.charAt(tpos) != '/') {
// 次の / 移行の topic に移動する(ACLで + なのでその階層はなんでも許可するため)
tpos++;
}
// 移動した結果どちらも最終文字だった場合
if (tpos == tlen && spos == slen) {
return true;
}
} else if (sub.charAt(spos) == '#') {
// sub が「#」ワイルドカードの場合
multiLevelWildCard = true;
if (spos + 1 != slen) {
// sub が最後から1文字目でない場合(要するに # のあとに何かを指定しちゃっている場合)
return false;
} else {
// # のあとに何も指定していない場合はすべてを許可する
return true;
}
} else {
// それ以外の文字の場合はマッチしない
return false;
}
}
}
// 最終的に # が使われていないかつ sub または topic の文字列が最後まで達していない場合
if (multiLevelWildCard == false && (tpos < tlen || spos < slen)) {
return false;
}
// 該当がない場合はエラーにする
return false;
}
}
一応C
とJava
で同じテストを実施して同じ結果になることは確認しています
mosquittoでは更にこれをコールしている上位のメソッドがあってこのメソッドの返り値を見て更に ACC という値と比較して Topic へのアクセス可否を判断していました
0 件のコメント:
コメントを投稿