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

Adding the acl subcommand to support acl features #2795

Merged
merged 31 commits into from
Dec 6, 2018
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
87c50d4
Merged with master
Nov 29, 2018
3ec0343
Formatting using goimports
Nov 21, 2018
a5c3860
Using the correct command for login
Nov 21, 2018
2d4b1db
Addressing comments
Nov 29, 2018
7c524ce
Adding todo for token refresh
Nov 22, 2018
3c7478f
Added opencensus tracing for login and recording client ip
Nov 26, 2018
8165f83
Refactored the code to checkpassword and inlining the predicate names
Nov 26, 2018
a7932be
Capitalizing the log messages
Nov 26, 2018
5808aa5
Storing all the acls inside a blob
Nov 27, 2018
f0003c4
Supports removing acls with negative perms
Nov 27, 2018
3c83edb
Support configurable jwt ttl
Nov 27, 2018
5b586f9
Polishing the pr
Nov 27, 2018
54a255b
Addressing comments
Nov 29, 2018
4f7b9dc
Error handling and goimports
Nov 29, 2018
303a749
goimports
Nov 29, 2018
b65a2af
Adding the utils and access_ee files
Nov 29, 2018
e7a7db1
Manish review
manishrjain Nov 29, 2018
0e242fd
Manish Review 2
manishrjain Nov 29, 2018
e51a5ad
Manish Review 3
manishrjain Nov 29, 2018
b130700
changed runTxn to a helper func
Nov 30, 2018
58167b4
Switch to jwt-go and fixing bug
Nov 30, 2018
02f5ecf
Addressing Gus's comments
Nov 30, 2018
9005787
Merge branch 'master' into gitlw/acl_subcommand
Dec 1, 2018
3440ca9
Fix issues so that make oss gets an empty acl subcommand
Dec 1, 2018
8b0c296
Added the command to show info about a user or group
Dec 5, 2018
ca088ba
Added authentication using the refresh token
Dec 5, 2018
c33e300
Addressing comments
Dec 5, 2018
56745bc
Added test for updateAcl
Dec 6, 2018
e6a5f44
fixing issues for make oss
Dec 6, 2018
375e581
making the golangcibot happy
Dec 6, 2018
7916fcc
make the golangcibot happy
Dec 6, 2018
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
29 changes: 26 additions & 3 deletions dgraph/cmd/alpha/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"crypto/tls"
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
Expand Down Expand Up @@ -54,6 +55,11 @@ import (
hapi "google.golang.org/grpc/health/grpc_health_v1"
)

const (
tlsNodeCert = "node.crt"
tlsNodeKey = "node.key"
)

var (
bindall bool
tlsConf x.TLSHelperConfig
Expand Down Expand Up @@ -120,6 +126,9 @@ they form a Raft group and provide synchronous replication.
"If set, all Alter requests to Dgraph would need to have this token."+
" The token can be passed as follows: For HTTP requests, in X-Dgraph-AuthToken header."+
" For Grpc, in auth-token key in the context.")
flag.String("hmac_secret_file", "", "The file storing the HMAC secret"+
" that is used for signing the JWT. Enterprise feature.")
flag.Duration("jwt_ttl", 6*time.Hour, "The TTL of jwt tokens. Enterprise feature.")
flag.Float64P("lru_mb", "l", -1,
"Estimated memory the LRU cache can take. "+
"Actual usage by the process would be more than specified here.")
Expand Down Expand Up @@ -380,7 +389,7 @@ var shutdownCh chan struct{}
func run() {
bindall = Alpha.Conf.GetBool("bindall")

edgraph.SetConfiguration(edgraph.Options{
edgraphOptions := edgraph.Options{
BadgerTables: Alpha.Conf.GetString("badger.tables"),
BadgerVlog: Alpha.Conf.GetString("badger.vlog"),

Expand All @@ -390,7 +399,21 @@ func run() {
Nomutations: Alpha.Conf.GetBool("nomutations"),
AuthToken: Alpha.Conf.GetString("auth_token"),
AllottedMemory: Alpha.Conf.GetFloat64("lru_mb"),
})
}

secretFile := Alpha.Conf.GetString("hmac_secret_file")
if secretFile != "" {
hmacSecret, err := ioutil.ReadFile(secretFile)
if err != nil {
glog.Fatalf("Unable to read HMAC secret from file: %v", secretFile)
}

edgraphOptions.HmacSecret = hmacSecret
edgraphOptions.JwtTtl = Alpha.Conf.GetDuration("jwt_ttl")

glog.Info("HMAC secret loaded successfully.")
}
edgraph.SetConfiguration(edgraphOptions)

ips, err := parseIPsFromString(Alpha.Conf.GetString("whitelist"))
x.Check(err)
Expand All @@ -406,7 +429,7 @@ func run() {
MaxRetries: Alpha.Conf.GetInt("max_retries"),
}

x.LoadTLSConfig(&tlsConf, Alpha.Conf)
x.LoadTLSConfig(&tlsConf, Alpha.Conf, tlsNodeCert, tlsNodeKey)
tlsConf.ClientAuth = Alpha.Conf.GetString("tls_client_auth")

setupCustomTokenizers()
Expand Down
41 changes: 3 additions & 38 deletions dgraph/cmd/live/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ import (
"strings"
"time"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"

"github.com/dgraph-io/badger"
Expand All @@ -48,11 +46,6 @@ import (
"github.com/spf13/cobra"
)

const (
tlsLiveCert = "client.live.crt"
tlsLiveKey = "client.live.key"
)

type options struct {
files string
schemaFile string
Expand Down Expand Up @@ -239,34 +232,6 @@ func (l *loader) processFile(ctx context.Context, file string) error {
return nil
}

func setupConnection(host string, insecure bool) (*grpc.ClientConn, error) {
if insecure {
return grpc.Dial(host,
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(x.GrpcMaxSize),
grpc.MaxCallSendMsgSize(x.GrpcMaxSize)),
grpc.WithInsecure(),
grpc.WithBlock(),
grpc.WithTimeout(10*time.Second))
}

tlsConf.ConfigType = x.TLSClientConfig
tlsConf.Cert = filepath.Join(tlsConf.CertDir, tlsLiveCert)
tlsConf.Key = filepath.Join(tlsConf.CertDir, tlsLiveKey)
tlsCfg, _, err := x.GenerateTLSConfig(tlsConf)
if err != nil {
return nil, err
}

return grpc.Dial(host,
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(x.GrpcMaxSize),
grpc.MaxCallSendMsgSize(x.GrpcMaxSize)),
grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg)),
grpc.WithBlock(),
grpc.WithTimeout(10*time.Second))
}

func fileList(files string) []string {
if len(files) == 0 {
return []string{}
Expand All @@ -285,7 +250,7 @@ func setup(opts batchMutationOptions, dc *dgo.Dgraph) *loader {
kv, err := badger.Open(o)
x.Checkf(err, "Error while creating badger KV posting store")

connzero, err := setupConnection(opt.zero, true)
connzero, err := x.SetupConnection(opt.zero, true, &tlsConf)
x.Checkf(err, "Unable to connect to zero, Is it running at %s?", opt.zero)

alloc := xidmap.New(
Expand Down Expand Up @@ -329,7 +294,7 @@ func run() error {
ignoreIndexConflict: Live.Conf.GetBool("ignore_index_conflict"),
authToken: Live.Conf.GetString("auth_token"),
}
x.LoadTLSConfig(&tlsConf, Live.Conf)
x.LoadTLSConfig(&tlsConf, Live.Conf, x.TlsClientCert, x.TlsClientKey)
tlsConf.ServerName = Live.Conf.GetString("tls_server_name")

go http.ListenAndServe("localhost:6060", nil)
Expand All @@ -345,7 +310,7 @@ func run() error {
ds := strings.Split(opt.dgraph, ",")
var clients []api.DgraphClient
for _, d := range ds {
conn, err := setupConnection(d, !tlsConf.CertRequired)
conn, err := x.SetupConnection(d, !tlsConf.CertRequired, &tlsConf)
x.Checkf(err, "While trying to setup connection to Dgraph alpha.")
defer conn.Close()

Expand Down
3 changes: 2 additions & 1 deletion dgraph/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/dgraph-io/dgraph/dgraph/cmd/live"
"github.com/dgraph-io/dgraph/dgraph/cmd/version"
"github.com/dgraph-io/dgraph/dgraph/cmd/zero"
"github.com/dgraph-io/dgraph/ee/acl/cmd"
"github.com/dgraph-io/dgraph/x"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
Expand Down Expand Up @@ -86,7 +87,7 @@ func init() {

var subcommands = []*x.SubCommand{
&bulk.Bulk, &cert.Cert, &conv.Conv, &live.Live, &alpha.Alpha, &zero.Zero,
&version.Version, &debug.Debug,
&version.Version, &debug.Debug, &acl.CmdAcl,
}
for _, sc := range subcommands {
RootCmd.AddCommand(sc.Cmd)
Expand Down
117 changes: 117 additions & 0 deletions edgraph/access_ee.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// +build !oss

/*
* Copyright 2018 Dgraph Labs, Inc. All rights reserved.
*
* Licensed under the Dgraph Community License (the "License"); you
* may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* https://github.com/dgraph-io/dgraph/blob/master/licenses/DCL.txt
*/

package edgraph

import (
"context"
"fmt"
"github.com/dgraph-io/dgo/protos/api"
"github.com/dgraph-io/dgraph/ee/acl"
"github.com/golang/glog"
"google.golang.org/grpc/peer"
"time"

otrace "go.opencensus.io/trace"
gitlw marked this conversation as resolved.
Show resolved Hide resolved
)

func (s *Server) Login(ctx context.Context,
request *api.LogInRequest) (*api.LogInResponse, error) {
ctx, span := otrace.StartSpan(ctx, "server.LogIn")
defer span.End()

// record the client ip for this login request
clientPeer, ok := peer.FromContext(ctx)
if ok {
span.Annotate([]otrace.Attribute{
otrace.StringAttribute("client_ip", clientPeer.Addr.String()),
}, "client ip for login")
}

if err := acl.ValidateLoginRequest(request); err != nil {
return nil, err
}

resp := &api.LogInResponse{
Context: &api.TxnContext{}, // context needed in order to set the jwt below
Code: api.AclResponseCode_UNAUTHENTICATED,
}

user, err := s.queryUser(ctx, request.Userid, request.Password)
if err != nil {
glog.Warningf("Unable to login user with user id: %v", request.Userid)
return nil, err
}
if user == nil {
errMsg := fmt.Sprintf("User not found for user id %v", request.Userid)
glog.Warningf(errMsg)
return nil, fmt.Errorf(errMsg)
}
if !user.PasswordMatch {
errMsg := fmt.Sprintf("Password mismatch for user: %v", request.Userid)
glog.Warningf(errMsg)
return nil, fmt.Errorf(errMsg)
}

jwt := &acl.Jwt{
Header: acl.StdJwtHeader,
Payload: acl.JwtPayload{
Userid: request.Userid,
Groups: acl.ToJwtGroups(user.Groups),
// TODO add the token refresh mechanism
Exp: time.Now().Add(Config.JwtTtl).Unix(), // set the jwt valid for 30 days
},
}

resp.Context.Jwt, err = jwt.EncodeToString(Config.HmacSecret)
if err != nil {
glog.Errorf("Unable to encode jwt to string: %v", err)
return nil, err
}

resp.Code = api.AclResponseCode_OK
return resp, nil
}

const queryUser = `
query search($userid: string, $password: string){
user(func: eq(dgraph.xid, $userid)) {
uid
password_match: checkpwd(dgraph.password, $password)
dgraph.user.group {
uid
dgraph.xid
}
}
}`

func (s *Server) queryUser(ctx context.Context, userid string, password string) (user *acl.User,
err error) {
queryVars := make(map[string]string)
queryVars["$userid"] = userid
queryVars["$password"] = password
queryRequest := api.Request{
Query: queryUser,
Vars: queryVars,
}

queryResp, err := s.Query(ctx, &queryRequest)
if err != nil {
glog.Errorf("Error while query user with id %s: %v", userid, err)
return nil, err
}
user, err = acl.UnmarshallUser(queryResp, "user")
if err != nil {
return nil, err
}
return user, nil
}
16 changes: 16 additions & 0 deletions edgraph/access_oss.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// +build oss

package edgraph

import (
"context"
"github.com/dgraph-io/dgo/protos/api"
"github.com/dgraph-io/dgraph/oss"
"github.com/golang/glog"
)

func (s *Server) Login(ctx context.Context,
request *api.LogInRequest) (*api.LogInResponse, error) {
glog.Infof("Login failed: %s", oss.ErrNotSupported)
return &api.LogInResponse{}, nil
}
4 changes: 4 additions & 0 deletions edgraph/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package edgraph
import (
"expvar"
"path/filepath"
"time"

"github.com/dgraph-io/dgraph/posting"
"github.com/dgraph-io/dgraph/worker"
Expand All @@ -34,6 +35,9 @@ type Options struct {
AuthToken string

AllottedMemory float64

HmacSecret []byte
JwtTtl time.Duration
}

var Config Options
Expand Down
5 changes: 5 additions & 0 deletions edgraph/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,11 @@ func parseNQuads(b []byte) ([]*api.NQuad, error) {
return nqs, nil
}

// parseMutationObject tries to consolidate fields of the api.Mutation into the
// corresponding field of the returned gql.Mutation. For example, the 3 fields,
// api.Mutation#SetJson, api.Mutation#SetNquads and api.Mutation#Set are consolidated into the
// gql.Mutation.Set field. Similarly the 3 fields api.Mutation#DeleteJson, api.Mutation#DelNquads
// and api.Mutation#Del are merged into the gql.Mutation#Del field.
func parseMutationObject(mu *api.Mutation) (*gql.Mutation, error) {
res := &gql.Mutation{}
if len(mu.SetJson) > 0 {
Expand Down
Loading