拡張領域で、鍵用途関連のパラメタをどう定義するかを決定した。
extendedKeyUsageにcriticalを設定していないが、
これは設定してもいいかもしれない。
EEsignは、署名用、EEauthは、SSLのクライアント認証用という位置付け。
RAAAは、EEauthと同様とする。
[EEsign]
keyUsage = critical,digitalSignature,nonRepudiation,keyEncipherment,keyAgreement
extendedKeyUsage = codeSigning,emailProtection
basicConstraints = critical,CA:false
[EEauth]
keyUsage = critical,digitalSignature,keyEncipherment,keyAgreement
extendedKeyUsage = clientAuth
basicConstraints = critical,CA:false
[Server]
keyUsage = critical,digitalSignature,keyEncipherment,keyAgreement
extendedKeyUsage = serverAuth
basicConstraints = critical,CA:false
[CA]
keyUsage = critical,cRLSign,keyCertSign
extendedKeyUsage = serverAuth,timeStamping
basicConstraints = critical,CA:true,pathlen:2
●EEserver
○ees_set_access_info(session_id,access_key_hash,email,kanji_name,romaji_name)
1.RAserverのCGIよりセッション情報を受け取る。
2.EEに証明書発行手続きのメールを送信する。
※SMTPエラーについて
存在しないメールアドレスを書いた時に、通信エラーと出てしまう。
・ees_issue_p12(p12_password,session_id,access_key)
1.EEserverのCGIよりリクエストを受け取る。
2.RAserverのras_issue_p12を呼び出す。
3.2が失敗したらリトライ。
●RAserver
○ras_issue_p12(p12_password,session_id)
1.EEserverのサーバープロセスより証明書発行のリクエストを受け取る。
2.セッション管理ファイルより証明書情報を読み出す。
3.IAサーバのias_issue_p12を呼び出し、証明書発行のリクエストを送信する。
4.IAサーバからPKCS12と証明書を受け取る。
5.LDAPに証明書を登録する。
●IAserver
○ias_issue_p12(p12_password,key_length,o,ou,cn,emailAddress,issuerAltName,friendy_name)
1.RAserverより証明書発行のリクエストを受けとる。
2.証明書を発行してRAserverに返す。
メールを送るときに、メールアドレスが存在しない場合、なぜか、
Net::SMTPServerBusyというようなエラーが出る。要するに、そんなユーザ知らんよ、とSMTPサーバが言っている訳だが、Ruby的に返されるクラスはNet::SMTPServerBusy。ま、いいんだけどね…
450: Recipient address rejected:...
#!/usr/bin/env ruby
require 'webrick'
require 'soap/rpc/httpserver'
require 'soap/rpc/driver'
class MyError < StandardError; end
class RAServer < SOAP::RPC::HTTPServer
def on_init
@log.level = Logger::Severity::DEBUG
add_method(self,'myerror')
end
def myerror
raise MyError,"This is an error."
return 0
end
end
server = RAServer::new(
:SOAPHTTPServerApplicationName => "myerror",
:SOAPDefaultNamespace => "http://localhost/soap/",
:BindAddress => "0.0.0.0",
:Port => 1969,
:AccessLog => []
)
trap(:INT) do
server.shutdown
end
server.start
要するに、独自に定義したMyErrorをraiseするサービスだ。次にクライアント側:
#!/usr/bin/env ruby
require 'webrick'
require 'soap/rpc/httpserver'
require 'soap/rpc/driver'
class MyError < StandardError; end
s = SOAP::RPC::Driver::new("http://localhost:1969/","http://localhost/soap/")
s.add_method("myerror")
s.wiredump_file_base = "myerror"
s.options["protcol.http.receive_timeout"]=300
ret = s.myerror
では実行してみよう。まずサーバ側を実行すると、正しく起動される。続いてクライアント側を実行する。
fujino@chimera{~/Works/MyError}$ ./error-client.rb
./error-server.rb:15:in `myerror': This is an error. (MyError)
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/soap/rpc/router.rb:259:in `call'
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/soap/rpc/router.rb:259:in `rpc_call'
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/soap/rpc/router.rb:240:in `call'
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/soap/rpc/router.rb:86:in `route'
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/soap/rpc/soaplet.rb:108:in `do_POST'
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/soap/rpc/soaplet.rb:103:in `with_headerhandler'
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/soap/rpc/soaplet.rb:103:in `do_POST'
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/webrick/httpservlet/abstract.rb:35:in `__send__'
... 15 levels...
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/soap/rpc/driver.rb:275:in `call'
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/soap/rpc/driver.rb:302:in `myerror'
from /CACAnet/app/ruby-1.8.2/lib/ruby/1.8/soap/rpc/driver.rb:297:in `myerror'
from ./error-client.rb:13
fujino@chimera{~/Works/MyError}$
というわけで、クライアント側でもMyErrorが定義してあるので、MyErrorをrescueできている。
実装するのは結構大変だ、と言うが前のエントリの考察で判明した。
そもそも論にまで立ち戻って考えてみて、もっとも大きな問題は、EEに対するウェブの応答時間が長くなることだ。であれば、そこだけを非同期にすればよいのではないか、という議論になった。
すなわち、EEからのウェブアクセスに対しては、「発行要求を受付けました」と即時応答し、別のプロセスがRAserverに対してPKCS#12発行を要求する。ここから先は、上り(req)下り(resp)別の非同期方式ではなく、同期方式で行く。ユーザへの応答時間は気にする必要はないので、何十秒かかっても構わない。タイムアウトすれば、しばらく待ってリトライしてもいいのではないか。
現状のシステムは、同期サービスで実現されている。この方式だと、各サーバ間の通信の途中、サーバの負荷が高い場合等に処理を保留された場合に問題が発生する。例えば、EEからのHTTPリクエストがタイムアウトしてしまう等だ。
この問題を解決するために、非同期サービスで実装する。つまり、今まで一つのSOAPメソッドであったものを、
- サーバ上の要求(req)用のメソッドと、
- 応答受付(resp)用のメソッド
の二つに分ける。
サービス名の命名だが、これはシステム全体で一意になった方が良かろう、ということで、命名規則を作った。
[サーバ名]_[サービス名]_[方向]
ここで言う方向とは、上で述べたreqおよびrespのことである。
サーバ名を付けるのは例えば、PKCS#12ファイルの発行を要求するメソッド(issue_p12)は、RAserverにもCAにも存在する。何故なら、EEからのPKCS#12発行要求は、EEserverで受付けられ、これがSOAPでRAserverに送られ、RAserverからCAへSOAPで送られるためだ。
この方式を採用すると、サーバからクライアントへの通信(resp)のあて先がどこになるのかを、サーバが知る必要がある。これに関しては、
- SOAPの通信元IPを何らかの方法で知る
- クライアントからサーバへの通信(req)のパラメータに埋め込む
の二つが考えられる。前者が自然だが、SOAPの下位層をIPに固定したり、ポート番号を固定することになる。後者は面倒ではあるが柔軟であるので、後者で実装する。
後者でクライアントからサーバへ渡すべき情報は、URIのみになる。SOAPのRPC呼び出しには、URIの他にメソッド名が必要になるが、これは上の命名規則で決まっているので、渡さなくても問題はない。
書くのを忘れていたが、この非同期方式を採用すると、上り(req)下り(resp)の通信が一対であることを確認するため、セッションIDつける必要がある。