利用Golang,利用Keycloak的SAML进行分析
1. 生成证书
SAML的Service Provider需要证书。使用以下命令生成证书:
# openssl req -x509 -newkey rsa:2048 -keyout myservice.key -out myservice.cert -days 365 -nodes -subj "/CN=myservice.example.com"
2. Service Provider Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
// https://github.com/ssup2/golang-Keycloak-SAML/blob/master/main.go
// Print SAML request
func samlRequestPrinter(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Printf("%+v\n", r)
next.ServeHTTP(w, r)
})
}
// Echo session info
func echoSession(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%v\n", samlsp.SessionFromContext(r.Context()))
}
func main() {
// Load certificate keypair
keyPair, err := tls.LoadX509KeyPair("myservice.cert", "myservice.key")
if err != nil {
panic(err)
}
keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
if err != nil {
panic(err)
}
// Get identity provider info from identity provider meta URL
idpMetadataURL, err := url.Parse("http://localhost:8080/realms/ssup2/protocol/saml/descriptor")
if err != nil {
panic(err)
}
idpMetadata, err := samlsp.FetchMetadata(context.Background(), http.DefaultClient,
*idpMetadataURL)
if err != nil {
panic(err)
}
// Get SAML service provider middleware
rootURL, err := url.Parse("http://localhost:8000")
if err != nil {
panic(err)
}
samlSP, _ := samlsp.New(samlsp.Options{
URL: *rootURL,
Key: keyPair.PrivateKey.(*rsa.PrivateKey),
Certificate: keyPair.Leaf,
IDPMetadata: idpMetadata,
})
// Set SAML's metadata and ACS (Assertion Consumer Service) endpoint with SAML request printer
http.Handle("/saml/", samlRequestPrinter(samlSP))
// Set session handler to print session info
app := http.HandlerFunc(echoSession)
http.Handle("/session", samlSP.RequireAccount(app))
// Serve HTTP
http.ListenAndServe(":8000", nil)
}
|
[Code1]是SAML Service Provider应用程序,通过SAML Identity Provider对用户进行身份验证,并输出通过身份验证过程获得的SAML Session信息。完整的App Code可在以下Repo中查看。
https://github.com/ssup2/golang-Keycloak-SAML
动作过程如下。
- 当用户连接到Service Provider的“/session”路径时,Service Provider通过RequireAccount()Middleware函数将SAML请求发送给Identity Provider,以便用户进行身份验证。SAML请求还包含验证后用户请求的URL信息。
- 通过Identity Provider完成身份验证后,Identity Provider将User重新定向到之前注册的Service Provider的ACS端点“/saml/acs”,身份验证信息SAML Response也将一起发送到ACS端点。SAML Response还包含SAML请求中包含的用户请求的URL信息。
- Service Provider的ACS接收SAML Response,然后查看身份验证信息,并在Web Browser的Cookie中设置身份验证。之后,Service Provider将User重新重定向到SAML Response中包含的User请求的URL,以便User可以使用Service。
[Code1]的每行说明如下:
- Line3,51:samlRequestPrinter()函数是一个Middleware,它输出传入ACS的请求。
- Line12:echoSession()函数是返回SAML设置的Session信息的函数。
- Line 55:samlSP.RequireAccount()函数是Middleware,在访问“/session”路径时要求Identity Provider进行身份验证。
3.提取Service Provider Metadata
必须提取[Code1]的Service Provider的Metadata。提取的Metadata用于在Identity Provider中注册Service Provider。使用以下命令提取Service Provider的Metadata:[Code1]的Service Provider可以通过“/saml/metadata”路径提取。
# go run main.go
# curl localhost:8000/saml/metadata > metadata
4.安装、设置Keycloak
使用Docker安装Keycloak。Keycloak的Admin ID/Password设置为admin/admin。
# docker run --name keycloak -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -d quay.io/keycloak/keycloak:17.0.0 start-dev
5. 运行Service Provider