OSDN Git Service

Cookie認証機構の大部分をJRE1.6に移行。
[jindolf/Jindolf.git] / src / main / java / jp / sfjp / jindolf / net / AuthManager.java
1 /*
2  * manage authentification info
3  *
4  * License : The MIT License
5  * Copyright(c) 2012 olyutorskii
6  */
7
8 package jp.sfjp.jindolf.net;
9
10 import java.io.UnsupportedEncodingException;
11 import java.net.CookieHandler;
12 import java.net.CookieManager;
13 import java.net.CookieStore;
14 import java.net.HttpCookie;
15 import java.net.URI;
16 import java.net.URISyntaxException;
17 import java.net.URL;
18 import java.net.URLEncoder;
19 import java.util.List;
20
21 /**
22  * Cookieを用いた人狼BBSサーバとの認証管理を行う。
23  * <p>2012-10現在、サポートするのはG国のみ。
24  * <p>2012-10より、Cookie "uniqID" の送出も必要になった模様。
25  */
26 public class AuthManager{
27
28     /** ログアウト用のPOSTデータ。 */
29     public static final String POST_LOGOUT;
30
31     private static final String COOKIE_LOGIN = "login";
32     private static final String ENC_POST = "UTF-8";
33     private static final String PARAM_REDIR;
34
35     private static final CookieManager COOKIE_MANAGER;
36
37     static{
38         PARAM_REDIR = "cgi_param=" + encodeForm4Post("&#bottom");
39         POST_LOGOUT = "cmd=logout" + '&' + PARAM_REDIR;
40
41         COOKIE_MANAGER = new CookieManager();
42         CookieHandler.setDefault(COOKIE_MANAGER);
43     }
44
45
46     private final URI baseURI;
47
48
49     /**
50      * コンストラクタ。
51      * @param bbsUri 人狼BBSサーバURI
52      * @throws NullPointerException 引数がnull
53      */
54     public AuthManager(URI bbsUri) throws NullPointerException{
55         if(bbsUri == null) throw new NullPointerException();
56         this.baseURI = bbsUri;
57         return;
58     }
59
60     /**
61      * コンストラクタ。
62      * @param bbsUrl 人狼BBSサーバURL
63      * @throws NullPointerException 引数がnull
64      * @throws IllegalArgumentException 不正な書式
65      */
66     public AuthManager(URL bbsUrl)
67             throws NullPointerException, IllegalArgumentException{
68         this(urlToUri(bbsUrl));
69         return;
70     }
71
72
73     /**
74      * URLからURIへ変換する。
75      * 書式に関する例外は非チェック例外へ変換される。
76      * @param url URL
77      * @return URI
78      * @throws NullPointerException 引数がnull
79      * @throws IllegalArgumentException 不正な書式
80      */
81     private static URI urlToUri(URL url)
82             throws NullPointerException, IllegalArgumentException{
83         if(url == null) throw new NullPointerException();
84
85         URI uri;
86         try{
87             uri = url.toURI();
88         }catch(URISyntaxException e){
89             throw new IllegalArgumentException(e);
90         }
91
92         return uri;
93     }
94
95     /**
96      * 与えられた文字列に対し
97      * 「application/x-www-form-urlencoded」符号化を行う。
98      * <p>この符号化はHTTPのPOSTメソッドで必要になる。
99      * この処理は、一般的なPC用Webブラウザにおける、
100      * HTML文書のFORMタグに伴うsubmit処理を模倣する。
101      * <p>生成文字列はUS-ASCIIの範疇に収まる。はず。
102      * @param formData 元の文字列
103      * @return 符号化された文字列
104      * @see java.net.URLEncoder
105      * @see
106      * <a href="http://tools.ietf.org/html/rfc1866#section-8.2.1">
107      * RFC1866 8.2.1
108      * </a>
109      */
110     public static String encodeForm4Post(String formData){
111         if(formData == null){
112             return null;
113         }
114
115         String result;
116         try{
117             result = URLEncoder.encode(formData, ENC_POST);
118         }catch(UnsupportedEncodingException e){
119             assert false;
120             result = null;
121         }
122
123         return result;
124     }
125
126     /**
127      * 配列版{@link #encodeForm4Post(java.lang.String)}。
128      * @param formData 元の文字列
129      * @return 符号化された文字列
130      * @see #encodeForm4Post(java.lang.String)
131      */
132     public static String encodeForm4Post(char[] formData){
133         return encodeForm4Post(new String(formData));
134     }
135
136     /**
137      * ログイン用POSTデータを生成する。
138      * @param userID 人狼BBSアカウント名
139      * @param password パスワード
140      * @return POSTデータ
141      */
142     public static String buildLoginPostData(String userID, char[] password){
143         String id = encodeForm4Post(userID);
144         if(id == null || id.isEmpty()){
145             return null;
146         }
147
148         String pw = encodeForm4Post(password);
149         if(pw == null || pw.isEmpty()){
150             return null;
151         }
152
153         StringBuilder postData = new StringBuilder();
154         postData.append("cmd=login");
155         postData.append('&').append(PARAM_REDIR);
156         postData.append('&').append("user_id=").append(id);
157         postData.append('&').append("password=").append(pw);
158
159         String result = postData.toString();
160         return result;
161     }
162
163
164     /**
165      * 人狼BBSサーバのベースURIを返す。
166      * @return ベースURI
167      */
168     public URI getBaseURI(){
169         return this.baseURI;
170     }
171
172     /**
173      * 人狼BBSサーバ管轄下の全Cookieを列挙する。
174      * 他サーバ由来のCookie群との区別はCookieドメイン名で判断される。
175      * @param cookieStore Cookie記憶域
176      * @return 人狼BBSサーバ管轄下のCookieのリスト
177      */
178     public List<HttpCookie> getCookieList(CookieStore cookieStore){
179         List<HttpCookie> cookieList = cookieStore.get(this.baseURI);
180         return cookieList;
181     }
182
183     /**
184      * 認証Cookieを取得する。
185      * <p>G国での認証Cookie名は"login"。
186      * <p>※ 2012-10より"uniqID"も増えた模様だが判定には使わない。
187      * @param cookieStore Cookie記憶域
188      * @return 認証Cookie。認証された状態に無いときはnull。
189      */
190     public HttpCookie getAuthCookie(CookieStore cookieStore){
191         List<HttpCookie> cookieList = getCookieList(cookieStore);
192         for(HttpCookie cookie : cookieList){
193             String cookieName = cookie.getName();
194             if(COOKIE_LOGIN.equals(cookieName)) return cookie;
195         }
196
197         return null;
198     }
199
200     /**
201      * 現在ログイン中か否か判別する。
202      * @return ログイン中ならtrue
203      */
204     public boolean hasLoggedIn(){
205         assert COOKIE_MANAGER == CookieHandler.getDefault();
206         CookieStore cookieStore = COOKIE_MANAGER.getCookieStore();
207
208         HttpCookie authCookie = getAuthCookie(cookieStore);
209         if(authCookie == null){
210             clearAuthentication();
211             return false;
212         }
213
214         return true;
215     }
216
217     /**
218      * 認証情報をクリアする。
219      */
220     public void clearAuthentication(){
221         assert COOKIE_MANAGER == CookieHandler.getDefault();
222         CookieStore cookieStore = COOKIE_MANAGER.getCookieStore();
223
224         HttpCookie authCookie = getAuthCookie(cookieStore);
225         if(authCookie != null){
226             cookieStore.remove(this.baseURI, authCookie);
227         }
228
229         return;
230     }
231
232 }