1
0
Fork 0
mirror of synced 2024-06-03 07:51:09 -04:00

Compare commits

...

3 commits

Author SHA1 Message Date
Ilya Sosnovsky 5eefd1b4d3 fix args in db queries 2022-12-02 19:34:21 +03:00
Ilya Sosnovsky bc7f26f14d change totp secret length; fixes 2022-12-02 14:12:43 +03:00
Ilya Sosnovsky 5cabdcb686 fixes; reset 2fa 2022-11-29 18:22:39 +03:00
6 changed files with 55 additions and 31 deletions

View file

@ -1,3 +1,3 @@
#!/usr/bin/env bash #!/usr/bin/env bash
env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -ldflags='-linkmode external -extldflags "-static" -s -w' -o openvpn-user env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -ldflags "-linkmode external -extldflags -static -s -w" -o openvpn-user

3
go.mod
View file

@ -5,9 +5,10 @@ go 1.14
require ( require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4 // indirect github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/dgoogauth v0.0.0-20190221195224-5a805980a5f3 github.com/dgryski/dgoogauth v0.0.0-20190221195224-5a805980a5f3
github.com/mattn/go-sqlite3 v1.14.16 github.com/mattn/go-sqlite3 v1.14.16
github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.7.0 // indirect
golang.org/x/crypto v0.2.0 golang.org/x/crypto v0.2.0
gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/alecthomas/kingpin.v2 v2.2.6
) )

4
go.sum
View file

@ -11,8 +11,6 @@ github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwp
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
@ -33,9 +31,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

View file

@ -10,7 +10,7 @@ import (
) )
const ( const (
version = "1.0.6" version = "1.0.9"
) )
var ( var (
@ -56,6 +56,9 @@ var (
registerAppCommandUserFlag = registerAppCommand.Flag("user", "Username.").Short('u').Required().String() registerAppCommandUserFlag = registerAppCommand.Flag("user", "Username.").Short('u').Required().String()
registerAppCommandTotpFlag = registerAppCommand.Flag("totp", "TOTP.").Short('t').Required().String() registerAppCommandTotpFlag = registerAppCommand.Flag("totp", "TOTP.").Short('t').Required().String()
resetAppCommand = kingpin.Command("reset-app", "register 2FA application")
resetAppCommandUserFlag = resetAppCommand.Flag("user", "Username.").Short('u').Required().String()
checkAppCommand = kingpin.Command("check-app", "check 2FA application") checkAppCommand = kingpin.Command("check-app", "check 2FA application")
checkAppCommandUserFlag = checkAppCommand.Flag("user", "Username.").Short('u').Required().String() checkAppCommandUserFlag = checkAppCommand.Flag("user", "Username.").Short('u').Required().String()
@ -109,7 +112,10 @@ func main() {
kingpin.Fatalf(authErr.Error()) kingpin.Fatalf(authErr.Error())
} else if authSuccessful { } else if authSuccessful {
fmt.Println("Authorization successful") fmt.Println("Authorization successful")
} else {
fmt.Println("Authorization failed")
} }
} else { } else {
fmt.Println("Please provide only one type of auth flag") fmt.Println("Please provide only one type of auth flag")
os.Exit(1) os.Exit(1)
@ -120,12 +126,16 @@ func main() {
wrap(openvpnUser.RegisterOtpSecret(*updateSecretCommandUserFlag, *updateSecretCommandSecretFlag)) wrap(openvpnUser.RegisterOtpSecret(*updateSecretCommandUserFlag, *updateSecretCommandSecretFlag))
case registerAppCommand.FullCommand(): case registerAppCommand.FullCommand():
wrap(openvpnUser.RegisterOtpApplication(*registerAppCommandUserFlag, *registerAppCommandTotpFlag)) wrap(openvpnUser.RegisterOtpApplication(*registerAppCommandUserFlag, *registerAppCommandTotpFlag))
case resetAppCommand.FullCommand():
wrap(openvpnUser.ResetOtpApplication(*resetAppCommandUserFlag))
case checkAppCommand.FullCommand(): case checkAppCommand.FullCommand():
appConfigured, appErr := openvpnUser.IsSecondFactorEnabled(*checkAppCommandUserFlag) appConfigured, appErr := openvpnUser.IsSecondFactorEnabled(*checkAppCommandUserFlag)
if appErr != nil { if appErr != nil {
kingpin.Fatalf(appErr.Error()) kingpin.Fatalf(appErr.Error())
} else if appConfigured { } else if appConfigured {
fmt.Println("App configured") fmt.Println("App configured")
} else {
fmt.Println("App not configured yet")
} }
case getSecretCommand.FullCommand(): case getSecretCommand.FullCommand():
wrap(openvpnUser.GetUserOtpSecret(*getSecretCommandUserFlag)) wrap(openvpnUser.GetUserOtpSecret(*getSecretCommandUserFlag))

View file

@ -5,7 +5,6 @@ import (
"encoding/base32" "encoding/base32"
"fmt" "fmt"
"github.com/dgryski/dgoogauth" "github.com/dgryski/dgoogauth"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"os" "os"
"strings" "strings"
@ -18,7 +17,7 @@ func (oUser *OpenvpnUser) InitDb() {
checkErr(err) checkErr(err)
_, err = oUser.Database.Exec("CREATE TABLE IF NOT EXISTS migrations(id integer not null primary key autoincrement, name string)") _, err = oUser.Database.Exec("CREATE TABLE IF NOT EXISTS migrations(id integer not null primary key autoincrement, name string)")
checkErr(err) checkErr(err)
log.Infof("Database initialized at %v", oUser.Database.Driver()) fmt.Println("Database initialized")
} }
func (oUser *OpenvpnUser) CreateUser(username, password string) (string, error) { func (oUser *OpenvpnUser) CreateUser(username, password string) (string, error) {
@ -150,7 +149,6 @@ func (oUser *OpenvpnUser) listUsers(all bool) []User {
u := User{} u := User{}
err = rows.Scan(&u.id, &u.name, &u.password, &u.revoked, &u.deleted, &u.appConfigured) err = rows.Scan(&u.id, &u.name, &u.password, &u.revoked, &u.deleted, &u.appConfigured)
if err != nil { if err != nil {
//log.Error(err)
continue continue
} }
users = append(users, u) users = append(users, u)
@ -169,7 +167,7 @@ func (oUser *OpenvpnUser) PrintUsers(all bool) {
} }
_ = w.Flush() _ = w.Flush()
} else { } else {
log.Print("No users created yet") fmt.Println("No users created yet")
} }
} }
@ -186,10 +184,9 @@ func (oUser *OpenvpnUser) ChangeUserPassword(username, password string) (string,
func (oUser *OpenvpnUser) RegisterOtpSecret(username, secret string) (string, error) { func (oUser *OpenvpnUser) RegisterOtpSecret(username, secret string) (string, error) {
if oUser.userIsActive(username) { if oUser.userIsActive(username) {
if secret == "generate" { if secret == "generate" {
randomStr := randStr(6, "alphanum") randomStr := RandStr(20, "num")
secret = base32.StdEncoding.EncodeToString([]byte(randomStr)) secret = base32.StdEncoding.EncodeToString([]byte(randomStr))
log.Debug("new generated secret for user %s: %s", username, secret)
} }
_, err := oUser.Database.Exec("UPDATE users SET secret = $1 WHERE username = $2", secret, username) _, err := oUser.Database.Exec("UPDATE users SET secret = $1 WHERE username = $2", secret, username)
@ -216,7 +213,7 @@ func (oUser *OpenvpnUser) RegisterOtpApplication(username, totp string) (string,
return "", authErr return "", authErr
} }
if authOk { if authOk {
_, err := oUser.Database.Exec("UPDATE users SET app_configured = 1 WHERE username = $2") _, err := oUser.Database.Exec("UPDATE users SET app_configured = 1 WHERE username = $1", username)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -227,6 +224,24 @@ func (oUser *OpenvpnUser) RegisterOtpApplication(username, totp string) (string,
} }
return "", userIsNotActiveError return "", userIsNotActiveError
} }
func (oUser *OpenvpnUser) ResetOtpApplication(username string) (string, error) {
if oUser.userIsActive(username) {
appConfigured, appErr := oUser.IsSecondFactorEnabled(username)
if appErr != nil {
return "", appErr
}
if appConfigured {
_, err := oUser.Database.Exec("UPDATE users SET app_configured = 0 WHERE username = $1", username)
if err != nil {
return "", err
}
return "OTP application reset successful", nil
}
return "OTP application not configured", nil
}
return "", userIsNotActiveError
}
func (oUser *OpenvpnUser) GetUserOtpSecret(username string) (string, error) { func (oUser *OpenvpnUser) GetUserOtpSecret(username string) (string, error) {
if oUser.userIsActive(username) { if oUser.userIsActive(username) {
@ -240,10 +255,15 @@ func (oUser *OpenvpnUser) GetUserOtpSecret(username string) (string, error) {
func (oUser *OpenvpnUser) IsSecondFactorEnabled(username string) (bool, error) { func (oUser *OpenvpnUser) IsSecondFactorEnabled(username string) (bool, error) {
if oUser.userIsActive(username) { if oUser.userIsActive(username) {
u := User{} u := User{}
_ = oUser.Database.QueryRow("SELECT username, appConfigured FROM users WHERE username = $1", username).Scan(&u.name, &u.appConfigured) err := oUser.Database.QueryRow("SELECT username, app_configured FROM users WHERE username = $1", username).Scan(&u.name, &u.appConfigured)
if err != nil {
return false, err
}
if u.name == username { if u.name == username {
return u.appConfigured, nil return u.appConfigured, nil
} }
return false, checkAppError return false, checkAppError
} }
return false, userIsNotActiveError return false, userIsNotActiveError
@ -272,10 +292,10 @@ func (oUser *OpenvpnUser) AuthUser(username, password, totp string) (bool, error
trimmedToken := strings.TrimSpace(totp) trimmedToken := strings.TrimSpace(totp)
ok, err := otpConfig.Authenticate(trimmedToken) ok, authErr := otpConfig.Authenticate(trimmedToken)
if err != nil { if authErr != nil {
log.Error(err) fmt.Println(authErr)
} }
if ok { if ok {
return true, nil return true, nil
@ -311,17 +331,17 @@ func (oUser *OpenvpnUser) MigrateDb() {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
continue continue
} }
log.Fatal(err) fmt.Println(err)
} }
if c == 0 { if c == 0 {
log.Info("Migrating database with new migration %s\n", migration.name) fmt.Printf("Migrating database with new migration %s\n", migration.name)
_, err = oUser.Database.Exec(migration.sql) _, err = oUser.Database.Exec(migration.sql)
checkErr(err) checkErr(err)
_, err = oUser.Database.Exec("INSERT INTO migrations(name) VALUES ($1)", migration.name) _, err = oUser.Database.Exec("INSERT INTO migrations(name) VALUES ($1)", migration.name)
checkErr(err) checkErr(err)
} }
} }
log.Info("Migrations are up to date") fmt.Println("Migrations are up to date")
} }
func checkErr(err error) { func checkErr(err error) {

View file

@ -2,20 +2,17 @@ package src
import "crypto/rand" import "crypto/rand"
func randStr(strSize int, randType string) string { func RandStr(strSize int, randType string) string {
var dictionary string var dictionary string
if randType == "alphanum" { switch randType {
dictionary = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" case "number":
}
if randType == "alpha" {
dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
}
if randType == "number" {
dictionary = "0123456789" dictionary = "0123456789"
case "alpha":
dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
default:
dictionary = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
} }
var bytes = make([]byte, strSize) var bytes = make([]byte, strSize)