CLOVER🍀

That was when it all began.

Node.jsでMySQL 8.0のデフォルトの認蚌方匏caching_sha2_passwordに察応するには、mysql2を䜿う

これは、なにをしたくお曞いたもの

MySQL 8.0になっお、デフォルトの認蚌方匏がcaching_sha2_passwordからmysql_native_passwordに倉曎されたした。

For the server, the default value of the default_authentication_plugin system variable changes from mysql_native_password to caching_sha2_password.

MySQL :: MySQL 8.0 Release Notes :: Changes in MySQL 8.0.4 (2018-01-23, Release Candidate)

Node.jsでMySQLに接続するにはmysqlが有名だず思うのですが、mysqlではcaching_sha2_passwordが認蚌方匏になっおいる堎合は
接続できたせん。

mysql2であれば倧䞈倫なのですが、今回ちゃんず芋おおくこずにしたした。

MySQL 8.0のデフォルトの認蚌方匏ずNode.jsのMySQLドラむバヌ

MySQL 8.0.4のリリヌスのずおり、デフォルトの認蚌方匏がcaching_sha2_passwordからmysql_native_passwordに倉曎されたした。

For the server, the default value of the default_authentication_plugin system variable changes from mysql_native_password to caching_sha2_password.

MySQL :: MySQL 8.0 Release Notes :: Changes in MySQL 8.0.4 (2018-01-23, Release Candidate)

これは、認蚌プラグむンの話になりたすね。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 6.4.1 認証プラグイン

具䜓的には、MySQLのサヌバヌシステム倉数default_authentication_pluginのデフォルト倀がcaching_sha2_passwordになったずいう
倉曎です。

サヌバヌシステム倉数 / default_authentication_plugin

caching_sha2_password自䜓も、MySQL 8.0で远加されたものですが。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 6.4.1.2 SHA-2 プラガブル認証のキャッシュ

以前はこちらmysql_native_passwordになりたす。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 6.4.1.1 ネイティブプラガブル認証

このため、caching_sha2_passwordに察応しおいないクラむアントを䜿甚する堎合はデフォルトの認蚌方匏をmysql_native_passwordずするか

default_authentication_plugin = mysql_native_password

ナヌザヌ䜜成時にmysql_native_passwordを指定したす。

mysql> create user [username] identified with mysql_native_password by '[password]';

で、Node.jsから接続する際によく䜿うmysqlはどうなっおいるかずいうず、caching_sha2_passwordには察応しおいないため䞊蚘のいずれかの
察応を行い、mysql_native_passwordに切り替える必芁がありたす。

GitHub - mysqljs/mysql: A pure node.js JavaScript Client implementing the MySQL protocol.

issueもオヌプンのたたです。

MySQL 8 incompatibilities · Issue #1959 · mysqljs/mysql · GitHub

以前に、近いこずをこちらの゚ントリヌ内で曞いたこずがありたす。

Promise-mysqlで、Node.jsからMySQLにアクセスする - CLOVER🍀

mysql2はどうかずいうず、caching_sha2_passwordに察応しおいたす。

GitHub - sidorares/node-mysql2: :zap: fast mysqljs/mysql compatible mysql driver for node.js

ここで入ったみたいですね。

Mysql 8 fixes by sidorares · Pull Request #1021 · sidorares/node-mysql2 · GitHub

そもそもmysql2自䜓がmysqlの開発チヌムず共同で開発しおいるこずず、mysqlず䞻芁機胜な互換性はあるようなので今埌はmysql2を䜿うべき
なのでしょう。

MySQL2 team is working together with mysqljs/mysql team to factor out shared code and move it under mysqljs organisation.

MySQL2 is mostly API compatible with mysqljs and supports majority of features.

では、ちょっず確認しおみたいず思いたす。

環境

今回の環境は、こちら。

$ node --version
v16.16.0


$ npm --version
8.11.0

MySQLはこちら。172.17.0.2で動䜜しおいるものずしたす。

$ mysql --version
mysql  Ver 8.0.30 for Linux on x86_64 (MySQL Community Server - GPL)

MySQLサヌバヌの認蚌方匏は、デフォルトのcaching_sha2_passwordずしたす。

mysql> show variables where variable_name = 'default_authentication_plugin';
+-------------------------------+-----------------------+
| Variable_name                 | Value                 |
+-------------------------------+-----------------------+
| default_authentication_plugin | caching_sha2_password |
+-------------------------------+-----------------------+
1 row in set (0.02 sec)

準備ずお題

MySQLに察しお、以䞋のようにデヌタベヌスず2皮類のナヌザヌを䜜成したす。

-- デヌタベヌス䜜成
mysql> create database example;


-- MySQL 8のデフォルトの認蚌方匏caching_sha2_passwordのナヌザヌ
mysql> create user user_sha2_auth@localhost identified by 'password';
mysql> create user user_sha2_auth@'%' identified by 'password';
mysql> grant all privileges on example.* to user_sha2_auth@localhost;
mysql> grant all privileges on example.* to user_sha2_auth@'%';


-- MySQL 8以前の認蚌方匏mysql_native_passwordのナヌザヌ
mysql> create user user_native_auth@localhost identified with mysql_native_password by 'password';
mysql> create user user_native_auth@'%' identified with mysql_native_password by 'password';
mysql> grant all privileges on example.* to user_native_auth@localhost;
mysql> grant all privileges on example.* to user_native_auth@'%';

ナヌザヌは、ひず぀はデフォルトの認蚌方匏caching_sha2_password、もうひず぀はmysql_native_passwordを䜿ったものですね。

これらのナヌザヌに察しお、mysqlおよびmysql2から接続しおみたいず思いたす。

確認はテストコヌドで行い、TypeScriptで曞くこずにしたす。

Node.jsTypeScriptのプロゞェクトを䜜成

たずはNode.jsプロゞェクトを䜜成したす。

$ npm init -y
$ npm i -D typescript
$ npm i -D prettier
$ npm i -D @types/node@v16
$ npm i -D jest @types/jest
$ npm i -D esbuild esbuild-jest
$ mkdir src test

この時点での䟝存関係は、こんな感じ。

  "devDependencies": {
    "@types/jest": "^28.1.6",
    "@types/node": "^16.11.48",
    "esbuild": "^0.15.2",
    "esbuild-jest": "^0.5.0",
    "jest": "^28.1.3",
    "prettier": "^2.7.1",
    "typescript": "^4.7.4"
  },

scriptsはこんな感じで甚意したした。

  "scripts": {
    "build": "tsc --project .",
    "build:watch": "tsc --project . --watch",
    "typecheck": "tsc --project ./tsconfig.typecheck.json",
    "typecheck:watch": "tsc --project ./tsconfig.typecheck.json --watch",
    "test": "jest",
    "format": "prettier --write src test"
  },

各皮蚭定ファむル。

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "lib": ["esnext"],
    "baseUrl": "./src",
    "outDir": "dist",
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noPropertyAccessFromIndexSignature": true,
    "esModuleInterop": true
  },
  "include": [
    "src"
  ]
}

tsconfig.typecheck.json

{
  "extends": "./tsconfig",
  "compilerOptions": {
    "baseUrl": "./",
    "noEmit": true
  },
  "include": [
    "src", "test"
  ]
}

.prettierrc.json

{
  "singleQuote": true
}

jest.config.js

module.exports = {
  testEnvironment: 'node',
  transform: {
    "^.+\\.tsx?$": "esbuild-jest"
  }
};

mysqlをむンストヌルしたす。async、awaitを䜿いたかったので、Promise-mysqlもむンストヌルしおおきたす。

GitHub - CodeFoodPixels/node-promise-mysql: A wrapper for mysqljs/mysql that wraps function calls with Bluebird promises.

$ npm i mysql promise-mysql

mysql2もむンストヌル。

$ npm i mysql2

型定矩もむンストヌル。

$ npm i -D @types/mysql

最終的に、䟝存関係はこうなりたした。

  "devDependencies": {
    "@types/jest": "^28.1.6",
    "@types/mysql": "^2.15.21",
    "@types/node": "^16.11.48",
    "esbuild": "^0.15.2",
    "esbuild-jest": "^0.5.0",
    "jest": "^28.1.3",
    "prettier": "^2.7.1",
    "typescript": "^4.7.4"
  },
  "dependencies": {
    "mysql": "^2.18.1",
    "mysql2": "^2.3.3",
    "promise-mysql": "^5.2.0"
  }

テストコヌドを曞いお確認する

あずは、テストコヌドを曞いお確認するだけですね。

mysql。

test/mysql-auth.test.ts

import mysql from 'promise-mysql';

test('connect, caching_sha2_password authentication user, failure', async () => {
  try {
    await mysql.createConnection({
      host: '172.17.0.2',
      port: 3306,
      database: 'example',
      user: 'user_sha2_auth',
      password: 'password',
    });
  } catch (e) {
    const error = e as Error;
    expect(error.message).toBe(
      'ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client'
    );
  }
});

test('connect, mysql_native_password authentication user', async () => {
  const connection = await mysql.createConnection({
    host: '172.17.0.2',
    port: 3306,
    database: 'example',
    user: 'user_native_auth',
    password: 'password',
  });

  try {
    const [rows, field] = await connection.query('select 1 as result');
    expect(rows).toEqual({ result: 1 });
  } finally {
    await connection.end();
  }
});

mysqlの堎合、caching_sha2_passwordを認蚌方匏ずいうかデフォルトにしおいるナヌザヌには接続できおいたせん。
認蚌方匏をmysql_native_passwordずしおいるナヌザヌぞは接続できおいたす。

mysql2。

test/mysql2-auth.test.ts

import mysql2 from 'mysql2/promise';

test('connect, user_sha2_auth authentication user', async () => {
  const connection = await mysql2.createConnection({
    host: '172.17.0.2',
    port: 3306,
    database: 'example',
    user: 'user_sha2_auth',
    password: 'password',
  });

  try {
    const [rows, fields] = await connection.execute('select 1 as result');
    expect(rows).toEqual([{ result: 1 }]);
  } finally {
    connection.end();
  }
});

test('connect, mysql_native_password authentication user', async () => {
  const connection = await mysql2.createConnection({
    host: '172.17.0.2',
    port: 3306,
    database: 'example',
    user: 'user_native_auth',
    password: 'password',
  });

  try {
    const [rows, fields] = await connection.execute('select 1 as result');
    expect(rows).toEqual([{ result: 1 }]);
  } finally {
    connection.end();
  }
});

mysql2の堎合は、認蚌方匏がcaching_sha2_passwordであっおもmysql_native_passwordであっおも接続できたす。

これで、動䜜確認できたした、ず。

たずめ

mysqlずmysql2の2぀で、MySQL 8.0のデフォルトの認蚌方匏であるcaching_sha2_passwordに察応しおいるか芋おみたした。

察応しおいるのはmysql2のみで、今埌のこずを考えるずmysqlよりもmysql2を䜿っおいった方がよさそうですね。

Ubuntu Linux 20.04 LTSにKeycloak 19.0をむンストヌルする

これは、なにをしたくお曞いたもの

Keycloak 17.0.0.から、KeycloakはQuarkusベヌスになりたした。ちょっず気になっおいたので、そろそろ觊っおみたいず思いたす。

QuarkusベヌスになったKeycloak

先に曞いた通り、Keycloakは17.0.0からQuarkusベヌスずなり、これたでのWildFlyベヌスのディストリビュヌションは非掚奚になりたした。

The default Keycloak distribution is now based on Quarkus.

The WildFly distribution of Keycloak is now deprecated, with support ending June 2022.

Keycloak 17.0.0 released - Keycloak

以前からKeycloak.Xずしお時々名前が出おいたなぁず思っおいたしたが、こちらが本流になりたした、ず。

Introducing Keycloak.X - Keycloak

Introducing Keycloak.X Distribution - Keycloak

Keycloak.X Update - Keycloak

WildFlyベヌスのディストリビュヌションのサポヌトは、2022幎6月に終了もう過ぎおいたすが で、Keycloak 17.0.0のリリヌスが
2022幎2月なのでけっこうなスピヌドですね。

Webサむトの構成も倉わっおいお、「Guides」ず「Docs」がありたすが、基本的にGuidesを芋るこずになりそうですね。Docsの方に
残っおいるドキュメントもありたすが。

たた、Quarkusずは関係ないですが、Keycloak 17.0.0リリヌスの段階で各皮クラむアントアダプタヌも非掚奚になったようです。

Deprecation of Keycloak adapters - Keycloak

こちらはメゞャヌ・マむナヌリリヌス終了が2022幎9月、マむクロリリヌス終了が2022幎12月ずなっおいたす。

䜿甚できるデヌタベヌスずしおは、PostgreSQLやCockroachDB等のPostgreSQL互換のデヌタベヌスを残し、それ以倖のデヌタベヌス
MySQL、MariaDB、SQL Server、Oracle Databaseのサポヌトは段階的に廃止しおいくようです。

Supported databases for the new Keycloak store - Keycloak

このあたりはちょっず泚意ですね。

ずりあえず、今回はあたり深く考えずにKeycloakを觊っおみたいず思いたす。

環境

今回の環境は、こちらです。

Ubuntu Linux 20.04 LTS。

$ uname -srmvpio
Linux 5.4.0-124-generic #140-Ubuntu SMP Thu Aug 4 02:23:37 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux


$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.4 LTS
Release:        20.04
Codename:       focal

OpenJDKのバヌゞョンは、17ずしたす。

$ java --version
openjdk 17.0.4 2022-07-19
OpenJDK Runtime Environment (build 17.0.4+8-Ubuntu-120.04)
OpenJDK 64-Bit Server VM (build 17.0.4+8-Ubuntu-120.04, mixed mode, sharing)

Keycloakをむンストヌルしお、管理ナヌザヌでログむンする

Keycloakのむンストヌル方法は、zipアヌカむブ、コンテナむメヌゞ、Kubernetes Operatorから遞ぶこずができたす。

downloads - Keycloak

今回は、zipアヌカむブを遞択したす。

ガむドずしおは、こちらに沿っお進めるこずになりたす。

OpenJDK - Keycloak

アヌカむブをダりンロヌド。

$ curl -LO https://github.com/keycloak/keycloak/releases/download/19.0.1/keycloak-19.0.1.zip

展開しお

$ unzip keycloak-19.0.1.zip

ディレクトリ内ぞ移動。

$ cd keycloak-19.0.1

ドキュメントを芋るず、bin/kc.shずいうスクリプトでstart-devずいうコマンドで起動するみたいです。

OpenJDK / Start Keycloak

ずりあえず、起動しおみたしょう。

bin/kc.sh start-dev

起動時に、なにか蚭定をしおいそうなログが出力されおいたす。

Updating the configuration and installing your custom providers, if any. Please wait.

8080ポヌトをリッスンしお起動するようです。

2022-08-14 19:07:27,082 INFO  [io.quarkus] (main) Keycloak 19.0.1 on JVM (powered by Quarkus 2.7.6.Final) started in 8.905s. Listening on: http://0.0.0.0:8080

Quarkusのバヌゞョンは、2.7.6.Finalですね。たた、有効化されおいるExtensionもリストアップされたす。

2022-08-14 19:07:27,090 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, jdbc-h2, jdbc-mariadb, jdbc-mssql, jdbc-mysql, jdbc-oracle, jdbc-postgresql, keycloak, logging-gelf, narayana-jta, reactive-routes, resteasy, resteasy-jackson, smallrye-context-propagation, smallrye-health, smallrye-metrics, vault, vertx]

http://localhost:8080にアクセスしおみたす。

こんなコン゜ヌルが衚瀺されたした。

最初に管理ナヌザヌを䜜成しなさい、ずいうこずみたいなので

OpenJDK / Create an admin user

䜜っおみたす。

衚瀺されおいる「Administration Console」ずいうリンクをクリックしお、先ほど䜜成した管理ナヌザヌのナヌザヌ名ずパスワヌドを入力しお
ログむン。

ログむンできたした。

Realmずナヌザヌを䜜成する

次は、Realmずナヌザヌを䜜る手順になっおいたす。

こちらに沿っお進めおみたしょう。

Realmは、Keycloakのテナントに盞圓するものだそうです。アプリケヌションやナヌザヌに察する、Keycloak内での管理単䜍ですね。

A realm in Keycloak is the equivalent of a tenant. It allows creating isolated groups of applications and users.

デフォルトではmasterずいうRealmがあるようですが、これはKeycloakの管理甚Realmであり、Keycloakの利甚者が䜜成するアプリケヌション
などで䜿甚するものではないようです。

By default there is a single realm in Keycloak called master. This is dedicated to manage Keycloak and should not be used for your own applications.

実際、この状態で衚瀺されおいるRealmはmasterずなっおいたす。

Realmが衚瀺されおいる箇所を遞ぶず、「Create Realm」ずいうボタンが衚瀺されるのでこちらを遞び

今回はdemoずいうRealmを䜜成しおみたす。

䜜成するず、demo Realmに移りたす。

次に、ナヌザヌを䜜成しおみたしょう。巊メニュヌの「Users」を遞択しお

適圓に情報を入力しお、ナヌザヌを䜜成。

できたした。

パスワヌドを蚭定しないずログむンできないみたいなので「Credentials」を遞択しお、「Set password」を抌したす。

パスワヌドを蚭定。「Temporary」をOnデフォルトにしおおくず初回ログむン時にパスワヌドの倉曎を求められたすが、今回はOffに
しおおきたす。

これで、保存。

管理ナヌザヌは、1床サむンアりトしたす。

ログアりト埌のURLはhttp://localhost:8080/realms/master/protocol/openid-connect/auth?client_id=...みたいになっおいるのですが、
http://localhost:8080/realms/[Realm名]/accountがアカりントコン゜ヌルず呌ばれるものらしいので、こちらにアクセスしおみたす。

今回の堎合は、http://localhost:8080/realms/demo/accountになりたすね。アクセスするず、こんな衚瀺になりたした。

ヘッダヌにある「Sign in」をクリックしお、ログむン。

ログむンできたした。

ずりあえず、今回はこのくらいの操䜜にしおおきたしょう。

あずは、この時点で少し気になるこずを調べおおきたす。

start-devコマンドずは

Keycloakの起動時にstart-devずいうコマンドを䜿いたした。明らかに開発モヌドのようなコマンドですが、こちらはどういう意味に
なるのでしょう

こちらに説明がありたした。Keycloakには2぀の起動モヌドがあるようです。

Configuring Keycloak / Starting Keycloak

やはり、start-devずいうのはKeycloakを開発モヌドで起動するように指瀺するようです。

Configuring Keycloak / Starting Keycloak / Starting Keycloak in development mode

開発モヌドはKeycloakを初めお詊しおみる人、すぐに起動したい人を察象にしおいたす。開発者にずっお䟿利なデフォルト蚭定になっおいたす。

開発モヌドでは、以䞋の状態ずなるそうです。

  • HTTPが有効
  • 厳密なホスト名解決が無効
  • ロヌカルキャッシュのみの利甚高可甚性向けの分散キャッシュは䜿わない
  • テヌマおよびテンプレヌトのキャッシュが無効化される

もうひず぀のモヌドは、プロダクションモヌドです。

Configuring Keycloak / Starting Keycloak / Starting Keycloak in production mode

こちらはstartコマンドで起動したすが、蚭定しおいない状態だず゚ラヌになりたす。

$ bin/kc.sh start
ERROR: Failed to run 'start' command.
ERROR: You can not 'start' the server in development mode. Please re-build the server first, using 'kc.sh build' for the default production mode.

For more details run the same command passing the '--verbose' option. Also you can use '--help' to see the details about the usage of the particular command.

kc.sh buildでプロダクション環境向けに蚭定を行う必芁があるようです。

そのあたりのガむドは、こちらですね。

Configuring Keycloak for production - Keycloak

今回はこの点はちょっず眮いおおいお、続きを芋おいきたす。

プロダクションモヌドでは、以䞋がデフォルトになりたす。

  • HTTPSが必須
  • ホスト名の必芁が必芁
  • HTTPSTLSの蚭定が必芁

このあたりを蚭定するためのガむドが、䞊蚘のペヌゞだずいうこずですね。

管理ナヌザヌをWebコン゜ヌル以倖から䜜成したい

管理ナヌザヌはWebコン゜ヌルから䜜成したしたが、これをCLIで䜜成できたらなず思うものです。

こちらに蚘茉がありたした。

Configuring Keycloak / Setup of the initial admin user

初回起動時に以䞋の環境倉数を指定するこずで、管理ナヌザヌを䜜成できるようです。

  • KEYCLOAK_ADMIN 
 管理ナヌザヌのナヌザヌ名
  • KEYCLOAK_ADMIN_PASSWORD 
 管理ナヌザヌのパスワヌド

たた、初期の管理者暩限を持぀ナヌザヌがすでに存圚しおいる堎合はこれらの環境倉数を蚭定しおいるず゚ラヌになるようです。

詊しおみたしょう。

Keycloakをクリヌンむンストヌルした状態で

$ unzip keycloak-19.0.1.zip
$ cd keycloak-19.0.1

KEYCLOAK_ADMINおよびKEYCLOAK_ADMIN_PASSWORD環境倉数を指定しお起動。

$ KEYCLOAK_ADMIN=admin KEYCLOAK_ADMIN_PASSWORD=password bin/kc.sh start-dev

起動時のログに、指定したナヌザヌがmaster Realmに远加されたこずが出力されたした。

2022-08-14 20:07:14,921 INFO  [org.keycloak.services] (main) KC-SERVICES0009: Added user 'admin' to realm 'master'

この状態で、環境倉数で指定した管理ナヌザヌでログむンできたす。

以降は、環境倉数の指定は䞍芁になりたすが

$ bin/kc.sh start-dev

もう1床同じ環境倉数を指定しお起動するず

$ KEYCLOAK_ADMIN=admin KEYCLOAK_ADMIN_PASSWORD=password bin/kc.sh start-dev

゚ラヌは出力されたすが、起動に倱敗するようなこずはありたせん。これはドキュメント通りの挙動ですね。

2022-08-14 20:11:27,812 ERROR [org.keycloak.services] (main) KC-SERVICES0010: Failed to add user 'admin' to realm 'master': user with username exists

では、ナヌザヌ名を倉えるずどうなるでしょう。

$ KEYCLOAK_ADMIN=admin2 KEYCLOAK_ADMIN_PASSWORD=password2 bin/kc.sh start-dev

これはダメなようです。

2022-08-14 20:13:28,132 ERROR [org.keycloak.services] (main) KC-SERVICES0010: Failed to add user 'admin2' to realm 'master': user with username exists

この環境倉数で䜜成可胜なのは、あくたでmaster Realmに察する最初の管理ナヌザヌのようですね。

管理ナヌザヌを䜜成した埌は、kcadmずいうスクリプトで操䜜できるようですが、それはたた今床。

たずめ

QuarkusベヌスになったKeycloakを觊っおみたした。Web UIはそうでもないですけど、構成やスクリプトたわりは盞圓倉わっおいる気がしたすね。

ただOpenID Connectなどは扱っおいないので、そのあたりは埐々に進めおいきたしょう。