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

Commit

Permalink
[patch] support multiple authz-bypass URLs (#41)
Browse files Browse the repository at this point in the history
* [patch] version is not added on released steps (#46)
  • Loading branch information
WindzCUHK committed Jan 31, 2020
1 parent 0d56eb0 commit 0a53b77
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 26 deletions.
19 changes: 8 additions & 11 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ jobs:
- run:
name: docker image build
command: |
TAG=`cat ./.tag`
if [ ! -z "$CIRCLE_TAG" ]; then
echo '$CIRCLE_TAG exists, use: '"$CIRCLE_TAG"
TAG="$CIRCLE_TAG"
elif [ -f ./.tag ]; then
TAG=`cat ./.tag`
fi
if [ ! -z "$TAG" ]; then
docker build --build-arg APP_VERSION=${TAG} -t ${REPO_NAME}/${IMAGE_NAME}:latest .
else
Expand Down Expand Up @@ -202,6 +207,7 @@ workflows:
build:
jobs:
- test
- versioning
- build:
requires:
- versioning
Expand All @@ -213,28 +219,19 @@ workflows:
branches:
only:
- master
- versioning:
- push:
filters:
branches:
only:
- master
- push:
requires:
- versioning
- gh_release:
requires:
- push
release:
jobs:
- versioning:
filters:
branches:
ignore: /.*/
tags:
only: /[0-9]+\.[0-9]+\.[0-9]+/
- build:
requires:
- versioning
filters:
branches:
ignore: /.*/
Expand Down
5 changes: 5 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ type Proxy struct {

// BufferSize represent the reverse proxy buffer size.
BufferSize uint64 `yaml:"buffer_size"`

// BypassURLPaths represent URL paths that require authorization bypassing.
// WARNING!!! Setting this configuration may introduce security hole in your system. Do NOT set this configuration with URL paths other than application's healthcheck endpoint.
// Tips for performance: define your healthcheck endpoint with different lenght from the most frequestly used endpoint, e.g. `/most_used` (len: 10) with `/healthcheck` (len: 12), instead of `/healthccc` (len: 10)
BypassURLPaths []string `yaml:"bypass_url_paths"`
}

// Authorization represents the detail configuration of the authorization proxy.
Expand Down
11 changes: 6 additions & 5 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,12 @@ func TestNew(t *testing.T) {
AthenzRootCA: "",
},
Proxy: Proxy{
Scheme: "http",
Host: "localhost",
Port: 80,
RoleHeader: "Athenz-Role-Auth",
BufferSize: 4096,
Scheme: "http",
Host: "localhost",
Port: 80,
RoleHeader: "Athenz-Role-Auth",
BufferSize: 4096,
BypassURLPaths: []string{},
},
Authorization: Authorization{
PubKeyRefreshDuration: "24h",
Expand Down
1 change: 1 addition & 0 deletions config/testdata/example_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ proxy:
port: 80
role_header_key: Athenz-Role-Auth
buffer_size: 4096
bypass_url_paths: []
provider:
pubKeyRefreshDuration: 24h
pubKeySysAuthDomain: sys.auth
Expand Down
9 changes: 8 additions & 1 deletion handler/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/yahoojapan/authorization-proxy/config"
"github.com/yahoojapan/authorization-proxy/service"

"github.com/kpango/glg"
"github.com/pkg/errors"
)

Expand All @@ -33,9 +34,15 @@ type transport struct {
}

func (t *transport) RoundTrip(r *http.Request) (*http.Response, error) {
for _, urlPath := range t.cfg.BypassURLPaths {
if urlPath == r.URL.Path {
glg.Info("Authorization checking skipped on: " + r.URL.Path)
return t.RoundTripper.RoundTrip(r)
}
}

if err := t.prov.VerifyRoleToken(r.Context(), r.Header.Get(t.cfg.RoleHeader), r.Method, r.URL.Path); err != nil {
return nil, errors.Wrap(err, ErrMsgVerifyRoleToken)
}

return t.RoundTripper.RoundTrip(r)
}
140 changes: 139 additions & 1 deletion handler/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func Test_transport_RoundTrip(t *testing.T) {
wantErr: true,
},
{
name: "Verify roletoken success",
name: "verify role token success",
fields: fields{
RoundTripper: &RoundTripperMock{
RoundTripFunc: func(req *http.Request) (*http.Response, error) {
Expand Down Expand Up @@ -78,6 +78,144 @@ func Test_transport_RoundTrip(t *testing.T) {
},
wantErr: false,
},
{
name: "verify role token success (empty bypass URLs)",
fields: fields{
RoundTripper: &RoundTripperMock{
RoundTripFunc: func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: 999,
}, nil
},
},
prov: &service.AuthorizerdMock{
VerifyRoleTokenFunc: func(ctx context.Context, tok, act, res string) error {
return nil
},
},
cfg: config.Proxy{
RoleHeader: "",
BypassURLPaths: []string{},
},
},
args: args{
r: func() *http.Request {
r, _ := http.NewRequest("GET", "http://athenz.io", nil)
return r
}(),
},
want: &http.Response{
StatusCode: 999,
},
wantErr: false,
},
{
name: "BypassURLPaths match, bypass role token verification",
fields: fields{
RoundTripper: &RoundTripperMock{
RoundTripFunc: func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: 200,
}, nil
},
},
prov: &service.AuthorizerdMock{
VerifyRoleTokenFunc: func(ctx context.Context, tok, act, res string) error {
return errors.New("role token error")
},
},
cfg: config.Proxy{
BypassURLPaths: []string{
"/healthz",
},
},
},
args: args{
r: func() *http.Request {
r, _ := http.NewRequest("GET", "http://athenz.io/healthz", nil)
return r
}(),
},
want: &http.Response{
StatusCode: 200,
},
wantErr: false,
},
{
name: "BypassURLPaths ANY match, bypass role token verification",
fields: fields{
RoundTripper: &RoundTripperMock{
RoundTripFunc: func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: 200,
}, nil
},
},
prov: &service.AuthorizerdMock{
VerifyRoleTokenFunc: func(ctx context.Context, tok, act, res string) error {
return errors.New("role token error")
},
},
cfg: config.Proxy{
BypassURLPaths: []string{
"/healthz",
"/healthz/",
},
},
},
args: args{
r: func() *http.Request {
r, _ := http.NewRequest("GET", "http://athenz.io/healthz/", nil)
return r
}(),
},
want: &http.Response{
StatusCode: 200,
},
wantErr: false,
},
{
name: "BypassURLPaths NONE match, verify role token",
fields: fields{
RoundTripper: nil,
prov: &service.AuthorizerdMock{
VerifyRoleTokenFunc: func(ctx context.Context, tok, act, res string) error {
return errors.New("role token error")
},
},
cfg: config.Proxy{
BypassURLPaths: []string{
"/healthz",
},
},
},
args: args{
r: func() *http.Request {
r, _ := http.NewRequest("GET", "http://athenz.io/healthz/", nil)
return r
}(),
},
wantErr: true,
},
{
name: "BypassURLPaths NOT set, verify role token",
fields: fields{
RoundTripper: nil,
prov: &service.AuthorizerdMock{
VerifyRoleTokenFunc: func(ctx context.Context, tok, act, res string) error {
return errors.New("role token error")
},
},
cfg: config.Proxy{},
},
args: args{
r: func() *http.Request {
r, _ := http.NewRequest("GET", "http://athenz.io/healthz", nil)
return r
}(),
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
10 changes: 2 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,8 @@ func main() {
}

if p.showVersion {
err := glg.Infof("authorization-proxy version -> %s", getVersion())
if err != nil {
glg.Fatal(err)
}
err = glg.Infof("authorization-proxy config version -> %s", config.GetVersion())
if err != nil {
glg.Fatal(err)
}
glg.Infof("authorization-proxy version -> %s", getVersion())
glg.Infof("authorization-proxy config version -> %s", config.GetVersion())
return
}

Expand Down

0 comments on commit 0a53b77

Please sign in to comment.