Skip to content

Commit

Permalink
feat(acl): allow setting a password at the time of creation of namesp…
Browse files Browse the repository at this point in the history
…ace (#7446)

Fix dgraph debug tool
Fix dgraph acl tool.
Creation of a namespace allows passing a password to be set for groot. Else, "password" is used.
  • Loading branch information
NamanJain8 authored Feb 18, 2021
1 parent 2eb7bc8 commit c04c1a2
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 33 deletions.
12 changes: 7 additions & 5 deletions dgraph/cmd/debug/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func uidToVal(itr *badger.Iterator, prefix string) map[uint64]int {
lastKey = append(lastKey[:0], item.Key()...)
pk, err := x.Parse(item.Key())
x.Check(err)
if !pk.IsData() || !strings.HasPrefix(pk.Attr, prefix) {
if !pk.IsData() || !strings.HasPrefix(x.ParseAttr(pk.Attr), prefix) {
continue
}
if pk.IsSchema() {
Expand Down Expand Up @@ -280,7 +280,8 @@ func showAllPostingsAt(db *badger.DB, readTs uint64) {
}

var acc *account
if strings.HasPrefix(pk.Attr, "key_") || strings.HasPrefix(pk.Attr, "amount_") {
attr := x.ParseAttr(pk.Attr)
if strings.HasPrefix(attr, "key_") || strings.HasPrefix(attr, "amount_") {
var has bool
acc, has = keys[pk.Uid]
if !has {
Expand All @@ -302,9 +303,9 @@ func showAllPostingsAt(db *badger.DB, readTs uint64) {
}
if num > 0 && acc != nil {
switch {
case strings.HasPrefix(pk.Attr, "key_"):
case strings.HasPrefix(attr, "key_"):
acc.Key = num
case strings.HasPrefix(pk.Attr, "amount_"):
case strings.HasPrefix(attr, "amount_"):
acc.Amt = num
}
}
Expand Down Expand Up @@ -909,7 +910,8 @@ func run() {
WithReadOnly(opt.readOnly).
WithEncryptionKey(opt.key).
WithBlockCacheSize(1 << 30).
WithIndexCacheSize(1 << 30)
WithIndexCacheSize(1 << 30).
WithNamespaceOffset(x.NamespaceOffset) // We don't want to see the banned data.

x.AssertTruef(len(bopts.Dir) > 0, "No posting or wal dir specified.")
fmt.Printf("Opening DB: %s\n", bopts.Dir)
Expand Down
6 changes: 3 additions & 3 deletions edgraph/access_ee.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ func ResetAcl(closer *z.Closer) {
ctx, cancel := context.WithTimeout(closer.Ctx(), time.Minute)
defer cancel()
ctx = x.AttachNamespace(ctx, x.GalaxyNamespace)
if err := upsertGroot(ctx); err != nil {
if err := upsertGroot(ctx, "password"); err != nil {
glog.Infof("Unable to upsert the groot account. Error: %v", err)
time.Sleep(100 * time.Millisecond)
continue
Expand Down Expand Up @@ -495,7 +495,7 @@ func upsertGuardian(ctx context.Context) error {
}

// upsertGroot must be called after setting the namespace in the context.
func upsertGroot(ctx context.Context) error {
func upsertGroot(ctx context.Context, passwd string) error {
// groot is the default user of guardians group.
query := fmt.Sprintf(`
{
Expand All @@ -505,7 +505,7 @@ func upsertGroot(ctx context.Context) error {
guid as var(func: eq(dgraph.xid, "%s"))
}
`, x.GrootId, x.GuardiansId)
userNQuads := acl.CreateUserNQuads(x.GrootId, "password")
userNQuads := acl.CreateUserNQuads(x.GrootId, passwd)
userNQuads = append(userNQuads, &api.NQuad{
Subject: "_:newuser",
Predicate: "dgraph.user.group",
Expand Down
2 changes: 1 addition & 1 deletion edgraph/multi_tenancy.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type ResetPasswordInput struct {
Namespace uint64
}

func (s *Server) CreateNamespace(ctx context.Context) (uint64, error) {
func (s *Server) CreateNamespace(ctx context.Context, passwd string) (uint64, error) {
return 0, nil
}

Expand Down
12 changes: 4 additions & 8 deletions edgraph/multi_tenancy_ee.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ type ResetPasswordInput struct {
}

func (s *Server) ResetPassword(ctx context.Context, inp *ResetPasswordInput) error {
if err := AuthGuardianOfTheGalaxy(ctx); err != nil {
return errors.Wrapf(err, "Reset password got error:")
}

query := fmt.Sprintf(`{
x as updateUser(func: eq(dgraph.xid, "%s")) @filter(type(dgraph.type.User)) {
uid
Expand Down Expand Up @@ -91,7 +87,7 @@ func (s *Server) ResetPassword(ctx context.Context, inp *ResetPasswordInput) err

// CreateNamespace creates a new namespace. Only guardian of galaxy is authorized to do so.
// Authorization is handled by middlewares.
func (s *Server) CreateNamespace(ctx context.Context) (uint64, error) {
func (s *Server) CreateNamespace(ctx context.Context, passwd string) (uint64, error) {
glog.V(2).Info("Got create namespace request.")

num := &pb.Num{Val: 1, Type: pb.Num_NS_ID}
Expand All @@ -116,7 +112,7 @@ func (s *Server) CreateNamespace(ctx context.Context) (uint64, error) {
if err = worker.WaitForIndexing(ctx, true); err != nil {
return 0, errors.Wrap(err, "Creating namespace, got error: ")
}
if err := createGuardianAndGroot(ctx, ids.StartId); err != nil {
if err := createGuardianAndGroot(ctx, ids.StartId, passwd); err != nil {
return 0, errors.Wrapf(err, "Failed to create guardian and groot: ")
}
glog.V(2).Infof("Created namespace: %d", ns)
Expand All @@ -125,11 +121,11 @@ func (s *Server) CreateNamespace(ctx context.Context) (uint64, error) {

// This function is used while creating new namespace. New namespace creation is only allowed
// by the guardians of the galaxy group.
func createGuardianAndGroot(ctx context.Context, namespace uint64) error {
func createGuardianAndGroot(ctx context.Context, namespace uint64, passwd string) error {
if err := upsertGuardian(ctx); err != nil {
return errors.Wrap(err, "While creating Guardian")
}
if err := upsertGroot(ctx); err != nil {
if err := upsertGroot(ctx, passwd); err != nil {
return errors.Wrap(err, "While creating Groot")
}
return nil
Expand Down
9 changes: 5 additions & 4 deletions ee/acl/run_ee.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ var (
CmdAcl x.SubCommand
)

const gName = "guardian_name"
const gPassword = "guardian_password"
const defaultGroupList = "dgraph-unused-group"

func init() {
Expand All @@ -40,8 +38,11 @@ func init() {
CmdAcl.Cmd.SetHelpTemplate(x.NonRootTemplate)
flag := CmdAcl.Cmd.PersistentFlags()
flag.StringP("alpha", "a", "127.0.0.1:9080", "Dgraph Alpha gRPC server address")
flag.StringP(gName, "w", x.GrootId, "Guardian username performing this operation")
flag.StringP(gPassword, "x", "", "Guardian password to authorize this operation")
flag.String("guardian-creds", "", `Login credentials for the guardian
user defines the username to login.
password defines the password of the user.
namespace defines the namespace to log into.
Sample flag could look like --guardian-creds user=username;password=mypass;namespace=2`)

// TLS configuration
x.RegisterClientTLSFlags(flag)
Expand Down
8 changes: 5 additions & 3 deletions ee/acl/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/dgraph-io/dgo/v200"
"github.com/dgraph-io/dgo/v200/protos/api"
"github.com/dgraph-io/dgraph/x"
"github.com/dgraph-io/ristretto/z"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/viper"
Expand Down Expand Up @@ -162,10 +163,11 @@ func UnmarshalGroups(input []byte, groupKey string) (group []Group, err error) {
// options, and then login using groot id and password
func getClientWithAdminCtx(conf *viper.Viper) (*dgo.Dgraph, x.CloseFunc, error) {
dg, closeClient := x.GetDgraphClient(conf, false)
creds := z.NewSuperFlag(conf.GetString("guardian-creds"))
err := x.GetPassAndLogin(dg, &x.CredOpt{
UserID: conf.GetString(gName),
Password: conf.GetString(gPassword),
// TODO(Ahsan): Which namespace do we need to pass here?
UserID: creds.GetString("user"),
Password: creds.GetString("password"),
Namespace: creds.GetUint64("namespace"),
})
if err != nil {
return nil, nil, err
Expand Down
1 change: 1 addition & 0 deletions graphql/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ var (
"updateGQLSchema": commonAdminMutationMWs,
"addNamespace": guardianOfTheGalaxyMutationMWs,
"deleteNamespace": guardianOfTheGalaxyMutationMWs,
"resetPassword": guardianOfTheGalaxyMutationMWs,
// for queries and mutations related to User/Group, dgraph handles Guardian auth,
// so no need to apply GuardianAuth Middleware
"addUser": {resolve.IpWhitelistingMW4Mutation, resolve.LoggingMWMutation},
Expand Down
10 changes: 7 additions & 3 deletions graphql/admin/endpoints_ee.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,11 @@ const adminTypes = `
numUids: Int
}
input NamespaceInput {
input AddNamespaceInput {
password: String
}
input DeleteNamespaceInput {
namespaceId: Int!
}
Expand Down Expand Up @@ -489,12 +493,12 @@ const adminMutations = `
"""
Add a new namespace.
"""
addNamespace: NamespacePayload
addNamespace(input: AddNamespaceInput): NamespacePayload
"""
Delete a namespace.
"""
deleteNamespace(input: NamespaceInput!): NamespacePayload
deleteNamespace(input: DeleteNamespaceInput!): NamespacePayload
"""
Reset password can only be used by the Guardians of the galaxy to reset password of
Expand Down
35 changes: 29 additions & 6 deletions graphql/admin/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,25 @@ import (
"github.com/dgraph-io/dgraph/graphql/schema"
)

type namespaceInput struct {
type addNamespaceInput struct {
Password string
}

type deleteNamespaceInput struct {
NamespaceId int
}

func resolveAddNamespace(ctx context.Context, m schema.Mutation) (*resolve.Resolved, bool) {
req, err := getAddNamespaceInput(m)
if err != nil {
return resolve.EmptyResult(m, err), false
}
if req.Password == "" {
// Use the default password, if the user does not specify.
req.Password = "password"
}
var ns uint64
var err error
if ns, err = (&edgraph.Server{}).CreateNamespace(ctx); err != nil {
if ns, err = (&edgraph.Server{}).CreateNamespace(ctx, req.Password); err != nil {
return resolve.EmptyResult(m, err), false
}
return resolve.DataResult(
Expand All @@ -47,7 +58,7 @@ func resolveAddNamespace(ctx context.Context, m schema.Mutation) (*resolve.Resol
}

func resolveDeleteNamespace(ctx context.Context, m schema.Mutation) (*resolve.Resolved, bool) {
req, err := getNamespaceInput(m)
req, err := getDeleteNamespaceInput(m)
if err != nil {
return resolve.EmptyResult(m, err), false
}
Expand All @@ -64,14 +75,26 @@ func resolveDeleteNamespace(ctx context.Context, m schema.Mutation) (*resolve.Re
), true
}

func getNamespaceInput(m schema.Mutation) (*namespaceInput, error) {
func getAddNamespaceInput(m schema.Mutation) (*addNamespaceInput, error) {
inputArg := m.ArgValue(schema.InputArgName)
inputByts, err := json.Marshal(inputArg)
if err != nil {
return nil, schema.GQLWrapf(err, "couldn't get input argument")
}

var input addNamespaceInput
err = json.Unmarshal(inputByts, &input)
return &input, schema.GQLWrapf(err, "couldn't get input argument")
}

func getDeleteNamespaceInput(m schema.Mutation) (*deleteNamespaceInput, error) {
inputArg := m.ArgValue(schema.InputArgName)
inputByts, err := json.Marshal(inputArg)
if err != nil {
return nil, schema.GQLWrapf(err, "couldn't get input argument")
}

var input namespaceInput
var input deleteNamespaceInput
err = json.Unmarshal(inputByts, &input)
return &input, schema.GQLWrapf(err, "couldn't get input argument")
}
2 changes: 2 additions & 0 deletions x/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ const (
GalaxyNamespace = uint64(0)
// IgnoreBytes is the byte range which will be ignored while prefix match in subscription.
IgnoreBytes = "1-8"
// NamespaceOffset is the offset in badger key from which the next 8 bytes contain namespace.
NamespaceOffset = 1
)

func NamespaceToBytes(ns uint64) []byte {
Expand Down

0 comments on commit c04c1a2

Please sign in to comment.