OSDN Git Service

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