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 13 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
gitlw marked this conversation as resolved.
Show resolved Hide resolved
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
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
121 changes: 121 additions & 0 deletions ee/acl/acl_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// +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 acl

import (
"os/exec"
"testing"
)

const (
userid = "alice"
userpassword = "simplepassword"
dgraphEndpoint = "localhost:9180"
)

func TestAcl(t *testing.T) {
t.Run("create user", CreateAndDeleteUsers)
t.Run("login", LogIn)
}

func checkOutput(t *testing.T, cmd *exec.Cmd, shouldFail bool) string {
out, err := cmd.CombinedOutput()
if (!shouldFail && err != nil) || (shouldFail && err == nil) {
t.Errorf("Error output from command:%v", string(out))
t.Fatal(err)
}

return string(out)
}

func CreateAndDeleteUsers(t *testing.T) {
createUserCmd1 := exec.Command("dgraph", "acl", "useradd", "-d", dgraphEndpoint, "-u", userid,
"-p", userpassword)
createUserOutput1 := checkOutput(t, createUserCmd1, false)
t.Logf("Got output when creating user:%v", createUserOutput1)

createUserCmd2 := exec.Command("dgraph", "acl", "useradd", "-d", dgraphEndpoint, "-u", userid,
"-p", userpassword)

// create the user again should fail
createUserOutput2 := checkOutput(t, createUserCmd2, true)
t.Logf("Got output when creating user:%v", createUserOutput2)

// delete the user
deleteUserCmd := exec.Command("dgraph", "acl", "userdel", "-d", dgraphEndpoint, "-u", userid)
deleteUserOutput := checkOutput(t, deleteUserCmd, false)
t.Logf("Got output when deleting user:%v", deleteUserOutput)

// now we should be able to create the user again
createUserCmd3 := exec.Command("dgraph", "acl", "useradd", "-d", dgraphEndpoint, "-u", userid,
"-p", userpassword)
createUserOutput3 := checkOutput(t, createUserCmd3, false)
t.Logf("Got output when creating user:%v", createUserOutput3)
}

func LogIn(t *testing.T) {
// delete and recreate the user to ensure a clean state
/*
deleteUserCmd := exec.Command("dgraph", "acl", "userdel", "-d", dgraphEndpoint, "-u", "lucas")
deleteUserOutput := checkOutput(t, deleteUserCmd, false)
createUserCmd := exec.Command("dgraph", "acl", "useradd", "-d", dgraphEndpoint, "-u", "lucas",
"-p", "haha")
createUserOutput := checkOutput(t, createUserCmd, false)
*/

// now try to login with the wrong password

//loginWithWrongPassword(t, ctx, adminClient)
//loginWithCorrectPassword(t, ctx, adminClient)
}

/*
func loginWithCorrectPassword(t *testing.T, ctx context.Context,
adminClient api.DgraphAccessClient) {
loginRequest := api.LogInRequest{
Userid: userid,
Password: userpassword,
}
response2, err := adminClient.LogIn(ctx, &loginRequest)
require.NoError(t, err)
if response2.Code != api.AclResponseCode_OK {
t.Errorf("Login with the correct password should result in the code %v",
api.AclResponseCode_OK)
}
jwt := acl.Jwt{}
jwt.DecodeString(response2.Context.Jwt, false, nil)
if jwt.Payload.Userid != userid {
t.Errorf("the jwt token should have the user id encoded")
}
jwtTime := time.Unix(jwt.Payload.Exp, 0)
jwtValidDays := jwtTime.Sub(time.Now()).Round(time.Hour).Hours() / 24
if jwtValidDays != 30.0 {
t.Errorf("The jwt token should be valid for 30 days, received %v days", jwtValidDays)
}
}

func loginWithWrongPassword(t *testing.T, ctx context.Context,
adminClient api.DgraphAccessClient) {
loginRequestWithWrongPassword := api.LogInRequest{
Userid: userid,
Password: userpassword + "123",
}

response, err := adminClient.LogIn(ctx, &loginRequestWithWrongPassword)
require.NoError(t, err)
if response.Code != api.AclResponseCode_UNAUTHENTICATED {
t.Errorf("Login with the wrong password should result in the code %v", api.AclResponseCode_UNAUTHENTICATED)
}
}

*/
Loading