github.com/go-kivik/kivik/v4@v4.3.2/x/kivikd/authdb/authgroup/authgroup_test.go (about)

     1  // Licensed under the Apache License, Version 2.0 (the "License"); you may not
     2  // use this file except in compliance with the License. You may obtain a copy of
     3  // the License at
     4  //
     5  //  http://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     9  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    10  // License for the specific language governing permissions and limitations under
    11  // the License.
    12  
    13  //go:build !js
    14  
    15  package authgroup
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"net/http"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/go-kivik/kivik/v4"
    25  	_ "github.com/go-kivik/kivik/v4/couchdb"
    26  	"github.com/go-kivik/kivik/v4/kiviktest/kt"
    27  	"github.com/go-kivik/kivik/v4/x/kivikd/authdb"
    28  	"github.com/go-kivik/kivik/v4/x/kivikd/authdb/confadmin"
    29  	"github.com/go-kivik/kivik/v4/x/kivikd/authdb/usersdb"
    30  	"github.com/go-kivik/kivik/v4/x/kivikd/conf"
    31  )
    32  
    33  type tuser struct {
    34  	ID       string   `json:"_id"`
    35  	Name     string   `json:"name"`
    36  	Type     string   `json:"type"`
    37  	Roles    []string `json:"roles"`
    38  	Password string   `json:"password"`
    39  }
    40  
    41  func TestConfAdminAuth(t *testing.T) {
    42  	t.Skip("Reconfigure test not to require Docker")
    43  	// Set up first auth backend
    44  	c1 := conf.New()
    45  	c1.Set("admins.bob", "-pbkdf2-792221164f257de22ad72a8e94760388233e5714,7897f3451f59da741c87ec5f10fe7abe,10")
    46  	auth1 := confadmin.New(c1)
    47  
    48  	// Set up second auth backend
    49  	client := kt.GetClient(t)
    50  	db := client.DB("_users")
    51  	if e := db.Err(); e != nil {
    52  		t.Fatalf("Failed to connect to db: %s", e)
    53  	}
    54  	name := kt.TestDBName(t)
    55  	user := &tuser{
    56  		ID:       kivik.UserPrefix + name,
    57  		Name:     name,
    58  		Type:     "user",
    59  		Roles:    []string{"coolguy"},
    60  		Password: "abc123",
    61  	}
    62  	rev, e := db.Put(context.Background(), user.ID, user)
    63  	if e != nil {
    64  		t.Fatalf("Failed to create user: %s", e)
    65  	}
    66  	defer db.Delete(context.Background(), user.ID, rev) // nolint: errcheck
    67  	auth2 := usersdb.New(db)
    68  
    69  	auth := New(auth1, auth2)
    70  
    71  	t.Run("sync", func(t *testing.T) {
    72  		t.Run("Validate", func(t *testing.T) {
    73  			t.Parallel()
    74  			t.Run("BobValid", func(t *testing.T) {
    75  				t.Parallel()
    76  				uCtx, err := auth.Validate(context.Background(), "bob", "abc123")
    77  				if err != nil {
    78  					t.Errorf("Validation failure for bob/good password: %s", err)
    79  				}
    80  				if uCtx == nil {
    81  					t.Errorf("User should have been validated")
    82  				}
    83  			})
    84  			t.Run("BobInvalid", func(t *testing.T) {
    85  				t.Parallel()
    86  				uCtx, err := auth.Validate(context.Background(), "bob", "foobar")
    87  				if kivik.HTTPStatus(err) != http.StatusUnauthorized {
    88  					t.Errorf("Expected Unauthorized for bad password, got %s", err)
    89  				}
    90  				if uCtx != nil {
    91  					t.Errorf("User should not have been validated with wrong password")
    92  				}
    93  			})
    94  			t.Run("TestUserValid", func(t *testing.T) {
    95  				t.Parallel()
    96  				uCtx, err := auth.Validate(context.Background(), user.Name, "abc123")
    97  				if err != nil {
    98  					t.Errorf("Validation failure for good password: %s", err)
    99  				}
   100  				if uCtx == nil {
   101  					t.Errorf("User should have been validated")
   102  				}
   103  			})
   104  			t.Run("TestUserInvalid", func(t *testing.T) {
   105  				t.Parallel()
   106  				uCtx, err := auth.Validate(context.Background(), user.Name, "foobar")
   107  				if kivik.HTTPStatus(err) != http.StatusUnauthorized {
   108  					t.Errorf("Expected Unauthorized for bad password, got %s", err)
   109  				}
   110  				if uCtx != nil {
   111  					t.Errorf("User should not have been validated with wrong password")
   112  				}
   113  			})
   114  			t.Run("MissingUser", func(t *testing.T) {
   115  				t.Parallel()
   116  				uCtx, err := auth.Validate(context.Background(), "nobody", "foo")
   117  				if kivik.HTTPStatus(err) != http.StatusUnauthorized {
   118  					t.Errorf("Expected Unauthorized for bad username, got %s", err)
   119  				}
   120  				if uCtx != nil {
   121  					t.Errorf("User should not have been validated with wrong username")
   122  				}
   123  			})
   124  		})
   125  		t.Run("Context", func(t *testing.T) {
   126  			t.Parallel()
   127  			t.Run("TestUser", func(t *testing.T) {
   128  				uCtx, err := auth.UserCtx(context.Background(), user.Name)
   129  				if err != nil {
   130  					t.Errorf("Failed to get roles for valid user: %s", err)
   131  				}
   132  				uCtx.Salt = "" // It's random, so don't fail if it doesn't match
   133  				if !reflect.DeepEqual(uCtx, &authdb.UserContext{Name: user.Name, Roles: []string{"coolguy"}}) {
   134  					t.Errorf("Got unexpected context: %v", uCtx)
   135  				}
   136  			})
   137  			t.Run("Bob", func(t *testing.T) {
   138  				t.Parallel()
   139  				uCtx, err := auth.UserCtx(context.Background(), "bob")
   140  				if err != nil {
   141  					t.Errorf("Failed to get roles for valid user: %s", err)
   142  				}
   143  				if !reflect.DeepEqual(uCtx, &authdb.UserContext{Name: "bob", Roles: []string{"_admin"}, Salt: "7897f3451f59da741c87ec5f10fe7abe"}) {
   144  					t.Errorf("Got unexpected context: %v", uCtx)
   145  				}
   146  			})
   147  			t.Run("MissingUser", func(t *testing.T) {
   148  				_, err := auth.UserCtx(context.Background(), "nobody")
   149  				if kivik.HTTPStatus(err) != http.StatusNotFound {
   150  					var msg string
   151  					if err != nil {
   152  						msg = fmt.Sprintf(" Got: %s", err)
   153  					}
   154  					t.Errorf("Expected Not Found fetching roles for bad username.%s", msg)
   155  				}
   156  			})
   157  		})
   158  	})
   159  }