Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 15 additions & 15 deletions .github/workflows/go_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ jobs:
test:
strategy:
matrix:
go-version: [1.23.x,1.24.x]
go-version: [1.24.x, 1.25.x]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v4
- name: Test
run: |
cd auth_server
go test ./...
- name: Build
run: |
cd auth_server
make
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v4
- name: Test
run: |
cd auth_server
go test ./...
- name: Build
run: |
cd auth_server
make
14 changes: 7 additions & 7 deletions auth_server/authn/ldap_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func NewLDAPAuth(c *LDAPAuthConfig) (*LDAPAuth, error) {
}, nil
}

//How to authenticate user, please refer to https://github.com/go-ldap/ldap/blob/master/example_test.go#L166
// How to authenticate user, please refer to https://github.com/go-ldap/ldap/blob/master/example_test.go#L166
func (la *LDAPAuth) Authenticate(account string, password api.PasswordString) (bool, api.Labels, error) {
if account == "" || password == "" {
return false, nil, api.NoMatch
Expand Down Expand Up @@ -160,10 +160,10 @@ func (la *LDAPAuth) bindInitialAsUser(l *ldap.Conn, account string, password api
return nil
}

//To prevent LDAP injection, some characters must be escaped for searching
//e.g. char '\' will be replaced by hex '\5c'
//Filter meta chars are choosen based on filter complier code
//https://github.com/go-ldap/ldap/blob/master/filter.go#L159
// To prevent LDAP injection, some characters must be escaped for searching
// e.g. char '\' will be replaced by hex '\5c'
// Filter meta chars are choosen based on filter complier code
// https://github.com/go-ldap/ldap/blob/master/filter.go#L159
func (la *LDAPAuth) escapeAccountInput(account string) string {
r := strings.NewReplacer(
`\`, `\5c`,
Expand Down Expand Up @@ -229,8 +229,8 @@ func (la *LDAPAuth) getFilter(account string) string {
return filter
}

//ldap search and return required attributes' value from searched entries
//default return entry's DN value if you leave attrs array empty
// ldap search and return required attributes' value from searched entries
// default return entry's DN value if you leave attrs array empty
func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (string, map[string][]string, error) {
if l == nil {
return "", nil, fmt.Errorf("No ldap connection!")
Expand Down
3 changes: 1 addition & 2 deletions auth_server/authn/mongo_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,7 @@ func (mauth *MongoAuth) authenticate(account string, password api.PasswordString
var dbUserRecord authUserEntry
collection := mauth.session.Database(mauth.config.MongoConfig.DialInfo.Database).Collection(mauth.config.Collection)


filter := bson.D{{"username", account}}
filter := bson.D{{"username", account}}
err := collection.FindOne(context.TODO(), filter).Decode(&dbUserRecord)

// If we connect and get no results we return a NoMatch so auth can fall-through
Expand Down
115 changes: 115 additions & 0 deletions auth_server/authn/rpc_auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
Copyright 2019 Cesanta Software Ltd.

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

https://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 authn

import (
"fmt"
"os/exec"

"github.com/cesanta/glog"
rpc "github.com/hashicorp/go-plugin"

"github.com/cesanta/docker_auth/auth_server/api"
shared "github.com/cesanta/docker_auth/auth_server/plugin"
plugin "github.com/cesanta/docker_auth/auth_server/plugin/authn"
)

type RPCAuthnConfig struct {
Command string `yaml:"command"`
Args []string `yaml:"args"`
}

func (c *RPCAuthnConfig) Validate() error {
if c.Command == "" {
return fmt.Errorf("command is not set")
}

if _, err := exec.LookPath(c.Command); err != nil {
return fmt.Errorf("no such command: %s: %w", c.Command, err)
}

return nil
}

type RPCAuthn struct {
client *rpc.Client
impl plugin.Authenticator
}

func (c *RPCAuthn) Authenticate(username string, password api.PasswordString) (bool, api.Labels, error) {
req := &plugin.AuthenticateRequest{
Username: username,
Password: string(password),
}
resp, err := c.impl.Authenticate(req)
switch {
case err == nil:
return true, api.Labels(resp), nil
case shared.IsError(err, shared.ErrUnauthorized):
return false, nil, nil
case shared.IsError(err, shared.ErrUnacceptable):
return false, nil, api.NoMatch
default:
return false, nil, err
}
}

func (c *RPCAuthn) Stop() {
if c.client != nil {
c.client.Kill()
}
}

func (c *RPCAuthn) Name() string {
return "rpc"
}

func NewRPCAuthn(cfg *RPCAuthnConfig) (*RPCAuthn, error) {
glog.Infof("RPC authenticator: %s", cfg)

conn := &rpc.ClientConfig{
HandshakeConfig: plugin.Handshake,
Plugins: plugin.PluginMap,
Cmd: exec.Command(cfg.Command, cfg.Args...),
}
client := rpc.NewClient(conn)

rpcClient, err := client.Client()
if err != nil {
client.Kill()
return nil, err
}

raw, err := rpcClient.Dispense(plugin.PluginNetRPC)
if err != nil {
client.Kill()
return nil, err
}

impl, ok := raw.(plugin.Authenticator)
if !ok {
client.Kill()
return nil, fmt.Errorf("no authenticator plugin provided: %T", impl)
}

result := &RPCAuthn{
client: client,
impl: impl,
}

return result, nil
}
4 changes: 2 additions & 2 deletions auth_server/authn/tokendb_gcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ func NewGCSTokenDB(options *GCSStoreConfig) (TokenDB, error) {
}

type gcsTokenDB struct {
gcs *storage.Client
bucket string
gcs *storage.Client
bucket string
tokenHashCost int
}

Expand Down
4 changes: 2 additions & 2 deletions auth_server/authn/tokendb_level.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ const (
var ExpiredToken = errors.New("expired token")

type LevelDBStoreConfig struct {
Path string `yaml:"path,omitempty"`
TokenHashCost int `yaml:"token_hash_cost,omitempty"`
Path string `yaml:"path,omitempty"`
TokenHashCost int `yaml:"token_hash_cost,omitempty"`
}

// TokenDB stores tokens using LevelDB
Expand Down
5 changes: 2 additions & 3 deletions auth_server/authn/tokendb_redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ type RedisClient interface {
}

// NewRedisTokenDB returns a new TokenDB structure which uses Redis as the storage backend.
//
func NewRedisTokenDB(options *RedisStoreConfig) (TokenDB, error) {
var client RedisClient
if options.ClusterOptions != nil {
Expand All @@ -58,11 +57,11 @@ func NewRedisTokenDB(options *RedisStoreConfig) (TokenDB, error) {
tokenHashCost = bcrypt.DefaultCost
}

return &redisTokenDB{client,tokenHashCost}, nil
return &redisTokenDB{client, tokenHashCost}, nil
}

type redisTokenDB struct {
client RedisClient
client RedisClient
tokenHashCost int
}

Expand Down
3 changes: 2 additions & 1 deletion auth_server/authn/xorm_sqlite_authn.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//+build sqlite
//go:build sqlite
// +build sqlite

/*
Copyright 2020 Cesanta Software Ltd.
Expand Down
3 changes: 2 additions & 1 deletion auth_server/authz/acl_xorm_sqlite.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//+build sqlite
//go:build sqlite
// +build sqlite

/*
Copyright 2020 Cesanta Software Ltd.
Expand Down
120 changes: 120 additions & 0 deletions auth_server/authz/rpc_auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
Copyright 2019 Cesanta Software Ltd.

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

https://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 authz

import (
"fmt"
"os/exec"

"github.com/cesanta/glog"
rpc "github.com/hashicorp/go-plugin"

"github.com/cesanta/docker_auth/auth_server/api"
shared "github.com/cesanta/docker_auth/auth_server/plugin"
plugin "github.com/cesanta/docker_auth/auth_server/plugin/authz"
)

type RPCAuthzConfig struct {
Command string `yaml:"command"`
Args []string `yaml:"args"`
}

func (c *RPCAuthzConfig) Validate() error {
if c.Command == "" {
return fmt.Errorf("command is not set")
}

if _, err := exec.LookPath(c.Command); err != nil {
return fmt.Errorf("no such command: %s: %w", c.Command, err)
}

return nil
}

type RPCAuthz struct {
client *rpc.Client
impl plugin.Authorizer
}

func (c *RPCAuthz) Authorize(ai *api.AuthRequestInfo) ([]string, error) {
req := &plugin.AuthorizeRequest{
Account: ai.Account,
Type: ai.Type,
Name: ai.Name,
Service: ai.Service,
IP: ai.IP,
Actions: ai.Actions,
Labels: ai.Labels,
}
resp, err := c.impl.Authorize(req)
switch {
case err == nil:
return resp, nil
case shared.IsError(err, shared.ErrForbidden):
return []string{}, nil
case shared.IsError(err, shared.ErrUnacceptable):
return nil, api.NoMatch
default:
return nil, err
}
}

func (c *RPCAuthz) Stop() {
if c.client != nil {
c.client.Kill()
}
}

func (c *RPCAuthz) Name() string {
return "rpc"
}

func NewRPCAuthz(cfg *RPCAuthzConfig) (*RPCAuthz, error) {
glog.Infof("RPC authorizer: %s", cfg)

conn := &rpc.ClientConfig{
HandshakeConfig: plugin.Handshake,
Plugins: plugin.PluginMap,
Cmd: exec.Command(cfg.Command, cfg.Args...),
}
client := rpc.NewClient(conn)

rpcClient, err := client.Client()
if err != nil {
client.Kill()
return nil, err
}

raw, err := rpcClient.Dispense(plugin.PluginNetRPC)
if err != nil {
client.Kill()
return nil, err
}

impl, ok := raw.(plugin.Authorizer)
if !ok {
client.Kill()
return nil, fmt.Errorf("no authorizer plugin provided: %T", impl)
}

result := &RPCAuthz{
client: client,
impl: impl,
}

return result, nil
}
3 changes: 2 additions & 1 deletion auth_server/gen_version.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//+build ignore
//go:build ignore
// +build ignore

/*
Copyright 2021 Cesanta Software Ltd.
Expand Down
Loading
Loading