001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.fukurou.security;
017
018
019import java.util.Map;
020import java.util.WeakHashMap;
021import java.util.HashMap;
022
023/**
024 * URLHashMap は、セキュリティ強化の為の Hybs独自の暗号化クラスです。
025 *
026 * このクラスは、暗号化キーを受け取り、それに基づいて暗号化/復号化を行います。
027 * ここでの暗号化は、秘密キー方式でバイト文字列に変換されたものを、16進アスキー文字に
028 * 直して、扱っています。よって、暗号化/復号化共に、文字列として扱うことが可能です。
029 *
030 * @og.rev 5.2.2.0 (2010/11/01) 新規追加
031 * @og.group ライセンス管理
032 *
033 * @version  5.2.2.0 (2010/11/01)
034 * @author   Kazuhiko Hasegawa
035 * @since    JDK1.6,
036 */
037public final class URLHashMap {
038        private static final int SIZE = 6000;
039        private static final Map<String,String> urlMap1 = new HashMap<String,String>( SIZE*4/3 );           // 現役世代1
040        private static       Map<String,String> urlMap2 = new HashMap<String,String>( SIZE*4/3 );           // 現役世代2
041        private static final Map<String,String> urlMap3 = new WeakHashMap<String,String>( SIZE*4/3 );       // 旧世代
042        private static final Object lock = new Object();
043
044        /**
045         * デフォルトコンストラクター
046         * これは、すべてstatic メソッドで構成されているクラスなので、直接インスタンスの生成を禁止します。
047         *
048         * @og.rev 5.3.0.0 (2010/12/01) 新規追加
049         */
050        private URLHashMap() {
051                // 直接インスタンスの生成を禁止
052        }
053
054        /**
055         * URL をハッシュ化/暗号化して返します。
056         * 共通処理を簡易化するための、便利メソッドです。
057         * ここでのハッシュ化/暗号化は、URLのパラメータ(?以降の部分)のみ行います。
058         * また、ここで渡す文字列は、URLを含む文字列なので、href のキーワードを
059         * 手がかりに、? を探して、その部分のみ、変換します。
060         * href を含まない場合は、それ自体が URL と判断して、? を探します。
061         * ? が存在しないケースは、url をそのまま返します。
062         *
063         * URLのアドレスが、"/" から始まる場合は、自身のアドレスと判断し、ハッシュ処理を行います。
064         * そうでない場合(http:// や ../ の場合)は、暗号化処理を行います。
065         * 第2引数は、ハッシュ化/暗号化されたパラメータを指定するキーになります。(標準は、h_r)
066         * 処理を選択します。
067         * href を含まず、'?' だけを含む場合は、'?' 以降を暗号化します。
068         *
069         * ハッシュの場合、このキーを元に、設定値を内部キャッシュ(Map)に設定します。
070         * Map は、3世代持っており、内部キャッシュ(SIZE=6000)を超えると、2世代目に移行し、
071         * さらに、超えると、3世代目に移行します。3世代目は、WeakHashMap を利用している
072         * ため、場合によってはデータがなくなり、アクセス不能になっている可能性があります。
073         *
074         * @param       url     オリジナルのURL または、URL を含む文字列
075         * @param       hkey    パラメータのキーとして使用する文字
076         * @param       extOnly 外部URLの場合のみ処理を実行する場合 true
077         *
078         * @return      変換されたURL を含む文字列
079         */
080        public static String makeUrlChange( final String url , final String hkey , final boolean extOnly ) {
081                if( url == null || hkey == null ) { return null; }
082                // 外部のみ(extOnly=true)で、かつ、内部URLの形式の場合、引数そのままを返します。
083                if( extOnly && url.indexOf( "href=\"/" ) >= 0 ) { return url; }
084
085                String rtnUrl = url;
086
087                int idx1 = url.indexOf( "href=\"" );
088                int idx2 = url.indexOf( '?', idx1 );            // href・・・ がない時(idx1 == -1)でも正常に動作する。
089                if( idx2 >= 0 ) {
090                        String url1 = url.substring( 0,idx2+1 );                // 最初から '?' まで(?を含む)
091                        int idx3 = url.indexOf( "\"",idx2+1 );
092                        if( idx3 >= 0 ) {
093                                String url2 = url.substring( idx2+1,idx3 );             // 純粋なパラメータ部分
094                                String url3 = url.substring( idx3 );                    // ダブルクオート(含む)以降
095                                // href="/ かどうか。文字列の有効長があるかどうかを先にチェックしている。
096                                if( idx1 >= 0 && url.length() > idx1+7 && url.charAt( idx1+7 ) == '/' ) {
097                                        url2 = makeHashKey( url2 );
098                                }
099                                else {
100                                        url2 = makeEncrypt( url2 );
101                                }
102                                rtnUrl = url1 + hkey + "=" + url2 + url3 ;
103                        }
104                        // '?' はあるが、最後のダブルクオートがない場合は、'?' から後ろすべてを暗号化する。
105                        else {
106                                String url2 = url.substring( idx2+1 );          // ?以降の部分
107                                rtnUrl = url1 + hkey + "=" + makeEncrypt( url2 ) ;
108                        }
109                }
110
111                return rtnUrl;
112        }
113
114        /**
115         * 引数の設定値をハッシュ化したときの値(=ハッシュキー)を作成します。
116         * 内部的に、このハッシュキーを元に、設定値を内部キャッシュ(Map)に設定します。
117         * このMapは、WeakHashMap を利用しているため、場合によってはデータがなくなり、
118         * アクセス不能になっている可能性があります。
119         *
120         * @param       val     オリジナルの設定値
121         *
122         * @return      ハッシュキー
123         */
124        public static String makeHashKey( final String val ) {
125                if( val == null ) { return ""; }
126
127                // 必殺技:最後に "X" を付けることで、ハッシュ処理されたことを示す。
128                String key = HybsCryptography.getMD5( val ) + "X";
129                synchronized( lock ) {
130                        urlMap1.put( key,val );
131                }
132                return key;
133        }
134
135        /**
136         * 引数の設定値を暗号化したときの値を作成します。
137         * 暗号化なので、ハッシュ化の時の用に、内部キャッシュ(Map)に設定しません。
138         * 処理時間等を考慮すると、外部URLの暗号化や、長期にわたるURL(一旦、システムの
139         * 外部にURLを渡す:例えば、メールでリンク先を送信するなど)の作成に使用します。
140         *
141         * @param       val     オリジナルの設定値
142         *
143         * @return      暗号化キー
144         */
145        public static String makeEncrypt( final String val ) {
146                if( val == null ) { return ""; }
147
148                // 必殺技:最後に "Y" を付けることで、暗号化処理されたことを示す。
149                HybsCryptography crypt = new HybsCryptography();
150                return crypt.encrypt( val ) + "Y";
151        }
152
153        /**
154         * 指定のキーに対応した設定値を取り出します。
155         * ここでは、ハッシュ化 または 暗号化されているキーに対して、
156         * ハッシュキーであれば、関連付けられた設定値を取り出し、暗号化キーで
157         * あれば、復号化処理を行います。
158         *
159         * @param       key     ハッシュ化/暗号化されたキー
160         *
161         * @return      オリジナルの設定値
162         */
163        public static String getValue( final String key ) {
164                if( key == null || key.isEmpty() ) { return null; }
165
166                String rtn = null;
167
168                char ch = key.charAt( key.length()-1 );
169                if( ch == 'X' ) {
170                        synchronized( lock ) {
171                                rtn = urlMap1.get( key );
172                                if( rtn == null ) { rtn = urlMap2.get( key ); }
173                                if( rtn == null ) { rtn = urlMap3.get( key ); }
174
175                                // ハッシュを作成するより取得する方が頻度が少ない。
176                                if( urlMap1.size() > SIZE ) {
177                                        urlMap3.putAll( urlMap2 );
178                                        urlMap2 = new HashMap<String,String>( urlMap1 );
179                                        urlMap1.clear();
180                                }
181                        }
182                }
183                else if( ch == 'Y' ) {
184                        HybsCryptography crypt = new HybsCryptography();
185                        rtn = crypt.decrypt( key.substring( 0,key.length()-1 ) );
186                }
187
188                return rtn ;
189        }
190}