mirror of https://github.com/dexidp/dex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
8.2 KiB
319 lines
8.2 KiB
package kubernetes |
|
|
|
import ( |
|
"errors" |
|
"fmt" |
|
"log" |
|
"os" |
|
"path/filepath" |
|
"time" |
|
|
|
homedir "github.com/mitchellh/go-homedir" |
|
|
|
"github.com/coreos/dex/storage" |
|
"github.com/coreos/dex/storage/kubernetes/k8sapi" |
|
) |
|
|
|
const ( |
|
kindAuthCode = "AuthCode" |
|
kindAuthRequest = "AuthRequest" |
|
kindClient = "OAuth2Client" |
|
kindRefreshToken = "RefreshToken" |
|
kindKeys = "SigningKey" |
|
kindPassword = "Password" |
|
) |
|
|
|
const ( |
|
resourceAuthCode = "authcodes" |
|
resourceAuthRequest = "authrequests" |
|
resourceClient = "oauth2clients" |
|
resourceRefreshToken = "refreshtokens" |
|
resourceKeys = "signingkeies" // Kubernetes attempts to pluralize. |
|
resourcePassword = "passwords" |
|
) |
|
|
|
// Config values for the Kubernetes storage type. |
|
type Config struct { |
|
InCluster bool `yaml:"inCluster"` |
|
KubeConfigPath string `yaml:"kubeConfigPath"` |
|
GCFrequency int64 `yaml:"gcFrequency"` // seconds |
|
} |
|
|
|
// Open returns a storage using Kubernetes third party resource. |
|
func (c *Config) Open() (storage.Storage, error) { |
|
cli, err := c.open() |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return cli, nil |
|
} |
|
|
|
// open returns a client with no garbage collection. |
|
func (c *Config) open() (*client, error) { |
|
if c.InCluster && (c.KubeConfigPath != "") { |
|
return nil, errors.New("cannot specify both 'inCluster' and 'kubeConfigPath'") |
|
} |
|
|
|
var ( |
|
cluster k8sapi.Cluster |
|
user k8sapi.AuthInfo |
|
namespace string |
|
err error |
|
) |
|
if c.InCluster { |
|
cluster, user, namespace, err = inClusterConfig() |
|
} else { |
|
kubeConfigPath := c.KubeConfigPath |
|
if kubeConfigPath == "" { |
|
kubeConfigPath = os.Getenv("KUBECONFIG") |
|
} |
|
if kubeConfigPath == "" { |
|
p, err := homedir.Dir() |
|
if err != nil { |
|
return nil, fmt.Errorf("finding homedir: %v", err) |
|
} |
|
kubeConfigPath = filepath.Join(p, ".kube", "config") |
|
} |
|
cluster, user, namespace, err = loadKubeConfig(kubeConfigPath) |
|
} |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return newClient(cluster, user, namespace) |
|
} |
|
|
|
func (cli *client) Close() error { |
|
return nil |
|
} |
|
|
|
func (cli *client) CreateAuthRequest(a storage.AuthRequest) error { |
|
return cli.post(resourceAuthRequest, cli.fromStorageAuthRequest(a)) |
|
} |
|
|
|
func (cli *client) CreateClient(c storage.Client) error { |
|
return cli.post(resourceClient, cli.fromStorageClient(c)) |
|
} |
|
|
|
func (cli *client) CreateAuthCode(c storage.AuthCode) error { |
|
return cli.post(resourceAuthCode, cli.fromStorageAuthCode(c)) |
|
} |
|
|
|
func (cli *client) CreatePassword(p storage.Password) error { |
|
return cli.post(resourcePassword, cli.fromStoragePassword(p)) |
|
} |
|
|
|
func (cli *client) CreateRefresh(r storage.RefreshToken) error { |
|
refresh := RefreshToken{ |
|
TypeMeta: k8sapi.TypeMeta{ |
|
Kind: kindRefreshToken, |
|
APIVersion: cli.apiVersionForResource(resourceRefreshToken), |
|
}, |
|
ObjectMeta: k8sapi.ObjectMeta{ |
|
Name: r.RefreshToken, |
|
Namespace: cli.namespace, |
|
}, |
|
ClientID: r.ClientID, |
|
ConnectorID: r.ConnectorID, |
|
Scopes: r.Scopes, |
|
Nonce: r.Nonce, |
|
Claims: fromStorageClaims(r.Claims), |
|
} |
|
return cli.post(resourceRefreshToken, refresh) |
|
} |
|
|
|
func (cli *client) GetAuthRequest(id string) (storage.AuthRequest, error) { |
|
var req AuthRequest |
|
if err := cli.get(resourceAuthRequest, id, &req); err != nil { |
|
return storage.AuthRequest{}, err |
|
} |
|
return toStorageAuthRequest(req), nil |
|
} |
|
|
|
func (cli *client) GetAuthCode(id string) (storage.AuthCode, error) { |
|
var code AuthCode |
|
if err := cli.get(resourceAuthCode, id, &code); err != nil { |
|
return storage.AuthCode{}, err |
|
} |
|
return toStorageAuthCode(code), nil |
|
} |
|
|
|
func (cli *client) GetClient(id string) (storage.Client, error) { |
|
var c Client |
|
if err := cli.get(resourceClient, id, &c); err != nil { |
|
return storage.Client{}, err |
|
} |
|
return toStorageClient(c), nil |
|
} |
|
|
|
func (cli *client) GetPassword(email string) (storage.Password, error) { |
|
var p Password |
|
if err := cli.get(resourcePassword, emailToID(email), &p); err != nil { |
|
return storage.Password{}, err |
|
} |
|
return toStoragePassword(p), nil |
|
} |
|
|
|
func (cli *client) GetKeys() (storage.Keys, error) { |
|
var keys Keys |
|
if err := cli.get(resourceKeys, keysName, &keys); err != nil { |
|
return storage.Keys{}, err |
|
} |
|
return toStorageKeys(keys), nil |
|
} |
|
|
|
func (cli *client) GetRefresh(id string) (storage.RefreshToken, error) { |
|
var r RefreshToken |
|
if err := cli.get(resourceRefreshToken, id, &r); err != nil { |
|
return storage.RefreshToken{}, err |
|
} |
|
return storage.RefreshToken{ |
|
RefreshToken: r.ObjectMeta.Name, |
|
ClientID: r.ClientID, |
|
ConnectorID: r.ConnectorID, |
|
Scopes: r.Scopes, |
|
Nonce: r.Nonce, |
|
Claims: toStorageClaims(r.Claims), |
|
}, nil |
|
} |
|
|
|
func (cli *client) ListClients() ([]storage.Client, error) { |
|
return nil, errors.New("not implemented") |
|
} |
|
|
|
func (cli *client) ListRefreshTokens() ([]storage.RefreshToken, error) { |
|
return nil, errors.New("not implemented") |
|
} |
|
|
|
func (cli *client) DeleteAuthRequest(id string) error { |
|
return cli.delete(resourceAuthRequest, id) |
|
} |
|
|
|
func (cli *client) DeleteAuthCode(code string) error { |
|
return cli.delete(resourceAuthCode, code) |
|
} |
|
|
|
func (cli *client) DeleteClient(id string) error { |
|
return cli.delete(resourceClient, id) |
|
} |
|
|
|
func (cli *client) DeleteRefresh(id string) error { |
|
return cli.delete(resourceRefreshToken, id) |
|
} |
|
|
|
func (cli *client) DeletePassword(email string) error { |
|
return cli.delete(resourcePassword, emailToID(email)) |
|
} |
|
|
|
func (cli *client) UpdateClient(id string, updater func(old storage.Client) (storage.Client, error)) error { |
|
var c Client |
|
if err := cli.get(resourceClient, id, &c); err != nil { |
|
return err |
|
} |
|
updated, err := updater(toStorageClient(c)) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
newClient := cli.fromStorageClient(updated) |
|
newClient.ObjectMeta = c.ObjectMeta |
|
return cli.put(resourceClient, id, newClient) |
|
} |
|
|
|
func (cli *client) UpdatePassword(email string, updater func(old storage.Password) (storage.Password, error)) error { |
|
id := emailToID(email) |
|
var p Password |
|
if err := cli.get(resourcePassword, id, &p); err != nil { |
|
return err |
|
} |
|
|
|
updated, err := updater(toStoragePassword(p)) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
newPassword := cli.fromStoragePassword(updated) |
|
newPassword.ObjectMeta = p.ObjectMeta |
|
return cli.put(resourcePassword, id, newPassword) |
|
} |
|
|
|
func (cli *client) UpdateKeys(updater func(old storage.Keys) (storage.Keys, error)) error { |
|
firstUpdate := false |
|
var keys Keys |
|
if err := cli.get(resourceKeys, keysName, &keys); err != nil { |
|
if err != storage.ErrNotFound { |
|
return err |
|
} |
|
firstUpdate = true |
|
} |
|
var oldKeys storage.Keys |
|
if !firstUpdate { |
|
oldKeys = toStorageKeys(keys) |
|
} |
|
|
|
updated, err := updater(oldKeys) |
|
if err != nil { |
|
return err |
|
} |
|
newKeys := cli.fromStorageKeys(updated) |
|
if firstUpdate { |
|
return cli.post(resourceKeys, newKeys) |
|
} |
|
newKeys.ObjectMeta = keys.ObjectMeta |
|
return cli.put(resourceKeys, keysName, newKeys) |
|
} |
|
|
|
func (cli *client) UpdateAuthRequest(id string, updater func(a storage.AuthRequest) (storage.AuthRequest, error)) error { |
|
var req AuthRequest |
|
err := cli.get(resourceAuthRequest, id, &req) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
updated, err := updater(toStorageAuthRequest(req)) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
newReq := cli.fromStorageAuthRequest(updated) |
|
newReq.ObjectMeta = req.ObjectMeta |
|
return cli.put(resourceAuthRequest, id, newReq) |
|
} |
|
|
|
func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err error) { |
|
var authRequests AuthRequestList |
|
if err := cli.list(resourceAuthRequest, &authRequests); err != nil { |
|
return result, fmt.Errorf("failed to list auth requests: %v", err) |
|
} |
|
|
|
var delErr error |
|
for _, authRequest := range authRequests.AuthRequests { |
|
if now.After(authRequest.Expiry) { |
|
if err := cli.delete(resourceAuthRequest, authRequest.ObjectMeta.Name); err != nil { |
|
log.Printf("failed to delete auth request: %v", err) |
|
delErr = fmt.Errorf("failed to delete auth request: %v", err) |
|
} |
|
result.AuthRequests++ |
|
} |
|
} |
|
if delErr != nil { |
|
return result, delErr |
|
} |
|
|
|
var authCodes AuthCodeList |
|
if err := cli.list(resourceAuthCode, &authCodes); err != nil { |
|
return result, fmt.Errorf("failed to list auth codes: %v", err) |
|
} |
|
|
|
for _, authCode := range authCodes.AuthCodes { |
|
if now.After(authCode.Expiry) { |
|
if err := cli.delete(resourceAuthCode, authCode.ObjectMeta.Name); err != nil { |
|
log.Printf("failed to delete auth code %v", err) |
|
delErr = fmt.Errorf("failed to delete auth code: %v", err) |
|
} |
|
result.AuthCodes++ |
|
} |
|
} |
|
return result, delErr |
|
}
|
|
|