2025年2月11日火曜日

Spring Boot で SAML 認証をする(署名無しバージョン)

前提

  • Java: 21
  • Spring Boot: 3.4.2
  • Keycloak: 26

開発環境の起動

詳細は docker-compose.yaml を参照。

Spring Initilizr

this

Keycloak の設定

  1. http://localhost:8080/ へ接続し、以下情報でログイン
    • ユーザー名: admin
    • パスワード: password
  2. レルムの作成
    • レルム名: myrealm
  3. クライアントの作成
    1. Clients > Create client
      • Client type: SAML
      • Client ID: saml-sp
      • Name: SAML Practice
    2. Settings タブで必要事項を設定
      • Root URL: http://localhost:8081/
      • Valid redirect URIs: http://localhost:8081/*
    3. Keys タブで必要事項を設定
      • Client signature required: Off
  4. ユーザーの追加
    1. Users > Add user で、必要事項を記入して Create 押下
      • Username: test
    2. Credentials タブで Set password を押下し、必要事項を記入し Save
      • Password: test
      • Password confirmation: test
      • Temporary: Off

依存を追加

pom.xml に Shiboleth のリポジトリを追加し、 spring-security-saml2-service-provider の dependency を追加する。

<repositories>
  <repository>
    <id>shibboleth</id>
    <name>Shibboleth Repository</name>
    <url>https://build.shibboleth.net/nexus/content/repositories/releases/</url>
    <releases>
      <enabled>true</enabled>
    </releases>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </repository>
</repositories>
...(snip
  <dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-saml2-service-provider</artifactId>
  </dependency>
...(snip

Security のコンフィギュレーションを作成

package dev.mikoto2000.study.saml.firststep.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(auth -> auth
          .requestMatchers("/", "/public").permitAll()
          .anyRequest().authenticated()
          )
      .saml2Login(saml2 -> saml2
          .loginProcessingUrl("/login/saml2/sso/myrealm")
          )
      .logout(logout -> logout
          .logoutSuccessUrl("/")
          );
    return http.build();
  }
}

署名に使うファイル群の作成

# 1. 秘密鍵を作成
openssl genpkey -algorithm RSA -out private.key

# 2. 証明書リクエストを作成
openssl req -new -key private.key -out cert.csr \
    -subj "/C=JP/ST=Tokyo/L=Shibuya/O=ExampleCorp/OU=IT/CN=localhost"

# 3. 証明書を発行
openssl x509 -req -days 3650 -in cert.csr -signkey private.key -out certificate.crt

# 4. 秘密鍵と証明書をクラスパス直下に移動
mv certificate.crt private.key ./src/main/resources/

アプリケーション設定

spring:
  security:
    saml2:
      relyingparty:
        registration:
          myrealm:
            # Keycloak の Client ID と合わせる
            entity-id: "saml-sp"
            signing:
              credentials:
                # さっき作った証明書などの情報を入力
                - private-key-location: "classpath:private.key"
                  certificate-location: "classpath:certificate.crt"
                  private-key-password: "changeit"
                  private-key-alias: "saml-key"
                  key-store-password: "changeit"
            assertingparty:
              metadata-uri: "http://keycloak:8080/realms/myrealm/protocol/saml/descriptor"

# デバッグ出力を有効化
logging:
  level:
    org:
      springframework.web: debug

# Keycloak とポートがかぶるのでこっちを変更
server:
  port: 8081

表示するページの作成

以下静的ページを src/main/resources/static 下に格納する。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>test</title>
</head>
<body>
  Hello, World!
</body>
</html>

hosts ファイルの更新

hosts ファイルに以下エントリーを追加。

127.0.0.1 keycloak

動作確認

  1. http://localhost:8081/index.html へ接続すると、 keycloak へリダイレクトされる
  2. 先ほど作った test ユーザーでログインすると、 index.html が表示される

OK.

2025年1月28日火曜日

Nuxt のアプリを nexe でシングルバイナリにする

Nuxt のアプリを nexe でシングルバイナリにしたいという方が居たので、 試しにやってみた。

Nuxt アプリケーションの作成

プロジェクトの初期化

vscode ➜ .../TIL/js/nuxtjs/firststep (master) $ npx nuxi@latest init firststep
Need to install the following packages:
nuxi@3.20.0
Ok to proceed? (y) y


 Which package manager would you like to use?
npm
 Installing dependencies...
npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported

> postinstall
> nuxt prepare

 Types generated in .nuxt

added 671 packages, and audited 673 packages in 1m

130 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
 Installation completed.
 Initialize git repository?
No
 Nuxt project has been created with the v3 template. Next steps:
  cd firststep
  Start development server with npm run dev
npm notice
npm notice New major version of npm available! 10.9.2 -> 11.0.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.0.0
npm notice To update run: npm install -g npm@11.0.0
npm notice

開発サーバー起動

cd firststep
npm run dev -- -o

動作確認

ブラウザで、 http://localhost:3000 へアクセスする。

ウェルカムページが見える。 OK.

Next プロジェクトのビルド

npm run build

.output/server/index.mjs にビルド結果のエントリーポイントが出力される。

シングルバイナリ化

esbuild を使ってバンドル・ミニファイ

npx esbuild .output/server/index.mjs --bundle --minify --platform=node --target=node14.17.0 --outdir=dist

Node のバージョンは、ビルド時間短縮のため、 nexe が提供している最新のプレビルドバイナリのバージョンで動くものを指定

これで、 ./dist/index.js にバンドル・ミニファイされたソースコードが出力される。

nexe を使ってシングルバイナリ化

npx nexe -i dist/index.js -o firststep --target windows-x64-14.15.3

windows-x64-14.15.3 が「nexe が提供している最新のプレビルドバイナリのバージョン」。

これで、 ./firststep.exe に実行バイナリが出力される。

動作確認

firststep.exe を Windows へ持っていき、ダブルクリック。

http://localhost:3000 へアクセス。OK.

もっと複雑なアプリケーションの場合は分からないが、 Get Started レベルのアプリならこれで OK なようだ。

最新の Node.js でビルドする

-b オプションを追加すると、指定した Node.js のソースをダウンロードし、 Node.js のビルドから開始する。

そのため、より新しい Node.js を使用したい場合には -b オプションを追加したうえで、 Node のバージョンに所望のバージョンを指定する。

npx esbuild .output/server/index.mjs --bundle --minify --platform=node --target=node22.13.1 --outdir=dist
npx nexe -i dist/index.js -o firststep -b --target windows-x64-22.13.1

Node.js のビルドが走るので、最悪数時間のビルド時間がかかる。

ただ、ビルド後の Node.js は ~/.nexe にキャッシュされるので、 2 回目以降のビルドは早くなる。

以上。

参考資料

2025年1月24日金曜日

ddt.vim を試す

Vim 上で動くターミナルに興味があるので、 denops の環境構築から試していく。

前提

今回使った devcontainer.json:
{
  "name": "ddt.vim study",
  "image": "ubuntu:24.04",
  "features": {
    "ghcr.io/devcontainers-community/features/deno:1": {}
  }
}

必要パッケージのインストール

プラグインインストール簡単化のために、 git が必要なので、インストールする。

apt update
apt install -y git

denops のインストール

Vim のパッケージ機能と git submodule を組み合わせてプラグインのインストールを行う。

なので今回は git submodulepack/denops/start/denops に配置する。

~/.vim に移動して、git リポジトリを初期化・サブモジュールの追加を行う。

cd ~
mkdir .vim
cd .vim
git init
git branch -m main
git submodule add https://github.com/vim-denops/denops.vim.git pack/denops/start/denops

ddt.vim のインストール

同様に `git submodule でインストールする。

git submodule add https://github.com/Shougo/ddt.vim.git pack/b/start/ddt.vim

ddt.vim の ui プラグインをインストール

git submodule add https://github.com/Shougo/ddt-ui-terminal.git pack/b/start/ddt-ui-terminal
git submodule add https://github.com/Shougo/ddt-ui-shell.git pack/b/start/ddt-ui-shell

設定

vimrc を作成し、プラグインの読み込みなど、最低限の設定を行う。

shougo-s-github/vim/rc/ddt.vim - Shougo/shougo-s-github を参考に、 deno の設定も追加。

~/ddt.vimrc:

packadd denops
packadd ddt.vim
packadd ddt-ui-terminal
packadd ddt-ui-shell

let g:denops#server#deno_args = [
    \   '-q',
    \   '-A',
    \ ]
let g:denops#server#deno_args += ['--unstable-ffi']

call ddt#custom#patch_global(#{
      \   uiParams: #{
      \     shell: #{
      \       nvimServer: '~/.cache/nvim/server.pipe',
      \       prompt: '=\\\>',
      \       promptPattern: '\w*=\\\> \?',
      \     },
      \     terminal: #{
      \       nvimServer: '~/.cache/nvim/server.pipe',
      \       command: ['bash'],
      \       promptPattern: has('win32') ? '\f\+>' : '\w*% \?',
      \     },
      \   },
      \ })

vimrc の作成が終わったら Vim を再起動し、以下コマンドで設定を読み込ませる。

:source ~/ddt.vimrc

ddt-ui-terminal の起動

こちらも shougo-s-github/vim/rc/ddt.vim - Shougo/shougo-s-github を参考に terminal ui を起動。

:call ddt#start(#{ name: t:->get('ddt_ui_terminal_last_name', 'terminal-' .. win_getid()), ui: 'terminal', })

Vim の :terminal が起動し、いつもと同じように操作できる。

ddt-ui-shell の起動

おなじく shougo-s-github/vim/rc/ddt.vim - Shougo/shougo-s-github を参考に shell ui を起動。

:call ddt#start(#{name: t:->get('ddt_ui_shell_last_name', 'shell-' .. win_getid()), ui: 'shell', })

空のバッファが表示されるが、一度エンターキーを押下すると、(前述の設定だと)以下のプロンプトが表示される。

/workspaces/TIL/vim/ddt
=\\\> 

ここからは癖強なので細かく説明していく。

  1. ここで、 uname -a を入力し、次の状態に持っていく
/workspaces/TIL/vim/ddt
=\\\> uname -a
  1. :call ddt#ui#do_action('executeLine') を実行する
  2. エンターキーを押下すると、以下のように uname -a の結果が表示される
/workspaces/TIL/vim/ddt
=\\\> uname -a
Linux 84223c761d6e 5.15.167.4-microsoft-standard-WSL2 #1 SMP Tue Nov 5 00:21:55 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
/workspaces/TIL/vim/ddt
=\\\>

このように、コマンドの実行すら関数を呼び出さないと行けないので、使い勝手の良いシェルにするには自分でマッピング定義をする必要がある。

ddt-ui-shell の設定

以下のようなマッピングを行うと、「プロンプトの行でエンターを押すと、記載されたコマンドの実行と結果表示」ができるようになる。

""" {{{ for ddt-ui-shell
augroup ddt-shell
    autocmd!
    autocmd FileType ddt-shell nnoremap <buffer> <CR> <Cmd>call ddt#ui#do_action('executeLine')<CR>
    autocmd FileType ddt-shell inoremap <buffer> <CR> <Cmd>call ddt#ui#do_action('executeLine')<CR>
augroup END
""" }}} for ddt-ui-shell

あとは ddt や ddt-ui-shell 等のヘルプを観ながら自分の好きなようにマッピングを追加していけばよい。

以上。

参考資料