blob: 738326f414ea6c875075848101fc58907733afa5 [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 v4_test
import (
"bytes"
"context"
"encoding/json"
"github.com/apache/servicecomb-service-center/pkg/rbacframe"
"github.com/apache/servicecomb-service-center/pkg/rest"
v4 "github.com/apache/servicecomb-service-center/server/rest/controller/v4"
"github.com/apache/servicecomb-service-center/server/service/rbac"
"github.com/apache/servicecomb-service-center/server/service/rbac/dao"
"github.com/astaxie/beego"
"github.com/go-chassis/go-archaius"
"github.com/go-chassis/go-chassis/security/secret"
"github.com/go-chassis/go-chassis/server/restful"
"github.com/stretchr/testify/assert"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"time"
_ "github.com/apache/servicecomb-service-center/server/handler/auth"
_ "github.com/apache/servicecomb-service-center/test"
)
func init() {
beego.AppConfig.Set("rbac_enabled", "true")
beego.AppConfig.Set(rbac.PubFilePath, "./rbac.pub")
beego.AppConfig.Set("rbac_rsa_private_key_file", "./private.key")
}
func TestAuthResource_Login(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)
ioutil.WriteFile("./private.key", b, 0600)
b, err = secret.RSAPublicKey2Bytes(pub)
err = ioutil.WriteFile("./rbac.pub", b, 0600)
assert.NoError(t, err)
archaius.Set(rbac.InitPassword, "Complicated_password1")
ctx := context.TODO()
dao.DeleteAccount(ctx, "root")
archaius.Init(archaius.WithMemorySource())
rbac.Init()
rest.RegisterServant(&v4.AuthResource{})
dao.DeleteAccount(ctx, "dev_account")
t.Run("invalid user login", func(t *testing.T) {
b, _ := json.Marshal(&rbacframe.Account{Name: "dev_account", Password: "Complicated_password1"})
r, _ := http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
w := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.NotEqual(t, http.StatusOK, w.Code)
})
err = dao.CreateAccount(ctx, &rbacframe.Account{Name: "dev_account",
Password: "Complicated_password1",
Role: "developer"})
assert.NoError(t, err)
t.Run("root login", func(t *testing.T) {
b, _ := json.Marshal(&rbacframe.Account{Name: "root", Password: "Complicated_password1"})
r, _ := http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
w := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusOK, w.Code)
})
t.Run("invalid password", func(t *testing.T) {
b, _ := json.Marshal(&rbacframe.Account{Name: "root", Password: "Complicated_password"})
r, _ := http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
w := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusUnauthorized, w.Code)
})
t.Run("dev_account login and change pwd,then login again", func(t *testing.T) {
b, _ := json.Marshal(&rbacframe.Account{Name: "dev_account", Password: "Complicated_password1"})
r, _ := http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
w := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusOK, w.Code)
to := &rbacframe.Token{}
json.Unmarshal(w.Body.Bytes(), to)
b2, _ := json.Marshal(&rbacframe.Account{CurrentPassword: "Complicated_password1", Password: "Complicated_password2"})
r, _ = http.NewRequest(http.MethodPost, "/v4/account/dev_account/password", bytes.NewBuffer(b2))
r.Header.Set(restful.HeaderAuth, "Bearer "+to.TokenStr)
w = httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusOK, w.Code)
b3, _ := json.Marshal(&rbacframe.Account{Name: "dev_account", Password: "Complicated_password2"})
r, _ = http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b3))
w = httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusOK, w.Code)
})
}
func TestAuthResource_DeleteAccount(t *testing.T) {
t.Run("dev_account can not even delete him self", func(t *testing.T) {
b, _ := json.Marshal(&rbacframe.Account{Name: "dev_account", Password: "Complicated_password2"})
r, _ := http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
w := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusOK, w.Code)
to := &rbacframe.Token{}
json.Unmarshal(w.Body.Bytes(), to)
r2, _ := http.NewRequest(http.MethodDelete, "/v4/account/dev_account", nil)
r2.Header.Set(restful.HeaderAuth, "Bearer "+to.TokenStr)
w2 := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w2, r2)
assert.Equal(t, http.StatusUnauthorized, w2.Code)
})
t.Run("root can delete account", func(t *testing.T) {
b, _ := json.Marshal(&rbacframe.Account{Name: "root", Password: "Complicated_password1"})
r, _ := http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
w := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusOK, w.Code)
to := &rbacframe.Token{}
json.Unmarshal(w.Body.Bytes(), to)
b, _ = json.Marshal(&rbacframe.Account{Name: "delete_account", Password: "Complicated_password1"})
r2, _ := http.NewRequest(http.MethodPost, "/v4/account", bytes.NewBuffer(b))
r2.Header.Set(restful.HeaderAuth, "Bearer "+to.TokenStr)
w2 := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w2, r2)
assert.Equal(t, http.StatusOK, w2.Code)
r3, _ := http.NewRequest(http.MethodDelete, "/v4/account/delete_account", nil)
r3.Header.Set(restful.HeaderAuth, "Bearer "+to.TokenStr)
w3 := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w3, r3)
assert.Equal(t, http.StatusNoContent, w3.Code)
})
}
func TestAuthResource_GetAccount(t *testing.T) {
t.Run("get account", func(t *testing.T) {
b, _ := json.Marshal(&rbacframe.Account{Name: "root", Password: "Complicated_password1"})
r, _ := http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
w := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusOK, w.Code)
to := &rbacframe.Token{}
json.Unmarshal(w.Body.Bytes(), to)
r3, _ := http.NewRequest(http.MethodGet, "/v4/account/dev_account", nil)
r3.Header.Set(restful.HeaderAuth, "Bearer "+to.TokenStr)
w3 := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w3, r3)
assert.Equal(t, http.StatusOK, w3.Code)
a := &rbacframe.Account{}
json.Unmarshal(w3.Body.Bytes(), a)
assert.Equal(t, "dev_account", a.Name)
assert.Equal(t, "developer", a.Role)
assert.Empty(t, a.Password)
})
t.Run("list account", func(t *testing.T) {
b, _ := json.Marshal(&rbacframe.Account{Name: "root", Password: "Complicated_password1"})
r, _ := http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
w := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusOK, w.Code)
to := &rbacframe.Token{}
json.Unmarshal(w.Body.Bytes(), to)
r3, _ := http.NewRequest(http.MethodGet, "/v4/account", nil)
r3.Header.Set(restful.HeaderAuth, "Bearer "+to.TokenStr)
w3 := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w3, r3)
assert.Equal(t, http.StatusOK, w3.Code)
a := &rbacframe.AccountResponse{}
json.Unmarshal(w3.Body.Bytes(), a)
assert.Greater(t, a.Total, int64(2))
assert.Empty(t, a.Accounts[0].Password)
})
t.Run("get a short expiration token", func(t *testing.T) {
b, _ := json.Marshal(&rbacframe.Account{Name: "root", Password: "Complicated_password1", TokenExpirationTime: "10s"})
r, _ := http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
w := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusOK, w.Code)
to := &rbacframe.Token{}
json.Unmarshal(w.Body.Bytes(), to)
time.Sleep(11 * time.Second)
r3, _ := http.NewRequest(http.MethodGet, "/v4/account", nil)
r3.Header.Set(restful.HeaderAuth, "Bearer "+to.TokenStr)
w3 := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w3, r3)
assert.Equal(t, http.StatusUnauthorized, w3.Code)
})
}
func TestAuthResource_Login2(t *testing.T) {
t.Run("bock user dev_account", func(t *testing.T) {
b, _ := json.Marshal(&rbacframe.Account{Name: "dev_account", Password: "Complicated_password1"})
r, _ := http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
w := httptest.NewRecorder()
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusUnauthorized, w.Code)
r, _ = http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusUnauthorized, w.Code)
r, _ = http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusUnauthorized, w.Code)
r, _ = http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusUnauthorized, w.Code)
w = httptest.NewRecorder()
r, _ = http.NewRequest(http.MethodPost, "/v4/token", bytes.NewBuffer(b))
rest.GetRouter().ServeHTTP(w, r)
assert.Equal(t, http.StatusForbidden, w.Code)
})
}