Skip to content
This repository has been archived by the owner on Feb 18, 2021. It is now read-only.

Commit

Permalink
Include destination path in CreateDestination resource URN (#205)
Browse files Browse the repository at this point in the history
* Include destination path in CreateDestination resource URN

* Add test for GetResourceURNCreateDestination

* Use path root prefix for CreateDestination resource URN

* Add Groups to Subject

* Pass AuthProvider in client command line tool

* Small update per comments

* Add security for CreateConsumerGroup

* Update cli/lib.go

* Fix lint issue
  • Loading branch information
Bo Yang authored May 17, 2017
1 parent cc76e57 commit 7ecf58d
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 9 deletions.
2 changes: 2 additions & 0 deletions common/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ type (
Type string
// Name is the entity name
Name string
// Groups contains the groups the entity belongs to
Groups []string
}

// Operation is type for an user operation, e.g. CreateDestination, PublishDestination
Expand Down
42 changes: 38 additions & 4 deletions common/auth_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,46 @@ import (
)

const (
resourceURNTemplateCreateDestination = "urn:cherami:dst:%v"
resourceURNTemplateCreateDestination = "urn:cherami:dst:%v:%v"
resourceURNTemplateCreateConsumerGroup = "urn:cherami:dst:%v:%v"
)

// GetResourceRootURN returns the root resource URN, e.g. urn:cherami:dst:zone1_prod
// GetResourceURNCreateDestination returns the resource URN to create destination, e.g. urn:cherami:dst:zone1_prod:/prefix1
// We use URN (Uniform Resource Name) like this: https://www.ietf.org/rfc/rfc2141.txt
func GetResourceRootURN(scommon SCommon) string {
func GetResourceURNCreateDestination(scommon SCommon, dstPath *string) string {
var dstPathString string
if dstPath == nil {
dstPathString = ""
} else {
dstPathString = getPathRootName(dstPath)
}
deploymentName := scommon.GetConfig().GetDeploymentName()
return fmt.Sprintf(resourceURNTemplateCreateDestination, strings.ToLower(deploymentName))
return fmt.Sprintf(resourceURNTemplateCreateDestination, strings.ToLower(deploymentName), strings.ToLower(dstPathString))
}

// GetResourceURNCreateConsumerGroup returns the resource URN to create consumer group, e.g. urn:cherami:dst:zone1_prod:/dst1
// We use URN (Uniform Resource Name) like this: https://www.ietf.org/rfc/rfc2141.txt
func GetResourceURNCreateConsumerGroup(scommon SCommon, dstPath *string) string {
var dstPathString string
if dstPath == nil {
dstPathString = ""
} else {
dstPathString = *dstPath
}
deploymentName := scommon.GetConfig().GetDeploymentName()
return fmt.Sprintf(resourceURNTemplateCreateConsumerGroup, strings.ToLower(deploymentName), strings.ToLower(dstPathString))
}

func getPathRootName(path *string) string {
if path == nil || *path == "" {
return ""
}

parts := strings.Split(*path, "/")

if strings.HasPrefix(*path, "/") {
return "/" + parts[1]
}

return parts[0]
}
98 changes: 98 additions & 0 deletions common/auth_util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package common

import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/uber/cherami-server/common/configure"
"testing"
)

type AuthUtilSuite struct {
*require.Assertions // override suite.Suite.Assertions with require.Assertions; this means that s.NotNil(nil) will stop the test, not merely log an error
suite.Suite
}

type serviceConfig struct {
configure.ServiceConfig
deploymentName string
}

func (r *serviceConfig) GetDeploymentName() string {
return r.deploymentName
}

func TestAuthUtilSuite(t *testing.T) {
suite.Run(t, new(AuthUtilSuite))
}

func (s *AuthUtilSuite) SetupTest() {
s.Assertions = require.New(s.T()) // Have to define our overridden assertions in the test setup. If we did it earlier, s.T() will return nil
}

func (s *AuthUtilSuite) TestGetResourceURNCreateDestination() {
mockService := new(MockService)

config := &serviceConfig{}

mockService.On("GetConfig").Return(config)

s.Equal("urn:cherami:dst::", GetResourceURNCreateDestination(mockService, nil))
s.Equal("urn:cherami:dst::", GetResourceURNCreateDestination(mockService, StringPtr("")))

config.deploymentName = "zone1"
s.Equal("urn:cherami:dst:zone1:", GetResourceURNCreateDestination(mockService, nil))
s.Equal("urn:cherami:dst:zone1:", GetResourceURNCreateDestination(mockService, StringPtr("")))
s.Equal("urn:cherami:dst:zone1:/", GetResourceURNCreateDestination(mockService, StringPtr("/")))
s.Equal("urn:cherami:dst:zone1:/", GetResourceURNCreateDestination(mockService, StringPtr("//")))

config.deploymentName = "Zone2_ABC"
s.Equal("urn:cherami:dst:zone2_abc:/dst1", GetResourceURNCreateDestination(mockService, StringPtr("/Dst1")))
s.Equal("urn:cherami:dst:zone2_abc:/root2", GetResourceURNCreateDestination(mockService, StringPtr("/Root2/Dst2")))

s.Equal("urn:cherami:dst:zone2_abc:dst2", GetResourceURNCreateDestination(mockService, StringPtr("Dst2")))
s.Equal("urn:cherami:dst:zone2_abc:root2", GetResourceURNCreateDestination(mockService, StringPtr("Root2/Dst2")))
}

func (s *AuthUtilSuite) TestGetResourceURNCreateConsumerGroup() {
mockService := new(MockService)

config := &serviceConfig{}

mockService.On("GetConfig").Return(config)

s.Equal("urn:cherami:dst::", GetResourceURNCreateConsumerGroup(mockService, nil))
s.Equal("urn:cherami:dst::", GetResourceURNCreateConsumerGroup(mockService, StringPtr("")))

config.deploymentName = "zone1"
s.Equal("urn:cherami:dst:zone1:", GetResourceURNCreateConsumerGroup(mockService, nil))
s.Equal("urn:cherami:dst:zone1:", GetResourceURNCreateConsumerGroup(mockService, StringPtr("")))
s.Equal("urn:cherami:dst:zone1:/", GetResourceURNCreateConsumerGroup(mockService, StringPtr("/")))
s.Equal("urn:cherami:dst:zone1://", GetResourceURNCreateConsumerGroup(mockService, StringPtr("//")))

config.deploymentName = "Zone2_ABC"
s.Equal("urn:cherami:dst:zone2_abc:/dst1", GetResourceURNCreateConsumerGroup(mockService, StringPtr("/Dst1")))
s.Equal("urn:cherami:dst:zone2_abc:/root2/dst2", GetResourceURNCreateConsumerGroup(mockService, StringPtr("/Root2/Dst2")))

s.Equal("urn:cherami:dst:zone2_abc:dst2", GetResourceURNCreateConsumerGroup(mockService, StringPtr("Dst2")))
s.Equal("urn:cherami:dst:zone2_abc:root2/dst2", GetResourceURNCreateConsumerGroup(mockService, StringPtr("Root2/Dst2")))
}
16 changes: 15 additions & 1 deletion services/frontendhost/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ func (h *Frontend) CreateDestination(ctx thrift.Context, createRequest *c.Create
return nil, err
}

authResource := common.GetResourceRootURN(h.SCommon)
authResource := common.GetResourceURNCreateDestination(h.SCommon, createRequest.Path)
err = h.GetAuthManager().Authorize(authSubject, common.OperationCreate, common.Resource(authResource))
if err != nil {
lclLg.WithField(common.TagSubject, authSubject).WithField(common.TagResource, authResource).Info("Not allowed to create destination")
Expand Down Expand Up @@ -1101,6 +1101,20 @@ func (h *Frontend) CreateConsumerGroup(ctx thrift.Context, createRequest *c.Crea
common.TagCnsPth: common.FmtCnsPth(createRequest.GetConsumerGroupName()),
})

authSubject, err := h.GetAuthManager().Authenticate(ctx)
if err != nil {
// TODO add metrics
return nil, err
}

authResource := common.GetResourceURNCreateConsumerGroup(h.SCommon, createRequest.DestinationPath)
err = h.GetAuthManager().Authorize(authSubject, common.OperationRead, common.Resource(authResource))
if err != nil {
lclLg.WithField(common.TagSubject, authSubject).WithField(common.TagResource, authResource).Info("Not allowed to create consumer group")
// TODO add metrics
return nil, err
}

// request to controller
var cClient controller.TChanController
cClient, err = h.getControllerClient()
Expand Down
15 changes: 13 additions & 2 deletions tools/admin/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"time"

"github.com/codegangsta/cli"
cherami2 "github.com/uber/cherami-client-go/client/cherami"
mcli "github.com/uber/cherami-server/clients/metadata"
"github.com/uber/cherami-server/common"
toolscommon "github.com/uber/cherami-server/tools/common"
Expand All @@ -45,7 +46,12 @@ const (

// CreateDestination creates a destination
func CreateDestination(c *cli.Context, cliHelper common.CliHelper) {
cClient := toolscommon.GetCClient(c, adminToolService)
CreateDestinationSecure(c, cliHelper, nil)
}

// CreateDestinationSecure creates a destination with security enabled
func CreateDestinationSecure(c *cli.Context, cliHelper common.CliHelper, authProvider cherami2.AuthProvider) {
cClient := toolscommon.GetCClientSecure(c, adminToolService, authProvider)
toolscommon.CreateDestination(c, cClient, cliHelper)
}

Expand All @@ -58,7 +64,12 @@ func UpdateDestination(c *cli.Context) {

// CreateConsumerGroup creates a consumer group
func CreateConsumerGroup(c *cli.Context, cliHelper common.CliHelper) {
cClient := toolscommon.GetCClient(c, adminToolService)
CreateConsumerGroupSecure(c, cliHelper, nil)
}

// CreateConsumerGroupSecure creates a consumer group with security enabled
func CreateConsumerGroupSecure(c *cli.Context, cliHelper common.CliHelper, authProvider cherami2.AuthProvider) {
cClient := toolscommon.GetCClientSecure(c, adminToolService, authProvider)
mClient := toolscommon.GetMClient(c, adminToolService)
toolscommon.CreateConsumerGroup(c, cClient, mClient, cliHelper)
}
Expand Down
15 changes: 13 additions & 2 deletions tools/cli/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package cli

import (
"github.com/codegangsta/cli"
cherami2 "github.com/uber/cherami-client-go/client/cherami"
scommon "github.com/uber/cherami-server/common"
"github.com/uber/cherami-server/tools/common"
)
Expand All @@ -38,7 +39,12 @@ func ReadCgBacklog(c *cli.Context) {

// CreateDestination creates a destination
func CreateDestination(c *cli.Context, cliHelper scommon.CliHelper) {
cClient := common.GetCClient(c, serviceName)
CreateDestinationSecure(c, cliHelper, nil)
}

// CreateDestinationSecure creates a destination with security enabled
func CreateDestinationSecure(c *cli.Context, cliHelper scommon.CliHelper, authProvider cherami2.AuthProvider) {
cClient := common.GetCClientSecure(c, serviceName, authProvider)
common.CreateDestination(c, cClient, cliHelper)
}

Expand All @@ -51,8 +57,13 @@ func UpdateDestination(c *cli.Context) {

// CreateConsumerGroup creates the CG
func CreateConsumerGroup(c *cli.Context, cliHelper scommon.CliHelper) {
CreateConsumerGroupSecure(c, cliHelper, nil)
}

// CreateConsumerGroupSecure creates the CG with security enabled
func CreateConsumerGroupSecure(c *cli.Context, cliHelper scommon.CliHelper, authProvider cherami2.AuthProvider) {
mClient := common.GetMClient(c, serviceName)
cClient := common.GetCClient(c, serviceName)
cClient := common.GetCClientSecure(c, serviceName, authProvider)
common.CreateConsumerGroup(c, cClient, mClient, cliHelper)
}

Expand Down
6 changes: 6 additions & 0 deletions tools/common/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,18 @@ func newGlobalOptionsFromCLIContext(c *cli.Context) *GlobalOptions {

// GetCClient return a cherami.Client
func GetCClient(c *cli.Context, serviceName string) ccli.Client {
return GetCClientSecure(c, serviceName, nil)
}

// GetCClientSecure return a cherami.Client with security enabled
func GetCClientSecure(c *cli.Context, serviceName string, authProvider ccli.AuthProvider) ccli.Client {
gOpts := newGlobalOptionsFromCLIContext(c)
var cClient ccli.Client
var err error
cOpts := ccli.ClientOptions{
Timeout: time.Duration(gOpts.timeoutSecs) * time.Second,
DeploymentStr: gOpts.env,
AuthProvider: authProvider,
}

if !(len(gOpts.frontendHost) > 0 || gOpts.frontendPort > 0) && gOpts.hyperbahn {
Expand Down

0 comments on commit 7ecf58d

Please sign in to comment.