かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その31 )( Spring Actuator の Basic 認証用ユーザの認証成功時には AuthenticationSuccessEvent イベントが発生しないようにする+いろいろ調整する )

概要

記事一覧はこちらです。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その30 )( Redis のクライアントライブラリを Jedis → Lettuce に変更する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Prometheus が Spring Actuator にアクセスした時に、コンソールにレスポンスの内容が出力されて他のログが見にくかったり、Basic 認証の成功時に AuthenticationSuccessEvent が発生して update 文が実行されたりしていたので、修正します。
    • 他に以下の点を変更します。
      • PostgreSQL のコンテナ起動時に毎回検索対象図書館を登録し直さなくてもよいようにします。
      • build タスク実行時に PMD の This analysis could be faster, ... のメッセージが出力されないようにします。
      • HikariCP を最新バージョンに変更して leak-detection-threshold の設定を変更します。
      • spring-boot-properties-migrator が何もメッセージを出力していないので削除します。

参照したサイト・書籍

  1. @EventListener for AuthenticationSuccessEvent or InteractiveAuthenticationSuccessEvent not fired
    https://stackoverflow.com/questions/41076500/eventlistener-for-authenticationsuccessevent-or-interactiveauthenticationsucces

目次

  1. Prometheus が Spring Actuator にアクセスした時に、コンソールにレスポンスの内容が出力されないようにする
  2. Prometheus が Spring Actuator にアクセスした時に AuthenticationSuccessEventListener#onApplicationEvent の update 文が実行されないようにする
  3. library_forsearch テーブルに初期データを登録して、最初に検索対象図書館を登録不要にする
  4. pmdMain タスク実行時の This analysis could be faster, ... のメッセージが出力されないようにする
  5. HikariCP は最新の 3.3.0 を dependenceis に指定し、spring.datasource.hikari.leak-detection-threshold の値を 5000 → 60000 に変更する
  6. runtimeOnly("org.springframework.boot:spring-boot-properties-migrator") を削除する
  7. 次回は。。。

手順

Prometheus が Spring Actuator にアクセスした時に、コンソールにレスポンスの内容が出力されないようにする

src/main/resources/application-develop.properties で logging.level.org.springframework.web=DEBUG を設定しているため、Prometheus が Spring Actuator にアクセスした時のレスポンスの内容もコンソールに出力されます。

f:id:ksby:20190106233612p:plain

このままではコンソールに大量に出力されるため、ログが全然確認できなくて調査等の時に困ったので出ないようにします。org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor の DEBUG ログなので、このクラスだけ log.level を INFO に変更して出力されないようにします。

src/main/resources/application-develop.properties に logging.level.org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor=INFO を追加します。

# Spring MVC
logging.level.org.springframework.web=DEBUG
logging.level.org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor=INFO

Prometheus が Spring Actuator にアクセスした時に AuthenticationSuccessEventListener#onApplicationEvent の update 文が実行されないようにする

Prometheus が Spring Actuator にアクセスした時のレスポンスの内容が出力されないようにしたら、今度は Prometheus が Spring Actuator にアクセスした時に Basic 認証で成功したら ksbysample.webapp.lending.security.AuthenticationSuccessEventListener#onApplicationEvent が呼び出されて update user_info set cnt_badcredentials = 0 where mail_address = 'actuator' 文が実行されていることに気づきました。Spring Actuator の Basic 認証用ユーザの場合には AuthenticationSuccessEvent イベントが発生しないようにします。

f:id:ksby:20190106235221p:plain

src/main/java/ksbysample/webapp/lending/config/WebSecurityConfig.java の以下の点を変更します。

@Configuration
public class WebSecurityConfig {

    public static final String DEFAULT_SUCCESS_URL = "/booklist";
    public static final String REMEMBERME_KEY = "ksbysample-webapp-lending";
    public static final String ACTUATOR_USERNAME = "actuator";

    ..........

    /**
     * Spring Actuator の Basic認証用ユーザの場合には AuthenticationSuccessEvent を発生させないための
     * AuthenticationEventPublisher
     */
    static class CustomAuthenticationEventPublisher extends DefaultAuthenticationEventPublisher {

        /**
         * コンストラクタ
         *
         * @param applicationEventPublisher {@link ApplicationEventPublisher} オブジェクト
         */
        public CustomAuthenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
            super(applicationEventPublisher);
        }

        /**
         * 認証成功時のメソッド
         * Spring Actuator の Basic認証用ユーザの場合には AuthenticationSuccessEvent を発生させない
         *
         * @param authentication {@link Authentication} オブジェクト
         */
        @Override
        public void publishAuthenticationSuccess(Authentication authentication) {
            if (StringUtils.equals(authentication.getName(), ACTUATOR_USERNAME)) {
                return;
            }
            super.publishAuthenticationSuccess(authentication);
        }

    }

    /**
     * @param auth ???
     * @throws Exception
     */
    @SuppressWarnings("PMD.SignatureDeclareThrowsException")
    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth
            , ApplicationEventPublisher applicationEventPublisher) throws Exception {
        // AuthenticationManagerBuilder#userDetailsService の後に auth.inMemoryAuthentication() を呼び出すと
        // AuthenticationManagerBuilder の defaultUserDetailsService に
        // org.springframework.security.provisioning.InMemoryUserDetailsManager がセットされて
        // Remember Me 認証で InMemoryUserDetailsManager が使用されて DB のユーザが参照されなくなるので、
        // Remember Me 認証で使用する UserDetailsService を一番最後に呼び出す
        // ※今回の場合には auth.userDetailsService(userDetailsService) が一番最後に呼び出されるようにする
        auth.inMemoryAuthentication()
                .withUser(ACTUATOR_USERNAME)
                .password("{noop}xxxxxxxx")
                .roles("ENDPOINT_ADMIN");
        auth.authenticationEventPublisher(new CustomAuthenticationEventPublisher(applicationEventPublisher))
                .userDetailsService(userDetailsService);
    }

}
  • public static final String ACTUATOR_USERNAME = "actuator"; を追加し、configAuthentication メソッド内の .withUser("actuator").withUser(ACTUATOR_USERNAME) に変更します。
  • DefaultAuthenticationEventPublisher を継承した CustomAuthenticationEventPublisher クラスを定義し、publishAuthenticationSuccess メソッドで Spring Actuator の Basic認証用ユーザの場合には何もしないようにします。
  • configAuthentication メソッドの以下の点を変更します。
    • 引数に ApplicationEventPublisher applicationEventPublisher を追加します。
    • .authenticationEventPublisher(new CustomAuthenticationEventPublisher(applicationEventPublisher)) を追加します。

これで update 文は実行されないようになります(DispatcherServlet の DEBUG ログだけが出ています)。

f:id:ksby:20190108021639p:plain

library_forsearch テーブルに初期データを登録して、最初に検索対象図書館を登録不要にする

PostgreSQL を Docker で起動して Flyway で初期データを登録するように変更しましたが、library_forsearch テーブルには初期データを登録していなかったため起動直後は検索対象図書館登録画面から図書館を選択する必要がありました。面倒なので初期データを登録するようにします。

f:id:ksby:20190108024127p:plain

src/main/resources/db/migration/V1.1__insert_data.sql を以下のように変更します。

..........
INSERT INTO public.user_role (role_id, user_id, role) VALUES (9, 8, 'ROLE_USER');

INSERT INTO public.library_forsearch (systemid, formal) VALUES ('Tokyo_NDL', '国立国会図書館東京本館');
  • INSERT INTO public.library_forsearch (systemid, formal) VALUES ('Tokyo_NDL', '国立国会図書館東京本館'); を追加します。

これで最初から「国立国会図書館東京本館」が選択された状態になります。

f:id:ksby:20190108030044p:plain

pmdMain タスク実行時の This analysis could be faster, ... のメッセージが出力されないようにする

build タスクを実行した時に pmdMain タスクで This analysis could be faster, please consider using Incremental Analysis: https://pmd.github.io/pmd-6.10.0/pmd_userdocs_incremental_analysis.html のメッセージが出力されますが、出力しないようにする方法が分かったので反映します。

f:id:ksby:20190108033429p:plain

build.gradle を以下のように変更します。

pmd {
    toolVersion = "6.10.0"
    sourceSets = [project.sourceSets.main]
    ignoreFailures = true
    consoleOutput = true
    ruleSetFiles = rootProject.files("/config/pmd/pmd-project-rulesets.xml")
    ruleSets = []
}
pmdMain {
    def backupLoggerLevel
    doFirst {
        backupLoggerLevel = logger.context.level
        logger.context.level = LogLevel.QUIET
    }
    doLast {
        logger.context.level = backupLoggerLevel
    }
}
  • pmdMain { ... } の部分を追加します。

build タスクを実行すると以下のように This analysis could be faster, ... のメッセージが出力されません。

f:id:ksby:20190108034709p:plain

また PMD で警告が出る場合は以下のように出力されます(WebSecurityConfig クラスで使用されない import 文が残るように変更して build しています)。

f:id:ksby:20190108035432p:plain

HikariCP は最新の 3.3.0 を dependenceis に指定し、spring.datasource.hikari.leak-detection-threshold の値を 5000 → 60000 に変更する

ここまでの状態で Tomcat を起動していろいろ画面を操作してみたのですが、そこそこの頻度で Connection leak detection triggered for org.postgresql.jdbc.PgConnection@4d36771 on thread http-nio-8080-exec-4, stack trace follows のようなメッセージがコンソールに出力されることに気づきました。現在 5 秒で設定していますが、もう少し長めにするとこのエラーは出なくなるようなので 60秒に変更します。

f:id:ksby:20190109214311p:plain

また依存関係にある HikariCP のバージョンが Spring Boot の 2.0.6 では 2.7.9、2.1.1 だと 3.2.0 なのですが、HikariCP/CHANGES を見ると Changes in 3.0.0update to Micrometer 1.0.0. という記述を見つけたので、最新の 3.3.0 に変更するとにします。

まずは build.gradle に implementation("com.zaxxer:HikariCP:3.3.0") を追加した後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

dependencies {
    ..........
    implementation("org.flywaydb:flyway-core:5.2.4")
    implementation("com.zaxxer:HikariCP:3.3.0")
    testImplementation("org.dbunit:dbunit:2.6.0")
    ..........

src/main/resources/application.properties を以下のように変更します。

#spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration
spring.datasource.hikari.jdbc-url=jdbc:postgresql://localhost/ksbylending
spring.datasource.hikari.username=ksbylending_user
spring.datasource.hikari.password=xxxxxxxx
spring.datasource.hikari.driver-class-name=org.postgresql.Driver
spring.datasource.hikari.leak-detection-threshold=60000
spring.datasource.hikari.register-mbeans=true
  • spring.datasource.hikari.leak-detection-threshold=5000spring.datasource.hikari.leak-detection-threshold=60000 に変更します。

runtimeOnly("org.springframework.boot:spring-boot-properties-migrator") を削除する

Tomcat 起動時に spring-boot-properties-migrator がメッセージを出力していなかったので、build.gradle の dependencies block から runtimeOnly("org.springframework.boot:spring-boot-properties-migrator") を削除します。削除後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

次回は。。。

Spring Framework の 5.1.4 がリリースされたので、まもなく Spring Boot の 2.0.8 が出るはずです。2.0.8 にバージョンアップしてから jar ファイルを作成→動作確認してから、最後に感想を書いて終わりにします。

履歴

2019/01/11
初版発行。