Skip to content

couchdb: Unexpected Unauthorized if PUT intervals closely match couchdb cookie timeout #657

@iivvoo

Description

@iivvoo

We have been getting unexpected Unauthorized responses when inserting documents at a really slow pace. The interval of those insertions seem to closely match the cookie timeout on couchdb.

To reproduce this, we've set the couch_httpd_auth.timeout to 60 (seconds) on a couch 3.1.1 instance (not in docker) and ran the following code:

package main

import (
	"context"
	"fmt"
	"net/url"
	"time"

	_ "github.com/go-kivik/couchdb/v4"
	"github.com/go-kivik/kivik/v4"
	"github.com/google/uuid"
)

type Sample struct {
	UUID string `json:"uuid"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

type DB struct {
	client *kivik.Client
	db     *kivik.DB
}

func Setup(dsn string, qShards, nCopies int) (*DB, error) {
	u, err := url.Parse(dsn)
	if err != nil {
		return nil, err
	}
	dbName := u.Path
	u.Path = ""
	dsn = u.String()
	client, err := kivik.New("couch", dsn)
	if err != nil {
		return nil, err
	}

	ctx := context.TODO()

	if exists, err := client.DBExists(ctx, dbName); err == nil && exists {
		client.DestroyDB(ctx, dbName)
	} else if err != nil {
		return nil, err
	}
	client.CreateDB(ctx, dbName, kivik.Options{
		"q": qShards,
		"n": nCopies,
	})
	db := client.DB(dbName)
	return &DB{
		client: client,
		db:     db,
	}, nil
}

func (f *DB) RepeatPut(t time.Duration) {
	for {
		fmt.Println("PUT doc")
		id := uuid.New().String()
		_, err := f.db.Put(context.TODO(), id, &Sample{id, "John Doe", 42})
		if err != nil {
			panic(err)
		}
		fmt.Println("Sleep", t)
		time.Sleep(t)
	}
}

func main() {
	f, err := Setup("http://admin:a-secret@localhost:5984/auth-test", 1, 1)
	if err != nil {
		panic(err)
	}
	f.RepeatPut(time.Second*60 - time.Millisecond*100)
}

running this

» go run main.go                                                                  1 ↵
PUT doc
Sleep 59.9s
PUT doc
Sleep 59.9s
PUT doc
Sleep 59.9s
PUT doc
panic: Unauthorized: You are not authorized to access this db.

goroutine 1 [running]:
main.(*DB).RepeatPut(0xc00018a320, 0xdf2517700)
	.../RnD/couch-auth/main.go:62 +0x2e0
main.main()
	.../RnD/couch-auth/main.go:74 +0x78
exit status 2

The Coouchd debug logs show

[debug] 2021-06-05T13:31:23.316469Z [email protected] <0.7274.224> d8f6067caa Attempt Login: admin
[debug] 2021-06-05T13:31:23.317540Z [email protected] <0.7274.224> d8f6067caa no record of user admin
[notice] 2021-06-05T13:31:23.318362Z [email protected] <0.7274.224> d8f6067caa localhost:5984 127.0.0.1 undefined POST /_session 200 ok 2
[debug] 2021-06-05T13:31:23.361040Z [email protected] <0.7759.224> 24c1844e6f no record of user admin
[debug] 2021-06-05T13:31:23.361187Z [email protected] <0.7759.224> 24c1844e6f timeout 60
[debug] 2021-06-05T13:31:23.361269Z [email protected] <0.7759.224> 24c1844e6f Successful cookie auth as: "admin"
[notice] 2021-06-05T13:31:23.369124Z [email protected] <0.7759.224> 24c1844e6f localhost:5984 127.0.0.1 admin PUT /auth-test/2c85a130-a5c4-4b79-b7be-796729e11b69 201 ok 9
[debug] 2021-06-05T13:32:23.291989Z [email protected] <0.7759.224> e75e50fda1 no record of user admin
[debug] 2021-06-05T13:32:23.292117Z [email protected] <0.7759.224> e75e50fda1 timeout 60
[error] 2021-06-05T13:32:23.292864Z [email protected] <0.8275.224> e75e50fda1 rexi_server: from: [email protected](<0.7759.224>) mfa: fabric_rpc:open_shard/2 throw:{unauthorized,<<"You are not authorized to access this db.">>} [{couch_db,open,2,[{file,"src/couch_db.erl"},{line,168}]},{fabric_rpc,open_shard,2,[{file,"src/fabric_rpc.erl"},{line,307}]},{rexi_server,init_p,3,[{file,"src/rexi_server.erl"},{line,138}]}]
[notice] 2021-06-05T13:32:23.293600Z [email protected] <0.7759.224> e75e50fda1 localhost:5984 127.0.0.1 undefined PUT /auth-test/d675aae3-2e24-435f-b5c4-794228a5dda5 401 ok 3

I am aware that there is an auth/cookie related fix in go-kivik/couchdb#280 that has been merged, but even with this change the problem occurs

» grep kivik go.sum
github.com/go-kivik/couchdb/v4 v4.0.0-20210603203912-7a5e3ef402b2 h1:9pc2vYfo000Vj4Yj+irBfcPMQQ3mgS+ujo0ERoL0Bak=
github.com/go-kivik/couchdb/v4 v4.0.0-20210603203912-7a5e3ef402b2/go.mod h1:O/j3V4Lx/XY2Dunvs8Kj2Gpg0a9ZSyFa51Fr9JpMGNM=
github.com/go-kivik/kivik/v4 v4.0.0-20201011094523-ab1764d67e62/go.mod h1:O2fxy5xMXO7vaVr2gQG38sYTj/mHwg5Md/8kP7qUZQk=
github.com/go-kivik/kivik/v4 v4.0.0-20201015190251-5d5c2f1c89fa/go.mod h1:O2fxy5xMXO7vaVr2gQG38sYTj/mHwg5Md/8kP7qUZQk=
github.com/go-kivik/kivik/v4 v4.0.0-20201202093909-da42f0daa1b2 h1:lxXbqi5ayfzXUGafeQjUGgeiXO2HjCzdZdcbmhklRLg=
github.com/go-kivik/kivik/v4 v4.0.0-20201202093909-da42f0daa1b2/go.mod h1:O2fxy5xMXO7vaVr2gQG38sYTj/mHwg5Md/8kP7qUZQk=
github.com/go-kivik/kiviktest/v4 v4.0.0-20210410161422-2df5be2daeb6 h1:FXnNxH7j79NFxnDKxSqL8vjPN9hsamOhs4Eu/OZ6KVU=
github.com/go-kivik/kiviktest/v4 v4.0.0-20210410161422-2df5be2daeb6/go.mod h1:d5boDDPySqnpjX41iT7H7FTyUcqjAKrw9gQPkdAo5Ko=

github.com/go-kivik/couchdb/v4 v4.0.0-20210603203912-7a5e3ef402b2 should contain that fix, right?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions