OSDN Git Service

Merge branch 'Branch_release-'
[jindolf/Jindolf.git] / src / main / java / jp / sfjp / jindolf / net / AuthManager.java
diff --git a/src/main/java/jp/sfjp/jindolf/net/AuthManager.java b/src/main/java/jp/sfjp/jindolf/net/AuthManager.java
new file mode 100644 (file)
index 0000000..cc0d4c1
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * manage authentification info
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 olyutorskii
+ */
+
+package jp.sfjp.jindolf.net;
+
+import java.io.UnsupportedEncodingException;
+import java.net.CookieHandler;
+import java.net.CookieManager;
+import java.net.CookieStore;
+import java.net.HttpCookie;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.List;
+
+/**
+ * Cookieを用いた人狼BBSサーバとの認証管理を行う。
+ *
+ * <p>2012-10現在、サポートするのはG国のみ。
+ *
+ * <p>2012-10より、Cookie "uniqID" の送出も必要になった模様。
+ */
+public class AuthManager{
+
+    /** ログアウト用のPOSTデータ。 */
+    public static final String POST_LOGOUT;
+
+    private static final String COOKIE_LOGIN = "login";
+    private static final String ENC_POST = "UTF-8";
+    private static final String PARAM_REDIR;
+
+    private static final CookieManager COOKIE_MANAGER;
+
+    static{
+        PARAM_REDIR = "cgi_param=" + encodeForm4Post("&#bottom");
+        POST_LOGOUT = "cmd=logout" + '&' + PARAM_REDIR;
+
+        COOKIE_MANAGER = new CookieManager();
+        CookieHandler.setDefault(COOKIE_MANAGER);
+    }
+
+
+    private final URI baseURI;
+
+
+    /**
+     * コンストラクタ。
+     * @param bbsUri 人狼BBSサーバURI
+     * @throws NullPointerException 引数がnull
+     */
+    public AuthManager(URI bbsUri) throws NullPointerException{
+        if(bbsUri == null) throw new NullPointerException();
+        this.baseURI = bbsUri;
+        return;
+    }
+
+    /**
+     * コンストラクタ。
+     * @param bbsUrl 人狼BBSサーバURL
+     * @throws NullPointerException 引数がnull
+     * @throws IllegalArgumentException 不正な書式
+     */
+    public AuthManager(URL bbsUrl)
+            throws NullPointerException, IllegalArgumentException{
+        this(urlToUri(bbsUrl));
+        return;
+    }
+
+
+    /**
+     * URLからURIへ変換する。
+     * 書式に関する例外は非チェック例外へ変換される。
+     * @param url URL
+     * @return URI
+     * @throws NullPointerException 引数がnull
+     * @throws IllegalArgumentException 不正な書式
+     */
+    private static URI urlToUri(URL url)
+            throws NullPointerException, IllegalArgumentException{
+        if(url == null) throw new NullPointerException();
+
+        URI uri;
+        try{
+            uri = url.toURI();
+        }catch(URISyntaxException e){
+            throw new IllegalArgumentException(e);
+        }
+
+        return uri;
+    }
+
+    /**
+     * 与えられた文字列に対し
+     * 「application/x-www-form-urlencoded」符号化を行う。
+     *
+     * <p>この符号化はHTTPのPOSTメソッドで必要になる。
+     * この処理は、一般的なPC用Webブラウザにおける、
+     * HTML文書のFORMタグに伴うsubmit処理を模倣する。
+     *
+     * <p>生成文字列はUS-ASCIIの範疇に収まる。はず。
+     *
+     * @param formData 元の文字列
+     * @return 符号化された文字列
+     * @see java.net.URLEncoder
+     * @see
+     * <a href="http://tools.ietf.org/html/rfc1866#section-8.2.1">
+     * RFC1866 8.2.1
+     * </a>
+     */
+    public static String encodeForm4Post(String formData){
+        if(formData == null){
+            return null;
+        }
+
+        String result;
+        try{
+            result = URLEncoder.encode(formData, ENC_POST);
+        }catch(UnsupportedEncodingException e){
+            assert false;
+            result = null;
+        }
+
+        return result;
+    }
+
+    /**
+     * 配列版{@link #encodeForm4Post(java.lang.String)}。
+     * @param formData 元の文字列
+     * @return 符号化された文字列
+     * @see #encodeForm4Post(java.lang.String)
+     */
+    public static String encodeForm4Post(char[] formData){
+        return encodeForm4Post(new String(formData));
+    }
+
+    /**
+     * ログイン用POSTデータを生成する。
+     * @param userID 人狼BBSアカウント名
+     * @param password パスワード
+     * @return POSTデータ
+     */
+    public static String buildLoginPostData(String userID, char[] password){
+        String id = encodeForm4Post(userID);
+        if(id == null || id.isEmpty()){
+            return null;
+        }
+
+        String pw = encodeForm4Post(password);
+        if(pw == null || pw.isEmpty()){
+            return null;
+        }
+
+        StringBuilder postData = new StringBuilder();
+        postData.append("cmd=login");
+        postData.append('&').append(PARAM_REDIR);
+        postData.append('&').append("user_id=").append(id);
+        postData.append('&').append("password=").append(pw);
+
+        String result = postData.toString();
+        return result;
+    }
+
+
+    /**
+     * 人狼BBSサーバのベースURIを返す。
+     * @return ベースURI
+     */
+    public URI getBaseURI(){
+        return this.baseURI;
+    }
+
+    /**
+     * 人狼BBSサーバ管轄下の全Cookieを列挙する。
+     * 他サーバ由来のCookie群との区別はCookieドメイン名で判断される。
+     * @param cookieStore Cookie記憶域
+     * @return 人狼BBSサーバ管轄下のCookieのリスト
+     */
+    public List<HttpCookie> getCookieList(CookieStore cookieStore){
+        List<HttpCookie> cookieList = cookieStore.get(this.baseURI);
+        return cookieList;
+    }
+
+    /**
+     * 認証Cookieを取得する。
+     *
+     * <p>G国での認証Cookie名は"login"。
+     *
+     * <p>※ 2012-10より"uniqID"も増えた模様だが判定には使わない。
+     *
+     * @param cookieStore Cookie記憶域
+     * @return 認証Cookie。認証された状態に無いときはnull。
+     */
+    public HttpCookie getAuthCookie(CookieStore cookieStore){
+        List<HttpCookie> cookieList = getCookieList(cookieStore);
+        for(HttpCookie cookie : cookieList){
+            String cookieName = cookie.getName();
+            if(COOKIE_LOGIN.equals(cookieName)) return cookie;
+        }
+
+        return null;
+    }
+
+    /**
+     * 現在ログイン中か否か判別する。
+     * @return ログイン中ならtrue
+     */
+    public boolean hasLoggedIn(){
+        assert COOKIE_MANAGER == CookieHandler.getDefault();
+        CookieStore cookieStore = COOKIE_MANAGER.getCookieStore();
+
+        HttpCookie authCookie = getAuthCookie(cookieStore);
+        if(authCookie == null){
+            clearAuthentication();
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * 認証情報をクリアする。
+     */
+    public void clearAuthentication(){
+        assert COOKIE_MANAGER == CookieHandler.getDefault();
+        CookieStore cookieStore = COOKIE_MANAGER.getCookieStore();
+
+        HttpCookie authCookie = getAuthCookie(cookieStore);
+        if(authCookie != null){
+            cookieStore.remove(this.baseURI, authCookie);
+        }
+
+        return;
+    }
+
+}