Browse Source

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

Signed-off-by: Ivan Zvyagintsev <ivan.zvyagintsev@flant.com>
pull/4325/merge
Ivan Zviagintsev 2 months ago committed by GitHub
parent
commit
d1b2722e39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 32
      cmd/dex/config.go
  2. 17
      cmd/dex/config_test.go
  3. 4
      config.dev.yaml
  4. 13
      config.yaml.dist
  5. 4
      examples/config-dev.yaml
  6. 4
      examples/k8s/dex.yaml
  7. 80
      server/handlers_test.go
  8. 14
      server/server.go
  9. 20
      server/server_test.go
  10. 20
      storage/conformance/conformance.go
  11. 4
      storage/ent/client/password.go
  12. 10
      storage/ent/client/types.go
  13. 2
      storage/ent/db/migrate/schema.go
  14. 173
      storage/ent/db/mutation.go
  15. 31
      storage/ent/db/password.go
  16. 13
      storage/ent/db/password/password.go
  17. 80
      storage/ent/db/password/where.go
  18. 41
      storage/ent/db/password_create.go
  19. 93
      storage/ent/db/password_update.go
  20. 6
      storage/ent/db/runtime.go
  21. 5
      storage/ent/schema/password.go
  22. 8
      storage/kubernetes/storage.go
  23. 28
      storage/kubernetes/types.go
  24. 18
      storage/sql/crud.go
  25. 40
      storage/sql/migrate.go
  26. 6
      storage/storage.go

32
cmd/dex/config.go

@ -95,19 +95,23 @@ type password storage.Password
func (p *password) UnmarshalJSON(b []byte) error { func (p *password) UnmarshalJSON(b []byte) error {
var data struct { var data struct {
Email string `json:"email"` Email string `json:"email"`
Username string `json:"username"` Username string `json:"username"`
UserID string `json:"userID"` PreferredUsername string `json:"preferredUsername"`
Hash string `json:"hash"` UserID string `json:"userID"`
HashFromEnv string `json:"hashFromEnv"` Hash string `json:"hash"`
HashFromEnv string `json:"hashFromEnv"`
Groups []string `json:"groups"`
} }
if err := json.Unmarshal(b, &data); err != nil { if err := json.Unmarshal(b, &data); err != nil {
return err return err
} }
*p = password(storage.Password{ *p = password(storage.Password{
Email: data.Email, Email: data.Email,
Username: data.Username, Username: data.Username,
UserID: data.UserID, PreferredUsername: data.PreferredUsername,
UserID: data.UserID,
Groups: data.Groups,
}) })
if len(data.Hash) == 0 && len(data.HashFromEnv) > 0 { if len(data.Hash) == 0 && len(data.HashFromEnv) > 0 {
data.Hash = os.Getenv(data.HashFromEnv) data.Hash = os.Getenv(data.HashFromEnv)
@ -275,12 +279,12 @@ var (
_ StorageConfig = (*ent.MySQL)(nil) _ StorageConfig = (*ent.MySQL)(nil)
) )
func getORMBasedSQLStorage(normal, entBased StorageConfig) func() StorageConfig { func getORMBasedSQLStorage(normal, entBased func() StorageConfig) func() StorageConfig {
return func() StorageConfig { return func() StorageConfig {
if featureflags.EntEnabled.Enabled() { 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) }, "etcd": func() StorageConfig { return new(etcd.Etcd) },
"kubernetes": func() StorageConfig { return new(kubernetes.Config) }, "kubernetes": func() StorageConfig { return new(kubernetes.Config) },
"memory": func() StorageConfig { return new(memory.Config) }, "memory": func() StorageConfig { return new(memory.Config) },
"sqlite3": getORMBasedSQLStorage(&sql.SQLite3{}, &ent.SQLite3{}), "sqlite3": getORMBasedSQLStorage(func() StorageConfig { return new(sql.SQLite3) }, func() StorageConfig { return new(ent.SQLite3) }),
"postgres": getORMBasedSQLStorage(&sql.Postgres{}, &ent.Postgres{}), "postgres": getORMBasedSQLStorage(func() StorageConfig { return new(sql.Postgres) }, func() StorageConfig { return new(ent.Postgres) }),
"mysql": getORMBasedSQLStorage(&sql.MySQL{}, &ent.MySQL{}), "mysql": getORMBasedSQLStorage(func() StorageConfig { return new(sql.MySQL) }, func() StorageConfig { return new(ent.MySQL) }),
} }
// UnmarshalJSON allows Storage to implement the unmarshaler interface to // UnmarshalJSON allows Storage to implement the unmarshaler interface to

17
cmd/dex/config_test.go

@ -116,6 +116,10 @@ staticPasswords:
# bcrypt hash of the string "password" # bcrypt hash of the string "password"
hash: "$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy" hash: "$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"
username: "admin" username: "admin"
preferredUsername: "admin-public"
groups:
- "team-a"
- "team-a/admins"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
- email: "foo@example.com" - email: "foo@example.com"
# base64'd value of the same bcrypt hash above. We want to be able to parse both of these # 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, EnablePasswordDB: true,
StaticPasswords: []password{ StaticPasswords: []password{
{ {
Email: "admin@example.com", Email: "admin@example.com",
Hash: []byte("$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"), Hash: []byte("$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"),
Username: "admin", Username: "admin",
UserID: "08a8684b-db88-4b73-90a9-3cd1661f5466", PreferredUsername: "admin-public",
UserID: "08a8684b-db88-4b73-90a9-3cd1661f5466",
Groups: []string{
"team-a",
"team-a/admins",
},
}, },
{ {
Email: "foo@example.com", Email: "foo@example.com",

4
config.dev.yaml

@ -32,4 +32,8 @@ staticPasswords:
- email: "admin@example.com" - email: "admin@example.com"
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
username: "admin" username: "admin"
preferredUsername: "admin"
groups:
- "team-a"
- "team-a/admins"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"

13
config.yaml.dist

@ -135,4 +135,15 @@ enablePasswordDB: true
# A static list of passwords for the password connector. # A static list of passwords for the password connector.
# #
# Alternatively, passwords my be added/updated through the gRPC API. # 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
examples/config-dev.yaml

@ -164,4 +164,8 @@ staticPasswords:
# bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2) # bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2)
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
username: "admin" username: "admin"
preferredUsername: "admin"
groups:
- "team-a"
- "team-a/admins"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"

4
examples/k8s/dex.yaml

@ -106,6 +106,10 @@ data:
# bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2) # bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2)
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
username: "admin" username: "admin"
preferredUsername: "admin"
groups:
- "team-a"
- "team-a/admins"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
--- ---
apiVersion: v1 apiVersion: v1

80
server/handlers_test.go

@ -18,6 +18,7 @@ import (
"github.com/AppsFlyer/go-sundheit/checks" "github.com/AppsFlyer/go-sundheit/checks"
"github.com/coreos/go-oidc/v3/oidc" "github.com/coreos/go-oidc/v3/oidc"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/crypto/bcrypt"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/dexidp/dex/storage" "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) { func TestHandlePasswordLoginWithSkipApproval(t *testing.T) {
ctx := t.Context() ctx := t.Context()

14
server/server.go

@ -565,10 +565,12 @@ func (db passwordDB) Login(ctx context.Context, s connector.Scopes, email, passw
return connector.Identity{}, false, nil return connector.Identity{}, false, nil
} }
return connector.Identity{ return connector.Identity{
UserID: p.UserID, UserID: p.UserID,
Username: p.Username, Username: p.Username,
Email: p.Email, PreferredUsername: p.PreferredUsername,
EmailVerified: true, Email: p.Email,
EmailVerified: true,
Groups: p.Groups,
}, true, nil }, true, nil
} }
@ -591,8 +593,10 @@ func (db passwordDB) Refresh(ctx context.Context, s connector.Scopes, identity c
// refreshed token. // refreshed token.
// //
// No other fields are expected to be refreshable as email is effectively used // 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.Username = p.Username
identity.PreferredUsername = p.PreferredUsername
identity.Groups = p.Groups
return identity, nil return identity, nil
} }

20
server/server_test.go

@ -1279,10 +1279,12 @@ func TestPasswordDB(t *testing.T) {
} }
s.CreatePassword(ctx, storage.Password{ s.CreatePassword(ctx, storage.Password{
Email: "jane@example.com", Email: "jane@example.com",
Username: "jane", Username: "jane",
UserID: "foobar", PreferredUsername: "jane-public",
Hash: h, UserID: "foobar",
Groups: []string{"team-a", "team-a/admins"},
Hash: h,
}) })
tests := []struct { tests := []struct {
@ -1298,10 +1300,12 @@ func TestPasswordDB(t *testing.T) {
username: "jane@example.com", username: "jane@example.com",
password: pw, password: pw,
wantIdentity: connector.Identity{ wantIdentity: connector.Identity{
Email: "jane@example.com", Email: "jane@example.com",
Username: "jane", Username: "jane",
UserID: "foobar", PreferredUsername: "jane-public",
EmailVerified: true, UserID: "foobar",
EmailVerified: true,
Groups: []string{"team-a", "team-a/admins"},
}, },
}, },
{ {

20
storage/conformance/conformance.go

@ -456,10 +456,12 @@ func testPasswordCRUD(t *testing.T, s storage.Storage) {
} }
password1 := storage.Password{ password1 := storage.Password{
Email: "jane@example.com", Email: "jane@example.com",
Hash: passwordHash1, Hash: passwordHash1,
Username: "jane", Username: "jane",
UserID: "foobar", PreferredUsername: "jane-public",
UserID: "foobar",
Groups: []string{"team-a", "team-a/admins"},
} }
if err := s.CreatePassword(ctx, password1); err != nil { if err := s.CreatePassword(ctx, password1); err != nil {
t.Fatalf("create password token: %v", err) t.Fatalf("create password token: %v", err)
@ -475,10 +477,12 @@ func testPasswordCRUD(t *testing.T, s storage.Storage) {
} }
password2 := storage.Password{ password2 := storage.Password{
Email: "john@example.com", Email: "john@example.com",
Hash: passwordHash2, Hash: passwordHash2,
Username: "john", Username: "john",
UserID: "barfoo", PreferredUsername: "john-public",
UserID: "barfoo",
Groups: []string{"team-b"},
} }
if err := s.CreatePassword(ctx, password2); err != nil { if err := s.CreatePassword(ctx, password2); err != nil {
t.Fatalf("create password token: %v", err) t.Fatalf("create password token: %v", err)

4
storage/ent/client/password.go

@ -14,7 +14,9 @@ func (d *Database) CreatePassword(ctx context.Context, password storage.Password
SetEmail(password.Email). SetEmail(password.Email).
SetHash(password.Hash). SetHash(password.Hash).
SetUsername(password.Username). SetUsername(password.Username).
SetPreferredUsername(password.PreferredUsername).
SetUserID(password.UserID). SetUserID(password.UserID).
SetGroups(password.Groups).
Save(ctx) Save(ctx)
if err != nil { if err != nil {
return convertDBError("create password: %w", err) return convertDBError("create password: %w", err)
@ -86,7 +88,9 @@ func (d *Database) UpdatePassword(ctx context.Context, email string, updater fun
SetEmail(newPassword.Email). SetEmail(newPassword.Email).
SetHash(newPassword.Hash). SetHash(newPassword.Hash).
SetUsername(newPassword.Username). SetUsername(newPassword.Username).
SetPreferredUsername(newPassword.PreferredUsername).
SetUserID(newPassword.UserID). SetUserID(newPassword.UserID).
SetGroups(newPassword.Groups).
Save(ctx) Save(ctx)
if err != nil { if err != nil {
return rollback(tx, "update password uploading: %w", err) return rollback(tx, "update password uploading: %w", err)

10
storage/ent/client/types.go

@ -139,10 +139,12 @@ func toStorageRefreshToken(r *db.RefreshToken) storage.RefreshToken {
func toStoragePassword(p *db.Password) storage.Password { func toStoragePassword(p *db.Password) storage.Password {
return storage.Password{ return storage.Password{
Email: p.Email, Email: p.Email,
Hash: p.Hash, Hash: p.Hash,
Username: p.Username, Username: p.Username,
UserID: p.UserID, PreferredUsername: p.PreferredUsername,
UserID: p.UserID,
Groups: p.Groups,
} }
} }

2
storage/ent/db/migrate/schema.go

@ -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: "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: "hash", Type: field.TypeBytes},
{Name: "username", Type: field.TypeString, Size: 2147483647, SchemaType: map[string]string{"mysql": "varchar(384)", "postgres": "text", "sqlite3": "text"}}, {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: "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 holds the schema information for the "passwords" table.
PasswordsTable = &schema.Table{ PasswordsTable = &schema.Table{

173
storage/ent/db/mutation.go

@ -6314,17 +6314,20 @@ func (m *OfflineSessionMutation) ResetEdge(name string) error {
// PasswordMutation represents an operation that mutates the Password nodes in the graph. // PasswordMutation represents an operation that mutates the Password nodes in the graph.
type PasswordMutation struct { type PasswordMutation struct {
config config
op Op op Op
typ string typ string
id *int id *int
email *string email *string
hash *[]byte hash *[]byte
username *string username *string
user_id *string preferred_username *string
clearedFields map[string]struct{} user_id *string
done bool groups *[]string
oldValue func(context.Context) (*Password, error) appendgroups []string
predicates []predicate.Password clearedFields map[string]struct{}
done bool
oldValue func(context.Context) (*Password, error)
predicates []predicate.Password
} }
var _ ent.Mutation = (*PasswordMutation)(nil) var _ ent.Mutation = (*PasswordMutation)(nil)
@ -6533,6 +6536,42 @@ func (m *PasswordMutation) ResetUsername() {
m.username = nil 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. // SetUserID sets the "user_id" field.
func (m *PasswordMutation) SetUserID(s string) { func (m *PasswordMutation) SetUserID(s string) {
m.user_id = &s m.user_id = &s
@ -6569,6 +6608,71 @@ func (m *PasswordMutation) ResetUserID() {
m.user_id = nil 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. // Where appends a list predicates to the PasswordMutation builder.
func (m *PasswordMutation) Where(ps ...predicate.Password) { func (m *PasswordMutation) Where(ps ...predicate.Password) {
m.predicates = append(m.predicates, ps...) 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 // order to get all numeric fields that were incremented/decremented, call
// AddedFields(). // AddedFields().
func (m *PasswordMutation) Fields() []string { func (m *PasswordMutation) Fields() []string {
fields := make([]string, 0, 4) fields := make([]string, 0, 6)
if m.email != nil { if m.email != nil {
fields = append(fields, password.FieldEmail) fields = append(fields, password.FieldEmail)
} }
@ -6613,9 +6717,15 @@ func (m *PasswordMutation) Fields() []string {
if m.username != nil { if m.username != nil {
fields = append(fields, password.FieldUsername) fields = append(fields, password.FieldUsername)
} }
if m.preferred_username != nil {
fields = append(fields, password.FieldPreferredUsername)
}
if m.user_id != nil { if m.user_id != nil {
fields = append(fields, password.FieldUserID) fields = append(fields, password.FieldUserID)
} }
if m.groups != nil {
fields = append(fields, password.FieldGroups)
}
return fields return fields
} }
@ -6630,8 +6740,12 @@ func (m *PasswordMutation) Field(name string) (ent.Value, bool) {
return m.Hash() return m.Hash()
case password.FieldUsername: case password.FieldUsername:
return m.Username() return m.Username()
case password.FieldPreferredUsername:
return m.PreferredUsername()
case password.FieldUserID: case password.FieldUserID:
return m.UserID() return m.UserID()
case password.FieldGroups:
return m.Groups()
} }
return nil, false return nil, false
} }
@ -6647,8 +6761,12 @@ func (m *PasswordMutation) OldField(ctx context.Context, name string) (ent.Value
return m.OldHash(ctx) return m.OldHash(ctx)
case password.FieldUsername: case password.FieldUsername:
return m.OldUsername(ctx) return m.OldUsername(ctx)
case password.FieldPreferredUsername:
return m.OldPreferredUsername(ctx)
case password.FieldUserID: case password.FieldUserID:
return m.OldUserID(ctx) return m.OldUserID(ctx)
case password.FieldGroups:
return m.OldGroups(ctx)
} }
return nil, fmt.Errorf("unknown Password field %s", name) 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) m.SetUsername(v)
return nil 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: case password.FieldUserID:
v, ok := value.(string) v, ok := value.(string)
if !ok { if !ok {
@ -6686,6 +6811,13 @@ func (m *PasswordMutation) SetField(name string, value ent.Value) error {
} }
m.SetUserID(v) m.SetUserID(v)
return nil 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) 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 // ClearedFields returns all nullable fields that were cleared during this
// mutation. // mutation.
func (m *PasswordMutation) ClearedFields() []string { 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 // 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 // ClearField clears the value of the field with the given name. It returns an
// error if the field is not defined in the schema. // error if the field is not defined in the schema.
func (m *PasswordMutation) ClearField(name string) error { 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) return fmt.Errorf("unknown Password nullable field %s", name)
} }
@ -6744,9 +6885,15 @@ func (m *PasswordMutation) ResetField(name string) error {
case password.FieldUsername: case password.FieldUsername:
m.ResetUsername() m.ResetUsername()
return nil return nil
case password.FieldPreferredUsername:
m.ResetPreferredUsername()
return nil
case password.FieldUserID: case password.FieldUserID:
m.ResetUserID() m.ResetUserID()
return nil return nil
case password.FieldGroups:
m.ResetGroups()
return nil
} }
return fmt.Errorf("unknown Password field %s", name) return fmt.Errorf("unknown Password field %s", name)
} }

31
storage/ent/db/password.go

@ -3,6 +3,7 @@
package db package db
import ( import (
"encoding/json"
"fmt" "fmt"
"strings" "strings"
@ -22,8 +23,12 @@ type Password struct {
Hash []byte `json:"hash,omitempty"` Hash []byte `json:"hash,omitempty"`
// Username holds the value of the "username" field. // Username holds the value of the "username" field.
Username string `json:"username,omitempty"` 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 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 selectValues sql.SelectValues
} }
@ -32,11 +37,11 @@ func (*Password) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns)) values := make([]any, len(columns))
for i := range columns { for i := range columns {
switch columns[i] { switch columns[i] {
case password.FieldHash: case password.FieldHash, password.FieldGroups:
values[i] = new([]byte) values[i] = new([]byte)
case password.FieldID: case password.FieldID:
values[i] = new(sql.NullInt64) 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) values[i] = new(sql.NullString)
default: default:
values[i] = new(sql.UnknownType) values[i] = new(sql.UnknownType)
@ -77,12 +82,26 @@ func (_m *Password) assignValues(columns []string, values []any) error {
} else if value.Valid { } else if value.Valid {
_m.Username = value.String _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: case password.FieldUserID:
if value, ok := values[i].(*sql.NullString); !ok { if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field user_id", values[i]) return fmt.Errorf("unexpected type %T for field user_id", values[i])
} else if value.Valid { } else if value.Valid {
_m.UserID = value.String _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: default:
_m.selectValues.Set(columns[i], values[i]) _m.selectValues.Set(columns[i], values[i])
} }
@ -128,8 +147,14 @@ func (_m *Password) String() string {
builder.WriteString("username=") builder.WriteString("username=")
builder.WriteString(_m.Username) builder.WriteString(_m.Username)
builder.WriteString(", ") builder.WriteString(", ")
builder.WriteString("preferred_username=")
builder.WriteString(_m.PreferredUsername)
builder.WriteString(", ")
builder.WriteString("user_id=") builder.WriteString("user_id=")
builder.WriteString(_m.UserID) builder.WriteString(_m.UserID)
builder.WriteString(", ")
builder.WriteString("groups=")
builder.WriteString(fmt.Sprintf("%v", _m.Groups))
builder.WriteByte(')') builder.WriteByte(')')
return builder.String() return builder.String()
} }

13
storage/ent/db/password/password.go

@ -17,8 +17,12 @@ const (
FieldHash = "hash" FieldHash = "hash"
// FieldUsername holds the string denoting the username field in the database. // FieldUsername holds the string denoting the username field in the database.
FieldUsername = "username" 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 holds the string denoting the user_id field in the database.
FieldUserID = "user_id" 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 holds the table name of the password in the database.
Table = "passwords" Table = "passwords"
) )
@ -29,7 +33,9 @@ var Columns = []string{
FieldEmail, FieldEmail,
FieldHash, FieldHash,
FieldUsername, FieldUsername,
FieldPreferredUsername,
FieldUserID, FieldUserID,
FieldGroups,
} }
// ValidColumn reports if the column name is valid (part of the table columns). // ValidColumn reports if the column name is valid (part of the table columns).
@ -47,6 +53,8 @@ var (
EmailValidator func(string) error EmailValidator func(string) error
// UsernameValidator is a validator for the "username" field. It is called by the builders before save. // UsernameValidator is a validator for the "username" field. It is called by the builders before save.
UsernameValidator func(string) error 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 is a validator for the "user_id" field. It is called by the builders before save.
UserIDValidator func(string) error UserIDValidator func(string) error
) )
@ -69,6 +77,11 @@ func ByUsername(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUsername, opts...).ToFunc() 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. // ByUserID orders the results by the user_id field.
func ByUserID(opts ...sql.OrderTermOption) OrderOption { func ByUserID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUserID, opts...).ToFunc() return sql.OrderByField(FieldUserID, opts...).ToFunc()

80
storage/ent/db/password/where.go

@ -67,6 +67,11 @@ func Username(v string) predicate.Password {
return predicate.Password(sql.FieldEQ(FieldUsername, v)) 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. // UserID applies equality check predicate on the "user_id" field. It's identical to UserIDEQ.
func UserID(v string) predicate.Password { func UserID(v string) predicate.Password {
return predicate.Password(sql.FieldEQ(FieldUserID, v)) return predicate.Password(sql.FieldEQ(FieldUserID, v))
@ -242,6 +247,71 @@ func UsernameContainsFold(v string) predicate.Password {
return predicate.Password(sql.FieldContainsFold(FieldUsername, v)) 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. // UserIDEQ applies the EQ predicate on the "user_id" field.
func UserIDEQ(v string) predicate.Password { func UserIDEQ(v string) predicate.Password {
return predicate.Password(sql.FieldEQ(FieldUserID, v)) return predicate.Password(sql.FieldEQ(FieldUserID, v))
@ -307,6 +377,16 @@ func UserIDContainsFold(v string) predicate.Password {
return predicate.Password(sql.FieldContainsFold(FieldUserID, v)) 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. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.Password) predicate.Password { func And(predicates ...predicate.Password) predicate.Password {
return predicate.Password(sql.AndPredicates(predicates...)) return predicate.Password(sql.AndPredicates(predicates...))

41
storage/ent/db/password_create.go

@ -37,12 +37,32 @@ func (_c *PasswordCreate) SetUsername(v string) *PasswordCreate {
return _c 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. // SetUserID sets the "user_id" field.
func (_c *PasswordCreate) SetUserID(v string) *PasswordCreate { func (_c *PasswordCreate) SetUserID(v string) *PasswordCreate {
_c.mutation.SetUserID(v) _c.mutation.SetUserID(v)
return _c 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. // Mutation returns the PasswordMutation object of the builder.
func (_c *PasswordCreate) Mutation() *PasswordMutation { func (_c *PasswordCreate) Mutation() *PasswordMutation {
return _c.mutation return _c.mutation
@ -50,6 +70,7 @@ func (_c *PasswordCreate) Mutation() *PasswordMutation {
// Save creates the Password in the database. // Save creates the Password in the database.
func (_c *PasswordCreate) Save(ctx context.Context) (*Password, error) { func (_c *PasswordCreate) Save(ctx context.Context) (*Password, error) {
_c.defaults()
return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) 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. // check runs all checks and user-defined validators on the builder.
func (_c *PasswordCreate) check() error { func (_c *PasswordCreate) check() error {
if _, ok := _c.mutation.Email(); !ok { 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)} 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 { if _, ok := _c.mutation.UserID(); !ok {
return &ValidationError{Name: "user_id", err: errors.New(`db: missing required field "Password.user_id"`)} 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) _spec.SetField(password.FieldUsername, field.TypeString, value)
_node.Username = 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 { if value, ok := _c.mutation.UserID(); ok {
_spec.SetField(password.FieldUserID, field.TypeString, value) _spec.SetField(password.FieldUserID, field.TypeString, value)
_node.UserID = value _node.UserID = value
} }
if value, ok := _c.mutation.Groups(); ok {
_spec.SetField(password.FieldGroups, field.TypeJSON, value)
_node.Groups = value
}
return _node, _spec return _node, _spec
} }
@ -167,6 +207,7 @@ func (_c *PasswordCreateBulk) Save(ctx context.Context) ([]*Password, error) {
for i := range _c.builders { for i := range _c.builders {
func(i int, root context.Context) { func(i int, root context.Context) {
builder := _c.builders[i] builder := _c.builders[i]
builder.defaults()
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*PasswordMutation) mutation, ok := m.(*PasswordMutation)
if !ok { if !ok {

93
storage/ent/db/password_update.go

@ -9,6 +9,7 @@ import (
"entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/dialect/sql/sqljson"
"entgo.io/ent/schema/field" "entgo.io/ent/schema/field"
"github.com/dexidp/dex/storage/ent/db/password" "github.com/dexidp/dex/storage/ent/db/password"
"github.com/dexidp/dex/storage/ent/db/predicate" "github.com/dexidp/dex/storage/ent/db/predicate"
@ -61,6 +62,20 @@ func (_u *PasswordUpdate) SetNillableUsername(v *string) *PasswordUpdate {
return _u 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. // SetUserID sets the "user_id" field.
func (_u *PasswordUpdate) SetUserID(v string) *PasswordUpdate { func (_u *PasswordUpdate) SetUserID(v string) *PasswordUpdate {
_u.mutation.SetUserID(v) _u.mutation.SetUserID(v)
@ -75,6 +90,24 @@ func (_u *PasswordUpdate) SetNillableUserID(v *string) *PasswordUpdate {
return _u 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. // Mutation returns the PasswordMutation object of the builder.
func (_u *PasswordUpdate) Mutation() *PasswordMutation { func (_u *PasswordUpdate) Mutation() *PasswordMutation {
return _u.mutation 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 { if value, ok := _u.mutation.Username(); ok {
_spec.SetField(password.FieldUsername, field.TypeString, value) _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 { if value, ok := _u.mutation.UserID(); ok {
_spec.SetField(password.FieldUserID, field.TypeString, value) _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 _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok { if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{password.Label} err = &NotFoundError{password.Label}
@ -205,6 +252,20 @@ func (_u *PasswordUpdateOne) SetNillableUsername(v *string) *PasswordUpdateOne {
return _u 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. // SetUserID sets the "user_id" field.
func (_u *PasswordUpdateOne) SetUserID(v string) *PasswordUpdateOne { func (_u *PasswordUpdateOne) SetUserID(v string) *PasswordUpdateOne {
_u.mutation.SetUserID(v) _u.mutation.SetUserID(v)
@ -219,6 +280,24 @@ func (_u *PasswordUpdateOne) SetNillableUserID(v *string) *PasswordUpdateOne {
return _u 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. // Mutation returns the PasswordMutation object of the builder.
func (_u *PasswordUpdateOne) Mutation() *PasswordMutation { func (_u *PasswordUpdateOne) Mutation() *PasswordMutation {
return _u.mutation return _u.mutation
@ -322,9 +401,23 @@ func (_u *PasswordUpdateOne) sqlSave(ctx context.Context) (_node *Password, err
if value, ok := _u.mutation.Username(); ok { if value, ok := _u.mutation.Username(); ok {
_spec.SetField(password.FieldUsername, field.TypeString, value) _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 { if value, ok := _u.mutation.UserID(); ok {
_spec.SetField(password.FieldUserID, field.TypeString, value) _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} _node = &Password{config: _u.config}
_spec.Assign = _node.assignValues _spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues _spec.ScanValues = _node.scanValues

6
storage/ent/db/runtime.go

@ -212,8 +212,12 @@ func init() {
passwordDescUsername := passwordFields[2].Descriptor() passwordDescUsername := passwordFields[2].Descriptor()
// password.UsernameValidator is a validator for the "username" field. It is called by the builders before save. // 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) 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 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 is a validator for the "user_id" field. It is called by the builders before save.
password.UserIDValidator = passwordDescUserID.Validators[0].(func(string) error) password.UserIDValidator = passwordDescUserID.Validators[0].(func(string) error)
refreshtokenFields := schema.RefreshToken{}.Fields() refreshtokenFields := schema.RefreshToken{}.Fields()

5
storage/ent/schema/password.go

@ -32,9 +32,14 @@ func (Password) Fields() []ent.Field {
field.Text("username"). field.Text("username").
SchemaType(textSchema). SchemaType(textSchema).
NotEmpty(), NotEmpty(),
field.Text("preferred_username").
SchemaType(textSchema).
Default(""),
field.Text("user_id"). field.Text("user_id").
SchemaType(textSchema). SchemaType(textSchema).
NotEmpty(), NotEmpty(),
field.JSON("groups", []string{}).
Optional(),
} }
} }

8
storage/kubernetes/storage.go

@ -383,13 +383,7 @@ func (cli *client) ListPasswords(ctx context.Context) (passwords []storage.Passw
} }
for _, password := range passwordList.Passwords { for _, password := range passwordList.Passwords {
p := storage.Password{ passwords = append(passwords, toStoragePassword(password))
Email: password.Email,
Hash: password.Hash,
Username: password.Username,
UserID: password.UserID,
}
passwords = append(passwords, p)
} }
return return

28
storage/kubernetes/types.go

@ -431,9 +431,11 @@ type Password struct {
// This field is IMMUTABLE. Do not change. // This field is IMMUTABLE. Do not change.
Email string `json:"email,omitempty"` Email string `json:"email,omitempty"`
Hash []byte `json:"hash,omitempty"` Hash []byte `json:"hash,omitempty"`
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
UserID string `json:"userID,omitempty"` PreferredUsername string `json:"preferredUsername,omitempty"`
UserID string `json:"userID,omitempty"`
Groups []string `json:"groups,omitempty"`
} }
// PasswordList is a list of Passwords. // PasswordList is a list of Passwords.
@ -454,19 +456,23 @@ func (cli *client) fromStoragePassword(p storage.Password) Password {
Name: cli.idToName(email), Name: cli.idToName(email),
Namespace: cli.namespace, Namespace: cli.namespace,
}, },
Email: email, Email: email,
Hash: p.Hash, Hash: p.Hash,
Username: p.Username, Username: p.Username,
UserID: p.UserID, PreferredUsername: p.PreferredUsername,
UserID: p.UserID,
Groups: p.Groups,
} }
} }
func toStoragePassword(p Password) storage.Password { func toStoragePassword(p Password) storage.Password {
return storage.Password{ return storage.Password{
Email: p.Email, Email: p.Email,
Hash: p.Hash, Hash: p.Hash,
Username: p.Username, Username: p.Username,
UserID: p.UserID, PreferredUsername: p.PreferredUsername,
UserID: p.UserID,
Groups: p.Groups,
} }
} }

18
storage/sql/crud.go

@ -598,13 +598,13 @@ func (c *conn) CreatePassword(ctx context.Context, p storage.Password) error {
p.Email = strings.ToLower(p.Email) p.Email = strings.ToLower(p.Email)
_, err := c.Exec(` _, err := c.Exec(`
insert into password ( insert into password (
email, hash, username, user_id email, hash, username, preferred_username, user_id, groups
) )
values ( values (
$1, $2, $3, $4 $1, $2, $3, $4, $5, $6
); );
`, `,
p.Email, p.Hash, p.Username, p.UserID, p.Email, p.Hash, p.Username, p.PreferredUsername, p.UserID, encoder(p.Groups),
) )
if err != nil { if err != nil {
if c.alreadyExistsCheck(err) { if c.alreadyExistsCheck(err) {
@ -629,10 +629,10 @@ func (c *conn) UpdatePassword(ctx context.Context, email string, updater func(p
_, err = tx.Exec(` _, err = tx.Exec(`
update password update password
set set
hash = $1, username = $2, user_id = $3 hash = $1, username = $2, preferred_username = $3, user_id = $4, groups = $5
where email = $4; where email = $6;
`, `,
np.Hash, np.Username, np.UserID, p.Email, np.Hash, np.Username, np.PreferredUsername, np.UserID, encoder(np.Groups), p.Email,
) )
if err != nil { if err != nil {
return fmt.Errorf("update password: %v", err) return fmt.Errorf("update password: %v", err)
@ -648,7 +648,7 @@ func (c *conn) GetPassword(ctx context.Context, email string) (storage.Password,
func getPassword(ctx context.Context, q querier, email string) (p storage.Password, err error) { func getPassword(ctx context.Context, q querier, email string) (p storage.Password, err error) {
return scanPassword(q.QueryRow(` return scanPassword(q.QueryRow(`
select select
email, hash, username, user_id email, hash, username, preferred_username, user_id, groups
from password where email = $1; from password where email = $1;
`, strings.ToLower(email))) `, strings.ToLower(email)))
} }
@ -656,7 +656,7 @@ func getPassword(ctx context.Context, q querier, email string) (p storage.Passwo
func (c *conn) ListPasswords(ctx context.Context) ([]storage.Password, error) { func (c *conn) ListPasswords(ctx context.Context) ([]storage.Password, error) {
rows, err := c.Query(` rows, err := c.Query(`
select select
email, hash, username, user_id email, hash, username, preferred_username, user_id, groups
from password; from password;
`) `)
if err != nil { if err != nil {
@ -680,7 +680,7 @@ func (c *conn) ListPasswords(ctx context.Context) ([]storage.Password, error) {
func scanPassword(s scanner) (p storage.Password, err error) { func scanPassword(s scanner) (p storage.Password, err error) {
err = s.Scan( err = s.Scan(
&p.Email, &p.Hash, &p.Username, &p.UserID, &p.Email, &p.Hash, &p.Username, &p.PreferredUsername, &p.UserID, decoder(&p.Groups),
) )
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {

40
storage/sql/migrate.go

@ -298,4 +298,44 @@ var migrations = []migration{
add column hmac_key bytea;`, add column hmac_key bytea;`,
}, },
}, },
{
stmts: []string{
`
alter table password
add column preferred_username text not null default '';`,
`
alter table password
add column groups bytea not null default convert_to('[]', 'UTF8');`,
},
flavor: &flavorPostgres,
},
{
stmts: []string{
`
alter table password
add column preferred_username text not null default '';`,
`
alter table password
add column groups bytea not null default '[]';`,
},
flavor: &flavorSQLite3,
},
{
stmts: []string{
`
alter table password
add column preferred_username text not null default '';`,
`
alter table password
add column groups bytea;`,
`
update password
set groups = '[]'
where groups is null;`,
`
alter table password
modify column groups bytea not null;`,
},
flavor: &flavorMySQL,
},
} }

6
storage/storage.go

@ -352,8 +352,14 @@ type Password struct {
// Optional username to display. NOT used during login. // Optional username to display. NOT used during login.
Username string `json:"username"` Username string `json:"username"`
// Optional preferred username for OIDC "preferred_username" claim.
PreferredUsername string `json:"preferredUsername"`
// Randomly generated user ID. This is NOT the primary ID of the Password object. // Randomly generated user ID. This is NOT the primary ID of the Password object.
UserID string `json:"userID"` UserID string `json:"userID"`
// Groups assigned to the user
Groups []string `json:"groups"`
} }
// Connector is an object that contains the metadata about connectors used to login to Dex. // Connector is an object that contains the metadata about connectors used to login to Dex.

Loading…
Cancel
Save