Skip to content

Commit

Permalink
Merge branch 'fork_master' into fix_ssl_label
Browse files Browse the repository at this point in the history
  • Loading branch information
starsz committed Jan 17, 2021
2 parents bc51c1d + 754f559 commit 5fc45b7
Show file tree
Hide file tree
Showing 34 changed files with 474 additions and 122 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ Note: Currently the Dashboard does not have complete coverage of Apache APISIX f

![architecture](./docs/images/architecture.png)

## Demo

```
URL: http://139.217.190.60/
Username: admin
Password: admin
```

## Project structure

```
Expand Down
8 changes: 5 additions & 3 deletions api/cmd/managerapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,17 @@ import (
"syscall"
"time"

"github.com/shiningrush/droplet"
"github.com/spf13/cobra"

"github.com/apisix/manager-api/internal"
"github.com/apisix/manager-api/internal/conf"
"github.com/apisix/manager-api/internal/core/storage"
"github.com/apisix/manager-api/internal/core/store"
"github.com/apisix/manager-api/internal/filter"
"github.com/apisix/manager-api/internal/handler"
"github.com/apisix/manager-api/internal/log"
"github.com/apisix/manager-api/internal/utils"
"github.com/shiningrush/droplet"
"github.com/spf13/cobra"
)

var (
Expand Down Expand Up @@ -62,7 +64,7 @@ func NewManagerAPICommand() *cobra.Command {
var newMws []droplet.Middleware
// default middleware order: resp_reshape, auto_input, traffic_log
// We should put err_transform at second to catch all error
newMws = append(newMws, mws[0], &handler.ErrorTransformMiddleware{})
newMws = append(newMws, mws[0], &handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
newMws = append(newMws, mws[1:]...)
return newMws
}
Expand Down
4 changes: 2 additions & 2 deletions api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ require (
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/prometheus/client_golang v1.8.0 // indirect
github.com/satori/go.uuid v1.2.0
github.com/shiningrush/droplet v0.2.3
github.com/shiningrush/droplet/wrapper/gin v0.2.0
github.com/shiningrush/droplet v0.2.4
github.com/shiningrush/droplet/wrapper/gin v0.2.1
github.com/sirupsen/logrus v1.7.0 // indirect
github.com/sony/sonyflake v1.0.0
github.com/spf13/cobra v0.0.3
Expand Down
4 changes: 4 additions & 0 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,12 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
github.com/shiningrush/droplet v0.0.0-20191118073048-00b06fe19ce4/go.mod h1:E/th13n/wtPi+Cj2f0hAAEFeT3gb5xsS6Ob4WRrdxdM=
github.com/shiningrush/droplet v0.2.3 h1:bzPDzkE0F54r94XsultGS8uAPeL3pZIRmjqM0zIlpeI=
github.com/shiningrush/droplet v0.2.3/go.mod h1:akW2vIeamvMD6zj6wIBfzYn6StGXBxwlW3gA+hcHu5M=
github.com/shiningrush/droplet v0.2.4 h1:OW4Pp+dXs9O61QKTiYSRWCdQeOyzO1n9h+i2PDJ5DK0=
github.com/shiningrush/droplet v0.2.4/go.mod h1:akW2vIeamvMD6zj6wIBfzYn6StGXBxwlW3gA+hcHu5M=
github.com/shiningrush/droplet/wrapper/gin v0.2.0 h1:LHkU+TbSkpePgXrTg3hJoSZlCMS03GeWMl0t+oLkd44=
github.com/shiningrush/droplet/wrapper/gin v0.2.0/go.mod h1:ZJu+sCRrVXn5Pg618c1KK3Ob2UiXGuPM1ROx5uMM9YQ=
github.com/shiningrush/droplet/wrapper/gin v0.2.1 h1:1o+5KUF2sKsdZ7SkmOC5ahAP1qaZKqnm0c5hOYFV6YQ=
github.com/shiningrush/droplet/wrapper/gin v0.2.1/go.mod h1:cx5BfLuStFDFIKuEOc1zBTpiT3B4Ezkg3MdlP6rW51I=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
Expand Down
19 changes: 10 additions & 9 deletions api/internal/core/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import (
type Interface interface {
Get(key string) (interface{}, error)
List(input ListInput) (*ListOutput, error)
Create(ctx context.Context, obj interface{}) error
Create(ctx context.Context, obj interface{}) (interface{}, error)
Update(ctx context.Context, obj interface{}, createIfNotExist bool) error
BatchDelete(ctx context.Context, keys []string) error
}
Expand Down Expand Up @@ -240,36 +240,36 @@ func (s *GenericStore) ingestValidate(obj interface{}) (err error) {
return err
}

func (s *GenericStore) Create(ctx context.Context, obj interface{}) error {
func (s *GenericStore) Create(ctx context.Context, obj interface{}) (interface{}, error) {
if setter, ok := obj.(entity.BaseInfoSetter); ok {
info := setter.GetBaseInfo()
info.Creating()
}

if err := s.ingestValidate(obj); err != nil {
return err
return nil, err
}

key := s.opt.KeyFunc(obj)
if key == "" {
return fmt.Errorf("key is required")
return nil, fmt.Errorf("key is required")
}
_, ok := s.cache.Load(key)
if ok {
log.Warnf("key: %s is conflicted", key)
return fmt.Errorf("key: %s is conflicted", key)
return nil, fmt.Errorf("key: %s is conflicted", key)
}

bs, err := json.Marshal(obj)
if err != nil {
log.Errorf("json marshal failed: %s", err)
return fmt.Errorf("json marshal failed: %s", err)
return nil, fmt.Errorf("json marshal failed: %s", err)
}
if err := s.Stg.Create(ctx, s.GetObjStorageKey(obj), string(bs)); err != nil {
return err
return nil, err
}

return nil
return obj, nil
}

func (s *GenericStore) Update(ctx context.Context, obj interface{}, createIfNotExist bool) error {
Expand All @@ -284,7 +284,8 @@ func (s *GenericStore) Update(ctx context.Context, obj interface{}, createIfNotE
storedObj, ok := s.cache.Load(key)
if !ok {
if createIfNotExist {
return s.Create(ctx, obj)
_, err := s.Create(ctx, obj)
return err
}
log.Warnf("key: %s is not found", key)
return fmt.Errorf("key: %s is not found", key)
Expand Down
5 changes: 3 additions & 2 deletions api/internal/core/store/store_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package store

import (
"context"

"github.com/stretchr/testify/mock"
)

Expand Down Expand Up @@ -48,9 +49,9 @@ func (m *MockInterface) List(input ListInput) (*ListOutput, error) {
return r0, r1
}

func (m *MockInterface) Create(ctx context.Context, obj interface{}) error {
func (m *MockInterface) Create(ctx context.Context, obj interface{}) (interface{}, error) {
ret := m.Mock.Called(ctx, obj)
return ret.Error(0)
return ret.Get(0), ret.Error(1)
}

func (m *MockInterface) Update(ctx context.Context, obj interface{}, createOnFail bool) error {
Expand Down
7 changes: 6 additions & 1 deletion api/internal/core/store/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,12 +613,17 @@ func TestGenericStore_Create(t *testing.T) {

tc.giveStore.Stg = mStorage
tc.giveStore.opt.Validator = mValidator
err := tc.giveStore.Create(context.TODO(), tc.giveObj)
ret, err := tc.giveStore.Create(context.TODO(), tc.giveObj)
assert.True(t, validateCalled, tc.caseDesc)
if err != nil {
assert.Equal(t, tc.wantErr, err, tc.caseDesc)
continue
}
retTs, ok := ret.(*TestStruct)
assert.True(t, ok)
// The returned value (retTs) should be the same as the input (tc.giveObj)
assert.Equal(t, tc.giveObj.Field1, retTs.Field1, tc.caseDesc)
assert.Equal(t, tc.giveObj.Field2, retTs.Field2, tc.caseDesc)
assert.True(t, createCalled, tc.caseDesc)
}
}
Expand Down
110 changes: 63 additions & 47 deletions api/internal/filter/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,62 +17,78 @@
package filter

import (
"errors"
"net/http"
"strings"

"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"github.com/shiningrush/droplet"
"github.com/shiningrush/droplet/data"
"github.com/shiningrush/droplet/middleware"

"github.com/apisix/manager-api/internal/conf"
"github.com/apisix/manager-api/internal/log"
)

func Authentication() gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.URL.Path != "/apisix/admin/user/login" && strings.HasPrefix(c.Request.URL.Path, "/apisix") {
tokenStr := c.GetHeader("Authorization")

// verify token
token, err := jwt.ParseWithClaims(tokenStr, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(conf.AuthConf.Secret), nil
})

errResp := gin.H{
"code": 010013,
"message": "Request Unauthorized",
}

if err != nil || token == nil || !token.Valid {
log.Warnf("token validate failed: %s", err)
c.AbortWithStatusJSON(http.StatusUnauthorized, errResp)
return
}

claims, ok := token.Claims.(*jwt.StandardClaims)
if !ok {
log.Warnf("token validate failed: %s, %v", err, token.Valid)
c.AbortWithStatusJSON(http.StatusUnauthorized, errResp)
return
}

if err := token.Claims.Valid(); err != nil {
log.Warnf("token claims validate failed: %s", err)
c.AbortWithStatusJSON(http.StatusUnauthorized, errResp)
return
}

if claims.Subject == "" {
log.Warn("token claims subject empty")
c.AbortWithStatusJSON(http.StatusUnauthorized, errResp)
return
}

if _, ok := conf.UserList[claims.Subject]; !ok {
log.Warnf("user not exists by token claims subject %s", claims.Subject)
c.AbortWithStatusJSON(http.StatusUnauthorized, errResp)
return
}
type AuthenticationMiddleware struct {
middleware.BaseMiddleware
}

func (mw *AuthenticationMiddleware) Handle(ctx droplet.Context) error {
httpReq := ctx.Get(middleware.KeyHttpRequest)
if httpReq == nil {
err := errors.New("input middleware cannot get http request")

// Wrong usage, just panic here and let recoverHandler to deal with
panic(err)
}

req := httpReq.(*http.Request)

if req.URL.Path != "/apisix/admin/user/login" && strings.HasPrefix(req.URL.Path, "/apisix") {
tokenStr := req.Header.Get("Authorization")

// verify token
token, err := jwt.ParseWithClaims(tokenStr, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(conf.AuthConf.Secret), nil
})

// TODO: design the response error code
response := data.Response{Code: 010013, Message: "request unauthorized"}

if err != nil || token == nil || !token.Valid {
log.Warnf("token validate failed: %s", err)
ctx.SetOutput(&data.SpecCodeResponse{StatusCode: http.StatusUnauthorized, Response: response})
return nil
}
c.Next()

claims, ok := token.Claims.(*jwt.StandardClaims)
if !ok {
log.Warnf("token validate failed: %s, %v", err, token.Valid)
ctx.SetOutput(&data.SpecCodeResponse{StatusCode: http.StatusUnauthorized, Response: response})
return nil
}

if err := token.Claims.Valid(); err != nil {
log.Warnf("token claims validate failed: %s", err)
ctx.SetOutput(&data.SpecCodeResponse{StatusCode: http.StatusUnauthorized, Response: response})
return nil
}

if claims.Subject == "" {
log.Warn("token claims subject empty")
ctx.SetOutput(&data.SpecCodeResponse{StatusCode: http.StatusUnauthorized, Response: response})
return nil
}

if _, ok := conf.UserList[claims.Subject]; !ok {
log.Warnf("user not exists by token claims subject %s", claims.Subject)
ctx.SetOutput(&data.SpecCodeResponse{StatusCode: http.StatusUnauthorized, Response: response})
return nil
}

return mw.BaseMiddleware.Handle(ctx)
}

return mw.BaseMiddleware.Handle(ctx)
}
Loading

0 comments on commit 5fc45b7

Please sign in to comment.