Commit 1ac213f9 authored by ale's avatar ale
Browse files

Add the "shard" field to UserInfo

Useful for partitioned (sharded) services that need to make
partition-related decisions at authentication time.
parent 66f3bb51
...@@ -90,9 +90,11 @@ func (r *Request) DecodeFromMap(m map[string]string, prefix string) { ...@@ -90,9 +90,11 @@ func (r *Request) DecodeFromMap(m map[string]string, prefix string) {
r.DeviceInfo = decodeDeviceInfoFromMap(m, prefix+"device.") r.DeviceInfo = decodeDeviceInfoFromMap(m, prefix+"device.")
} }
// UserInfo contains optional user information. // UserInfo contains optional user information that may be useful to
// authentication endpoints.
type UserInfo struct { type UserInfo struct {
Email string Email string
Shard string
Groups []string Groups []string
} }
...@@ -100,13 +102,19 @@ func (u *UserInfo) EncodeToMap(m map[string]string, prefix string) { ...@@ -100,13 +102,19 @@ func (u *UserInfo) EncodeToMap(m map[string]string, prefix string) {
if u.Email != "" { if u.Email != "" {
m[prefix+"email"] = u.Email m[prefix+"email"] = u.Email
} }
if u.Shard != "" {
m[prefix+"shard"] = u.Shard
}
for i, g := range u.Groups { for i, g := range u.Groups {
m[fmt.Sprintf("%sgroup.%d.", prefix, i)] = g m[fmt.Sprintf("%sgroup.%d.", prefix, i)] = g
} }
} }
func decodeUserInfoFromMap(m map[string]string, prefix string) *UserInfo { func decodeUserInfoFromMap(m map[string]string, prefix string) *UserInfo {
u := UserInfo{Email: m[prefix+"email"]} u := UserInfo{
Email: m[prefix+"email"],
Shard: m[prefix+"shard"],
}
i := 0 i := 0
for { for {
s, ok := m[fmt.Sprintf("%sgroup.%d.", prefix, i)] s, ok := m[fmt.Sprintf("%sgroup.%d.", prefix, i)]
......
...@@ -71,6 +71,7 @@ func TestProtocol_SerializeResponse(t *testing.T) { ...@@ -71,6 +71,7 @@ func TestProtocol_SerializeResponse(t *testing.T) {
}, },
UserInfo: &UserInfo{ UserInfo: &UserInfo{
Email: "test@example.com", Email: "test@example.com",
Shard: "42",
Groups: []string{"group1", "group2", "group3"}, Groups: []string{"group1", "group2", "group3"},
}, },
} }
......
...@@ -26,6 +26,7 @@ import ( ...@@ -26,6 +26,7 @@ import (
type User struct { type User struct {
Name string Name string
Email string Email string
Shard string
EncryptedPassword []byte EncryptedPassword []byte
TOTPSecret string TOTPSecret string
U2FRegistrations []u2f.Registration U2FRegistrations []u2f.Registration
...@@ -59,6 +60,7 @@ func (u *User) HasU2F() bool { ...@@ -59,6 +60,7 @@ func (u *User) HasU2F() bool {
func (u *User) UserInfo() *auth.UserInfo { func (u *User) UserInfo() *auth.UserInfo {
return &auth.UserInfo{ return &auth.UserInfo{
Email: u.Email, Email: u.Email,
Shard: u.Shard,
Groups: u.Groups, Groups: u.Groups,
} }
} }
......
...@@ -73,6 +73,7 @@ var ( ...@@ -73,6 +73,7 @@ var (
- name: 2fauser - name: 2fauser
email: 2fauser@example.com email: 2fauser@example.com
shard: 42
password: "16384$8$1$c479e8eb722f1b071efea7826ccf9c20$96d63ebed0c64afb746026f56f71b2a1f8796c73141d2d6b1958d4ea26c60a0b" password: "16384$8$1$c479e8eb722f1b071efea7826ccf9c20$96d63ebed0c64afb746026f56f71b2a1f8796c73141d2d6b1958d4ea26c60a0b"
totp_secret: "O32OBVS5BL5EAPB5" totp_secret: "O32OBVS5BL5EAPB5"
` `
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
type fileBackendUser struct { type fileBackendUser struct {
Name string `yaml:"name"` Name string `yaml:"name"`
Email string `yaml:"email"` Email string `yaml:"email"`
Shard string `yaml:"shard"`
EncryptedPassword string `yaml:"password"` EncryptedPassword string `yaml:"password"`
TOTPSecret string `yaml:"totp_secret"` TOTPSecret string `yaml:"totp_secret"`
Groups []string `yaml:"groups"` Groups []string `yaml:"groups"`
...@@ -20,6 +21,7 @@ func (f *fileBackendUser) ToUser() *User { ...@@ -20,6 +21,7 @@ func (f *fileBackendUser) ToUser() *User {
return &User{ return &User{
Name: f.Name, Name: f.Name,
Email: f.Email, Email: f.Email,
Shard: f.Shard,
EncryptedPassword: []byte(f.EncryptedPassword), EncryptedPassword: []byte(f.EncryptedPassword),
TOTPSecret: f.TOTPSecret, TOTPSecret: f.TOTPSecret,
Groups: f.Groups, Groups: f.Groups,
......
...@@ -100,10 +100,13 @@ func (c *LDAPServiceConfig) userFromResponse(username string, result *ldap.Searc ...@@ -100,10 +100,13 @@ func (c *LDAPServiceConfig) userFromResponse(username string, result *ldap.Searc
entry := result.Entries[0] entry := result.Entries[0]
// Apply the attribute map. // Apply the attribute map. We don't care if an attribute is
// not defined in the map, as the get* functions will silently
// ignore an empty attribute name.
u := User{ u := User{
Name: username, Name: username,
Email: getStringFromLDAPEntry(entry, c.Attrs["email"]), Email: getStringFromLDAPEntry(entry, c.Attrs["email"]),
Shard: getStringFromLDAPEntry(entry, c.Attrs["shard"]),
EncryptedPassword: []byte(dropCryptPrefix(getStringFromLDAPEntry(entry, c.Attrs["password"]))), EncryptedPassword: []byte(dropCryptPrefix(getStringFromLDAPEntry(entry, c.Attrs["password"]))),
TOTPSecret: getStringFromLDAPEntry(entry, c.Attrs["totp_secret"]), TOTPSecret: getStringFromLDAPEntry(entry, c.Attrs["totp_secret"]),
AppSpecificPasswords: decodeAppSpecificPasswordList(getListFromLDAPEntry(entry, c.Attrs["app_specific_password"])), AppSpecificPasswords: decodeAppSpecificPasswordList(getListFromLDAPEntry(entry, c.Attrs["app_specific_password"])),
......
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