    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 * ここでの暗号化は、秘密キー方式でバイト文字列に変換されたものを、１６進アスキー文字に
    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         * 第２引数は、ハッシュ化/暗号化されたパラメータを指定するキーになります。(標準は、h_r)
    066         * 処理を選択します。
    067         * href を含まず、'?' だけを含む場合は、'?' 以降を暗号化します。
    068         *
    069         * ハッシュの場合、このキーを元に、設定値を内部キャッシュ(Map)に設定します。
    070         * Map は、３世代持っており、内部キャッシュ(SIZE=6000)を超えると、２世代目に移行し、
    071         * さらに、超えると、３世代目に移行します。３世代目は、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}