feat: support groups and preferred_username for staticPasswords (#4456)

Signed-off-by: Ivan Zvyagintsev <ivan.zvyagintsev@flant.com>
This commit is contained in:
Ivan Zviagintsev
2026-01-13 10:07:21 +01:00
committed by GitHub
parent 2d7ecd30a2
commit d1b2722e39
26 changed files with 678 additions and 88 deletions
+18 -14
View File
@@ -95,19 +95,23 @@ type password storage.Password
func (p *password) UnmarshalJSON(b []byte) error {
var data struct {
Email string `json:"email"`
Username string `json:"username"`
UserID string `json:"userID"`
Hash string `json:"hash"`
HashFromEnv string `json:"hashFromEnv"`
Email string `json:"email"`
Username string `json:"username"`
PreferredUsername string `json:"preferredUsername"`
UserID string `json:"userID"`
Hash string `json:"hash"`
HashFromEnv string `json:"hashFromEnv"`
Groups []string `json:"groups"`
}
if err := json.Unmarshal(b, &data); err != nil {
return err
}
*p = password(storage.Password{
Email: data.Email,
Username: data.Username,
UserID: data.UserID,
Email: data.Email,
Username: data.Username,
PreferredUsername: data.PreferredUsername,
UserID: data.UserID,
Groups: data.Groups,
})
if len(data.Hash) == 0 && len(data.HashFromEnv) > 0 {
data.Hash = os.Getenv(data.HashFromEnv)
@@ -275,12 +279,12 @@ var (
_ StorageConfig = (*ent.MySQL)(nil)
)
func getORMBasedSQLStorage(normal, entBased StorageConfig) func() StorageConfig {
func getORMBasedSQLStorage(normal, entBased func() StorageConfig) func() StorageConfig {
return func() StorageConfig {
if featureflags.EntEnabled.Enabled() {
return entBased
return entBased()
}
return normal
return normal()
}
}
@@ -309,9 +313,9 @@ var storages = map[string]func() StorageConfig{
"etcd": func() StorageConfig { return new(etcd.Etcd) },
"kubernetes": func() StorageConfig { return new(kubernetes.Config) },
"memory": func() StorageConfig { return new(memory.Config) },
"sqlite3": getORMBasedSQLStorage(&sql.SQLite3{}, &ent.SQLite3{}),
"postgres": getORMBasedSQLStorage(&sql.Postgres{}, &ent.Postgres{}),
"mysql": getORMBasedSQLStorage(&sql.MySQL{}, &ent.MySQL{}),
"sqlite3": getORMBasedSQLStorage(func() StorageConfig { return new(sql.SQLite3) }, func() StorageConfig { return new(ent.SQLite3) }),
"postgres": getORMBasedSQLStorage(func() StorageConfig { return new(sql.Postgres) }, func() StorageConfig { return new(ent.Postgres) }),
"mysql": getORMBasedSQLStorage(func() StorageConfig { return new(sql.MySQL) }, func() StorageConfig { return new(ent.MySQL) }),
}
// UnmarshalJSON allows Storage to implement the unmarshaler interface to
+13 -4
View File
@@ -116,6 +116,10 @@ staticPasswords:
# bcrypt hash of the string "password"
hash: "$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"
username: "admin"
preferredUsername: "admin-public"
groups:
- "team-a"
- "team-a/admins"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
- email: "foo@example.com"
# base64'd value of the same bcrypt hash above. We want to be able to parse both of these
@@ -206,10 +210,15 @@ additionalFeatures: [
EnablePasswordDB: true,
StaticPasswords: []password{
{
Email: "admin@example.com",
Hash: []byte("$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"),
Username: "admin",
UserID: "08a8684b-db88-4b73-90a9-3cd1661f5466",
Email: "admin@example.com",
Hash: []byte("$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"),
Username: "admin",
PreferredUsername: "admin-public",
UserID: "08a8684b-db88-4b73-90a9-3cd1661f5466",
Groups: []string{
"team-a",
"team-a/admins",
},
},
{
Email: "foo@example.com",
+4
View File
@@ -32,4 +32,8 @@ staticPasswords:
- email: "admin@example.com"
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
username: "admin"
preferredUsername: "admin"
groups:
- "team-a"
- "team-a/admins"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
+12 -1
View File
@@ -135,4 +135,15 @@ enablePasswordDB: true
# A static list of passwords for the password connector.
#
# Alternatively, passwords my be added/updated through the gRPC API.
# staticPasswords: []
# staticPasswords:
# - email: "user@example.com"
# # bcrypt hash of the string "password"
# hash: "$2a$10$examplehash..."
# username: "user-login"
# # Optional. Maps to OIDC "preferred_username" claim.
# preferredUsername: "user-public"
# # Optional. Maps to OIDC "groups" claim (when 'groups' scope is requested).
# groups:
# - "team-a"
# - "team-a/admins"
# userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
+4
View File
@@ -164,4 +164,8 @@ staticPasswords:
# bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2)
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
username: "admin"
preferredUsername: "admin"
groups:
- "team-a"
- "team-a/admins"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
+4
View File
@@ -106,6 +106,10 @@ data:
# bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2)
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
username: "admin"
preferredUsername: "admin"
groups:
- "team-a"
- "team-a/admins"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
---
apiVersion: v1
+80
View File
@@ -18,6 +18,7 @@ import (
"github.com/AppsFlyer/go-sundheit/checks"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/bcrypt"
"golang.org/x/oauth2"
"github.com/dexidp/dex/storage"
@@ -402,6 +403,85 @@ func TestHandlePassword(t *testing.T) {
}
}
func TestHandlePassword_LocalPasswordDBClaims(t *testing.T) {
ctx := t.Context()
// Setup a dex server.
httpServer, s := newTestServer(t, func(c *Config) {
c.PasswordConnector = "local"
})
defer httpServer.Close()
// Client credentials for password grant.
client := storage.Client{
ID: "test",
Secret: "barfoo",
RedirectURIs: []string{"foo://bar.com/", "https://auth.example.com"},
}
require.NoError(t, s.storage.CreateClient(ctx, client))
// Enable local connector.
localConn := storage.Connector{
ID: "local",
Type: LocalConnector,
Name: "Email",
ResourceVersion: "1",
}
require.NoError(t, s.storage.CreateConnector(ctx, localConn))
_, err := s.OpenConnector(localConn)
require.NoError(t, err)
// Create a user in the password DB with groups and preferred_username.
pw := "secret"
hash, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost)
require.NoError(t, err)
require.NoError(t, s.storage.CreatePassword(ctx, storage.Password{
Email: "user@example.com",
Username: "user-login",
PreferredUsername: "user-public",
UserID: "user-id",
Groups: []string{"team-a", "team-a/admins"},
Hash: hash,
}))
u, err := url.Parse(s.issuerURL.String())
require.NoError(t, err)
u.Path = path.Join(u.Path, "/token")
v := url.Values{}
v.Add("scope", "openid profile email groups")
v.Add("grant_type", "password")
v.Add("username", "user@example.com")
v.Add("password", pw)
req, _ := http.NewRequest("POST", u.String(), bytes.NewBufferString(v.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.SetBasicAuth("test", "barfoo")
rr := httptest.NewRecorder()
s.ServeHTTP(rr, req)
require.Equal(t, http.StatusOK, rr.Code)
var tokenResponse struct {
IDToken string `json:"id_token"`
}
require.NoError(t, json.Unmarshal(rr.Body.Bytes(), &tokenResponse))
require.NotEmpty(t, tokenResponse.IDToken)
p, err := oidc.NewProvider(ctx, httpServer.URL)
require.NoError(t, err)
idToken, err := p.Verifier(&oidc.Config{SkipClientIDCheck: true}).Verify(ctx, tokenResponse.IDToken)
require.NoError(t, err)
var claims struct {
PreferredUsername string `json:"preferred_username"`
Groups []string `json:"groups"`
}
require.NoError(t, idToken.Claims(&claims))
require.Equal(t, "user-public", claims.PreferredUsername)
require.Equal(t, []string{"team-a", "team-a/admins"}, claims.Groups)
}
func TestHandlePasswordLoginWithSkipApproval(t *testing.T) {
ctx := t.Context()
+9 -5
View File
@@ -565,10 +565,12 @@ func (db passwordDB) Login(ctx context.Context, s connector.Scopes, email, passw
return connector.Identity{}, false, nil
}
return connector.Identity{
UserID: p.UserID,
Username: p.Username,
Email: p.Email,
EmailVerified: true,
UserID: p.UserID,
Username: p.Username,
PreferredUsername: p.PreferredUsername,
Email: p.Email,
EmailVerified: true,
Groups: p.Groups,
}, true, nil
}
@@ -591,8 +593,10 @@ func (db passwordDB) Refresh(ctx context.Context, s connector.Scopes, identity c
// refreshed token.
//
// No other fields are expected to be refreshable as email is effectively used
// as an ID and this implementation doesn't deal with groups.
// as an ID.
identity.Username = p.Username
identity.PreferredUsername = p.PreferredUsername
identity.Groups = p.Groups
return identity, nil
}
+12 -8
View File
@@ -1279,10 +1279,12 @@ func TestPasswordDB(t *testing.T) {
}
s.CreatePassword(ctx, storage.Password{
Email: "jane@example.com",
Username: "jane",
UserID: "foobar",
Hash: h,
Email: "jane@example.com",
Username: "jane",
PreferredUsername: "jane-public",
UserID: "foobar",
Groups: []string{"team-a", "team-a/admins"},
Hash: h,
})
tests := []struct {
@@ -1298,10 +1300,12 @@ func TestPasswordDB(t *testing.T) {
username: "jane@example.com",
password: pw,
wantIdentity: connector.Identity{
Email: "jane@example.com",
Username: "jane",
UserID: "foobar",
EmailVerified: true,
Email: "jane@example.com",
Username: "jane",
PreferredUsername: "jane-public",
UserID: "foobar",
EmailVerified: true,
Groups: []string{"team-a", "team-a/admins"},
},
},
{
+12 -8
View File
@@ -456,10 +456,12 @@ func testPasswordCRUD(t *testing.T, s storage.Storage) {
}
password1 := storage.Password{
Email: "jane@example.com",
Hash: passwordHash1,
Username: "jane",
UserID: "foobar",
Email: "jane@example.com",
Hash: passwordHash1,
Username: "jane",
PreferredUsername: "jane-public",
UserID: "foobar",
Groups: []string{"team-a", "team-a/admins"},
}
if err := s.CreatePassword(ctx, password1); err != nil {
t.Fatalf("create password token: %v", err)
@@ -475,10 +477,12 @@ func testPasswordCRUD(t *testing.T, s storage.Storage) {
}
password2 := storage.Password{
Email: "john@example.com",
Hash: passwordHash2,
Username: "john",
UserID: "barfoo",
Email: "john@example.com",
Hash: passwordHash2,
Username: "john",
PreferredUsername: "john-public",
UserID: "barfoo",
Groups: []string{"team-b"},
}
if err := s.CreatePassword(ctx, password2); err != nil {
t.Fatalf("create password token: %v", err)
+4
View File
@@ -14,7 +14,9 @@ func (d *Database) CreatePassword(ctx context.Context, password storage.Password
SetEmail(password.Email).
SetHash(password.Hash).
SetUsername(password.Username).
SetPreferredUsername(password.PreferredUsername).
SetUserID(password.UserID).
SetGroups(password.Groups).
Save(ctx)
if err != nil {
return convertDBError("create password: %w", err)
@@ -86,7 +88,9 @@ func (d *Database) UpdatePassword(ctx context.Context, email string, updater fun
SetEmail(newPassword.Email).
SetHash(newPassword.Hash).
SetUsername(newPassword.Username).
SetPreferredUsername(newPassword.PreferredUsername).
SetUserID(newPassword.UserID).
SetGroups(newPassword.Groups).
Save(ctx)
if err != nil {
return rollback(tx, "update password uploading: %w", err)
+6 -4
View File
@@ -139,10 +139,12 @@ func toStorageRefreshToken(r *db.RefreshToken) storage.RefreshToken {
func toStoragePassword(p *db.Password) storage.Password {
return storage.Password{
Email: p.Email,
Hash: p.Hash,
Username: p.Username,
UserID: p.UserID,
Email: p.Email,
Hash: p.Hash,
Username: p.Username,
PreferredUsername: p.PreferredUsername,
UserID: p.UserID,
Groups: p.Groups,
}
}
+2
View File
@@ -161,7 +161,9 @@ var (
{Name: "email", Type: field.TypeString, Unique: true, Size: 2147483647, SchemaType: map[string]string{"mysql": "varchar(384)", "postgres": "text", "sqlite3": "text"}},
{Name: "hash", Type: field.TypeBytes},
{Name: "username", Type: field.TypeString, Size: 2147483647, SchemaType: map[string]string{"mysql": "varchar(384)", "postgres": "text", "sqlite3": "text"}},
{Name: "preferred_username", Type: field.TypeString, Size: 2147483647, Default: "", SchemaType: map[string]string{"mysql": "varchar(384)", "postgres": "text", "sqlite3": "text"}},
{Name: "user_id", Type: field.TypeString, Size: 2147483647, SchemaType: map[string]string{"mysql": "varchar(384)", "postgres": "text", "sqlite3": "text"}},
{Name: "groups", Type: field.TypeJSON, Nullable: true},
}
// PasswordsTable holds the schema information for the "passwords" table.
PasswordsTable = &schema.Table{
+160 -13
View File
@@ -6314,17 +6314,20 @@ func (m *OfflineSessionMutation) ResetEdge(name string) error {
// PasswordMutation represents an operation that mutates the Password nodes in the graph.
type PasswordMutation struct {
config
op Op
typ string
id *int
email *string
hash *[]byte
username *string
user_id *string
clearedFields map[string]struct{}
done bool
oldValue func(context.Context) (*Password, error)
predicates []predicate.Password
op Op
typ string
id *int
email *string
hash *[]byte
username *string
preferred_username *string
user_id *string
groups *[]string
appendgroups []string
clearedFields map[string]struct{}
done bool
oldValue func(context.Context) (*Password, error)
predicates []predicate.Password
}
var _ ent.Mutation = (*PasswordMutation)(nil)
@@ -6533,6 +6536,42 @@ func (m *PasswordMutation) ResetUsername() {
m.username = nil
}
// SetPreferredUsername sets the "preferred_username" field.
func (m *PasswordMutation) SetPreferredUsername(s string) {
m.preferred_username = &s
}
// PreferredUsername returns the value of the "preferred_username" field in the mutation.
func (m *PasswordMutation) PreferredUsername() (r string, exists bool) {
v := m.preferred_username
if v == nil {
return
}
return *v, true
}
// OldPreferredUsername returns the old "preferred_username" field's value of the Password entity.
// If the Password object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *PasswordMutation) OldPreferredUsername(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldPreferredUsername is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldPreferredUsername requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldPreferredUsername: %w", err)
}
return oldValue.PreferredUsername, nil
}
// ResetPreferredUsername resets all changes to the "preferred_username" field.
func (m *PasswordMutation) ResetPreferredUsername() {
m.preferred_username = nil
}
// SetUserID sets the "user_id" field.
func (m *PasswordMutation) SetUserID(s string) {
m.user_id = &s
@@ -6569,6 +6608,71 @@ func (m *PasswordMutation) ResetUserID() {
m.user_id = nil
}
// SetGroups sets the "groups" field.
func (m *PasswordMutation) SetGroups(s []string) {
m.groups = &s
m.appendgroups = nil
}
// Groups returns the value of the "groups" field in the mutation.
func (m *PasswordMutation) Groups() (r []string, exists bool) {
v := m.groups
if v == nil {
return
}
return *v, true
}
// OldGroups returns the old "groups" field's value of the Password entity.
// If the Password object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *PasswordMutation) OldGroups(ctx context.Context) (v []string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldGroups is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldGroups requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldGroups: %w", err)
}
return oldValue.Groups, nil
}
// AppendGroups adds s to the "groups" field.
func (m *PasswordMutation) AppendGroups(s []string) {
m.appendgroups = append(m.appendgroups, s...)
}
// AppendedGroups returns the list of values that were appended to the "groups" field in this mutation.
func (m *PasswordMutation) AppendedGroups() ([]string, bool) {
if len(m.appendgroups) == 0 {
return nil, false
}
return m.appendgroups, true
}
// ClearGroups clears the value of the "groups" field.
func (m *PasswordMutation) ClearGroups() {
m.groups = nil
m.appendgroups = nil
m.clearedFields[password.FieldGroups] = struct{}{}
}
// GroupsCleared returns if the "groups" field was cleared in this mutation.
func (m *PasswordMutation) GroupsCleared() bool {
_, ok := m.clearedFields[password.FieldGroups]
return ok
}
// ResetGroups resets all changes to the "groups" field.
func (m *PasswordMutation) ResetGroups() {
m.groups = nil
m.appendgroups = nil
delete(m.clearedFields, password.FieldGroups)
}
// Where appends a list predicates to the PasswordMutation builder.
func (m *PasswordMutation) Where(ps ...predicate.Password) {
m.predicates = append(m.predicates, ps...)
@@ -6603,7 +6707,7 @@ func (m *PasswordMutation) Type() string {
// order to get all numeric fields that were incremented/decremented, call
// AddedFields().
func (m *PasswordMutation) Fields() []string {
fields := make([]string, 0, 4)
fields := make([]string, 0, 6)
if m.email != nil {
fields = append(fields, password.FieldEmail)
}
@@ -6613,9 +6717,15 @@ func (m *PasswordMutation) Fields() []string {
if m.username != nil {
fields = append(fields, password.FieldUsername)
}
if m.preferred_username != nil {
fields = append(fields, password.FieldPreferredUsername)
}
if m.user_id != nil {
fields = append(fields, password.FieldUserID)
}
if m.groups != nil {
fields = append(fields, password.FieldGroups)
}
return fields
}
@@ -6630,8 +6740,12 @@ func (m *PasswordMutation) Field(name string) (ent.Value, bool) {
return m.Hash()
case password.FieldUsername:
return m.Username()
case password.FieldPreferredUsername:
return m.PreferredUsername()
case password.FieldUserID:
return m.UserID()
case password.FieldGroups:
return m.Groups()
}
return nil, false
}
@@ -6647,8 +6761,12 @@ func (m *PasswordMutation) OldField(ctx context.Context, name string) (ent.Value
return m.OldHash(ctx)
case password.FieldUsername:
return m.OldUsername(ctx)
case password.FieldPreferredUsername:
return m.OldPreferredUsername(ctx)
case password.FieldUserID:
return m.OldUserID(ctx)
case password.FieldGroups:
return m.OldGroups(ctx)
}
return nil, fmt.Errorf("unknown Password field %s", name)
}
@@ -6679,6 +6797,13 @@ func (m *PasswordMutation) SetField(name string, value ent.Value) error {
}
m.SetUsername(v)
return nil
case password.FieldPreferredUsername:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetPreferredUsername(v)
return nil
case password.FieldUserID:
v, ok := value.(string)
if !ok {
@@ -6686,6 +6811,13 @@ func (m *PasswordMutation) SetField(name string, value ent.Value) error {
}
m.SetUserID(v)
return nil
case password.FieldGroups:
v, ok := value.([]string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetGroups(v)
return nil
}
return fmt.Errorf("unknown Password field %s", name)
}
@@ -6715,7 +6847,11 @@ func (m *PasswordMutation) AddField(name string, value ent.Value) error {
// ClearedFields returns all nullable fields that were cleared during this
// mutation.
func (m *PasswordMutation) ClearedFields() []string {
return nil
var fields []string
if m.FieldCleared(password.FieldGroups) {
fields = append(fields, password.FieldGroups)
}
return fields
}
// FieldCleared returns a boolean indicating if a field with the given name was
@@ -6728,6 +6864,11 @@ func (m *PasswordMutation) FieldCleared(name string) bool {
// ClearField clears the value of the field with the given name. It returns an
// error if the field is not defined in the schema.
func (m *PasswordMutation) ClearField(name string) error {
switch name {
case password.FieldGroups:
m.ClearGroups()
return nil
}
return fmt.Errorf("unknown Password nullable field %s", name)
}
@@ -6744,9 +6885,15 @@ func (m *PasswordMutation) ResetField(name string) error {
case password.FieldUsername:
m.ResetUsername()
return nil
case password.FieldPreferredUsername:
m.ResetPreferredUsername()
return nil
case password.FieldUserID:
m.ResetUserID()
return nil
case password.FieldGroups:
m.ResetGroups()
return nil
}
return fmt.Errorf("unknown Password field %s", name)
}
+28 -3
View File
@@ -3,6 +3,7 @@
package db
import (
"encoding/json"
"fmt"
"strings"
@@ -22,8 +23,12 @@ type Password struct {
Hash []byte `json:"hash,omitempty"`
// Username holds the value of the "username" field.
Username string `json:"username,omitempty"`
// PreferredUsername holds the value of the "preferred_username" field.
PreferredUsername string `json:"preferred_username,omitempty"`
// UserID holds the value of the "user_id" field.
UserID string `json:"user_id,omitempty"`
UserID string `json:"user_id,omitempty"`
// Groups holds the value of the "groups" field.
Groups []string `json:"groups,omitempty"`
selectValues sql.SelectValues
}
@@ -32,11 +37,11 @@ func (*Password) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
for i := range columns {
switch columns[i] {
case password.FieldHash:
case password.FieldHash, password.FieldGroups:
values[i] = new([]byte)
case password.FieldID:
values[i] = new(sql.NullInt64)
case password.FieldEmail, password.FieldUsername, password.FieldUserID:
case password.FieldEmail, password.FieldUsername, password.FieldPreferredUsername, password.FieldUserID:
values[i] = new(sql.NullString)
default:
values[i] = new(sql.UnknownType)
@@ -77,12 +82,26 @@ func (_m *Password) assignValues(columns []string, values []any) error {
} else if value.Valid {
_m.Username = value.String
}
case password.FieldPreferredUsername:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field preferred_username", values[i])
} else if value.Valid {
_m.PreferredUsername = value.String
}
case password.FieldUserID:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field user_id", values[i])
} else if value.Valid {
_m.UserID = value.String
}
case password.FieldGroups:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field groups", values[i])
} else if value != nil && len(*value) > 0 {
if err := json.Unmarshal(*value, &_m.Groups); err != nil {
return fmt.Errorf("unmarshal field groups: %w", err)
}
}
default:
_m.selectValues.Set(columns[i], values[i])
}
@@ -128,8 +147,14 @@ func (_m *Password) String() string {
builder.WriteString("username=")
builder.WriteString(_m.Username)
builder.WriteString(", ")
builder.WriteString("preferred_username=")
builder.WriteString(_m.PreferredUsername)
builder.WriteString(", ")
builder.WriteString("user_id=")
builder.WriteString(_m.UserID)
builder.WriteString(", ")
builder.WriteString("groups=")
builder.WriteString(fmt.Sprintf("%v", _m.Groups))
builder.WriteByte(')')
return builder.String()
}
+13
View File
@@ -17,8 +17,12 @@ const (
FieldHash = "hash"
// FieldUsername holds the string denoting the username field in the database.
FieldUsername = "username"
// FieldPreferredUsername holds the string denoting the preferred_username field in the database.
FieldPreferredUsername = "preferred_username"
// FieldUserID holds the string denoting the user_id field in the database.
FieldUserID = "user_id"
// FieldGroups holds the string denoting the groups field in the database.
FieldGroups = "groups"
// Table holds the table name of the password in the database.
Table = "passwords"
)
@@ -29,7 +33,9 @@ var Columns = []string{
FieldEmail,
FieldHash,
FieldUsername,
FieldPreferredUsername,
FieldUserID,
FieldGroups,
}
// ValidColumn reports if the column name is valid (part of the table columns).
@@ -47,6 +53,8 @@ var (
EmailValidator func(string) error
// UsernameValidator is a validator for the "username" field. It is called by the builders before save.
UsernameValidator func(string) error
// DefaultPreferredUsername holds the default value on creation for the "preferred_username" field.
DefaultPreferredUsername string
// UserIDValidator is a validator for the "user_id" field. It is called by the builders before save.
UserIDValidator func(string) error
)
@@ -69,6 +77,11 @@ func ByUsername(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUsername, opts...).ToFunc()
}
// ByPreferredUsername orders the results by the preferred_username field.
func ByPreferredUsername(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldPreferredUsername, opts...).ToFunc()
}
// ByUserID orders the results by the user_id field.
func ByUserID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUserID, opts...).ToFunc()
+80
View File
@@ -67,6 +67,11 @@ func Username(v string) predicate.Password {
return predicate.Password(sql.FieldEQ(FieldUsername, v))
}
// PreferredUsername applies equality check predicate on the "preferred_username" field. It's identical to PreferredUsernameEQ.
func PreferredUsername(v string) predicate.Password {
return predicate.Password(sql.FieldEQ(FieldPreferredUsername, v))
}
// UserID applies equality check predicate on the "user_id" field. It's identical to UserIDEQ.
func UserID(v string) predicate.Password {
return predicate.Password(sql.FieldEQ(FieldUserID, v))
@@ -242,6 +247,71 @@ func UsernameContainsFold(v string) predicate.Password {
return predicate.Password(sql.FieldContainsFold(FieldUsername, v))
}
// PreferredUsernameEQ applies the EQ predicate on the "preferred_username" field.
func PreferredUsernameEQ(v string) predicate.Password {
return predicate.Password(sql.FieldEQ(FieldPreferredUsername, v))
}
// PreferredUsernameNEQ applies the NEQ predicate on the "preferred_username" field.
func PreferredUsernameNEQ(v string) predicate.Password {
return predicate.Password(sql.FieldNEQ(FieldPreferredUsername, v))
}
// PreferredUsernameIn applies the In predicate on the "preferred_username" field.
func PreferredUsernameIn(vs ...string) predicate.Password {
return predicate.Password(sql.FieldIn(FieldPreferredUsername, vs...))
}
// PreferredUsernameNotIn applies the NotIn predicate on the "preferred_username" field.
func PreferredUsernameNotIn(vs ...string) predicate.Password {
return predicate.Password(sql.FieldNotIn(FieldPreferredUsername, vs...))
}
// PreferredUsernameGT applies the GT predicate on the "preferred_username" field.
func PreferredUsernameGT(v string) predicate.Password {
return predicate.Password(sql.FieldGT(FieldPreferredUsername, v))
}
// PreferredUsernameGTE applies the GTE predicate on the "preferred_username" field.
func PreferredUsernameGTE(v string) predicate.Password {
return predicate.Password(sql.FieldGTE(FieldPreferredUsername, v))
}
// PreferredUsernameLT applies the LT predicate on the "preferred_username" field.
func PreferredUsernameLT(v string) predicate.Password {
return predicate.Password(sql.FieldLT(FieldPreferredUsername, v))
}
// PreferredUsernameLTE applies the LTE predicate on the "preferred_username" field.
func PreferredUsernameLTE(v string) predicate.Password {
return predicate.Password(sql.FieldLTE(FieldPreferredUsername, v))
}
// PreferredUsernameContains applies the Contains predicate on the "preferred_username" field.
func PreferredUsernameContains(v string) predicate.Password {
return predicate.Password(sql.FieldContains(FieldPreferredUsername, v))
}
// PreferredUsernameHasPrefix applies the HasPrefix predicate on the "preferred_username" field.
func PreferredUsernameHasPrefix(v string) predicate.Password {
return predicate.Password(sql.FieldHasPrefix(FieldPreferredUsername, v))
}
// PreferredUsernameHasSuffix applies the HasSuffix predicate on the "preferred_username" field.
func PreferredUsernameHasSuffix(v string) predicate.Password {
return predicate.Password(sql.FieldHasSuffix(FieldPreferredUsername, v))
}
// PreferredUsernameEqualFold applies the EqualFold predicate on the "preferred_username" field.
func PreferredUsernameEqualFold(v string) predicate.Password {
return predicate.Password(sql.FieldEqualFold(FieldPreferredUsername, v))
}
// PreferredUsernameContainsFold applies the ContainsFold predicate on the "preferred_username" field.
func PreferredUsernameContainsFold(v string) predicate.Password {
return predicate.Password(sql.FieldContainsFold(FieldPreferredUsername, v))
}
// UserIDEQ applies the EQ predicate on the "user_id" field.
func UserIDEQ(v string) predicate.Password {
return predicate.Password(sql.FieldEQ(FieldUserID, v))
@@ -307,6 +377,16 @@ func UserIDContainsFold(v string) predicate.Password {
return predicate.Password(sql.FieldContainsFold(FieldUserID, v))
}
// GroupsIsNil applies the IsNil predicate on the "groups" field.
func GroupsIsNil() predicate.Password {
return predicate.Password(sql.FieldIsNull(FieldGroups))
}
// GroupsNotNil applies the NotNil predicate on the "groups" field.
func GroupsNotNil() predicate.Password {
return predicate.Password(sql.FieldNotNull(FieldGroups))
}
// And groups predicates with the AND operator between them.
func And(predicates ...predicate.Password) predicate.Password {
return predicate.Password(sql.AndPredicates(predicates...))
+41
View File
@@ -37,12 +37,32 @@ func (_c *PasswordCreate) SetUsername(v string) *PasswordCreate {
return _c
}
// SetPreferredUsername sets the "preferred_username" field.
func (_c *PasswordCreate) SetPreferredUsername(v string) *PasswordCreate {
_c.mutation.SetPreferredUsername(v)
return _c
}
// SetNillablePreferredUsername sets the "preferred_username" field if the given value is not nil.
func (_c *PasswordCreate) SetNillablePreferredUsername(v *string) *PasswordCreate {
if v != nil {
_c.SetPreferredUsername(*v)
}
return _c
}
// SetUserID sets the "user_id" field.
func (_c *PasswordCreate) SetUserID(v string) *PasswordCreate {
_c.mutation.SetUserID(v)
return _c
}
// SetGroups sets the "groups" field.
func (_c *PasswordCreate) SetGroups(v []string) *PasswordCreate {
_c.mutation.SetGroups(v)
return _c
}
// Mutation returns the PasswordMutation object of the builder.
func (_c *PasswordCreate) Mutation() *PasswordMutation {
return _c.mutation
@@ -50,6 +70,7 @@ func (_c *PasswordCreate) Mutation() *PasswordMutation {
// Save creates the Password in the database.
func (_c *PasswordCreate) Save(ctx context.Context) (*Password, error) {
_c.defaults()
return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks)
}
@@ -75,6 +96,14 @@ func (_c *PasswordCreate) ExecX(ctx context.Context) {
}
}
// defaults sets the default values of the builder before save.
func (_c *PasswordCreate) defaults() {
if _, ok := _c.mutation.PreferredUsername(); !ok {
v := password.DefaultPreferredUsername
_c.mutation.SetPreferredUsername(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (_c *PasswordCreate) check() error {
if _, ok := _c.mutation.Email(); !ok {
@@ -96,6 +125,9 @@ func (_c *PasswordCreate) check() error {
return &ValidationError{Name: "username", err: fmt.Errorf(`db: validator failed for field "Password.username": %w`, err)}
}
}
if _, ok := _c.mutation.PreferredUsername(); !ok {
return &ValidationError{Name: "preferred_username", err: errors.New(`db: missing required field "Password.preferred_username"`)}
}
if _, ok := _c.mutation.UserID(); !ok {
return &ValidationError{Name: "user_id", err: errors.New(`db: missing required field "Password.user_id"`)}
}
@@ -142,10 +174,18 @@ func (_c *PasswordCreate) createSpec() (*Password, *sqlgraph.CreateSpec) {
_spec.SetField(password.FieldUsername, field.TypeString, value)
_node.Username = value
}
if value, ok := _c.mutation.PreferredUsername(); ok {
_spec.SetField(password.FieldPreferredUsername, field.TypeString, value)
_node.PreferredUsername = value
}
if value, ok := _c.mutation.UserID(); ok {
_spec.SetField(password.FieldUserID, field.TypeString, value)
_node.UserID = value
}
if value, ok := _c.mutation.Groups(); ok {
_spec.SetField(password.FieldGroups, field.TypeJSON, value)
_node.Groups = value
}
return _node, _spec
}
@@ -167,6 +207,7 @@ func (_c *PasswordCreateBulk) Save(ctx context.Context) ([]*Password, error) {
for i := range _c.builders {
func(i int, root context.Context) {
builder := _c.builders[i]
builder.defaults()
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*PasswordMutation)
if !ok {
+93
View File
@@ -9,6 +9,7 @@ import (
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/dialect/sql/sqljson"
"entgo.io/ent/schema/field"
"github.com/dexidp/dex/storage/ent/db/password"
"github.com/dexidp/dex/storage/ent/db/predicate"
@@ -61,6 +62,20 @@ func (_u *PasswordUpdate) SetNillableUsername(v *string) *PasswordUpdate {
return _u
}
// SetPreferredUsername sets the "preferred_username" field.
func (_u *PasswordUpdate) SetPreferredUsername(v string) *PasswordUpdate {
_u.mutation.SetPreferredUsername(v)
return _u
}
// SetNillablePreferredUsername sets the "preferred_username" field if the given value is not nil.
func (_u *PasswordUpdate) SetNillablePreferredUsername(v *string) *PasswordUpdate {
if v != nil {
_u.SetPreferredUsername(*v)
}
return _u
}
// SetUserID sets the "user_id" field.
func (_u *PasswordUpdate) SetUserID(v string) *PasswordUpdate {
_u.mutation.SetUserID(v)
@@ -75,6 +90,24 @@ func (_u *PasswordUpdate) SetNillableUserID(v *string) *PasswordUpdate {
return _u
}
// SetGroups sets the "groups" field.
func (_u *PasswordUpdate) SetGroups(v []string) *PasswordUpdate {
_u.mutation.SetGroups(v)
return _u
}
// AppendGroups appends value to the "groups" field.
func (_u *PasswordUpdate) AppendGroups(v []string) *PasswordUpdate {
_u.mutation.AppendGroups(v)
return _u
}
// ClearGroups clears the value of the "groups" field.
func (_u *PasswordUpdate) ClearGroups() *PasswordUpdate {
_u.mutation.ClearGroups()
return _u
}
// Mutation returns the PasswordMutation object of the builder.
func (_u *PasswordUpdate) Mutation() *PasswordMutation {
return _u.mutation
@@ -148,9 +181,23 @@ func (_u *PasswordUpdate) sqlSave(ctx context.Context) (_node int, err error) {
if value, ok := _u.mutation.Username(); ok {
_spec.SetField(password.FieldUsername, field.TypeString, value)
}
if value, ok := _u.mutation.PreferredUsername(); ok {
_spec.SetField(password.FieldPreferredUsername, field.TypeString, value)
}
if value, ok := _u.mutation.UserID(); ok {
_spec.SetField(password.FieldUserID, field.TypeString, value)
}
if value, ok := _u.mutation.Groups(); ok {
_spec.SetField(password.FieldGroups, field.TypeJSON, value)
}
if value, ok := _u.mutation.AppendedGroups(); ok {
_spec.AddModifier(func(u *sql.UpdateBuilder) {
sqljson.Append(u, password.FieldGroups, value)
})
}
if _u.mutation.GroupsCleared() {
_spec.ClearField(password.FieldGroups, field.TypeJSON)
}
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{password.Label}
@@ -205,6 +252,20 @@ func (_u *PasswordUpdateOne) SetNillableUsername(v *string) *PasswordUpdateOne {
return _u
}
// SetPreferredUsername sets the "preferred_username" field.
func (_u *PasswordUpdateOne) SetPreferredUsername(v string) *PasswordUpdateOne {
_u.mutation.SetPreferredUsername(v)
return _u
}
// SetNillablePreferredUsername sets the "preferred_username" field if the given value is not nil.
func (_u *PasswordUpdateOne) SetNillablePreferredUsername(v *string) *PasswordUpdateOne {
if v != nil {
_u.SetPreferredUsername(*v)
}
return _u
}
// SetUserID sets the "user_id" field.
func (_u *PasswordUpdateOne) SetUserID(v string) *PasswordUpdateOne {
_u.mutation.SetUserID(v)
@@ -219,6 +280,24 @@ func (_u *PasswordUpdateOne) SetNillableUserID(v *string) *PasswordUpdateOne {
return _u
}
// SetGroups sets the "groups" field.
func (_u *PasswordUpdateOne) SetGroups(v []string) *PasswordUpdateOne {
_u.mutation.SetGroups(v)
return _u
}
// AppendGroups appends value to the "groups" field.
func (_u *PasswordUpdateOne) AppendGroups(v []string) *PasswordUpdateOne {
_u.mutation.AppendGroups(v)
return _u
}
// ClearGroups clears the value of the "groups" field.
func (_u *PasswordUpdateOne) ClearGroups() *PasswordUpdateOne {
_u.mutation.ClearGroups()
return _u
}
// Mutation returns the PasswordMutation object of the builder.
func (_u *PasswordUpdateOne) Mutation() *PasswordMutation {
return _u.mutation
@@ -322,9 +401,23 @@ func (_u *PasswordUpdateOne) sqlSave(ctx context.Context) (_node *Password, err
if value, ok := _u.mutation.Username(); ok {
_spec.SetField(password.FieldUsername, field.TypeString, value)
}
if value, ok := _u.mutation.PreferredUsername(); ok {
_spec.SetField(password.FieldPreferredUsername, field.TypeString, value)
}
if value, ok := _u.mutation.UserID(); ok {
_spec.SetField(password.FieldUserID, field.TypeString, value)
}
if value, ok := _u.mutation.Groups(); ok {
_spec.SetField(password.FieldGroups, field.TypeJSON, value)
}
if value, ok := _u.mutation.AppendedGroups(); ok {
_spec.AddModifier(func(u *sql.UpdateBuilder) {
sqljson.Append(u, password.FieldGroups, value)
})
}
if _u.mutation.GroupsCleared() {
_spec.ClearField(password.FieldGroups, field.TypeJSON)
}
_node = &Password{config: _u.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues
+5 -1
View File
@@ -212,8 +212,12 @@ func init() {
passwordDescUsername := passwordFields[2].Descriptor()
// password.UsernameValidator is a validator for the "username" field. It is called by the builders before save.
password.UsernameValidator = passwordDescUsername.Validators[0].(func(string) error)
// passwordDescPreferredUsername is the schema descriptor for preferred_username field.
passwordDescPreferredUsername := passwordFields[3].Descriptor()
// password.DefaultPreferredUsername holds the default value on creation for the preferred_username field.
password.DefaultPreferredUsername = passwordDescPreferredUsername.Default.(string)
// passwordDescUserID is the schema descriptor for user_id field.
passwordDescUserID := passwordFields[3].Descriptor()
passwordDescUserID := passwordFields[4].Descriptor()
// password.UserIDValidator is a validator for the "user_id" field. It is called by the builders before save.
password.UserIDValidator = passwordDescUserID.Validators[0].(func(string) error)
refreshtokenFields := schema.RefreshToken{}.Fields()

Some files were not shown because too many files have changed in this diff Show More