feat: support OIDC (#893)
* feat: support oidc * refactor: sso -> oidc * refactor: add AccessToken * refactor: change some naming
This commit is contained in:
parent
7b3cb2eb00
commit
a67356639b
|
@ -121,6 +121,20 @@ Nickname = "cn"
|
|||
Phone = "mobile"
|
||||
Email = "mail"
|
||||
|
||||
[OIDC]
|
||||
Enable = false
|
||||
RedirectURL = "http://n9e.com/callback"
|
||||
SsoAddr = "http://sso.example.org"
|
||||
ClientId = ""
|
||||
ClientSecret = ""
|
||||
CoverAttributes = true
|
||||
DefaultRoles = ["Standard"]
|
||||
|
||||
[OIDC.Attributes]
|
||||
Nickname = "nickname"
|
||||
Phone = "phone_number"
|
||||
Email = "email"
|
||||
|
||||
[Redis]
|
||||
# address, ip:port
|
||||
Address = "127.0.0.1:6379"
|
||||
|
|
4
go.mod
4
go.mod
|
@ -3,6 +3,7 @@ module github.com/didi/nightingale/v5
|
|||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/fatih/camelcase v1.0.0 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
|
@ -20,6 +21,7 @@ require (
|
|||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/prometheus/common v0.26.0
|
||||
github.com/prometheus/prometheus v2.5.0+incompatible
|
||||
|
@ -27,11 +29,13 @@ require (
|
|||
github.com/toolkits/pkg v1.2.9
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect
|
||||
google.golang.org/genproto v0.0.0-20211007155348-82e027067bd4 // indirect
|
||||
google.golang.org/grpc v1.41.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gorm.io/driver/mysql v1.1.2
|
||||
gorm.io/driver/postgres v1.1.1
|
||||
gorm.io/gorm v1.21.15
|
||||
|
|
9
go.sum
9
go.sum
|
@ -29,6 +29,8 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH
|
|||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
|
@ -249,6 +251,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc=
|
||||
github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
|
@ -298,6 +302,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
|
||||
|
@ -376,6 +381,7 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQ
|
|||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -448,6 +454,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
|
@ -489,6 +496,8 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
|
|||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
|
@ -89,6 +89,14 @@ func (u *User) Add() error {
|
|||
return Insert(u)
|
||||
}
|
||||
|
||||
func (u *User) Update(selectField interface{}, selectFields ...interface{}) error {
|
||||
if err := u.Verify(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return DB().Model(u).Select(selectField, selectFields).Updates(u).Error
|
||||
}
|
||||
|
||||
func (u *User) UpdateAllFields() error {
|
||||
if err := u.Verify(); err != nil {
|
||||
return err
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
package oidcc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/v5/src/storage"
|
||||
|
||||
oidc "github.com/coreos/go-oidc"
|
||||
"github.com/google/uuid"
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type ssoClient struct {
|
||||
verifier *oidc.IDTokenVerifier
|
||||
config oauth2.Config
|
||||
ssoAddr string
|
||||
callbackAddr string
|
||||
coverAttributes bool
|
||||
attributes struct {
|
||||
username string
|
||||
nickname string
|
||||
phone string
|
||||
email string
|
||||
}
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Enable bool
|
||||
RedirectURL string
|
||||
SsoAddr string
|
||||
ClientId string
|
||||
ClientSecret string
|
||||
CoverAttributes bool
|
||||
Attributes struct {
|
||||
Nickname string
|
||||
Phone string
|
||||
Email string
|
||||
}
|
||||
DefaultRoles []string
|
||||
}
|
||||
|
||||
var (
|
||||
cli ssoClient
|
||||
)
|
||||
|
||||
func Init(cf Config) {
|
||||
if !cf.Enable {
|
||||
return
|
||||
}
|
||||
|
||||
cli.ssoAddr = cf.SsoAddr
|
||||
cli.callbackAddr = cf.RedirectURL
|
||||
cli.coverAttributes = cf.CoverAttributes
|
||||
cli.attributes.username = "sub"
|
||||
cli.attributes.nickname = cf.Attributes.Nickname
|
||||
cli.attributes.phone = cf.Attributes.Phone
|
||||
cli.attributes.email = cf.Attributes.Email
|
||||
provider, err := oidc.NewProvider(context.Background(), cf.SsoAddr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
oidcConfig := &oidc.Config{
|
||||
ClientID: cf.ClientId,
|
||||
}
|
||||
|
||||
cli.verifier = provider.Verifier(oidcConfig)
|
||||
cli.config = oauth2.Config{
|
||||
ClientID: cf.ClientId,
|
||||
ClientSecret: cf.ClientSecret,
|
||||
Endpoint: provider.Endpoint(),
|
||||
RedirectURL: cf.RedirectURL,
|
||||
Scopes: []string{oidc.ScopeOpenID, "profile", "email", "phone"},
|
||||
}
|
||||
}
|
||||
|
||||
func wrapStateKey(key string) string {
|
||||
return "n9e_oidc_" + key
|
||||
}
|
||||
|
||||
// Authorize return the sso authorize location with state
|
||||
func Authorize(redirect string) (string, error) {
|
||||
state := uuid.New().String()
|
||||
ctx := context.Background()
|
||||
|
||||
err := storage.Redis.Set(ctx, wrapStateKey(state), redirect, time.Duration(300*time.Second)).Err()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return cli.config.AuthCodeURL(state), nil
|
||||
}
|
||||
|
||||
func fetchRedirect(ctx context.Context, state string) (string, error) {
|
||||
return storage.Redis.Get(ctx, wrapStateKey(state)).Result()
|
||||
}
|
||||
|
||||
func deleteRedirect(ctx context.Context, state string) error {
|
||||
return storage.Redis.Del(ctx, wrapStateKey(state)).Err()
|
||||
}
|
||||
|
||||
// Callback 用 code 兑换 accessToken 以及 用户信息,
|
||||
func Callback(ctx context.Context, code, state string) (*CallbackOutput, error) {
|
||||
ret, err := exchangeUser(code)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ilegal user:%v", err)
|
||||
}
|
||||
|
||||
ret.Redirect, err = fetchRedirect(ctx, state)
|
||||
if err != nil {
|
||||
logger.Debugf("get redirect err:%v code:%s state:%s", code, state, err)
|
||||
}
|
||||
|
||||
err = deleteRedirect(ctx, state)
|
||||
if err != nil {
|
||||
logger.Debugf("delete redirect err:%v code:%s state:%s", code, state, err)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
type CallbackOutput struct {
|
||||
Redirect string `json:"redirect"`
|
||||
Msg string `json:"msg"`
|
||||
AccessToken string `json:"accessToken"`
|
||||
Username string `json:"username"`
|
||||
Nickname string `json:"nickname"`
|
||||
Phone string `yaml:"phone"`
|
||||
Email string `yaml:"email"`
|
||||
}
|
||||
|
||||
func exchangeUser(code string) (*CallbackOutput, error) {
|
||||
ctx := context.Background()
|
||||
oauth2Token, err := cli.config.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to exchange token: %s", err)
|
||||
}
|
||||
|
||||
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("No id_token field in oauth2 token.")
|
||||
}
|
||||
idToken, err := cli.verifier.Verify(ctx, rawIDToken)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to verify ID Token: %s", err)
|
||||
}
|
||||
|
||||
data := map[string]interface{}{}
|
||||
if err := idToken.Claims(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := func(k string) string {
|
||||
if in := data[k]; in == nil {
|
||||
return ""
|
||||
} else {
|
||||
return in.(string)
|
||||
}
|
||||
}
|
||||
|
||||
return &CallbackOutput{
|
||||
AccessToken: oauth2Token.AccessToken,
|
||||
Username: v(cli.attributes.username),
|
||||
Nickname: v(cli.attributes.nickname),
|
||||
Phone: v(cli.attributes.phone),
|
||||
Email: v(cli.attributes.email),
|
||||
}, nil
|
||||
}
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/didi/nightingale/v5/src/pkg/httpx"
|
||||
"github.com/didi/nightingale/v5/src/pkg/ldapx"
|
||||
"github.com/didi/nightingale/v5/src/pkg/logx"
|
||||
"github.com/didi/nightingale/v5/src/pkg/oidcc"
|
||||
"github.com/didi/nightingale/v5/src/storage"
|
||||
"github.com/didi/nightingale/v5/src/webapi/prom"
|
||||
)
|
||||
|
@ -94,6 +95,7 @@ type Config struct {
|
|||
Postgres storage.Postgres
|
||||
Clusters []prom.Options
|
||||
Ibex Ibex
|
||||
OIDC oidcc.Config
|
||||
}
|
||||
|
||||
type LabelAndKey struct {
|
||||
|
|
|
@ -114,6 +114,9 @@ func configRoute(r *gin.Engine, version string) {
|
|||
pages.POST("/auth/logout", logoutPost)
|
||||
pages.POST("/auth/refresh", refreshPost)
|
||||
|
||||
pages.GET("/auth/redirect", loginRedirect)
|
||||
pages.GET("/auth/callback", loginCallback)
|
||||
|
||||
pages.GET("/metrics/desc", metricsDescGetFile)
|
||||
pages.POST("/metrics/desc", metricsDescGetMap)
|
||||
|
||||
|
|
|
@ -4,12 +4,15 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/toolkits/pkg/ginx"
|
||||
"github.com/toolkits/pkg/logger"
|
||||
|
||||
"github.com/didi/nightingale/v5/src/models"
|
||||
"github.com/didi/nightingale/v5/src/pkg/oidcc"
|
||||
"github.com/didi/nightingale/v5/src/webapi/config"
|
||||
)
|
||||
|
||||
|
@ -136,3 +139,103 @@ func refreshPost(c *gin.Context) {
|
|||
ginx.NewRender(c, http.StatusUnauthorized).Message("refresh token expired")
|
||||
}
|
||||
}
|
||||
|
||||
func loginRedirect(c *gin.Context) {
|
||||
redirect := ginx.QueryStr(c, "redirect", "/")
|
||||
|
||||
v, exsits := c.Get("userid")
|
||||
if exsits {
|
||||
userid := v.(int64)
|
||||
user, err := models.UserGetById(userid)
|
||||
ginx.Dangerous(err)
|
||||
if user == nil {
|
||||
ginx.Bomb(200, "user not found")
|
||||
}
|
||||
|
||||
if user.Username != "" { // alread login
|
||||
ginx.NewRender(c).Data(redirect, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !config.C.OIDC.Enable {
|
||||
ginx.NewRender(c).Data("", nil)
|
||||
return
|
||||
}
|
||||
|
||||
redirect, err := oidcc.Authorize(redirect)
|
||||
ginx.Dangerous(err)
|
||||
|
||||
ginx.NewRender(c).Data(redirect, err)
|
||||
}
|
||||
|
||||
type CallbackOutput struct {
|
||||
Redirect string `json:"redirect"`
|
||||
User *models.User `json:"user"`
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
||||
|
||||
func loginCallback(c *gin.Context) {
|
||||
code := ginx.QueryStr(c, "code", "")
|
||||
state := ginx.QueryStr(c, "state", "")
|
||||
|
||||
ret, err := oidcc.Callback(c.Request.Context(), code, state)
|
||||
if err != nil {
|
||||
logger.Debugf("sso.callback() get ret %+v error %v", ret, err)
|
||||
ginx.NewRender(c).Data(CallbackOutput{}, err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := models.UserGet("username=?", ret.Username)
|
||||
ginx.Dangerous(err)
|
||||
|
||||
if user != nil {
|
||||
if config.C.OIDC.CoverAttributes {
|
||||
user.Nickname = ret.Nickname
|
||||
user.Email = ret.Email
|
||||
user.Phone = ret.Phone
|
||||
user.UpdateAt = time.Now().Unix()
|
||||
|
||||
user.Update("email", "nickname", "phone", "update_at")
|
||||
}
|
||||
} else {
|
||||
now := time.Now().Unix()
|
||||
user = &models.User{
|
||||
Username: ret.Username,
|
||||
Password: "******",
|
||||
Nickname: ret.Nickname,
|
||||
Phone: ret.Phone,
|
||||
Email: ret.Email,
|
||||
Portrait: "",
|
||||
Roles: strings.Join(config.C.OIDC.DefaultRoles, " "),
|
||||
RolesLst: config.C.OIDC.DefaultRoles,
|
||||
Contacts: []byte("{}"),
|
||||
CreateAt: now,
|
||||
UpdateAt: now,
|
||||
CreateBy: "oidc",
|
||||
UpdateBy: "oidc",
|
||||
}
|
||||
|
||||
// create user from oidc
|
||||
ginx.Dangerous(user.Add())
|
||||
}
|
||||
|
||||
// set user login state
|
||||
userIdentity := fmt.Sprintf("%d-%s", user.Id, user.Username)
|
||||
ts, err := createTokens(config.C.JWTAuth.SigningKey, userIdentity)
|
||||
ginx.Dangerous(err)
|
||||
ginx.Dangerous(createAuth(c.Request.Context(), userIdentity, ts))
|
||||
|
||||
redirect := "/"
|
||||
if ret.Redirect != "/login" {
|
||||
redirect = ret.Redirect
|
||||
}
|
||||
|
||||
ginx.NewRender(c).Data(CallbackOutput{
|
||||
Redirect: redirect,
|
||||
User: user,
|
||||
AccessToken: ts.AccessToken,
|
||||
RefreshToken: ts.RefreshToken,
|
||||
}, nil)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/didi/nightingale/v5/src/pkg/httpx"
|
||||
"github.com/didi/nightingale/v5/src/pkg/ldapx"
|
||||
"github.com/didi/nightingale/v5/src/pkg/logx"
|
||||
"github.com/didi/nightingale/v5/src/pkg/oidcc"
|
||||
"github.com/didi/nightingale/v5/src/storage"
|
||||
"github.com/didi/nightingale/v5/src/webapi/config"
|
||||
"github.com/didi/nightingale/v5/src/webapi/prom"
|
||||
|
@ -90,6 +91,9 @@ func (a Webapi) initialize() (func(), error) {
|
|||
// init ldap
|
||||
ldapx.Init(config.C.LDAP)
|
||||
|
||||
// init oidc
|
||||
oidcc.Init(config.C.OIDC)
|
||||
|
||||
// init logger
|
||||
loggerClean, err := logx.Init(config.C.Log)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue