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

✨ (yaldap): Add password hash mecanism #67

Merged
merged 6 commits into from
Feb 17, 2024
Merged
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
7 changes: 7 additions & 0 deletions .github/workflows/merge_group,pull_request.all.lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: 1.21
- uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0
with:
version: latest
args: --help # Just force the action to download the latest version of golangci-lint

- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: trunk-io/trunk-action@97ecd21fe6c743bf7a606791584b683a7995c70e # v1.1.9
2 changes: 2 additions & 0 deletions .github/workflows/merge_group,pull_request.go.test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ on:
- go.mod
- go.sum
- .github/workflows/pull_request,push.go.test.yaml
push:
branches: [main]

permissions: read-all

Expand Down
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ RUN set -eux; \
# └───────────────────────────────────────────────────────────────────────────┘
FROM docker.io/library/alpine:3.19.1

# renovate: datasource=github-tags depName=xunleii/yaldap versioning=semver
# renovate: datasource=github-tags depName=chezmoi-sh/yaldap versioning=semver
ARG YALDAP_VERSION="v0.1.2"

# renovate: datasource=repology depName=alpine_3_19/ca-certificates versioning=loose
Expand All @@ -47,7 +47,7 @@ ENV PATH=/opt/yaldap:${PATH}

USER yaldap
WORKDIR /opt/yaldap
ENTRYPOINT [ "yaldap" ]
ENTRYPOINT yaldap

EXPOSE 389
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
Expand All @@ -59,10 +59,10 @@ LABEL \
org.opencontainers.image.authors="xunleii <[email protected]>" \
org.opencontainers.image.created="01/01/1970T00:00:00.000" \
org.opencontainers.image.description="Your identity, your rules." \
org.opencontainers.image.documentation="https://github.com/xunleii/yaldap" \
org.opencontainers.image.documentation="https://github.com/chezmoi-sh/yaldap" \
org.opencontainers.image.licenses="AGPL-3.0" \
org.opencontainers.image.revision="" \
org.opencontainers.image.source="" \
org.opencontainers.image.title="yaldap" \
org.opencontainers.image.url="https://github.com/xunleii/yaldap" \
org.opencontainers.image.url="https://github.com/chezmoi-sh/yaldap" \
org.opencontainers.image.version=${YALDAP_VERSION}
28 changes: 23 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

yaLDAP is an easy-to-use LDAP server using YAML file as directory definition.

![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/xunleii/yaldap)
[![Go](https://github.com/xunleii/yaldap/actions/workflows/pull_request,push.go.test.yaml/badge.svg)](https://github.com/xunleii/yaldap/actions/workflows/pull_request,push.go.test.yaml)
[![CodeQL](https://github.com/xunleii/yaldap/actions/workflows/pull_request,push,schedule.codeql.yaml/badge.svg)](https://github.com/xunleii/yaldap/actions/workflows/pull_request,push,schedule.codeql.yaml)
[![codecov](https://codecov.io/gh/xunleii/yaldap/branch/main/graph/badge.svg?token=20J4XPYH1H)](https://codecov.io/gh/xunleii/yaldap)
[![Go Report Card](https://goreportcard.com/badge/github.com/xunleii/yaldap)](https://goreportcard.com/report/github.com/xunleii/yaldap)
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/chezmoi-sh/yaldap)
[![Test code (Go)](https://github.com/chezmoi-sh/yaldap/actions/workflows/merge_group,pull_request.go.test.yaml/badge.svg?event=push)](https://github.com/chezmoi-sh/yaldap/actions/workflows/merge_group,pull_request.go.test.yaml)
[![CodeQL](https://github.com/chezmoi-sh/yaldap/actions/workflows/pull_request,push,schedule.codeql.yaml/badge.svg)](https://github.com/chezmoi-sh/yaldap/actions/workflows/pull_request,push,schedule.codeql.yaml)
[![codecov](https://codecov.io/gh/chezmoi-sh/yaldap/branch/main/graph/badge.svg?token=20J4XPYH1H)](https://codecov.io/gh/chezmoi-sh/yaldap)
[![Go Report Card](https://goreportcard.com/badge/github.com/chezmoi-sh/yaldap)](https://goreportcard.com/report/github.com/chezmoi-sh/yaldap)

_Sometimes, we just need a simple LDAP compatible server to store user/group information and other information.
For this purpose, many simple LDAP server exists and manage user/group in a better way than yaLDAP. However, no one can
Expand Down Expand Up @@ -103,4 +103,22 @@ dc:org: #dn: dc=org
userPassword: eve
```

### Hashed passwords

In order to avoid storing clear text passwords in the YAML file, yaLDAP supports hashed passwords.
Currently, only `argon2`, `bcrypt`, `pbkdf2` and `scrypt` are supported.

#### How to hash a password

```sh
echo -n "<password>" | yaldap tools hash <alogrithm> [<options>] -
```

For example, to hash a password using `bcrypt` and a cost of 10:

```sh
$ echo -n "password" | yaldap tools hash bcrypt --rounds 10 -
$bcrypt$v=0$r=10$$243261243130247935525748646434736f52794a2e474f3162714856755331496c616e54384b4d387346494a746c6b3141776e7a6c36736f377a6471
```

## Contribution
22 changes: 17 additions & 5 deletions cmd/yaldap/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,38 @@ import (
"os"

"github.com/alecthomas/kong"
"github.com/xunleii/yaldap/pkg/cmd"
"github.com/chezmoi-sh/yaldap/pkg/cmd"
)

// yaLDAP represents the main application struct, interpretted by kong.
type yaLDAP struct {
cmd.Base `embed:""`

Server cmd.Server `cmd:"" name:"run" help:"Start the yaLDAP server"`
Tools cmd.Tools `cmd:"" name:"tools" help:"yaLDAP utilities"`
}

func main() {
var server cmd.Server
var yaldap yaLDAP

yaldap.Server.Base = &yaldap.Base
yaldap.Tools.Base = &yaldap.Base

// Parse command-line arguments using kong.
ctx := kong.Parse(
&server,
&yaldap,
kong.Name("yaldap"),
kong.Description(`
yaLDAP is an LDAP server that is backed by different read-only data sources,
such as YAML files. It is intended to be lightweight, secure and easy to configure.

See https://github.com/xunleii/yaldap for more information.
See https://github.com/chezmoi-sh/yaldap for more information.
`),
kong.UsageOnError(),
)

if err := ctx.Run(); err != nil {
server.Logger().Error(err.Error())
yaldap.Logger().Error(err.Error())
os.Exit(1)
}
}
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/xunleii/yaldap
module github.com/chezmoi-sh/yaldap

go 1.21

Expand All @@ -14,6 +14,7 @@ require (
github.com/prometheus/common v0.47.0
github.com/puzpuzpuz/xsync/v3 v3.0.2
github.com/stretchr/testify v1.8.4
go.pact.im/x/phcformat v0.0.6
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3
golang.org/x/sync v0.3.0
gopkg.in/yaml.v3 v3.0.1
Expand All @@ -34,11 +35,13 @@ require (
github.com/prometheus/procfs v0.12.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
go.pact.im/x/option v0.0.6 // indirect
google.golang.org/protobuf v1.32.0 // indirect
)

require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/aldy505/phc-crypto v1.2.0
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/google/uuid v1.6.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7Y
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/aldy505/phc-crypto v1.2.0 h1:IbovWYUDUqqqI1wva9U2+sMJ4HABK5L32pScoJw2tc4=
github.com/aldy505/phc-crypto v1.2.0/go.mod h1:tpy0uE4Cqb7I6LUO7BLihCdX56MxvZylsZ1LIzuRw0M=
github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0=
github.com/alecthomas/assert/v2 v2.1.0/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA=
github.com/alecthomas/kong v0.8.1 h1:acZdn3m4lLRobeh3Zi2S2EpnXTd1mOL6U7xVml+vfkY=
Expand Down Expand Up @@ -100,6 +102,10 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.pact.im/x/option v0.0.6 h1:8lam/SPqUxr/AhQV8S6pNs+2npB+Fcwgmfwqea6vrik=
go.pact.im/x/option v0.0.6/go.mod h1:mpzKc/UIz4m3X4/47trnsCXP15YoUJsAcSZTiqTkmqA=
go.pact.im/x/phcformat v0.0.6 h1:1Vww+WEVbTTxyr+SLSsHaI3zCYwOe7KmY/8RRZ4RVgU=
go.pact.im/x/phcformat v0.0.6/go.mod h1:q+HHj0v7P1fA3WObC9Ts7YvAm21Jmviw+Kep/DlJjRc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
Expand Down
2 changes: 1 addition & 1 deletion internal/ldap/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"sync"
"time"

ldap "github.com/chezmoi-sh/yaldap/pkg/ldap/directory"
xsync "github.com/puzpuzpuz/xsync/v3"
ldap "github.com/xunleii/yaldap/pkg/ldap/directory"
)

type (
Expand Down
4 changes: 2 additions & 2 deletions internal/ldap/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ import (
"testing"
"time"

ldap "github.com/chezmoi-sh/yaldap/pkg/ldap/directory"
"github.com/jimlambrt/gldap"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ldap "github.com/xunleii/yaldap/pkg/ldap/directory"
)

type mockLDAPObject map[string][]string

func (o mockLDAPObject) DN() string { return "" }
func (o mockLDAPObject) Attributes() ldap.Attributes { return ldap.Attributes(o) }
func (o mockLDAPObject) Search(gldap.Scope, string) ([]ldap.Object, error) { return nil, nil }
func (o mockLDAPObject) Bind(string) bool { return false }
func (o mockLDAPObject) Bind(string) (bool, error) { return false, nil }
func (o mockLDAPObject) CanSearchOn(string) bool { return true }

func TestSessions_NewSession(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
"slices"

"github.com/alecthomas/kong"
"github.com/chezmoi-sh/yaldap/pkg/utils"
"github.com/prometheus/common/version"
"github.com/xunleii/yaldap/pkg/utils"
)

type (
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"testing"

"github.com/alecthomas/kong"
"github.com/chezmoi-sh/yaldap/pkg/cmd"
"github.com/chezmoi-sh/yaldap/pkg/utils"
"github.com/stretchr/testify/assert"
"github.com/xunleii/yaldap/pkg/cmd"
"github.com/xunleii/yaldap/pkg/utils"
)

func TestLogger_Format(t *testing.T) {
Expand Down
12 changes: 6 additions & 6 deletions pkg/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ import (
"time"

"github.com/alecthomas/kong"
"github.com/chezmoi-sh/yaldap/internal/ldap/auth"
"github.com/chezmoi-sh/yaldap/pkg/ldap"
"github.com/chezmoi-sh/yaldap/pkg/ldap/directory"
yamldir "github.com/chezmoi-sh/yaldap/pkg/ldap/directory/yaml"
"github.com/chezmoi-sh/yaldap/pkg/utils"
"github.com/jimlambrt/gldap"
"github.com/xunleii/yaldap/internal/ldap/auth"
"github.com/xunleii/yaldap/pkg/ldap"
"github.com/xunleii/yaldap/pkg/ldap/directory"
yamldir "github.com/xunleii/yaldap/pkg/ldap/directory/yaml"
"github.com/xunleii/yaldap/pkg/utils"
"golang.org/x/sync/errgroup"
)

type Server struct {
Base `embed:""`
*Base `kong:"-"`

ListenAddr string `name:"listen-address" help:"Address to listen on" default:":389"`

Expand Down
9 changes: 6 additions & 3 deletions pkg/cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cmd
import (
"crypto/tls"
"fmt"
"log/slog"
"net"
"os"
"testing"
Expand All @@ -18,9 +17,10 @@ import (

func TestServer_Defaults(t *testing.T) {
var actual, expected Server
actual.Base = &Base{}
expected.Base = &Base{}

expected.ListenAddr = ":389"
expected.Base.Log.Format = "json"
expected.Base.Log.Level = LogLevel(slog.LevelInfo)
expected.Backend.Name = "yaml"
expected.Backend.URL = "file://../ldap/directory/yaml/fixtures/basic.yaml" //nolint:goconst
expected.SessionTTL = 168 * time.Hour
Expand All @@ -34,6 +34,7 @@ func TestServer_Defaults(t *testing.T) {

func TestServer_YAML_Simple(t *testing.T) {
server := Server{ListenAddr: fmt.Sprintf("localhost:%d", freePort(t))}
server.Base = &Base{}
server.Base.Log.Format = "test"
server.Backend.Name = "yaml"
server.Backend.URL = "file://../ldap/directory/yaml/fixtures/basic.yaml"
Expand Down Expand Up @@ -63,6 +64,7 @@ func TestServer_YAML_WithTLS(t *testing.T) {
require.NoError(t, err)

server := Server{ListenAddr: fmt.Sprintf("localhost:%d", freePort(t))}
server.Base = &Base{}
server.Base.Log.Format = "test"
server.Backend.Name = "yaml"
server.Backend.URL = "file://../ldap/directory/yaml/fixtures/basic.yaml"
Expand Down Expand Up @@ -98,6 +100,7 @@ func TestServer_YAML_WithMutualTLS(t *testing.T) {
require.NoError(t, err)

server := Server{ListenAddr: fmt.Sprintf("localhost:%d", freePort(t))}
server.Base = &Base{}
server.Base.Log.Format = "test"
server.Backend.Name = "yaml"
server.Backend.URL = "file://../ldap/directory/yaml/fixtures/basic.yaml"
Expand Down
Loading
Loading