forked from mystiq/dex
storage: add connector object to backend storage.
This commit is contained in:
parent
6e50c18458
commit
bc55b86d0d
7 changed files with 363 additions and 0 deletions
|
@ -48,6 +48,7 @@ func RunTests(t *testing.T, newStorage func() storage.Storage) {
|
||||||
{"PasswordCRUD", testPasswordCRUD},
|
{"PasswordCRUD", testPasswordCRUD},
|
||||||
{"KeysCRUD", testKeysCRUD},
|
{"KeysCRUD", testKeysCRUD},
|
||||||
{"OfflineSessionCRUD", testOfflineSessionCRUD},
|
{"OfflineSessionCRUD", testOfflineSessionCRUD},
|
||||||
|
{"ConnectorCRUD", testConnectorCRUD},
|
||||||
{"GarbageCollection", testGC},
|
{"GarbageCollection", testGC},
|
||||||
{"TimezoneSupport", testTimezones},
|
{"TimezoneSupport", testTimezones},
|
||||||
})
|
})
|
||||||
|
@ -571,6 +572,74 @@ func testOfflineSessionCRUD(t *testing.T, s storage.Storage) {
|
||||||
mustBeErrNotFound(t, "offline session", err)
|
mustBeErrNotFound(t, "offline session", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testConnectorCRUD(t *testing.T, s storage.Storage) {
|
||||||
|
id1 := storage.NewID()
|
||||||
|
config1 := []byte(`{"issuer": "https://accounts.google.com"}`)
|
||||||
|
c1 := storage.Connector{
|
||||||
|
ID: id1,
|
||||||
|
Type: "Default",
|
||||||
|
Name: "Default",
|
||||||
|
ResourceVersion: "1",
|
||||||
|
Config: config1,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.CreateConnector(c1); err != nil {
|
||||||
|
t.Fatalf("create connector with ID = %s: %v", c1.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to create same Connector twice.
|
||||||
|
err := s.CreateConnector(c1)
|
||||||
|
mustBeErrAlreadyExists(t, "connector", err)
|
||||||
|
|
||||||
|
id2 := storage.NewID()
|
||||||
|
config2 := []byte(`{"redirectURIi": "http://127.0.0.1:5556/dex/callback"}`)
|
||||||
|
c2 := storage.Connector{
|
||||||
|
ID: id2,
|
||||||
|
Type: "Mock",
|
||||||
|
Name: "Mock",
|
||||||
|
ResourceVersion: "2",
|
||||||
|
Config: config2,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.CreateConnector(c2); err != nil {
|
||||||
|
t.Fatalf("create connector with ID = %s: %v", c2.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getAndCompare := func(id string, want storage.Connector) {
|
||||||
|
gr, err := s.GetConnector(id)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("get connector: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(want, gr); diff != "" {
|
||||||
|
t.Errorf("connector retrieved from storage did not match: %s", diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getAndCompare(id1, c1)
|
||||||
|
|
||||||
|
if err := s.UpdateConnector(c1.ID, func(old storage.Connector) (storage.Connector, error) {
|
||||||
|
old.Type = "oidc"
|
||||||
|
return old, nil
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("failed to update Connector: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c1.Type = "oidc"
|
||||||
|
getAndCompare(id1, c1)
|
||||||
|
|
||||||
|
if err := s.DeleteConnector(c1.ID); err != nil {
|
||||||
|
t.Fatalf("failed to delete connector: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.DeleteConnector(c2.ID); err != nil {
|
||||||
|
t.Fatalf("failed to delete connector: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.GetConnector(c1.ID)
|
||||||
|
mustBeErrNotFound(t, "connector", err)
|
||||||
|
}
|
||||||
|
|
||||||
func testKeysCRUD(t *testing.T, s storage.Storage) {
|
func testKeysCRUD(t *testing.T, s storage.Storage) {
|
||||||
updateAndCompare := func(k storage.Keys) {
|
updateAndCompare := func(k storage.Keys) {
|
||||||
err := s.UpdateKeys(func(oldKeys storage.Keys) (storage.Keys, error) {
|
err := s.UpdateKeys(func(oldKeys storage.Keys) (storage.Keys, error) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ const (
|
||||||
kindKeys = "SigningKey"
|
kindKeys = "SigningKey"
|
||||||
kindPassword = "Password"
|
kindPassword = "Password"
|
||||||
kindOfflineSessions = "OfflineSessions"
|
kindOfflineSessions = "OfflineSessions"
|
||||||
|
kindConnector = "Connector"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -30,6 +31,7 @@ const (
|
||||||
resourceKeys = "signingkeies" // Kubernetes attempts to pluralize.
|
resourceKeys = "signingkeies" // Kubernetes attempts to pluralize.
|
||||||
resourcePassword = "passwords"
|
resourcePassword = "passwords"
|
||||||
resourceOfflineSessions = "offlinesessionses" // Again attempts to pluralize.
|
resourceOfflineSessions = "offlinesessionses" // Again attempts to pluralize.
|
||||||
|
resourceConnector = "connectors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config values for the Kubernetes storage type.
|
// Config values for the Kubernetes storage type.
|
||||||
|
@ -173,6 +175,10 @@ func (cli *client) CreateOfflineSessions(o storage.OfflineSessions) error {
|
||||||
return cli.post(resourceOfflineSessions, cli.fromStorageOfflineSessions(o))
|
return cli.post(resourceOfflineSessions, cli.fromStorageOfflineSessions(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cli *client) CreateConnector(c storage.Connector) error {
|
||||||
|
return cli.post(resourceConnector, cli.fromStorageConnector(c))
|
||||||
|
}
|
||||||
|
|
||||||
func (cli *client) GetAuthRequest(id string) (storage.AuthRequest, error) {
|
func (cli *client) GetAuthRequest(id string) (storage.AuthRequest, error) {
|
||||||
var req AuthRequest
|
var req AuthRequest
|
||||||
if err := cli.get(resourceAuthRequest, id, &req); err != nil {
|
if err := cli.get(resourceAuthRequest, id, &req); err != nil {
|
||||||
|
@ -271,6 +277,14 @@ func (cli *client) getOfflineSessions(userID string, connID string) (o OfflineSe
|
||||||
return o, nil
|
return o, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cli *client) GetConnector(id string) (storage.Connector, error) {
|
||||||
|
var c Connector
|
||||||
|
if err := cli.get(resourceConnector, id, &c); err != nil {
|
||||||
|
return storage.Connector{}, err
|
||||||
|
}
|
||||||
|
return toStorageConnector(c), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (cli *client) ListClients() ([]storage.Client, error) {
|
func (cli *client) ListClients() ([]storage.Client, error) {
|
||||||
return nil, errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
@ -298,6 +312,20 @@ func (cli *client) ListPasswords() (passwords []storage.Password, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cli *client) ListConnectors() (connectors []storage.Connector, err error) {
|
||||||
|
var connectorList ConnectorList
|
||||||
|
if err = cli.list(resourceConnector, &connectorList); err != nil {
|
||||||
|
return connectors, fmt.Errorf("failed to list connectors: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
connectors = make([]storage.Connector, len(connectorList.Connectors))
|
||||||
|
for i, connector := range connectorList.Connectors {
|
||||||
|
connectors[i] = toStorageConnector(connector)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (cli *client) DeleteAuthRequest(id string) error {
|
func (cli *client) DeleteAuthRequest(id string) error {
|
||||||
return cli.delete(resourceAuthRequest, id)
|
return cli.delete(resourceAuthRequest, id)
|
||||||
}
|
}
|
||||||
|
@ -337,6 +365,10 @@ func (cli *client) DeleteOfflineSessions(userID string, connID string) error {
|
||||||
return cli.delete(resourceOfflineSessions, o.ObjectMeta.Name)
|
return cli.delete(resourceOfflineSessions, o.ObjectMeta.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cli *client) DeleteConnector(id string) error {
|
||||||
|
return cli.delete(resourceConnector, id)
|
||||||
|
}
|
||||||
|
|
||||||
func (cli *client) UpdateRefreshToken(id string, updater func(old storage.RefreshToken) (storage.RefreshToken, error)) error {
|
func (cli *client) UpdateRefreshToken(id string, updater func(old storage.RefreshToken) (storage.RefreshToken, error)) error {
|
||||||
r, err := cli.getRefreshToken(id)
|
r, err := cli.getRefreshToken(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -446,6 +478,23 @@ func (cli *client) UpdateAuthRequest(id string, updater func(a storage.AuthReque
|
||||||
return cli.put(resourceAuthRequest, id, newReq)
|
return cli.put(resourceAuthRequest, id, newReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cli *client) UpdateConnector(id string, updater func(a storage.Connector) (storage.Connector, error)) error {
|
||||||
|
var c Connector
|
||||||
|
err := cli.get(resourceConnector, id, &c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
updated, err := updater(toStorageConnector(c))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newConn := cli.fromStorageConnector(updated)
|
||||||
|
newConn.ObjectMeta = c.ObjectMeta
|
||||||
|
return cli.put(resourceConnector, id, newConn)
|
||||||
|
}
|
||||||
|
|
||||||
func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err error) {
|
func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err error) {
|
||||||
var authRequests AuthRequestList
|
var authRequests AuthRequestList
|
||||||
if err := cli.list(resourceAuthRequest, &authRequests); err != nil {
|
if err := cli.list(resourceAuthRequest, &authRequests); err != nil {
|
||||||
|
|
|
@ -74,6 +74,14 @@ var thirdPartyResources = []k8sapi.ThirdPartyResource{
|
||||||
Description: "User sessions with an active refresh token.",
|
Description: "User sessions with an active refresh token.",
|
||||||
Versions: []k8sapi.APIVersion{{Name: "v1"}},
|
Versions: []k8sapi.APIVersion{{Name: "v1"}},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: k8sapi.ObjectMeta{
|
||||||
|
Name: "connector.oidc.coreos.com",
|
||||||
|
},
|
||||||
|
TypeMeta: tprMeta,
|
||||||
|
Description: "Connectors available for login",
|
||||||
|
Versions: []k8sapi.APIVersion{{Name: "v1"}},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// There will only ever be a single keys resource. Maintain this by setting a
|
// There will only ever be a single keys resource. Maintain this by setting a
|
||||||
|
@ -513,3 +521,52 @@ func toStorageOfflineSessions(o OfflineSessions) storage.OfflineSessions {
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Connector is a mirrored struct from storage with JSON struct tags and Kubernetes
|
||||||
|
// type metadata.
|
||||||
|
type Connector struct {
|
||||||
|
k8sapi.TypeMeta `json:",inline"`
|
||||||
|
k8sapi.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
ResourceVersion string `json:"resourceVersion,omitempty"`
|
||||||
|
// Config holds connector specific configuration information
|
||||||
|
Config []byte `json:"config,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli *client) fromStorageConnector(c storage.Connector) Connector {
|
||||||
|
return Connector{
|
||||||
|
TypeMeta: k8sapi.TypeMeta{
|
||||||
|
Kind: kindConnector,
|
||||||
|
APIVersion: cli.apiVersion,
|
||||||
|
},
|
||||||
|
ObjectMeta: k8sapi.ObjectMeta{
|
||||||
|
Name: c.ID,
|
||||||
|
Namespace: cli.namespace,
|
||||||
|
},
|
||||||
|
ID: c.ID,
|
||||||
|
Type: c.Type,
|
||||||
|
Name: c.Name,
|
||||||
|
ResourceVersion: c.ResourceVersion,
|
||||||
|
Config: c.Config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toStorageConnector(c Connector) storage.Connector {
|
||||||
|
return storage.Connector{
|
||||||
|
ID: c.ID,
|
||||||
|
Type: c.Type,
|
||||||
|
Name: c.Name,
|
||||||
|
ResourceVersion: c.ResourceVersion,
|
||||||
|
Config: c.Config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectorList is a list of Connectors.
|
||||||
|
type ConnectorList struct {
|
||||||
|
k8sapi.TypeMeta `json:",inline"`
|
||||||
|
k8sapi.ListMeta `json:"metadata,omitempty"`
|
||||||
|
Connectors []Connector `json:"items"`
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ func New(logger logrus.FieldLogger) storage.Storage {
|
||||||
authReqs: make(map[string]storage.AuthRequest),
|
authReqs: make(map[string]storage.AuthRequest),
|
||||||
passwords: make(map[string]storage.Password),
|
passwords: make(map[string]storage.Password),
|
||||||
offlineSessions: make(map[offlineSessionID]storage.OfflineSessions),
|
offlineSessions: make(map[offlineSessionID]storage.OfflineSessions),
|
||||||
|
connectors: make(map[string]storage.Connector),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +45,7 @@ type memStorage struct {
|
||||||
authReqs map[string]storage.AuthRequest
|
authReqs map[string]storage.AuthRequest
|
||||||
passwords map[string]storage.Password
|
passwords map[string]storage.Password
|
||||||
offlineSessions map[offlineSessionID]storage.OfflineSessions
|
offlineSessions map[offlineSessionID]storage.OfflineSessions
|
||||||
|
connectors map[string]storage.Connector
|
||||||
|
|
||||||
keys storage.Keys
|
keys storage.Keys
|
||||||
|
|
||||||
|
@ -152,6 +154,17 @@ func (s *memStorage) CreateOfflineSessions(o storage.OfflineSessions) (err error
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *memStorage) CreateConnector(connector storage.Connector) (err error) {
|
||||||
|
s.tx(func() {
|
||||||
|
if _, ok := s.connectors[connector.ID]; ok {
|
||||||
|
err = storage.ErrAlreadyExists
|
||||||
|
} else {
|
||||||
|
s.connectors[connector.ID] = connector
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *memStorage) GetAuthCode(id string) (c storage.AuthCode, err error) {
|
func (s *memStorage) GetAuthCode(id string) (c storage.AuthCode, err error) {
|
||||||
s.tx(func() {
|
s.tx(func() {
|
||||||
var ok bool
|
var ok bool
|
||||||
|
@ -226,6 +239,16 @@ func (s *memStorage) GetOfflineSessions(userID string, connID string) (o storage
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *memStorage) GetConnector(id string) (connector storage.Connector, err error) {
|
||||||
|
s.tx(func() {
|
||||||
|
var ok bool
|
||||||
|
if connector, ok = s.connectors[id]; !ok {
|
||||||
|
err = storage.ErrNotFound
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *memStorage) ListClients() (clients []storage.Client, err error) {
|
func (s *memStorage) ListClients() (clients []storage.Client, err error) {
|
||||||
s.tx(func() {
|
s.tx(func() {
|
||||||
for _, client := range s.clients {
|
for _, client := range s.clients {
|
||||||
|
@ -253,6 +276,15 @@ func (s *memStorage) ListPasswords() (passwords []storage.Password, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *memStorage) ListConnectors() (conns []storage.Connector, err error) {
|
||||||
|
s.tx(func() {
|
||||||
|
for _, c := range s.connectors {
|
||||||
|
conns = append(conns, c)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *memStorage) DeletePassword(email string) (err error) {
|
func (s *memStorage) DeletePassword(email string) (err error) {
|
||||||
email = strings.ToLower(email)
|
email = strings.ToLower(email)
|
||||||
s.tx(func() {
|
s.tx(func() {
|
||||||
|
@ -324,6 +356,17 @@ func (s *memStorage) DeleteOfflineSessions(userID string, connID string) (err er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *memStorage) DeleteConnector(id string) (err error) {
|
||||||
|
s.tx(func() {
|
||||||
|
if _, ok := s.connectors[id]; !ok {
|
||||||
|
err = storage.ErrNotFound
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(s.connectors, id)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *memStorage) UpdateClient(id string, updater func(old storage.Client) (storage.Client, error)) (err error) {
|
func (s *memStorage) UpdateClient(id string, updater func(old storage.Client) (storage.Client, error)) (err error) {
|
||||||
s.tx(func() {
|
s.tx(func() {
|
||||||
client, ok := s.clients[id]
|
client, ok := s.clients[id]
|
||||||
|
@ -408,3 +451,17 @@ func (s *memStorage) UpdateOfflineSessions(userID string, connID string, updater
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *memStorage) UpdateConnector(id string, updater func(c storage.Connector) (storage.Connector, error)) (err error) {
|
||||||
|
s.tx(func() {
|
||||||
|
r, ok := s.connectors[id]
|
||||||
|
if !ok {
|
||||||
|
err = storage.ErrNotFound
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r, err = updater(r); err == nil {
|
||||||
|
s.connectors[id] = r
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -717,6 +717,104 @@ func scanOfflineSessions(s scanner) (o storage.OfflineSessions, err error) {
|
||||||
return o, nil
|
return o, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *conn) CreateConnector(connector storage.Connector) error {
|
||||||
|
_, err := c.Exec(`
|
||||||
|
insert into connector (
|
||||||
|
id, type, name, resource_version, config
|
||||||
|
)
|
||||||
|
values (
|
||||||
|
$1, $2, $3, $4, $5
|
||||||
|
);
|
||||||
|
`,
|
||||||
|
connector.ID, connector.Type, connector.Name, connector.ResourceVersion, connector.Config,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if c.alreadyExistsCheck(err) {
|
||||||
|
return storage.ErrAlreadyExists
|
||||||
|
}
|
||||||
|
return fmt.Errorf("insert connector: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) UpdateConnector(id string, updater func(s storage.Connector) (storage.Connector, error)) error {
|
||||||
|
return c.ExecTx(func(tx *trans) error {
|
||||||
|
connector, err := getConnector(tx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newConn, err := updater(connector)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tx.Exec(`
|
||||||
|
update connector
|
||||||
|
set
|
||||||
|
type = $1,
|
||||||
|
name = $2,
|
||||||
|
resource_version = $3,
|
||||||
|
config = $4
|
||||||
|
where id = $5;
|
||||||
|
`,
|
||||||
|
newConn.Type, newConn.Name, newConn.ResourceVersion, newConn.Config, connector.ID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("update connector: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) GetConnector(id string) (storage.Connector, error) {
|
||||||
|
return getConnector(c, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConnector(q querier, id string) (storage.Connector, error) {
|
||||||
|
return scanConnector(q.QueryRow(`
|
||||||
|
select
|
||||||
|
id, type, name, resource_version, config
|
||||||
|
from connector
|
||||||
|
where id = $1;
|
||||||
|
`, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanConnector(s scanner) (c storage.Connector, err error) {
|
||||||
|
err = s.Scan(
|
||||||
|
&c.ID, &c.Type, &c.Name, &c.ResourceVersion, &c.Config,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return c, storage.ErrNotFound
|
||||||
|
}
|
||||||
|
return c, fmt.Errorf("select connector: %v", err)
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) ListConnectors() ([]storage.Connector, error) {
|
||||||
|
rows, err := c.Query(`
|
||||||
|
select
|
||||||
|
id, type, name, resource_version, config
|
||||||
|
from connector;
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var connectors []storage.Connector
|
||||||
|
for rows.Next() {
|
||||||
|
conn, err := scanConnector(rows)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
connectors = append(connectors, conn)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return connectors, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *conn) DeleteAuthRequest(id string) error { return c.delete("auth_request", "id", id) }
|
func (c *conn) DeleteAuthRequest(id string) error { return c.delete("auth_request", "id", id) }
|
||||||
func (c *conn) DeleteAuthCode(id string) error { return c.delete("auth_code", "id", id) }
|
func (c *conn) DeleteAuthCode(id string) error { return c.delete("auth_code", "id", id) }
|
||||||
func (c *conn) DeleteClient(id string) error { return c.delete("client", "id", id) }
|
func (c *conn) DeleteClient(id string) error { return c.delete("client", "id", id) }
|
||||||
|
@ -724,6 +822,7 @@ func (c *conn) DeleteRefresh(id string) error { return c.delete("refresh_tok
|
||||||
func (c *conn) DeletePassword(email string) error {
|
func (c *conn) DeletePassword(email string) error {
|
||||||
return c.delete("password", "email", strings.ToLower(email))
|
return c.delete("password", "email", strings.ToLower(email))
|
||||||
}
|
}
|
||||||
|
func (c *conn) DeleteConnector(id string) error { return c.delete("connector", "id", id) }
|
||||||
|
|
||||||
func (c *conn) DeleteOfflineSessions(userID string, connID string) error {
|
func (c *conn) DeleteOfflineSessions(userID string, connID string) error {
|
||||||
result, err := c.Exec(`delete from offline_session where user_id = $1 AND conn_id = $2`, userID, connID)
|
result, err := c.Exec(`delete from offline_session where user_id = $1 AND conn_id = $2`, userID, connID)
|
||||||
|
|
|
@ -176,4 +176,15 @@ var migrations = []migration{
|
||||||
);
|
);
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
stmt: `
|
||||||
|
create table connector (
|
||||||
|
id text not null primary key,
|
||||||
|
type text not null,
|
||||||
|
name text not null,
|
||||||
|
resource_version text not null,
|
||||||
|
config bytea
|
||||||
|
);
|
||||||
|
`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ type Storage interface {
|
||||||
CreateRefresh(r RefreshToken) error
|
CreateRefresh(r RefreshToken) error
|
||||||
CreatePassword(p Password) error
|
CreatePassword(p Password) error
|
||||||
CreateOfflineSessions(s OfflineSessions) error
|
CreateOfflineSessions(s OfflineSessions) error
|
||||||
|
CreateConnector(c Connector) error
|
||||||
|
|
||||||
// TODO(ericchiang): return (T, bool, error) so we can indicate not found
|
// TODO(ericchiang): return (T, bool, error) so we can indicate not found
|
||||||
// requests that way instead of using ErrNotFound.
|
// requests that way instead of using ErrNotFound.
|
||||||
|
@ -63,10 +64,12 @@ type Storage interface {
|
||||||
GetRefresh(id string) (RefreshToken, error)
|
GetRefresh(id string) (RefreshToken, error)
|
||||||
GetPassword(email string) (Password, error)
|
GetPassword(email string) (Password, error)
|
||||||
GetOfflineSessions(userID string, connID string) (OfflineSessions, error)
|
GetOfflineSessions(userID string, connID string) (OfflineSessions, error)
|
||||||
|
GetConnector(id string) (Connector, error)
|
||||||
|
|
||||||
ListClients() ([]Client, error)
|
ListClients() ([]Client, error)
|
||||||
ListRefreshTokens() ([]RefreshToken, error)
|
ListRefreshTokens() ([]RefreshToken, error)
|
||||||
ListPasswords() ([]Password, error)
|
ListPasswords() ([]Password, error)
|
||||||
|
ListConnectors() ([]Connector, error)
|
||||||
|
|
||||||
// Delete methods MUST be atomic.
|
// Delete methods MUST be atomic.
|
||||||
DeleteAuthRequest(id string) error
|
DeleteAuthRequest(id string) error
|
||||||
|
@ -75,6 +78,7 @@ type Storage interface {
|
||||||
DeleteRefresh(id string) error
|
DeleteRefresh(id string) error
|
||||||
DeletePassword(email string) error
|
DeletePassword(email string) error
|
||||||
DeleteOfflineSessions(userID string, connID string) error
|
DeleteOfflineSessions(userID string, connID string) error
|
||||||
|
DeleteConnector(id string) error
|
||||||
|
|
||||||
// Update methods take a function for updating an object then performs that update within
|
// Update methods take a function for updating an object then performs that update within
|
||||||
// a transaction. "updater" functions may be called multiple times by a single update call.
|
// a transaction. "updater" functions may be called multiple times by a single update call.
|
||||||
|
@ -96,6 +100,7 @@ type Storage interface {
|
||||||
UpdateRefreshToken(id string, updater func(r RefreshToken) (RefreshToken, error)) error
|
UpdateRefreshToken(id string, updater func(r RefreshToken) (RefreshToken, error)) error
|
||||||
UpdatePassword(email string, updater func(p Password) (Password, error)) error
|
UpdatePassword(email string, updater func(p Password) (Password, error)) error
|
||||||
UpdateOfflineSessions(userID string, connID string, updater func(s OfflineSessions) (OfflineSessions, error)) error
|
UpdateOfflineSessions(userID string, connID string, updater func(s OfflineSessions) (OfflineSessions, error)) error
|
||||||
|
UpdateConnector(id string, updater func(c Connector) (Connector, error)) error
|
||||||
|
|
||||||
// GarbageCollect deletes all expired AuthCodes and AuthRequests.
|
// GarbageCollect deletes all expired AuthCodes and AuthRequests.
|
||||||
GarbageCollect(now time.Time) (GCResult, error)
|
GarbageCollect(now time.Time) (GCResult, error)
|
||||||
|
@ -290,6 +295,22 @@ type Password struct {
|
||||||
UserID string `json:"userID"`
|
UserID string `json:"userID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Connector is an object that contains the metadata about connectors used to login to Dex.
|
||||||
|
type Connector struct {
|
||||||
|
// ID that will uniquely identify the connector object.
|
||||||
|
ID string
|
||||||
|
// The Type of the connector. E.g. 'oidc' or 'ldap'
|
||||||
|
Type string
|
||||||
|
// The Name of the connector that is used when displaying it to the end user.
|
||||||
|
Name string
|
||||||
|
// ResourceVersion is the static versioning used to keep track of dynamic configuration
|
||||||
|
// changes to the connector object made by the API calls.
|
||||||
|
ResourceVersion string
|
||||||
|
// Config holds all the configuration information specific to the connector type. Since there
|
||||||
|
// no generic struct we can use for this purpose, it is stored as a byte stream.
|
||||||
|
Config []byte
|
||||||
|
}
|
||||||
|
|
||||||
// VerificationKey is a rotated signing key which can still be used to verify
|
// VerificationKey is a rotated signing key which can still be used to verify
|
||||||
// signatures.
|
// signatures.
|
||||||
type VerificationKey struct {
|
type VerificationKey struct {
|
||||||
|
|
Loading…
Reference in a new issue