Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(acl): allow setting a password at the time of creation of namespace #7446

Merged
merged 4 commits into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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