blob: 1ae6189851822f8a4662fa35c6b5d4fa4739a6a4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 buildin_test
// initialize
import (
"context"
"net/http"
"net/http/httptest"
"os"
"testing"
_ "github.com/apache/servicecomb-service-center/test"
"github.com/apache/servicecomb-service-center/pkg/rest"
"github.com/apache/servicecomb-service-center/pkg/util"
"github.com/apache/servicecomb-service-center/server/config"
"github.com/apache/servicecomb-service-center/server/plugin/auth/buildin"
rbacsvc "github.com/apache/servicecomb-service-center/server/service/rbac"
beego "github.com/beego/beego/v2/server/web"
"github.com/go-chassis/cari/pkg/errsvc"
carirbac "github.com/go-chassis/cari/rbac"
rbacmodel "github.com/go-chassis/cari/rbac"
"github.com/go-chassis/go-archaius"
"github.com/go-chassis/go-chassis/v2/security/authr"
"github.com/go-chassis/go-chassis/v2/security/secret"
"github.com/go-chassis/go-chassis/v2/server/restful"
"github.com/stretchr/testify/assert"
)
func init() {
beego.AppConfig.Set("registry_plugin", "etcd")
beego.AppConfig.Set("rbac_enabled", "true")
beego.AppConfig.Set("rbac_rsa_public_key_file", "./rbac.pub")
beego.AppConfig.Set("rbac_rsa_private_key_file", "./private.key")
config.Init()
}
func TestTokenAuthenticator_Identify(t *testing.T) {
rbacsvc.DeleteAccount(context.TODO(), "root")
rbacsvc.DeleteAccount(context.TODO(), "non-admin")
t.Run("init rbac", func(t *testing.T) {
err := archaius.Init(archaius.WithMemorySource(), archaius.WithENVSource())
assert.NoError(t, err)
pri, pub, err := secret.GenRSAKeyPair(4096)
assert.NoError(t, err)
b, err := secret.RSAPrivate2Bytes(pri)
assert.NoError(t, err)
os.WriteFile("./private.key", b, 0600)
b, err = secret.RSAPublicKey2Bytes(pub)
err = os.WriteFile("./rbac.pub", b, 0600)
assert.NoError(t, err)
archaius.Set(rbacsvc.InitPassword, "Complicated_password1")
rbacsvc.Init()
})
a := buildin.New()
ta := a.(*buildin.TokenAuthenticator)
t.Run("without auth header should failed", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/any", nil)
err := ta.Identify(r)
assert.NotNil(t, err)
t.Log(err)
svcErr := err.(*errsvc.Error)
assert.Equal(t, carirbac.ErrNoAuthHeader, svcErr.Code)
})
t.Run("with wrong auth header should failed", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/any", nil)
r.Header.Set(restful.HeaderAuth, "Bear")
err := ta.Identify(r)
t.Log(err)
assert.Equal(t, carirbac.ErrInvalidHeader, err)
})
t.Run("with valid header and invalid token, should failed", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/any", nil)
r.Header.Set(restful.HeaderAuth, "Bear fake_token")
err := ta.Identify(r)
t.Log(err)
assert.Error(t, err)
})
t.Run("valid admin token, should be able to get account", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/v4/accounts", nil)
to, err := authr.Login(context.TODO(), "root", "Complicated_password1")
assert.NoError(t, err)
r.Header.Set(restful.HeaderAuth, "Bear "+to)
err = ta.Identify(r)
assert.NoError(t, err)
})
t.Run("valid normal token, should no be able to get account", func(t *testing.T) {
a := &rbacmodel.Account{
Name: "non-admin",
Password: "Complicated_password1",
Roles: []string{rbacmodel.RoleDeveloper},
}
err := rbacsvc.CreateAccount(context.TODO(), a)
assert.NoError(t, err)
r := httptest.NewRequest(http.MethodGet, "/v4/accounts", nil)
to, err := authr.Login(context.TODO(), "non-admin", "Complicated_password1")
assert.NoError(t, err)
r.Header.Set(restful.HeaderAuth, "Bear "+to)
err = ta.Identify(r)
t.Log(err)
assert.Error(t, err)
})
t.Run("valid normal token, should no be able to delete account", func(t *testing.T) {
r := httptest.NewRequest(http.MethodDelete, "/v4/accounts", nil)
v := r.URL.Query()
v.Set(":name", "non-admin")
to, err := authr.Login(context.TODO(), "non-admin", "Complicated_password1")
assert.NoError(t, err)
r.Header.Set(restful.HeaderAuth, "Bear "+to)
err = ta.Identify(r)
t.Log(err)
assert.Error(t, err)
})
t.Run("valid admin token, should be able to delete account", func(t *testing.T) {
r := httptest.NewRequest(http.MethodDelete, "/v4/accounts/:name", nil)
v := r.URL.Query()
v.Set(":name", "admin")
to, err := authr.Login(context.TODO(), "root", "Complicated_password1")
assert.NoError(t, err)
r.Header.Set(restful.HeaderAuth, "Bear "+to)
err = ta.Identify(r)
assert.NoError(t, err)
})
t.Run("TestTokenAuthenticator_ResourceScopes", func(t *testing.T) {
url := "/v4/accounts/:name"
tests := []struct {
name string
request *http.Request
wantType string
wantVerb string
}{
{"method GET should return verb=get",
httptest.NewRequest(http.MethodPut, url, nil), "account", "update"},
{"method POST should return verb=create",
httptest.NewRequest(http.MethodPost, url, nil), "account", "create"},
{"method PUT should return verb=update",
httptest.NewRequest(http.MethodPut, url, nil), "account", "update"},
{"method DELETE should return verb=delete",
httptest.NewRequest(http.MethodDelete, url, nil), "account", "delete"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
util.SetRequestContext(tt.request, rest.CtxMatchPattern, url)
scopes := buildin.FromRequest(tt.request)
assert.NotNil(t, scopes)
assert.Equal(t, tt.wantType, scopes.Type)
assert.Equal(t, tt.wantVerb, scopes.Verb)
})
}
})
}