Commit 7570ba15 authored by ale's avatar ale

Support U2F registrations in the 'file' backend

parent 9fe285ce
Pipeline #2561 passed with stages
in 1 minute and 24 seconds
......@@ -76,6 +76,9 @@ var (
shard: 42
password: "$s$16384$8$1$c479e8eb722f1b071efea7826ccf9c20$96d63ebed0c64afb746026f56f71b2a1f8796c73141d2d6b1958d4ea26c60a0b"
totp_secret: "O32OBVS5BL5EAPB5"
u2f_registrations:
- key_handle: "JcolXA6KaoihO8VuxSugtCT5jyh-6lFuWXLkFAPe8s9qszxTMvDAtJn8gmYg9uGO-kmjgap1h0llchlqqjCpKw"
public_key: "0498ee4565cd348031cf36ee3549b63b5ea23b5e7ea6f297e7cccaeba99983d185110fb94fa6455c82d3e5c8d0be10be71308d76062fb5fa50d3ea8228048f0037"
`
testConfigStr = `---
......@@ -235,3 +238,21 @@ func TestAuthServer_Blacklist_BelowLimit(t *testing.T) {
t.Fatal("user was incorrectly blacklisted")
}
}
func TestAuthServer_File_HasU2F(t *testing.T) {
s := createTestServer(t, map[string]string{
"users.yml": testUsersFileStr,
"config.yml": testConfigStr,
})
defer s.Close()
// Check that the user U2F registrations were decoded successfully.
svc, _ := s.srv.getService("test")
u, ok := s.srv.getUser(context.Background(), svc, "2fauser")
if !ok {
t.Fatal("user not found")
}
if len(u.U2FRegistrations) != 1 {
t.Fatalf("found %d u2f registrations, expecting 1", len(u.U2FRegistrations))
}
}
......@@ -2,9 +2,13 @@ package server
import (
"context"
"encoding/base64"
"encoding/hex"
"path/filepath"
"strings"
ct "git.autistici.org/ai3/go-common/ldap/compositetypes"
"github.com/tstranex/u2f"
"gopkg.in/yaml.v2"
)
......@@ -20,6 +24,39 @@ type fileUser struct {
EncryptedPassword string `yaml:"password"`
TOTPSecret string `yaml:"totp_secret"`
Groups []string `yaml:"groups"`
// U2F registrations are encoded in a similar format as the
// one produced by 'pamu2fcfg': the key handle is
// base64-encoded (this is "websafe" base64, without padding),
// the public key is hex encoded.
U2FRegistrations []struct {
KeyHandle string `yaml:"key_handle"`
PublicKey string `yaml:"public_key"`
} `yaml:"u2f_registrations"`
}
func (f *fileUser) getU2FRegistrations() []u2f.Registration {
var out []u2f.Registration
for _, r := range f.U2FRegistrations {
kh, err := base64.RawURLEncoding.DecodeString(r.KeyHandle)
if err != nil {
continue
}
pk, err := hex.DecodeString(r.PublicKey)
if err != nil {
continue
}
ctr := ct.U2FRegistration{
KeyHandle: kh,
PublicKey: pk,
}
reg, err := ctr.Decode()
if err != nil {
continue
}
out = append(out, *reg)
}
return out
}
func (f *fileUser) ToUser() *User {
......@@ -30,6 +67,7 @@ func (f *fileUser) ToUser() *User {
EncryptedPassword: []byte(f.EncryptedPassword),
TOTPSecret: f.TOTPSecret,
Groups: f.Groups,
U2FRegistrations: f.getU2FRegistrations(),
}
}
......
......@@ -257,7 +257,7 @@ func (b *ldapServiceBackend) GetUser(ctx context.Context, name string) (*User, b
return b.userFromResponse(name, result)
}
var hex = "0123456789abcdef"
var hexChars = "0123456789abcdef"
func mustEscape(c byte) bool {
return (c > 0x7f || c == '<' || c == '>' || c == '\\' || c == '*' ||
......@@ -285,8 +285,8 @@ func escapeDN(s string) string {
c := s[i]
if mustEscape(c) {
buf[j+0] = '\\'
buf[j+1] = hex[c>>4]
buf[j+2] = hex[c&0xf]
buf[j+1] = hexChars[c>>4]
buf[j+2] = hexChars[c&0xf]
j += 3
} else {
buf[j] = c
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment