Skip to content
This repository has been archived by the owner on Dec 20, 2022. It is now read-only.

Commit

Permalink
[minor] fix multi domain fetch (#38)
Browse files Browse the repository at this point in the history
* fix multi domain fetch (add fetcher implementation)
- add Init() function to authorizerd
  • Loading branch information
WindzCUHK authored and kevindiu committed Sep 5, 2019
1 parent 2803acb commit d1efce0
Show file tree
Hide file tree
Showing 25 changed files with 2,606 additions and 1,656 deletions.
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![License: Apache](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square)](https://opensource.org/licenses/Apache-2.0) [![release](https://img.shields.io/github/release/yahoojapan/athenz-authorizer.svg?style=flat-square)](https://github.com/yahoojapan/athenz-authorizer/releases/latest) [![CircleCI](https://circleci.com/gh/yahoojapan/athenz-authorizer.svg)](https://circleci.com/gh/yahoojapan/athenz-authorizer) [![codecov](https://codecov.io/gh/yahoojapan/athenz-authorizer/branch/master/graph/badge.svg?token=2CzooNJtUu&style=flat-square)](https://codecov.io/gh/yahoojapan/athenz-authorizer) [![Go Report Card](https://goreportcard.com/badge/github.com/yahoojapan/athenz-authorizer)](https://goreportcard.com/report/github.com/yahoojapan/athenz-authorizer) [![GolangCI](https://golangci.com/badges/github.com/yahoojapan/athenz-authorizer.svg?style=flat-square)](https://golangci.com/r/github.com/yahoojapan/athenz-authorizer) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/828220605c43419e92fb0667876dd2d0)](https://www.codacy.com/app/i.can.feel.gravity/athenz-authorizer?utm_source=github.com&utm_medium=referral&utm_content=yahoojapan/athenz-authorizer&utm_campaign=Badge_Grade) [![GoDoc](http://godoc.org/github.com/yahoojapan/athenz-authorizer?status.svg)](http://godoc.org/github.com/yahoojapan/athenz-authorizer)
## What is Athenz authorizer

Athenz authorizer is a library to cache the policies of [Athenz](https://github.com/yahoo/athenz) to authorizer authenication and authorization check of user request.
Athenz authorizer is a library to cache the policies of [Athenz](https://github.com/yahoo/athenz) to authorizer authentication and authorization check of user request.

![Overview](./doc/policy_updater_overview.png)

Expand Down Expand Up @@ -33,7 +33,7 @@ go func() {

// Verify role token
if err := daemon.VerifyRoleToken(ctx, roleTok, act, res); err != nil {
// token not authorizated
// token not authorized
}
```

Expand All @@ -49,9 +49,9 @@ Athenz pubkey daemon (pubkeyd) is responsible for periodically update the Athenz

### Athenz policy daemon

Athenz policy daemon (policyd) is responsible for periodically update the policy data of specified Athenz domain from Athenz server. The received policy data will be verified using the public key got from pubkeyd, and cache into memory. Whenever user requesting for the access check, the verification check will be used instead of asking Athenz server everytime.
Athenz policy daemon (policyd) is responsible for periodically update the policy data of specified Athenz domain from Athenz server. The received policy data will be verified using the public key got from pubkeyd, and cache into memory. Whenever user requesting for the access check, the verification check will be used instead of asking Athenz server every time.

## Configuratrion
## Configuration

The authorizer uses functional options pattern to initialize the instance. All the options are defined [here](./option.go).

Expand All @@ -66,8 +66,7 @@ The authorizer uses functional options pattern to initialize the instance. All t
| PubkeyEtagExpTime | ETag cache TTL of Athenz public key data | 168 Hours (1 Week) | No | |
| PubkeyEtagFlushDur | ETag cache purge duration | 84 Hours | No | |
| PolicyRefreshDuration | The refresh duration to update Athenz policy data | 30 Minutes | No | |
| PolicyExpireMargin | The expire margin to update the policy data. It forces update the policy data before the policy expiration margin. | 3 Hours | No | |
| PolicyEtagFlushDur | Policy data cache purge duration | 12 Hours | No | |
| PolicyExpireMargin | The expire margin to update the policy data. It forces update the policy data before the policy expiration margin. | 3 Hours | No | |

## License

Expand Down
42 changes: 38 additions & 4 deletions authorizerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

"github.com/kpango/gache"
"github.com/kpango/glg"
"golang.org/x/sync/errgroup"

"github.com/pkg/errors"
"github.com/yahoojapan/athenz-authorizer/v2/jwk"
Expand All @@ -35,6 +36,7 @@ import (

// Authorizerd represents a daemon for user to verify the role token
type Authorizerd interface {
Init(ctx context.Context) error
Start(ctx context.Context) <-chan error
VerifyRoleToken(ctx context.Context, tok, act, res string) error
VerifyRoleJWT(ctx context.Context, tok, act, res string) error
Expand Down Expand Up @@ -74,7 +76,6 @@ type authorizer struct {
athenzDomains []string
policyRefreshDuration string
policyErrRetryInterval string
policyEtagFlushDur string

// jwkd parameters
disableJwkd bool
Expand Down Expand Up @@ -127,13 +128,12 @@ func New(opts ...Option) (Authorizerd, error) {
if !prov.disablePolicyd {
if prov.policyd, err = policy.New(
policy.WithExpireMargin(prov.policyExpireMargin),
policy.WithEtagFlushDuration(prov.policyEtagFlushDur),
policy.WithAthenzURL(prov.athenzURL),
policy.WithAthenzDomains(prov.athenzDomains...),
policy.WithRefreshDuration(prov.policyRefreshDuration),
policy.WithErrRetryInterval(prov.policyErrRetryInterval),
policy.WithHTTPClient(prov.client),
policy.WithPubKeyProvider(prov.pubkeyd.GetProvider()),
policy.WithPubKeyProvider(pubkeyProvider),
); err != nil {
return nil, errors.Wrap(err, "error create policyd")
}
Expand All @@ -159,6 +159,40 @@ func New(opts ...Option) (Authorizerd, error) {
return prov, nil
}

// Init initializes child daemons synchronously.
func (a *authorizer) Init(ctx context.Context) error {
eg, egCtx := errgroup.WithContext(ctx)
eg.Go(func() error {
select {
case <-egCtx.Done():
return egCtx.Err()
default:
if !a.disablePubkeyd {
err := a.pubkeyd.Update(egCtx)
if err != nil {
return err
}
}
if !a.disablePolicyd {
return a.policyd.Update(egCtx)
}
return nil
}
})
if !a.disableJwkd {
eg.Go(func() error {
select {
case <-egCtx.Done():
return egCtx.Err()
default:
return a.jwkd.Update(egCtx)
}
})
}

return eg.Wait()
}

// Start starts authorizer daemon.
func (a *authorizer) Start(ctx context.Context) <-chan error {
var (
Expand Down Expand Up @@ -260,7 +294,7 @@ func (a *authorizer) verify(ctx context.Context, m mode, tok, act, res string) e
}

func (a *authorizer) VerifyRoleCert(ctx context.Context, peerCerts []*x509.Certificate, act, res string) error {
dr := make([]string, 0, 2)
var dr []string
drcheck := make(map[string]struct{})
domainRoles := make(map[string][]string)
for _, cert := range peerCerts {
Expand Down
27 changes: 27 additions & 0 deletions authorizerd_mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,33 @@ func (cm *ConfdMock) Start(ctx context.Context) <-chan error {
return ech
}

type PubkeydMock struct {
StartFunc func(context.Context) <-chan error
UpdateFunc func(context.Context) error
GetProviderFunc func() pubkey.Provider
}

func (pm *PubkeydMock) Start(ctx context.Context) <-chan error {
if pm.StartFunc != nil {
return pm.StartFunc(ctx)
}
return nil
}

func (pm *PubkeydMock) Update(ctx context.Context) error {
if pm.UpdateFunc != nil {
return pm.UpdateFunc(ctx)
}
return nil
}

func (pm *PubkeydMock) GetProvider() pubkey.Provider {
if pm.GetProviderFunc != nil {
return pm.GetProviderFunc()
}
return nil
}

type PolicydMock struct {
UpdateFunc func(context.Context) error
CheckPolicyFunc func(ctx context.Context, domain string, roles []string, action, resource string) error
Expand Down
172 changes: 164 additions & 8 deletions authorizerd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,170 @@ func TestNew(t *testing.T) {
}
}

func Test_authorizer_Init(t *testing.T) {
type fields struct {
pubkeyd pubkey.Daemon
policyd policy.Daemon
jwkd jwk.Daemon
disablePubkeyd bool
disablePolicyd bool
disableJwkd bool
}
type args struct {
ctx context.Context
}
tests := []struct {
name string
fields fields
args args
wantErrStr string
}{
{
name: "cancelled context, no waiting",
fields: fields{
pubkeyd: &PubkeydMock{
UpdateFunc: func(context.Context) error {
time.Sleep(10 * time.Millisecond)
return errors.New("pubkeyd error")
},
},
policyd: nil,
jwkd: &JwkdMock{
UpdateFunc: func(context.Context) error {
time.Sleep(10 * time.Millisecond)
return errors.New("jwkd error")
},
},
disablePubkeyd: false,
disablePolicyd: true,
disableJwkd: false,
},
args: args{
ctx: func() context.Context {
ctx, cancel := context.WithCancel(context.Background())
cancel()
return ctx
}(),
},
wantErrStr: context.Canceled.Error(),
},
{
name: "all disable",
fields: fields{
pubkeyd: nil,
policyd: nil,
jwkd: nil,
disablePubkeyd: true,
disablePolicyd: true,
disableJwkd: true,
},
args: args{
ctx: context.Background(),
},
wantErrStr: "",
},
{
name: "jwkd is not blocked",
fields: fields{
pubkeyd: &PubkeydMock{
UpdateFunc: func(context.Context) error {
time.Sleep(10 * time.Millisecond)
return errors.New("pubkeyd error")
},
},
policyd: nil,
jwkd: &JwkdMock{
UpdateFunc: func(context.Context) error {
return errors.New("jwkd done")
},
},
disablePubkeyd: false,
disablePolicyd: true,
disableJwkd: false,
},
args: args{
ctx: context.Background(),
},
wantErrStr: "jwkd done",
},
{
name: "policyd is blocked by pubkeyd",
fields: *(func() *fields {
pubkeydDone := false
return &fields{
pubkeyd: &PubkeydMock{
UpdateFunc: func(context.Context) error {
time.Sleep(10 * time.Millisecond)
pubkeydDone = true
return nil
},
},
policyd: &PolicydMock{
UpdateFunc: func(context.Context) error {
if pubkeydDone {
return nil
}
return errors.New("policyd error")
},
},
jwkd: nil,
disablePubkeyd: false,
disablePolicyd: true,
disableJwkd: true,
}
}()),
args: args{
ctx: context.Background(),
},
wantErrStr: "",
},
{
name: "all daemons init success",
fields: fields{
pubkeyd: &PubkeydMock{
UpdateFunc: func(context.Context) error {
return nil
},
},
policyd: &PolicydMock{
UpdateFunc: func(context.Context) error {
return nil
},
},
jwkd: &JwkdMock{
UpdateFunc: func(context.Context) error {
return nil
},
},
disablePubkeyd: false,
disablePolicyd: false,
disableJwkd: false,
},
args: args{
ctx: context.Background(),
},
wantErrStr: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &authorizer{
pubkeyd: tt.fields.pubkeyd,
policyd: tt.fields.policyd,
jwkd: tt.fields.jwkd,
disablePubkeyd: tt.fields.disablePubkeyd,
disablePolicyd: tt.fields.disablePolicyd,
disableJwkd: tt.fields.disableJwkd,
}
err := a.Init(tt.args.ctx)
if (err == nil && tt.wantErrStr != "") || (err != nil && err.Error() != tt.wantErrStr) {
t.Errorf("authorizer.Init() error = %v, wantErr %v", err, tt.wantErrStr)
return
}
})
}
}

func Test_authorizer_Start(t *testing.T) {
type fields struct {
pubkeyd pubkey.Daemon
Expand Down Expand Up @@ -503,7 +667,6 @@ func Test_authorizer_VerifyRoleJWT(t *testing.T) {
policyExpireMargin string
athenzDomains []string
policyRefreshDuration string
policyEtagFlushDur string
}
type args struct {
ctx context.Context
Expand Down Expand Up @@ -695,7 +858,6 @@ func Test_authorizer_VerifyRoleJWT(t *testing.T) {
policyExpireMargin: tt.fields.policyExpireMargin,
athenzDomains: tt.fields.athenzDomains,
policyRefreshDuration: tt.fields.policyRefreshDuration,
policyEtagFlushDur: tt.fields.policyEtagFlushDur,
}
err := p.VerifyRoleJWT(tt.args.ctx, tt.args.tok, tt.args.act, tt.args.res)
if err != nil {
Expand Down Expand Up @@ -736,7 +898,6 @@ func Test_authorizer_verify(t *testing.T) {
policyExpireMargin string
athenzDomains []string
policyRefreshDuration string
policyEtagFlushDur string
}
type args struct {
ctx context.Context
Expand Down Expand Up @@ -772,7 +933,6 @@ func Test_authorizer_verify(t *testing.T) {
policyExpireMargin: tt.fields.policyExpireMargin,
athenzDomains: tt.fields.athenzDomains,
policyRefreshDuration: tt.fields.policyRefreshDuration,
policyEtagFlushDur: tt.fields.policyEtagFlushDur,
}
if err := p.verify(tt.args.ctx, tt.args.m, tt.args.tok, tt.args.act, tt.args.res); (err != nil) != tt.wantErr {
t.Errorf("authorizer.verify() error = %v, wantErr %v", err, tt.wantErr)
Expand All @@ -799,7 +959,6 @@ func Test_authorizer_VerifyRoleCert(t *testing.T) {
policyExpireMargin string
athenzDomains []string
policyRefreshDuration string
policyEtagFlushDur string
}
type args struct {
ctx context.Context
Expand Down Expand Up @@ -971,7 +1130,6 @@ bu80CwTnWhmdBo36Ig==
policyExpireMargin: tt.fields.policyExpireMargin,
athenzDomains: tt.fields.athenzDomains,
policyRefreshDuration: tt.fields.policyRefreshDuration,
policyEtagFlushDur: tt.fields.policyEtagFlushDur,
}
if err := p.VerifyRoleCert(tt.args.ctx, tt.args.peerCerts, tt.args.act, tt.args.res); (err != nil) != tt.wantErr {
t.Errorf("authorizer.VerifyRoleCert() error = %v, wantErr %v", err, tt.wantErr)
Expand All @@ -998,7 +1156,6 @@ func Test_authorizer_GetPolicyCache(t *testing.T) {
policyExpireMargin string
athenzDomains []string
policyRefreshDuration string
policyEtagFlushDur string
}
type args struct {
ctx context.Context
Expand Down Expand Up @@ -1039,7 +1196,6 @@ func Test_authorizer_GetPolicyCache(t *testing.T) {
policyExpireMargin: tt.fields.policyExpireMargin,
athenzDomains: tt.fields.athenzDomains,
policyRefreshDuration: tt.fields.policyRefreshDuration,
policyEtagFlushDur: tt.fields.policyEtagFlushDur,
}
if got := a.GetPolicyCache(tt.args.ctx); !reflect.DeepEqual(got, tt.want) {
t.Errorf("authorizer.GetPolicyCache() = %v, want %v", got, tt.want)
Expand Down
Loading

0 comments on commit d1efce0

Please sign in to comment.