Java版でBasic認証をかけてみる

サーバーサイドJavaで、コンテナの機能(設定)に依存しない形でBasic認証をかけようとした場合、
まっさきに思いつくのがServletFilterで認証する方法なのですが…
GoogleAppEngine for Javaで上記の方法を採用した際、ちょっとつまりました。。
静的なHTMLファイルに対してアクセスした際、認証のダイアログは表示されるのですが、
その段階(認証前)でブラウザにHTMLの内容が表示されてしまいます。


Filterの実装は以下のような感じ。


/**
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
* javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {

HttpServletRequest httpReq = (HttpServletRequest) req;
String authHeader = httpReq.getHeader("Authorization");
if (isAuth(authHeader)) {
log.warning("認証成功");
chain.doFilter(req, res);
} else {
HttpServletResponse httpRes = (HttpServletResponse) res;
httpRes.setHeader("WWW-Authenticate", "BASIC realm=HogeHoge");
httpRes.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}

/**
* 認証処理
* @param authHeader HttpヘッダのAuthorization値
* @return 認証結果(true=認証成功、false=認証失敗)
*/
private boolean isAuth(String authHeader) {

if (authHeader == null || authHeader.length() <= 6) {
return false;
}
// Authorizationヘッダ値はBase64エンコードされているので、まずデコードする
String useridAndPass;
try {
useridAndPass = new String(Base64.decode(authHeader.substring(6).getBytes()));
} catch (Base64DecoderException e) {
return false;
}
log.warning("認証値:" + useridAndPass);

// 値は「ユーザID:パスワード」形式のため、それぞれ別文字列に分解して認証
String[] userPassArray = useridAndPass.split(":");
if (userMap.containsKey(userPassArray[0]) { // userMapにはkey:ユーザ名、value=パスワードを格納済みとする
&& userMap.get(userPassArray[0]).equals(userPassArray[1])) {
return true;
}
return false;
}

web.xmlの設定はこんな感じ。



CertificateFilter
jp.co.hogehoge.filter.CertificateFilter


CertificateFilter
/*



理由はわかりませんねー。例の分散キャッシュとかが問題になってるのかな?とか思いましたけど、
ローカル段階ですでにおかしいですし。Jettyの仕様なんですかね?
#ちなみにlocalhostで起動したTomcatだと正常動作しました。


とりあえず、回避方法としてはHTMLをJSPに変更してやればOKでした。
#でも、これだとイメージファイルとかに直接アクセスした場合問題な気もするなぁ。。まぁ、今はいいか。