storage: Add OfflineSession object to backend storage.
This commit is contained in:
@@ -58,6 +58,12 @@ func (c *client) idToName(s string) string {
|
||||
return idToName(s, c.hash)
|
||||
}
|
||||
|
||||
// offlineTokenName maps two arbitrary IDs, to a single Kubernetes object name.
|
||||
// This is used when more than one field is used to uniquely identify the object.
|
||||
func (c *client) offlineTokenName(userID string, connID string) string {
|
||||
return offlineTokenName(userID, connID, c.hash)
|
||||
}
|
||||
|
||||
// Kubernetes names must match the regexp '[a-z0-9]([-a-z0-9]*[a-z0-9])?'.
|
||||
var encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")
|
||||
|
||||
@@ -65,6 +71,12 @@ func idToName(s string, h func() hash.Hash) string {
|
||||
return strings.TrimRight(encoding.EncodeToString(h().Sum([]byte(s))), "=")
|
||||
}
|
||||
|
||||
func offlineTokenName(userID string, connID string, h func() hash.Hash) string {
|
||||
h().Write([]byte(userID))
|
||||
h().Write([]byte(connID))
|
||||
return strings.TrimRight(encoding.EncodeToString(h().Sum(nil)), "=")
|
||||
}
|
||||
|
||||
func (c *client) urlFor(apiVersion, namespace, resource, name string) string {
|
||||
basePath := "apis/"
|
||||
if apiVersion == "v1" {
|
||||
|
@@ -15,21 +15,23 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
kindAuthCode = "AuthCode"
|
||||
kindAuthRequest = "AuthRequest"
|
||||
kindClient = "OAuth2Client"
|
||||
kindRefreshToken = "RefreshToken"
|
||||
kindKeys = "SigningKey"
|
||||
kindPassword = "Password"
|
||||
kindAuthCode = "AuthCode"
|
||||
kindAuthRequest = "AuthRequest"
|
||||
kindClient = "OAuth2Client"
|
||||
kindRefreshToken = "RefreshToken"
|
||||
kindKeys = "SigningKey"
|
||||
kindPassword = "Password"
|
||||
kindOfflineSessions = "OfflineSessions"
|
||||
)
|
||||
|
||||
const (
|
||||
resourceAuthCode = "authcodes"
|
||||
resourceAuthRequest = "authrequests"
|
||||
resourceClient = "oauth2clients"
|
||||
resourceRefreshToken = "refreshtokens"
|
||||
resourceKeys = "signingkeies" // Kubernetes attempts to pluralize.
|
||||
resourcePassword = "passwords"
|
||||
resourceAuthCode = "authcodes"
|
||||
resourceAuthRequest = "authrequests"
|
||||
resourceClient = "oauth2clients"
|
||||
resourceRefreshToken = "refreshtokens"
|
||||
resourceKeys = "signingkeies" // Kubernetes attempts to pluralize.
|
||||
resourcePassword = "passwords"
|
||||
resourceOfflineSessions = "offlinesessions"
|
||||
)
|
||||
|
||||
// Config values for the Kubernetes storage type.
|
||||
@@ -156,6 +158,10 @@ func (cli *client) CreateRefresh(r storage.RefreshToken) error {
|
||||
return cli.post(resourceRefreshToken, cli.fromStorageRefreshToken(r))
|
||||
}
|
||||
|
||||
func (cli *client) CreateOfflineSessions(o storage.OfflineSessions) error {
|
||||
return cli.post(resourceOfflineSessions, cli.fromStorageOfflineSessions(o))
|
||||
}
|
||||
|
||||
func (cli *client) GetAuthRequest(id string) (storage.AuthRequest, error) {
|
||||
var req AuthRequest
|
||||
if err := cli.get(resourceAuthRequest, id, &req); err != nil {
|
||||
@@ -235,6 +241,25 @@ func (cli *client) getRefreshToken(id string) (r RefreshToken, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *client) GetOfflineSessions(userID string, connID string) (storage.OfflineSessions, error) {
|
||||
o, err := cli.getOfflineSessions(userID, connID)
|
||||
if err != nil {
|
||||
return storage.OfflineSessions{}, err
|
||||
}
|
||||
return toStorageOfflineSessions(o), nil
|
||||
}
|
||||
|
||||
func (cli *client) getOfflineSessions(userID string, connID string) (o OfflineSessions, err error) {
|
||||
name := cli.offlineTokenName(userID, connID)
|
||||
if err = cli.get(resourceOfflineSessions, name, &o); err != nil {
|
||||
return OfflineSessions{}, err
|
||||
}
|
||||
if userID != o.UserID || connID != o.ConnID {
|
||||
return OfflineSessions{}, fmt.Errorf("get offline session: wrong session retrieved")
|
||||
}
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func (cli *client) ListClients() ([]storage.Client, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
@@ -292,6 +317,15 @@ func (cli *client) DeletePassword(email string) error {
|
||||
return cli.delete(resourcePassword, p.ObjectMeta.Name)
|
||||
}
|
||||
|
||||
func (cli *client) DeleteOfflineSessions(userID string, connID string) error {
|
||||
// Check for hash collition.
|
||||
o, err := cli.getOfflineSessions(userID, connID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cli.delete(resourceOfflineSessions, o.ObjectMeta.Name)
|
||||
}
|
||||
|
||||
func (cli *client) UpdateRefreshToken(id string, updater func(old storage.RefreshToken) (storage.RefreshToken, error)) error {
|
||||
r, err := cli.getRefreshToken(id)
|
||||
if err != nil {
|
||||
@@ -342,6 +376,22 @@ func (cli *client) UpdatePassword(email string, updater func(old storage.Passwor
|
||||
return cli.put(resourcePassword, p.ObjectMeta.Name, newPassword)
|
||||
}
|
||||
|
||||
func (cli *client) UpdateOfflineSessions(userID string, connID string, updater func(old storage.OfflineSessions) (storage.OfflineSessions, error)) error {
|
||||
o, err := cli.getOfflineSessions(userID, connID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updated, err := updater(toStorageOfflineSessions(o))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newOfflineSessions := cli.fromStorageOfflineSessions(updated)
|
||||
newOfflineSessions.ObjectMeta = o.ObjectMeta
|
||||
return cli.put(resourceOfflineSessions, o.ObjectMeta.Name, newOfflineSessions)
|
||||
}
|
||||
|
||||
func (cli *client) UpdateKeys(updater func(old storage.Keys) (storage.Keys, error)) error {
|
||||
firstUpdate := false
|
||||
var keys Keys
|
||||
|
@@ -66,6 +66,14 @@ var thirdPartyResources = []k8sapi.ThirdPartyResource{
|
||||
Description: "Passwords managed by the OIDC server.",
|
||||
Versions: []k8sapi.APIVersion{{Name: "v1"}},
|
||||
},
|
||||
{
|
||||
ObjectMeta: k8sapi.ObjectMeta{
|
||||
Name: "offline-sessions.oidc.coreos.com",
|
||||
},
|
||||
TypeMeta: tprMeta,
|
||||
Description: "User sessions with an active refresh token.",
|
||||
Versions: []k8sapi.APIVersion{{Name: "v1"}},
|
||||
},
|
||||
}
|
||||
|
||||
// There will only ever be a single keys resource. Maintain this by setting a
|
||||
@@ -465,3 +473,38 @@ func toStorageKeys(keys Keys) storage.Keys {
|
||||
NextRotation: keys.NextRotation,
|
||||
}
|
||||
}
|
||||
|
||||
// OfflineSessions is a mirrored struct from storage with JSON struct tags and Kubernetes
|
||||
// type metadata.
|
||||
type OfflineSessions struct {
|
||||
k8sapi.TypeMeta `json:",inline"`
|
||||
k8sapi.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
UserID string `json:"userID,omitempty"`
|
||||
ConnID string `json:"connID,omitempty"`
|
||||
Refresh map[string]*storage.RefreshTokenRef `json:"refresh,omitempty"`
|
||||
}
|
||||
|
||||
func (cli *client) fromStorageOfflineSessions(o storage.OfflineSessions) OfflineSessions {
|
||||
return OfflineSessions{
|
||||
TypeMeta: k8sapi.TypeMeta{
|
||||
Kind: kindOfflineSessions,
|
||||
APIVersion: cli.apiVersion,
|
||||
},
|
||||
ObjectMeta: k8sapi.ObjectMeta{
|
||||
Name: cli.offlineTokenName(o.UserID, o.ConnID),
|
||||
Namespace: cli.namespace,
|
||||
},
|
||||
UserID: o.UserID,
|
||||
ConnID: o.ConnID,
|
||||
Refresh: o.Refresh,
|
||||
}
|
||||
}
|
||||
|
||||
func toStorageOfflineSessions(o OfflineSessions) storage.OfflineSessions {
|
||||
return storage.OfflineSessions{
|
||||
UserID: o.UserID,
|
||||
ConnID: o.ConnID,
|
||||
Refresh: o.Refresh,
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user