Server integration test for Device Flow (#3)

Extracted test cases from OAuth2Code flow tests to reuse in device flow

deviceHandler unit tests to test specific device endpoints

Include client secret as an optional parameter for standards compliance

Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
This commit is contained in:
Justin Slowik
2020-02-04 10:07:18 -05:00
committed by justin-slowik
parent 9bbdc721d5
commit 9c699b1028
14 changed files with 1239 additions and 351 deletions

View File

@@ -843,11 +843,12 @@ func testGC(t *testing.T, s storage.Storage) {
}
d := storage.DeviceRequest{
UserCode: userCode,
DeviceCode: storage.NewID(),
ClientID: "client1",
Scopes: []string{"openid", "email"},
Expiry: expiry,
UserCode: userCode,
DeviceCode: storage.NewID(),
ClientID: "client1",
ClientSecret: "secret1",
Scopes: []string{"openid", "email"},
Expiry: expiry,
}
if err := s.CreateDeviceRequest(d); err != nil {
@@ -863,9 +864,9 @@ func testGC(t *testing.T, s storage.Storage) {
t.Errorf("expected no device garbage collection results, got %#v", result)
}
}
//if _, err := s.GetDeviceRequest(d.UserCode); err != nil {
// t.Errorf("expected to be able to get auth request after GC: %v", err)
//}
if _, err := s.GetDeviceRequest(d.UserCode); err != nil {
t.Errorf("expected to be able to get auth request after GC: %v", err)
}
}
if r, err := s.GarbageCollect(expiry.Add(time.Hour)); err != nil {
t.Errorf("garbage collection failed: %v", err)
@@ -873,18 +874,19 @@ func testGC(t *testing.T, s storage.Storage) {
t.Errorf("expected to garbage collect 1 device request, got %d", r.DeviceRequests)
}
//TODO add this code back once Getters are written for device requests
//if _, err := s.GetDeviceRequest(d.UserCode); err == nil {
// t.Errorf("expected device request to be GC'd")
//} else if err != storage.ErrNotFound {
// t.Errorf("expected storage.ErrNotFound, got %v", err)
//}
if _, err := s.GetDeviceRequest(d.UserCode); err == nil {
t.Errorf("expected device request to be GC'd")
} else if err != storage.ErrNotFound {
t.Errorf("expected storage.ErrNotFound, got %v", err)
}
dt := storage.DeviceToken{
DeviceCode: storage.NewID(),
Status: "pending",
Token: "foo",
Expiry: expiry,
DeviceCode: storage.NewID(),
Status: "pending",
Token: "foo",
Expiry: expiry,
LastRequestTime: time.Now(),
PollIntervalSeconds: 0,
}
if err := s.CreateDeviceToken(dt); err != nil {
@@ -969,11 +971,12 @@ func testDeviceRequestCRUD(t *testing.T, s storage.Storage) {
panic(err)
}
d1 := storage.DeviceRequest{
UserCode: userCode,
DeviceCode: storage.NewID(),
ClientID: "client1",
Scopes: []string{"openid", "email"},
Expiry: neverExpire,
UserCode: userCode,
DeviceCode: storage.NewID(),
ClientID: "client1",
ClientSecret: "secret1",
Scopes: []string{"openid", "email"},
Expiry: neverExpire,
}
if err := s.CreateDeviceRequest(d1); err != nil {

View File

@@ -595,7 +595,7 @@ func (c *conn) listDeviceRequests(ctx context.Context) (requests []DeviceRequest
func (c *conn) CreateDeviceToken(t storage.DeviceToken) error {
ctx, cancel := context.WithTimeout(context.Background(), defaultStorageTimeout)
defer cancel()
return c.txnCreate(ctx, keyID(deviceRequestPrefix, t.DeviceCode), fromStorageDeviceToken(t))
return c.txnCreate(ctx, keyID(deviceTokenPrefix, t.DeviceCode), fromStorageDeviceToken(t))
}
func (c *conn) GetDeviceToken(deviceCode string) (t storage.DeviceToken, err error) {

View File

@@ -44,6 +44,8 @@ func cleanDB(c *conn) error {
passwordPrefix,
offlineSessionPrefix,
connectorPrefix,
deviceRequestPrefix,
deviceTokenPrefix,
} {
_, err := c.db.Delete(ctx, prefix, clientv3.WithPrefix())
if err != nil {

View File

@@ -219,20 +219,22 @@ func toStorageOfflineSessions(o OfflineSessions) storage.OfflineSessions {
// DeviceRequest is a mirrored struct from storage with JSON struct tags
type DeviceRequest struct {
UserCode string `json:"user_code"`
DeviceCode string `json:"device_code"`
ClientID string `json:"client_id"`
Scopes []string `json:"scopes"`
Expiry time.Time `json:"expiry"`
UserCode string `json:"user_code"`
DeviceCode string `json:"device_code"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
Scopes []string `json:"scopes"`
Expiry time.Time `json:"expiry"`
}
func fromStorageDeviceRequest(d storage.DeviceRequest) DeviceRequest {
return DeviceRequest{
UserCode: d.UserCode,
DeviceCode: d.DeviceCode,
ClientID: d.ClientID,
Scopes: d.Scopes,
Expiry: d.Expiry,
UserCode: d.UserCode,
DeviceCode: d.DeviceCode,
ClientID: d.ClientID,
ClientSecret: d.ClientSecret,
Scopes: d.Scopes,
Expiry: d.Expiry,
}
}

View File

@@ -672,10 +672,11 @@ type DeviceRequest struct {
k8sapi.TypeMeta `json:",inline"`
k8sapi.ObjectMeta `json:"metadata,omitempty"`
DeviceCode string `json:"device_code,omitempty"`
CLientID string `json:"client_id,omitempty"`
Scopes []string `json:"scopes,omitempty"`
Expiry time.Time `json:"expiry"`
DeviceCode string `json:"device_code,omitempty"`
ClientID string `json:"client_id,omitempty"`
ClientSecret string `json:"client_secret,omitempty"`
Scopes []string `json:"scopes,omitempty"`
Expiry time.Time `json:"expiry"`
}
// AuthRequestList is a list of AuthRequests.
@@ -695,21 +696,23 @@ func (cli *client) fromStorageDeviceRequest(a storage.DeviceRequest) DeviceReque
Name: strings.ToLower(a.UserCode),
Namespace: cli.namespace,
},
DeviceCode: a.DeviceCode,
CLientID: a.ClientID,
Scopes: a.Scopes,
Expiry: a.Expiry,
DeviceCode: a.DeviceCode,
ClientID: a.ClientID,
ClientSecret: a.ClientSecret,
Scopes: a.Scopes,
Expiry: a.Expiry,
}
return req
}
func toStorageDeviceRequest(req DeviceRequest) storage.DeviceRequest {
return storage.DeviceRequest{
UserCode: strings.ToUpper(req.ObjectMeta.Name),
DeviceCode: req.DeviceCode,
ClientID: req.CLientID,
Scopes: req.Scopes,
Expiry: req.Expiry,
UserCode: strings.ToUpper(req.ObjectMeta.Name),
DeviceCode: req.DeviceCode,
ClientID: req.ClientID,
ClientSecret: req.ClientSecret,
Scopes: req.Scopes,
Expiry: req.Expiry,
}
}

View File

@@ -888,12 +888,12 @@ func (c *conn) delete(table, field, id string) error {
func (c *conn) CreateDeviceRequest(d storage.DeviceRequest) error {
_, err := c.Exec(`
insert into device_request (
user_code, device_code, client_id, scopes, expiry
user_code, device_code, client_id, client_secret, scopes, expiry
)
values (
$1, $2, $3, $4, $5
$1, $2, $3, $4, $5, $6
);`,
d.UserCode, d.DeviceCode, d.ClientID, encoder(d.Scopes), d.Expiry,
d.UserCode, d.DeviceCode, d.ClientID, d.ClientSecret, encoder(d.Scopes), d.Expiry,
)
if err != nil {
if c.alreadyExistsCheck(err) {
@@ -930,10 +930,10 @@ func (c *conn) GetDeviceRequest(userCode string) (storage.DeviceRequest, error)
func getDeviceRequest(q querier, userCode string) (d storage.DeviceRequest, err error) {
err = q.QueryRow(`
select
device_code, client_id, scopes, expiry
device_code, client_id, client_secret, scopes, expiry
from device_request where user_code = $1;
`, userCode).Scan(
&d.DeviceCode, &d.ClientID, decoder(&d.Scopes), &d.Expiry,
&d.DeviceCode, &d.ClientID, &d.ClientSecret, decoder(&d.Scopes), &d.Expiry,
)
if err != nil {
if err == sql.ErrNoRows {

View File

@@ -235,6 +235,7 @@ var migrations = []migration{
user_code text not null primary key,
device_code text not null,
client_id text not null,
client_secret text ,
scopes bytea not null, -- JSON array of strings
expiry timestamptz not null
);`,

View File

@@ -392,6 +392,8 @@ type DeviceRequest struct {
DeviceCode string
//The client ID the code is for
ClientID string
//The Client Secret
ClientSecret string
//The scopes the device requests
Scopes []string
//The expire time