Use pure implementation of crypt to generate and check password hashes.
This allows to remove the dependency to libc.pull/425/head
parent
ee2b181a7f
commit
5bd9e831eb
|
@ -6,6 +6,7 @@ Release Notes - Version 4.0.0
|
|||
* The local storage has been replaced by a good old sqlite3 database.
|
||||
* The "secure" flag from the SMTP notifier configuration has been removed as TLS is used by default when available.
|
||||
* authelia-scripts tool has been rewritten in Go.
|
||||
* Use pure implementation of crypt to avoid CGO and dependency to libc.
|
||||
|
||||
Release Notes - Version 3.16.3
|
||||
------------------------------
|
||||
|
|
44
Dockerfile
44
Dockerfile
|
@ -1,16 +1,40 @@
|
|||
FROM alpine:3.9.4
|
||||
# =======================================
|
||||
# ===== Build image for the backend =====
|
||||
# =======================================
|
||||
FROM golang:1.13-alpine AS builder-backend
|
||||
|
||||
# gcc and musl-dev are required for building go-sqlite3
|
||||
RUN apk --no-cache add gcc musl-dev
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY . .
|
||||
|
||||
# CGO_ENABLED=1 is mandatory for building go-sqlite3
|
||||
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o authelia
|
||||
|
||||
|
||||
# ========================================
|
||||
# ===== Build image for the frontend =====
|
||||
# ========================================
|
||||
FROM node:11-alpine AS builder-frontend
|
||||
|
||||
WORKDIR /node/src/app
|
||||
COPY client .
|
||||
|
||||
# Install the dependencies and build
|
||||
RUN npm ci && npm run build
|
||||
|
||||
# ===================================
|
||||
# ===== Authelia official image =====
|
||||
# ===================================
|
||||
FROM alpine:3.10.3
|
||||
|
||||
RUN apk --no-cache add ca-certificates tzdata
|
||||
|
||||
WORKDIR /usr/app
|
||||
|
||||
RUN apk --no-cache add ca-certificates tzdata wget
|
||||
|
||||
# Install the libc required by the password hashing compiled with CGO.
|
||||
RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
|
||||
RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.30-r0/glibc-2.30-r0.apk
|
||||
RUN apk --no-cache add glibc-2.30-r0.apk
|
||||
|
||||
ADD dist/authelia authelia
|
||||
ADD dist/public_html public_html
|
||||
COPY --from=builder-backend /go/src/app/authelia authelia
|
||||
COPY --from=builder-frontend /node/src/app/build public_html
|
||||
|
||||
EXPOSE 9091
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ func (p *FileUserProvider) UpdatePassword(username string, newPassword string) e
|
|||
return fmt.Errorf("User '%s' does not exist in database", username)
|
||||
}
|
||||
|
||||
hash := HashPassword(newPassword, nil)
|
||||
hash := HashPassword(newPassword, "")
|
||||
details.HashedPassword = fmt.Sprintf("{CRYPT}%s", hash)
|
||||
|
||||
p.lock.Lock()
|
||||
|
|
|
@ -1,29 +1,15 @@
|
|||
package authentication
|
||||
|
||||
// #cgo LDFLAGS: -lcrypt
|
||||
// #define _GNU_SOURCE
|
||||
// #include <crypt.h>
|
||||
// #include <stdlib.h>
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Crypt wraps C library crypt_r
|
||||
func crypt(key string, salt string) string {
|
||||
data := C.struct_crypt_data{}
|
||||
ckey := C.CString(key)
|
||||
csalt := C.CString(salt)
|
||||
out := C.GoString(C.crypt_r(ckey, csalt, &data))
|
||||
C.free(unsafe.Pointer(ckey))
|
||||
C.free(unsafe.Pointer(csalt))
|
||||
return out
|
||||
}
|
||||
"github.com/simia-tech/crypt"
|
||||
)
|
||||
|
||||
// PasswordHash represents all characteristics of a password hash.
|
||||
// Authelia only supports salted SHA512 method, i.e., $6$ mode.
|
||||
|
@ -79,14 +65,15 @@ func RandomString(n int) string {
|
|||
|
||||
// HashPassword generate a salt and hash the password with the salt and a constant
|
||||
// number of rounds.
|
||||
func HashPassword(password string, salt *string) string {
|
||||
var generatedSalt string
|
||||
if salt == nil {
|
||||
generatedSalt = fmt.Sprintf("$6$rounds=50000$%s$", RandomString(16))
|
||||
} else {
|
||||
generatedSalt = *salt
|
||||
func HashPassword(password string, salt string) string {
|
||||
if salt == "" {
|
||||
salt = fmt.Sprintf("$6$rounds=50000$%s", RandomString(16))
|
||||
}
|
||||
return crypt(password, generatedSalt)
|
||||
hash, err := crypt.Crypt(password, salt)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// CheckPassword check a password against a hash.
|
||||
|
@ -96,6 +83,6 @@ func CheckPassword(password string, hash string) (bool, error) {
|
|||
return false, err
|
||||
}
|
||||
salt := fmt.Sprintf("$6$rounds=%d$%s$", passwordHash.Rounds, passwordHash.Salt)
|
||||
pHash := HashPassword(password, &salt)
|
||||
pHash := HashPassword(password, salt)
|
||||
return pHash == hash, nil
|
||||
}
|
||||
|
|
|
@ -7,13 +7,12 @@ import (
|
|||
)
|
||||
|
||||
func TestShouldHashPassword(t *testing.T) {
|
||||
salt := "$6$rounds=5000$aFr56HjK3DrB8t3S$"
|
||||
hash := HashPassword("password", &salt)
|
||||
assert.Equal(t, "$6$rounds=5000$aFr56HjK3DrB8t3S$3yTiN5991WnlmhE8qlMmayIiUiT5ppq68CIuHBrGgQHJ4RWSCb0AykB0E6Ij761ZTzLaCZKuXpurcBiqDR1hu.", hash)
|
||||
hash := HashPassword("password", "$6$rounds=50000$aFr56HjK3DrB8t3S")
|
||||
assert.Equal(t, "$6$rounds=50000$aFr56HjK3DrB8t3S$zhPQiS85cgBlNhUKKE6n/AHMlpqrvYSnSL3fEVkK0yHFQ.oFFAd8D4OhPAy18K5U61Z2eBhxQXExGU/eknXlY1", hash)
|
||||
}
|
||||
|
||||
func TestShouldCheckPassword(t *testing.T) {
|
||||
ok, err := CheckPassword("password", "$6$rounds=5000$aFr56HjK3DrB8t3S$3yTiN5991WnlmhE8qlMmayIiUiT5ppq68CIuHBrGgQHJ4RWSCb0AykB0E6Ij761ZTzLaCZKuXpurcBiqDR1hu.")
|
||||
ok, err := CheckPassword("password", "$6$rounds=50000$aFr56HjK3DrB8t3S$zhPQiS85cgBlNhUKKE6n/AHMlpqrvYSnSL3fEVkK0yHFQ.oFFAd8D4OhPAy18K5U61Z2eBhxQXExGU/eknXlY1")
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
|
|
@ -9,5 +9,5 @@ import (
|
|||
|
||||
// HashPassword hash the provided password with crypt sha256 hash function
|
||||
func HashPassword(cobraCmd *cobra.Command, args []string) {
|
||||
fmt.Println(authentication.HashPassword(args[0], nil))
|
||||
fmt.Println(authentication.HashPassword(args[0], ""))
|
||||
}
|
||||
|
|
1
go.mod
1
go.mod
|
@ -14,6 +14,7 @@ require (
|
|||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.11.0
|
||||
github.com/pquerna/otp v1.2.0
|
||||
github.com/simia-tech/crypt v0.2.0
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/stretchr/testify v1.4.0
|
||||
|
|
5
go.sum
5
go.sum
|
@ -59,6 +59,8 @@ github.com/savsgio/dictpool v0.0.0-20191028211042-a886cee3358a h1:HHo8bk/5tOTL+U
|
|||
github.com/savsgio/dictpool v0.0.0-20191028211042-a886cee3358a/go.mod h1:hnGRFeigcU3gTEMTWW8OjfoSYztn2GPcriOY9iIzCrA=
|
||||
github.com/savsgio/gotils v0.0.0-20190925070755-524bc4f47500 h1:9Pi10H7E8E79/x2HSe1FmMGd7BJ1WAqDKzwjpv+ojFg=
|
||||
github.com/savsgio/gotils v0.0.0-20190925070755-524bc4f47500/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY=
|
||||
github.com/simia-tech/crypt v0.2.0 h1:cU8qdqUYNuEFKSMq15yaB2aI1aC5vrn6dFOonT6Kg6o=
|
||||
github.com/simia-tech/crypt v0.2.0/go.mod h1:DMwvjPTzsiHrjqHVW5HvIbF4vUUzMCYDKVLsPWmLdTo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
|
@ -71,6 +73,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
|
|||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
|
@ -92,6 +95,7 @@ github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0
|
|||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=
|
||||
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
@ -99,6 +103,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20181116161606-93218def8b18/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||
|
|
Loading…
Reference in New Issue