mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-23 00:57:44 +01:00
add the controller for ocdi onboard user
Signed-off-by: wang yan <wangyan@vmware.com>
This commit is contained in:
parent
8d6299fed9
commit
0de5999f52
@ -13,6 +13,25 @@ CREATE TABLE robot (
|
||||
|
||||
CREATE TRIGGER robot_update_time_at_modtime BEFORE UPDATE ON robot FOR EACH ROW EXECUTE PROCEDURE update_update_time_at_column();
|
||||
|
||||
CREATE TABLE oidc_user (
|
||||
id SERIAL NOT NULL,
|
||||
user_id int NOT NULL,
|
||||
secret varchar(255) NOT NULL,
|
||||
/*
|
||||
Subject and Issuer
|
||||
Subject: Subject Identifier.
|
||||
Issuer: Issuer Identifier for the Issuer of the response.
|
||||
The sub (subject) and iss (issuer) Claims, used together, are the only Claims that an RP can rely upon as a stable identifier for the End-User
|
||||
*/
|
||||
subiss varchar(255) NOT NULL,
|
||||
creation_time timestamp default CURRENT_TIMESTAMP,
|
||||
update_time timestamp default CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE (subiss)
|
||||
);
|
||||
|
||||
CREATE TRIGGER odic_user_update_time_at_modtime BEFORE UPDATE ON oidc_user FOR EACH ROW EXECUTE PROCEDURE update_update_time_at_column();
|
||||
|
||||
/*add master role*/
|
||||
INSERT INTO role (role_code, name) VALUES ('DRWS', 'master');
|
||||
|
||||
|
154
src/common/dao/oidc_user.go
Normal file
154
src/common/dao/oidc_user.go
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// AddOIDCUser adds a oidc user
|
||||
func AddOIDCUser(meta *models.OIDCUser) (int64, error) {
|
||||
now := time.Now()
|
||||
meta.CreationTime = now
|
||||
meta.UpdateTime = now
|
||||
id, err := GetOrmer().Insert(meta)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "duplicate key value violates unique constraint") {
|
||||
return 0, ErrDupRows
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// GetOIDCUserByID ...
|
||||
func GetOIDCUserByID(id int64) (*models.OIDCUser, error) {
|
||||
oidcUser := &models.OIDCUser{
|
||||
ID: id,
|
||||
}
|
||||
if err := GetOrmer().Read(oidcUser); err != nil {
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return oidcUser, nil
|
||||
}
|
||||
|
||||
// GetUserBySub ...
|
||||
func GetUserBySub(sub string) (*models.User, error) {
|
||||
var oidcUsers []models.OIDCUser
|
||||
n, err := GetOrmer().Raw(`select * from oidc_user where subiss = ? `, sub).QueryRows(&oidcUsers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
user, err := GetUser(models.User{
|
||||
UserID: oidcUsers[0].UserID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user == nil {
|
||||
return nil, fmt.Errorf("can not get user %d", oidcUsers[0].UserID)
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// GetOIDCUserByUserID ...
|
||||
func GetOIDCUserByUserID(userID int) (*models.OIDCUser, error) {
|
||||
var oidcUsers []models.OIDCUser
|
||||
n, err := GetOrmer().Raw(`select * from oidc_user where user_id = ? `, userID).QueryRows(&oidcUsers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &oidcUsers[0], nil
|
||||
}
|
||||
|
||||
// UpdateOIDCUser ...
|
||||
func UpdateOIDCUser(oidcUser *models.OIDCUser) error {
|
||||
oidcUser.UpdateTime = time.Now()
|
||||
_, err := GetOrmer().Update(oidcUser)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteOIDCUser ...
|
||||
func DeleteOIDCUser(id int64) error {
|
||||
_, err := GetOrmer().QueryTable(&models.OIDCUser{}).Filter("ID", id).Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
// OnBoardOIDCUser onboard OIDC user
|
||||
func OnBoardOIDCUser(u models.User) error {
|
||||
o := orm.NewOrm()
|
||||
err := o.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// the password is the required attribute of user table,
|
||||
// but not required in the oidc user login scenario.
|
||||
u.Email = "odicpassword"
|
||||
var errInsert error
|
||||
userID, err := o.Insert(&u)
|
||||
if err != nil {
|
||||
errInsert = err
|
||||
log.Errorf("fail to insert user, %v", err)
|
||||
if strings.Contains(err.Error(), "duplicate key value violates unique constraint") {
|
||||
errInsert = ErrDupRows
|
||||
}
|
||||
err := o.Rollback()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errInsert
|
||||
|
||||
}
|
||||
u.OIDCUserMeta.UserID = int(userID)
|
||||
_, err = o.Insert(u.OIDCUserMeta)
|
||||
if err != nil {
|
||||
errInsert = err
|
||||
log.Errorf("fail to insert user, %v", err)
|
||||
if strings.Contains(err.Error(), "duplicate key value violates unique constraint") {
|
||||
errInsert = ErrDupRows
|
||||
}
|
||||
err := o.Rollback()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errInsert
|
||||
}
|
||||
err = o.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
123
src/common/dao/oidc_user_test.go
Normal file
123
src/common/dao/oidc_user_test.go
Normal file
@ -0,0 +1,123 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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 (
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
user111 = models.User{
|
||||
Username: "user111",
|
||||
Email: "user111@email.com",
|
||||
}
|
||||
user222 = models.User{
|
||||
Username: "user222",
|
||||
Email: "user222@email.com",
|
||||
}
|
||||
ou111 = &models.OIDCUser{
|
||||
SubIss: "QWE123123RT1",
|
||||
Secret: "QWEQWE1",
|
||||
}
|
||||
ou222 = &models.OIDCUser{
|
||||
SubIss: "QWE123123RT2",
|
||||
Secret: "QWEQWE2",
|
||||
}
|
||||
)
|
||||
|
||||
func TestOIDCUserMetaDaoMethods(t *testing.T) {
|
||||
|
||||
err := OnBoardUser(&user111)
|
||||
require.Nil(t, err)
|
||||
ou111.UserID = user111.UserID
|
||||
err = OnBoardUser(&user222)
|
||||
require.Nil(t, err)
|
||||
ou222.UserID = user222.UserID
|
||||
|
||||
// test add
|
||||
_, err = AddOIDCUser(ou111)
|
||||
require.Nil(t, err)
|
||||
_, err = AddOIDCUser(ou222)
|
||||
require.Nil(t, err)
|
||||
|
||||
// test get
|
||||
oidcUser1, err := GetOIDCUserByID(ou111.ID)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, ou111.UserID, oidcUser1.UserID)
|
||||
|
||||
// test update
|
||||
meta3 := &models.OIDCUser{
|
||||
ID: ou111.ID,
|
||||
UserID: ou111.UserID,
|
||||
SubIss: "newSub",
|
||||
}
|
||||
require.Nil(t, UpdateOIDCUser(meta3))
|
||||
oidcUser1Update, err := GetOIDCUserByID(ou111.ID)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "newSub", oidcUser1Update.SubIss)
|
||||
|
||||
user, err := GetUserBySub("newSub")
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "user111", user.Username)
|
||||
}
|
||||
|
||||
func TestOIDCOnboard(t *testing.T) {
|
||||
user333 := models.User{
|
||||
Username: "user333",
|
||||
Email: "user333@email.com",
|
||||
}
|
||||
user555 := models.User{
|
||||
Username: "user555",
|
||||
Email: "user555@email.com",
|
||||
}
|
||||
ou333 := &models.OIDCUser{
|
||||
UserID: 333,
|
||||
SubIss: "QWE123123RT1",
|
||||
Secret: "QWEQWE333",
|
||||
}
|
||||
ouDupSub := &models.OIDCUser{
|
||||
UserID: 444,
|
||||
SubIss: "QWE123123RT1",
|
||||
Secret: "QWEQWE444",
|
||||
}
|
||||
|
||||
// duplicate user -- ErrDupRows
|
||||
user111.OIDCUserMeta = ou333
|
||||
err := OnBoardOIDCUser(user111)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, err, ErrDupRows)
|
||||
|
||||
// duplicate OIDC user -- ErrDupRows
|
||||
user333.OIDCUserMeta = ou111
|
||||
err = OnBoardOIDCUser(user333)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, err, ErrDupRows)
|
||||
|
||||
// success
|
||||
user333.OIDCUserMeta = ou333
|
||||
err = OnBoardOIDCUser(user333)
|
||||
require.Nil(t, err)
|
||||
|
||||
// duplicate OIDC user's sub -- ErrDupRows
|
||||
user555.OIDCUserMeta = ouDupSub
|
||||
err = OnBoardOIDCUser(user555)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, err, ErrDupRows)
|
||||
|
||||
}
|
@ -38,5 +38,6 @@ func init() {
|
||||
new(UserGroup),
|
||||
new(AdminJob),
|
||||
new(JobLog),
|
||||
new(Robot))
|
||||
new(Robot),
|
||||
new(OIDCUser))
|
||||
}
|
||||
|
20
src/common/models/oidc_user.go
Normal file
20
src/common/models/oidc_user.go
Normal file
@ -0,0 +1,20 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// OIDCUser ...
|
||||
type OIDCUser struct {
|
||||
ID int64 `orm:"pk;auto;column(id)" json:"id"`
|
||||
UserID int `orm:"column(user_id)" json:"user_id"`
|
||||
Secret string `orm:"column(secret)" json:"secret"`
|
||||
SubIss string `orm:"column(subiss)" json:"subiss"`
|
||||
CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"`
|
||||
UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"`
|
||||
}
|
||||
|
||||
// TableName ...
|
||||
func (o *OIDCUser) TableName() string {
|
||||
return "oidc_user"
|
||||
}
|
@ -41,6 +41,7 @@ type User struct {
|
||||
CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"`
|
||||
UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"`
|
||||
GroupList []*UserGroup `orm:"-" json:"-"`
|
||||
OIDCUserMeta *OIDCUser `orm:"-" json:"oidc_user_meta"`
|
||||
}
|
||||
|
||||
// UserQuery ...
|
||||
|
@ -50,6 +50,7 @@ func init() {
|
||||
beego.Router("/c/reset", &CommonController{}, "post:ResetPassword")
|
||||
beego.Router("/c/userExists", &CommonController{}, "post:UserExists")
|
||||
beego.Router("/c/sendEmail", &CommonController{}, "get:SendResetEmail")
|
||||
beego.Router("/c/oidc/onboard", &OIDCController{}, "post:Onboard")
|
||||
beego.Router("/v2/*", &RegistryProxy{}, "*:Handle")
|
||||
}
|
||||
|
||||
@ -138,4 +139,9 @@ func TestAll(t *testing.T) {
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(404), w.Code, "GET v2/noproject/manifests/1.0 should get a 404 response")
|
||||
|
||||
r, _ = http.NewRequest("POST", "/c/oidc/onboard", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(500), w.Code, "/c/oidc/onboard httpStatusCode should be 500")
|
||||
}
|
||||
|
@ -95,4 +95,4 @@ func (oc *OIDCController) Onboard() {
|
||||
oc.RenderError(http.StatusNotImplemented, "")
|
||||
return
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user