Skip to content

Commit

Permalink
move files
Browse files Browse the repository at this point in the history
  • Loading branch information
chilagrow committed Feb 15, 2024
1 parent bcfd350 commit 3699034
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 97 deletions.
125 changes: 125 additions & 0 deletions internal/handler/authentication.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright 2021 FerretDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package handler

import (
"context"
"errors"

"github.com/FerretDB/FerretDB/internal/clientconn/conninfo"
"github.com/FerretDB/FerretDB/internal/handler/common"
"github.com/FerretDB/FerretDB/internal/handler/handlererrors"
"github.com/FerretDB/FerretDB/internal/types"
"github.com/FerretDB/FerretDB/internal/util/iterator"
"github.com/FerretDB/FerretDB/internal/util/lazyerrors"
"github.com/FerretDB/FerretDB/internal/util/must"
"github.com/FerretDB/FerretDB/internal/util/password"
"github.com/FerretDB/FerretDB/internal/wire"
)

// authenticate validates the user's credentials in the connection with the
// credentials in the database. If EnableNewAuth is false, it does nothing.
//
// When admin.systems.user contains no user, the authentication succeeds until
// the first user is created.
func (h *Handler) authenticate(ctx context.Context, msg *wire.OpMsg) error {
if !h.EnableNewAuth {
return nil

Check warning on line 39 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L39

Added line #L39 was not covered by tests
}

adminDB, err := h.b.Database("admin")
if err != nil {
return lazyerrors.Error(err)

Check warning on line 44 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L44

Added line #L44 was not covered by tests
}

usersCol, err := adminDB.Collection("system.users")
if err != nil {
return lazyerrors.Error(err)

Check warning on line 49 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L49

Added line #L49 was not covered by tests
}

document, err := msg.Document()
if err != nil {
return lazyerrors.Error(err)

Check warning on line 54 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L54

Added line #L54 was not covered by tests
}

var dbName string

if dbName, err = common.GetRequiredParam[string](document, "$db"); err != nil {
return err

Check warning on line 60 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L60

Added line #L60 was not covered by tests
}

username, pwd := conninfo.Get(ctx).Auth()

// NOTE: how does a user with access to all database look like?
filter := must.NotFail(types.NewDocument("_id", dbName+"."+username))

qr, err := usersCol.Query(ctx, nil)
if err != nil {
return lazyerrors.Error(err)

Check warning on line 70 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L70

Added line #L70 was not covered by tests
}

defer qr.Iter.Close()

var storedUser *types.Document

var hasUser bool

for {
var v *types.Document
_, v, err = qr.Iter.Next()

if errors.Is(err, iterator.ErrIteratorDone) {
break
}

if err != nil {
return lazyerrors.Error(err)

Check warning on line 88 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L87-L88

Added lines #L87 - L88 were not covered by tests
}

hasUser = true

Check warning on line 91 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L91

Added line #L91 was not covered by tests

var matches bool

Check warning on line 93 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L93

Added line #L93 was not covered by tests

if matches, err = common.FilterDocument(v, filter); err != nil {
return lazyerrors.Error(err)

Check warning on line 96 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L95-L96

Added lines #L95 - L96 were not covered by tests
}

if matches {
storedUser = v
break

Check warning on line 101 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L99-L101

Added lines #L99 - L101 were not covered by tests
}
}

if !hasUser {
// an exception where authentication is skipped until the first user is created.
return nil
}

credentials := must.NotFail(storedUser.Get("credentials")).(*types.Document)
if !credentials.Has("PLAIN") {
return handlererrors.NewCommandErrorMsgWithArgument(
handlererrors.ErrAuthenticationFailed,
"TODO: wrong authentication mechanism",
"PLAIN",
)

Check warning on line 116 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L110-L116

Added lines #L110 - L116 were not covered by tests
}

err = password.PlainVerify(pwd, credentials)
if err != nil {
return lazyerrors.Error(err)

Check warning on line 121 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L119-L121

Added lines #L119 - L121 were not covered by tests
}

return nil

Check warning on line 124 in internal/handler/authentication.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authentication.go#L124

Added line #L124 was not covered by tests
}
99 changes: 2 additions & 97 deletions internal/handler/msg_saslstart.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,14 @@ import (
"bytes"
"context"
"encoding/base64"
"errors"
"fmt"

"github.com/FerretDB/FerretDB/internal/clientconn/conninfo"
"github.com/FerretDB/FerretDB/internal/handler/common"
"github.com/FerretDB/FerretDB/internal/handler/handlererrors"
"github.com/FerretDB/FerretDB/internal/types"
"github.com/FerretDB/FerretDB/internal/util/iterator"
"github.com/FerretDB/FerretDB/internal/util/lazyerrors"
"github.com/FerretDB/FerretDB/internal/util/must"
"github.com/FerretDB/FerretDB/internal/util/password"
"github.com/FerretDB/FerretDB/internal/wire"
)

Expand Down Expand Up @@ -74,6 +71,8 @@ func (h *Handler) MsgSASLStart(ctx context.Context, msg *wire.OpMsg) (*wire.OpMs
}

if h.EnableNewAuth {
// even if the database does not contain the first user yet
// backend authentication is bypassed
conninfo.Get(ctx).BypassBackendAuth = true
} else {
conninfo.Get(ctx).SetAuth(username, password)

Check warning on line 78 in internal/handler/msg_saslstart.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/msg_saslstart.go#L78

Added line #L78 was not covered by tests
Expand Down Expand Up @@ -139,97 +138,3 @@ func saslStartPlain(doc *types.Document) (string, string, error) {

return string(authcid), string(passwd), nil
}

// authenticate validates the user's credentials in the connection with the credentials in the database.
// If the authentication fails, it returns error.
//
// An exception where database collection contains no user, it succeeds authentication.
func (h *Handler) authenticate(ctx context.Context, msg *wire.OpMsg) error {
if !h.EnableNewAuth {
return nil
}

adminDB, err := h.b.Database("admin")
if err != nil {
return lazyerrors.Error(err)
}

usersCol, err := adminDB.Collection("system.users")
if err != nil {
return lazyerrors.Error(err)
}

document, err := msg.Document()
if err != nil {
return lazyerrors.Error(err)
}

var dbName string

if dbName, err = common.GetRequiredParam[string](document, "$db"); err != nil {
return err
}

username, pwd := conninfo.Get(ctx).Auth()

// NOTE: how does a user with access to all database look like?
filter := must.NotFail(types.NewDocument("_id", dbName+"."+username))

qr, err := usersCol.Query(ctx, nil)
if err != nil {
return lazyerrors.Error(err)
}

defer qr.Iter.Close()

var storedUser *types.Document

var hasUser bool

for {
var v *types.Document
_, v, err = qr.Iter.Next()

if errors.Is(err, iterator.ErrIteratorDone) {
break
}

if err != nil {
return lazyerrors.Error(err)
}

hasUser = true

var matches bool

if matches, err = common.FilterDocument(v, filter); err != nil {
return lazyerrors.Error(err)
}

if matches {
storedUser = v
break
}
}

if !hasUser {
// an exception where authentication is skipped until the first user is created.
return nil
}

credentials := must.NotFail(storedUser.Get("credentials")).(*types.Document)
if !credentials.Has("PLAIN") {
return handlererrors.NewCommandErrorMsgWithArgument(
handlererrors.ErrAuthenticationFailed,
"TODO: wrong authentication mechanism",
"PLAIN",
)
}

err = password.PlainVerify(pwd, credentials)
if err != nil {
return lazyerrors.Error(err)
}

return nil
}

0 comments on commit 3699034

Please sign in to comment.