🔐

GolangでローカルでSAML認証を実装してみる

2024/10/20に公開

SAML認証の実装を試してみたいと思い、ローカルで雑に動くSAML実装をGolangでやってみました。
https://github.com/crewjam/saml を使えばとても簡単にできました。

ローカルで動くIdPを用意

まずローカルで動くIdPを用意します。
これに関しては以下の記事を参照下さい。
ローカル環境でテストに用に起動できるSAML-IdPサーバ #Node.js - Qiita

npm run saml-idp

を実行して http://localhost:7000 にアクセスすると以下の画面がでるはずです。

SP(Service Provide)側の実装

次にSP(Service Provide)側を実装します。
基本的に、 https://github.com/crewjam/samlGetting Started as a Service Provider を進めてくことになります。

SAMLアサーションの署名検証のために公開鍵と秘密鍵を生成する必要があります。以下のコマンドで生成します。実行場所はどこでもいいですが、分かりやすくするためプロジェクトの直下で実行しました。

openssl req -x509 -newkey rsa:2048 -keyout myservice.key -out myservice.cert -days 365 -nodes -subj "/CN=myservice.example.com"

次にGoの実装です。
以下の内容のmain.goを用意します。

package main

import (
	"context"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"net/http"
	"net/url"

	"github.com/crewjam/saml/samlsp"
)

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, %s!", samlsp.AttributeFromContext(r.Context(), "displayName"))
}

func main() {
	keyPair, err := tls.LoadX509KeyPair("myservice.cert", "myservice.key")
	if err != nil {
		panic(err) // TODO handle error
	}
	keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
	if err != nil {
		panic(err) // TODO handle error
	}

	idpMetadataURL, err := url.Parse("http://localhost:7000/metadata") // ここを変更
	if err != nil {
		panic(err) // TODO handle error
	}
	idpMetadata, err := samlsp.FetchMetadata(context.Background(), http.DefaultClient,
		*idpMetadataURL)
	if err != nil {
		panic(err) // TODO handle error
	}

	rootURL, err := url.Parse("http://localhost:8000")
	if err != nil {
		panic(err) // TODO handle error
	}

	samlSP, _ := samlsp.New(samlsp.Options{
		URL:         *rootURL,
		Key:         keyPair.PrivateKey.(*rsa.PrivateKey),
		Certificate: keyPair.Leaf,
		IDPMetadata: idpMetadata,
	})
	app := http.HandlerFunc(hello)
	http.Handle("/hello", samlSP.RequireAccount(app))
	http.Handle("/saml/", samlSP)
	http.ListenAndServe(":8000", nil)
}

次にプロジェクト直下で以下を実行します。

go mod init go-saml-test
go mod tidy

すると以下でサーバーが立ち上がります。

go run main.go

IdPからSPの設定

次にIdPからSPの設定をします。
http://localhost:7000 にアクセスして、右上のSettingsにアクセスします。

下の方にService Provider Settingsエリアがあるので、以下のように変更します。

これで準備完了です。

SAML認証を試す

http://localhost:8000/hello にアクセスすると、 IdPの画面にリダイレクトされます。
画面下にSign inのボタンがあるのでクリックします。

すると、SP側の画面に戻り Hello, saml jackson! という文字が表示されます。

実際には、hello関数をlogin関数にしてその中でログイン処理(SAMLレスポンスからユーザ情報を抜き出しセッションの作成)をすることになると思います。

まとめ

https://github.com/crewjam/saml を使うことで簡単にSAML認証が実装できました。
実際に動かしてみると理解が深まりますね。
プロダクトとして動かすにはログアウト周り(Single LogoutやSP側でログアウトした場合IdP側でもログアウトするなど)を考えないといけないので、もう少し実装が必要そうです。

Discussion