Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
D
dex
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
dex
Commits
42c1eed2
Commit
42c1eed2
authored
Mar 28, 2017
by
rithu leena john
Committed by
GitHub
Mar 28, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #880 from rithujohn191/connector-object
storage: add connector object to backend storage.
parents
6e50c184
bc55b86d
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
363 additions
and
0 deletions
+363
-0
conformance.go
storage/conformance/conformance.go
+69
-0
storage.go
storage/kubernetes/storage.go
+49
-0
types.go
storage/kubernetes/types.go
+57
-0
memory.go
storage/memory/memory.go
+57
-0
crud.go
storage/sql/crud.go
+99
-0
migrate.go
storage/sql/migrate.go
+11
-0
storage.go
storage/storage.go
+21
-0
No files found.
storage/conformance/conformance.go
View file @
42c1eed2
...
...
@@ -48,6 +48,7 @@ func RunTests(t *testing.T, newStorage func() storage.Storage) {
{
"PasswordCRUD"
,
testPasswordCRUD
},
{
"KeysCRUD"
,
testKeysCRUD
},
{
"OfflineSessionCRUD"
,
testOfflineSessionCRUD
},
{
"ConnectorCRUD"
,
testConnectorCRUD
},
{
"GarbageCollection"
,
testGC
},
{
"TimezoneSupport"
,
testTimezones
},
})
...
...
@@ -571,6 +572,74 @@ func testOfflineSessionCRUD(t *testing.T, s storage.Storage) {
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
)
{
updateAndCompare
:=
func
(
k
storage
.
Keys
)
{
err
:=
s
.
UpdateKeys
(
func
(
oldKeys
storage
.
Keys
)
(
storage
.
Keys
,
error
)
{
...
...
storage/kubernetes/storage.go
View file @
42c1eed2
...
...
@@ -20,6 +20,7 @@ const (
kindKeys
=
"SigningKey"
kindPassword
=
"Password"
kindOfflineSessions
=
"OfflineSessions"
kindConnector
=
"Connector"
)
const
(
...
...
@@ -30,6 +31,7 @@ const (
resourceKeys
=
"signingkeies"
// Kubernetes attempts to pluralize.
resourcePassword
=
"passwords"
resourceOfflineSessions
=
"offlinesessionses"
// Again attempts to pluralize.
resourceConnector
=
"connectors"
)
// 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
))
}
func
(
cli
*
client
)
CreateConnector
(
c
storage
.
Connector
)
error
{
return
cli
.
post
(
resourceConnector
,
cli
.
fromStorageConnector
(
c
))
}
func
(
cli
*
client
)
GetAuthRequest
(
id
string
)
(
storage
.
AuthRequest
,
error
)
{
var
req
AuthRequest
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
}
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
)
{
return
nil
,
errors
.
New
(
"not implemented"
)
}
...
...
@@ -298,6 +312,20 @@ func (cli *client) ListPasswords() (passwords []storage.Password, err error) {
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
{
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
)
}
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
{
r
,
err
:=
cli
.
getRefreshToken
(
id
)
if
err
!=
nil
{
...
...
@@ -446,6 +478,23 @@ func (cli *client) UpdateAuthRequest(id string, updater func(a storage.AuthReque
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
)
{
var
authRequests
AuthRequestList
if
err
:=
cli
.
list
(
resourceAuthRequest
,
&
authRequests
);
err
!=
nil
{
...
...
storage/kubernetes/types.go
View file @
42c1eed2
...
...
@@ -74,6 +74,14 @@ var thirdPartyResources = []k8sapi.ThirdPartyResource{
Description
:
"User sessions with an active refresh token."
,
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
...
...
@@ -513,3 +521,52 @@ func toStorageOfflineSessions(o OfflineSessions) storage.OfflineSessions {
}
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"`
}
storage/memory/memory.go
View file @
42c1eed2
...
...
@@ -19,6 +19,7 @@ func New(logger logrus.FieldLogger) storage.Storage {
authReqs
:
make
(
map
[
string
]
storage
.
AuthRequest
),
passwords
:
make
(
map
[
string
]
storage
.
Password
),
offlineSessions
:
make
(
map
[
offlineSessionID
]
storage
.
OfflineSessions
),
connectors
:
make
(
map
[
string
]
storage
.
Connector
),
logger
:
logger
,
}
}
...
...
@@ -44,6 +45,7 @@ type memStorage struct {
authReqs
map
[
string
]
storage
.
AuthRequest
passwords
map
[
string
]
storage
.
Password
offlineSessions
map
[
offlineSessionID
]
storage
.
OfflineSessions
connectors
map
[
string
]
storage
.
Connector
keys
storage
.
Keys
...
...
@@ -152,6 +154,17 @@ func (s *memStorage) CreateOfflineSessions(o storage.OfflineSessions) (err error
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
)
{
s
.
tx
(
func
()
{
var
ok
bool
...
...
@@ -226,6 +239,16 @@ func (s *memStorage) GetOfflineSessions(userID string, connID string) (o storage
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
)
{
s
.
tx
(
func
()
{
for
_
,
client
:=
range
s
.
clients
{
...
...
@@ -253,6 +276,15 @@ func (s *memStorage) ListPasswords() (passwords []storage.Password, err error) {
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
)
{
email
=
strings
.
ToLower
(
email
)
s
.
tx
(
func
()
{
...
...
@@ -324,6 +356,17 @@ func (s *memStorage) DeleteOfflineSessions(userID string, connID string) (err er
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
)
{
s
.
tx
(
func
()
{
client
,
ok
:=
s
.
clients
[
id
]
...
...
@@ -408,3 +451,17 @@ func (s *memStorage) UpdateOfflineSessions(userID string, connID string, updater
})
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
}
storage/sql/crud.go
View file @
42c1eed2
...
...
@@ -717,6 +717,104 @@ func scanOfflineSessions(s scanner) (o storage.OfflineSessions, err error) {
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
)
DeleteAuthCode
(
id
string
)
error
{
return
c
.
delete
(
"auth_code"
,
"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
{
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
{
result
,
err
:=
c
.
Exec
(
`delete from offline_session where user_id = $1 AND conn_id = $2`
,
userID
,
connID
)
...
...
storage/sql/migrate.go
View file @
42c1eed2
...
...
@@ -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
);
`
,
},
}
storage/storage.go
View file @
42c1eed2
...
...
@@ -53,6 +53,7 @@ type Storage interface {
CreateRefresh
(
r
RefreshToken
)
error
CreatePassword
(
p
Password
)
error
CreateOfflineSessions
(
s
OfflineSessions
)
error
CreateConnector
(
c
Connector
)
error
// TODO(ericchiang): return (T, bool, error) so we can indicate not found
// requests that way instead of using ErrNotFound.
...
...
@@ -63,10 +64,12 @@ type Storage interface {
GetRefresh
(
id
string
)
(
RefreshToken
,
error
)
GetPassword
(
email
string
)
(
Password
,
error
)
GetOfflineSessions
(
userID
string
,
connID
string
)
(
OfflineSessions
,
error
)
GetConnector
(
id
string
)
(
Connector
,
error
)
ListClients
()
([]
Client
,
error
)
ListRefreshTokens
()
([]
RefreshToken
,
error
)
ListPasswords
()
([]
Password
,
error
)
ListConnectors
()
([]
Connector
,
error
)
// Delete methods MUST be atomic.
DeleteAuthRequest
(
id
string
)
error
...
...
@@ -75,6 +78,7 @@ type Storage interface {
DeleteRefresh
(
id
string
)
error
DeletePassword
(
email
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
// 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
UpdatePassword
(
email
string
,
updater
func
(
p
Password
)
(
Password
,
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
(
now
time
.
Time
)
(
GCResult
,
error
)
...
...
@@ -290,6 +295,22 @@ type Password struct {
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
// signatures.
type
VerificationKey
struct
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment