Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set up ory kratos, add identity admin api #1460

Merged
merged 2 commits into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .erda/migrations/kratos/20210914-kratos-uc-id.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE TABLE `kratos_uc_userid_mapping` (
`id` varchar(50) NOT NULL COMMENT 'uc userid',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change id to uc_user_id.

add index for both uc_user_id and user_id separately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add user_id index

`user_id` varchar(191) NOT NULL COMMENT 'kratos user uuid',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'created time',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'updated time',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='id mapping';
5 changes: 5 additions & 0 deletions apistructs/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ type UserListResponse struct {
Data UserListResponseData `json:"data"`
}

type UserIDResponse struct {
Header
Data string `json:"data"`
}

// UserListResponseData 用户批量查询响应数据
type UserListResponseData struct {
Users []UserInfo `json:"users"`
Expand Down
21 changes: 21 additions & 0 deletions bundle/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ func (b *Bundle) ListUsers(req apistructs.UserListRequest) (*apistructs.UserList
return &userResp.Data, nil
}

func (b *Bundle) GetUcUserID(uuid string) (string, error) {
host, err := b.urls.CoreServices()
if err != nil {
return "", err
}
hc := b.hc

var userResp apistructs.UserIDResponse
resp, err := hc.Get(host).Path("/api/users/actions/get-uc-user-id").
Header(httputil.InternalHeader, "bundle").
Param("id", uuid).
Do().JSON(&userResp)
if err != nil {
return "", apierrors.ErrInvoke.InternalError(err)
}
if !resp.IsOK() || !userResp.Success {
return "", toAPIError(resp.StatusCode(), userResp.Error)
}
return userResp.Data, nil
}

func (b *Bundle) SearchUser(params url.Values) (*apistructs.UserListResponseData, error) {
host, err := b.urls.CoreServices()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion conf/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ openapi-auth:
openapi-auth-ory-kratos:
_enable: ${ORY_ENABLED:false}
weight: 100
ory_kratos_addr: "${ORY_KRATOS_ADDR:kratos:4433}"
ory_kratos_addr: "${ORY_KRATOS_ADDR:kratos-public}"
openapi-auth-uc:
_enable: ${UC_ENABLED:true}
weight: 100
Expand Down
3 changes: 1 addition & 2 deletions modules/cmp/conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ type Conf struct {
UCClientSecret string `env:"UC_CLIENT_SECRET"`
// ory/kratos config
OryEnabled bool `default:"false" env:"ORY_ENABLED"`
OryKratosAddr string `default:"kratos:4433" env:"KRATOS_ADDR"`
OryKratosPrivateAddr string `default:"kratos:4434" env:"KRATOS_PRIVATE_ADDR"`
OryKratosPrivateAddr string `default:"kratos-admin" env:"ORY_KRATOS_ADMIN_ADDR"`

// size of steve server cache, default 1Gi
CacheSize int64 `default:"1073741824" env:"CMP_CACHE_SIZE"`
Expand Down
1 change: 1 addition & 0 deletions modules/cmp/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ func do(ctx context.Context) (*httpserver.Server, error) {
uc := ucauth.NewUCClient(discover.UC(), conf.UCClientID(), conf.UCClientSecret())
if conf.OryEnabled() {
uc = ucauth.NewUCClient(conf.OryKratosPrivateAddr(), conf.OryCompatibleClientID(), conf.OryCompatibleClientSecret())
uc.SetDBClient(db.DB)
}

// init Bundle
Expand Down
4 changes: 1 addition & 3 deletions modules/core-services/conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ type Conf struct {

// ory/kratos config
OryEnabled bool `default:"false" env:"ORY_ENABLED"`
OryKratosAddr string `default:"kratos:4433" env:"KRATOS_ADDR"`
OryKratosPrivateAddr string `default:"kratos:4434" env:"KRATOS_PRIVATE_ADDR"`
OryKratosPrivateAddr string `default:"kratos-admin" env:"ORY_KRATOS_ADMIN_ADDR"`

// Allow people who are not admin to create org
CreateOrgEnabled bool `default:"false" env:"CREATE_ORG_ENABLED"`
Expand Down Expand Up @@ -112,7 +111,6 @@ var (
func initPermissions() {
permissions = getAllFiles("erda-configs/permission", permissions)
}

func initAuditTemplate() {
auditsTemplate = genTempFromFiles("erda-configs/audit/template.json")
}
Expand Down
58 changes: 58 additions & 0 deletions modules/core-services/dao/migration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) 2021 Terminus, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dao

import (
"fmt"
"strconv"

"github.com/jinzhu/gorm"

"github.com/erda-project/erda/modules/core-services/model"
)

var joinMap = "LEFT OUTER JOIN kratos_uc_userid_mapping on kratos_uc_userid_mapping.id = uc_user.id"

const noPass = "no pass"

func (client *DBClient) GetUcUserList() ([]model.User, error) {
var users []model.User
sql := client.Table("uc_user").Joins(joinMap)
if err := sql.Where("password != ? AND password IS NOT NULL AND kratos_uc_userid_mapping.id IS NULL", noPass).Find(&users).Error; err != nil {
return nil, err
}
return users, nil
}

func (client *DBClient) InsertMapping(userID, uuid, hash string) error {
return client.Transaction(func(tx *gorm.DB) error {
sql := fmt.Sprintf("UPDATE identity_credentials SET config = JSON_SET(config, '$.hashed_password', ?) WHERE identity_id = ?")
if err := tx.Exec(sql, hash, uuid).Error; err != nil {
return err
}
return client.Table("kratos_uc_userid_mapping").Create(&model.UserIDMapping{ID: userID, UserID: uuid}).Error
})
}

func (client *DBClient) GetUcUserID(uuid string) (string, error) {
var users []model.User
if err := client.Table("kratos_uc_userid_mapping").Select("id").Where("user_id = ?", uuid).Find(&users).Error; err != nil {
return "", err
}
if len(users) == 0 {
return "", nil
}
return strconv.FormatInt(users[0].ID, 10), nil
}
15 changes: 15 additions & 0 deletions modules/core-services/dao/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,18 @@ func (client *DBClient) BulkInsert(objects interface{}, excludeColumns ...string
}
return gormbulk.BulkInsert(client.DB, structSlice, BULK_INSERT_CHUNK_SIZE, excludeColumns...)
}

func (db *DBClient) Transaction(f func(tx *gorm.DB) error) error {
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
if err := f(tx); err != nil {
tx.Rollback()
return err
}

return tx.Commit().Error
}
13 changes: 13 additions & 0 deletions modules/core-services/endpoints/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/erda-project/erda/modules/core-services/services/org"
"github.com/erda-project/erda/modules/core-services/services/permission"
"github.com/erda-project/erda/modules/core-services/services/project"
"github.com/erda-project/erda/modules/core-services/services/user"
"github.com/erda-project/erda/pkg/http/httpserver"
"github.com/erda-project/erda/pkg/i18n"
"github.com/erda-project/erda/pkg/jsonstore"
Expand Down Expand Up @@ -71,6 +72,7 @@ type Endpoints struct {
audit *audit.Audit
errorbox *errorbox.ErrorBox
fileSvc *filesvc.FileService
user *user.User
}

type Option func(*Endpoints)
Expand Down Expand Up @@ -244,6 +246,12 @@ func WithFileSvc(svc *filesvc.FileService) Option {
}
}

func WithUserSvc(svc *user.User) Option {
return func(e *Endpoints) {
e.user = svc
}
}

// DBClient 获取db client
func (e *Endpoints) DBClient() *dao.DBClient {
return e.db
Expand All @@ -254,6 +262,10 @@ func (e *Endpoints) GetLocale(request *http.Request) *i18n.LocaleResource {
return e.bdl.GetLocaleByRequest(request)
}

func (e *Endpoints) UserSvc() *user.User {
return e.user
}

// Routes 返回 endpoints 的所有 endpoint 方法,也就是 route.
func (e *Endpoints) Routes() []httpserver.Endpoint {
return []httpserver.Endpoint{
Expand Down Expand Up @@ -433,5 +445,6 @@ func (e *Endpoints) Routes() []httpserver.Endpoint {
{Path: "/api/users", Method: http.MethodGet, Handler: e.ListUser},
{Path: "/api/users/current", Method: http.MethodGet, Handler: e.GetCurrentUser},
{Path: "/api/users/actions/search", Method: http.MethodGet, Handler: e.SearchUser},
{Path: "/api/users/actions/get-uc-user-id", Method: http.MethodGet, Handler: e.GetUcUserID},
}
}
10 changes: 10 additions & 0 deletions modules/core-services/endpoints/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ func (e *Endpoints) GetCurrentUser(ctx context.Context, r *http.Request, vars ma
return httpserver.OkResp(*convertToUserInfo(user, false))
}

func (e *Endpoints) GetUcUserID(ctx context.Context, r *http.Request, vars map[string]string) (
httpserver.Responser, error) {
id := r.URL.Query().Get("id")
userID, err := e.db.GetUcUserID(id)
if err != nil {
return apierrors.ErrGetUser.InternalError(err).ToResp(), nil
}
return httpserver.OkResp(userID)
}

func convertToUserInfo(user *ucauth.User, plaintext bool) *apistructs.UserInfo {
if !plaintext {
user.Phone = desensitize.Mobile(user.Phone)
Expand Down
10 changes: 10 additions & 0 deletions modules/core-services/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
"github.com/erda-project/erda/modules/core-services/services/org"
"github.com/erda-project/erda/modules/core-services/services/permission"
"github.com/erda-project/erda/modules/core-services/services/project"
"github.com/erda-project/erda/modules/core-services/services/user"
"github.com/erda-project/erda/modules/core-services/utils"
"github.com/erda-project/erda/pkg/discover"
"github.com/erda-project/erda/pkg/http/httpclient"
Expand Down Expand Up @@ -74,6 +75,8 @@ func (p *provider) Initialize() error {
bundle.WithCollector(),
)

go ep.UserSvc().UcUserMigration()

server := httpserver.New(conf.ListenAddr())
server.RegisterEndpoint(ep.Routes())
server.WithLocaleLoader(bdl.GetLocaleLoader())
Expand Down Expand Up @@ -143,6 +146,7 @@ func (p *provider) initEndpoints() (*endpoints.Endpoints, error) {
uc := ucauth.NewUCClient(discover.UC(), conf.UCClientID(), conf.UCClientSecret())
if conf.OryEnabled() {
uc = ucauth.NewUCClient(conf.OryKratosPrivateAddr(), conf.OryCompatibleClientID(), conf.OryCompatibleClientSecret())
uc.SetDBClient(db.DB)
}

// init bundle
Expand Down Expand Up @@ -253,6 +257,11 @@ func (p *provider) initEndpoints() (*endpoints.Endpoints, error) {
filesvc.WithEtcdClient(etcdStore),
)

user := user.New(
user.WithDBClient(db),
user.WithUCClient(uc),
)

// queryStringDecoder
queryStringDecoder := schema.NewDecoder()
queryStringDecoder.IgnoreUnknownKeys(true)
Expand Down Expand Up @@ -282,6 +291,7 @@ func (p *provider) initEndpoints() (*endpoints.Endpoints, error) {
endpoints.WithAudit(audit),
endpoints.WithErrorBox(errorBox),
endpoints.WithFileSvc(fileSvc),
endpoints.WithUserSvc(user),
)

return ep, nil
Expand Down
34 changes: 34 additions & 0 deletions modules/core-services/model/uc_migration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) 2021 Terminus, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package model

type User struct {
BaseModel
Avatar string
Username string
Nickname string
Mobile string
Email string
Password string
}

type Config struct {
HashedPassword string `json:"hashed_password"`
}

type UserIDMapping struct {
ID string
UserID string
}
Loading