Skip to content

Commit

Permalink
Generalize redis & gcs tokendb, support in OIDC & Google auth
Browse files Browse the repository at this point in the history
  • Loading branch information
andsens committed Oct 30, 2023
1 parent 846f2b5 commit 28301af
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 78 deletions.
15 changes: 2 additions & 13 deletions auth_server/authn/github_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"time"

"github.com/cesanta/glog"
"github.com/go-redis/redis"

"github.com/cesanta/docker_auth/auth_server/api"
)
Expand Down Expand Up @@ -62,25 +61,15 @@ type GitHubAuthConfig struct {
ClientSecret string `yaml:"client_secret,omitempty"`
ClientSecretFile string `yaml:"client_secret_file,omitempty"`
TokenDB string `yaml:"token_db,omitempty"`
GCSTokenDB *GitHubGCSStoreConfig `yaml:"gcs_token_db,omitempty"`
RedisTokenDB *GitHubRedisStoreConfig `yaml:"redis_token_db,omitempty"`
GCSTokenDB *GCSStoreConfig `yaml:"gcs_token_db,omitempty"`
RedisTokenDB *RedisStoreConfig `yaml:"redis_token_db,omitempty"`
HTTPTimeout time.Duration `yaml:"http_timeout,omitempty"`
RevalidateAfter time.Duration `yaml:"revalidate_after,omitempty"`
GithubWebUri string `yaml:"github_web_uri,omitempty"`
GithubApiUri string `yaml:"github_api_uri,omitempty"`
RegistryUrl string `yaml:"registry_url,omitempty"`
}

type GitHubGCSStoreConfig struct {
Bucket string `yaml:"bucket,omitempty"`
ClientSecretFile string `yaml:"client_secret_file,omitempty"`
}

type GitHubRedisStoreConfig struct {
ClientOptions *redis.Options `yaml:"redis_options,omitempty"`
ClusterOptions *redis.ClusterOptions `yaml:"redis_cluster_options,omitempty"`
}

type GitHubAuthRequest struct {
Action string `json:"action,omitempty"`
Code string `json:"code,omitempty"`
Expand Down
41 changes: 15 additions & 26 deletions auth_server/authn/gitlab_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"time"

"github.com/cesanta/glog"
"github.com/go-redis/redis"

"github.com/cesanta/docker_auth/auth_server/api"
)
Expand Down Expand Up @@ -57,20 +56,20 @@ type ParentGitlabTeam struct {
}

type GitlabAuthConfig struct {
Organization string `yaml:"organization,omitempty"`
ClientId string `yaml:"client_id,omitempty"`
ClientSecret string `yaml:"client_secret,omitempty"`
ClientSecretFile string `yaml:"client_secret_file,omitempty"`
TokenDB string `yaml:"token_db,omitempty"`
GCSTokenDB *GitlabGCSStoreConfig `yaml:"gcs_token_db,omitempty"`
RedisTokenDB *GitlabRedisStoreConfig `yaml:"redis_token_db,omitempty"`
HTTPTimeout time.Duration `yaml:"http_timeout,omitempty"`
RevalidateAfter time.Duration `yaml:"revalidate_after,omitempty"`
GitlabWebUri string `yaml:"gitlab_web_uri,omitempty"`
GitlabApiUri string `yaml:"gitlab_api_uri,omitempty"`
RegistryUrl string `yaml:"registry_url,omitempty"`
GrantType string `yaml:"grant_type,omitempty"`
RedirectUri string `yaml:"redirect_uri,omitempty"`
Organization string `yaml:"organization,omitempty"`
ClientId string `yaml:"client_id,omitempty"`
ClientSecret string `yaml:"client_secret,omitempty"`
ClientSecretFile string `yaml:"client_secret_file,omitempty"`
TokenDB string `yaml:"token_db,omitempty"`
GCSTokenDB *GCSStoreConfig `yaml:"gcs_token_db,omitempty"`
RedisTokenDB *RedisStoreConfig `yaml:"redis_token_db,omitempty"`
HTTPTimeout time.Duration `yaml:"http_timeout,omitempty"`
RevalidateAfter time.Duration `yaml:"revalidate_after,omitempty"`
GitlabWebUri string `yaml:"gitlab_web_uri,omitempty"`
GitlabApiUri string `yaml:"gitlab_api_uri,omitempty"`
RegistryUrl string `yaml:"registry_url,omitempty"`
GrantType string `yaml:"grant_type,omitempty"`
RedirectUri string `yaml:"redirect_uri,omitempty"`
}

type CodeToGitlabTokenResponse struct {
Expand All @@ -85,16 +84,6 @@ type CodeToGitlabTokenResponse struct {
ErrorDescription string `json:"error_description,omitempty"`
}

type GitlabGCSStoreConfig struct {
Bucket string `yaml:"bucket,omitempty"`
ClientSecretFile string `yaml:"client_secret_file,omitempty"`
}

type GitlabRedisStoreConfig struct {
ClientOptions *redis.Options `yaml:"redis_options,omitempty"`
ClusterOptions *redis.ClusterOptions `yaml:"redis_cluster_options,omitempty"`
}

type GitlabAuthRequest struct {
Action string `json:"action,omitempty"`
Code string `json:"code,omitempty"`
Expand Down Expand Up @@ -125,7 +114,7 @@ func NewGitlabAuth(c *GitlabAuthConfig) (*GitlabAuth, error) {
db, err = NewGCSTokenDB(c.GCSTokenDB.Bucket, c.GCSTokenDB.ClientSecretFile)
dbName = "GCS: " + c.GCSTokenDB.Bucket
case c.RedisTokenDB != nil:
db, err = NewRedisGitlabTokenDB(c.RedisTokenDB)
db, err = NewRedisTokenDB(c.RedisTokenDB)
dbName = db.(*redisTokenDB).String()
default:
db, err = NewTokenDB(c.TokenDB)
Expand Down
31 changes: 23 additions & 8 deletions auth_server/authn/google_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ import (
)

type GoogleAuthConfig struct {
Domain string `yaml:"domain,omitempty"`
ClientId string `yaml:"client_id,omitempty"`
ClientSecret string `yaml:"client_secret,omitempty"`
ClientSecretFile string `yaml:"client_secret_file,omitempty"`
TokenDB string `yaml:"token_db,omitempty"`
HTTPTimeout time.Duration `yaml:"http_timeout,omitempty"`
Domain string `yaml:"domain,omitempty"`
ClientId string `yaml:"client_id,omitempty"`
ClientSecret string `yaml:"client_secret,omitempty"`
ClientSecretFile string `yaml:"client_secret_file,omitempty"`
TokenDB string `yaml:"token_db,omitempty"`
GCSTokenDB *GCSStoreConfig `yaml:"gcs_token_db,omitempty"`
RedisTokenDB *RedisStoreConfig `yaml:"redis_token_db,omitempty"`
HTTPTimeout time.Duration `yaml:"http_timeout,omitempty"`
}

type GoogleAuthRequest struct {
Expand Down Expand Up @@ -127,11 +129,24 @@ type GoogleAuth struct {
}

func NewGoogleAuth(c *GoogleAuthConfig) (*GoogleAuth, error) {
db, err := NewTokenDB(c.TokenDB)
var db TokenDB
var err error
dbName := c.TokenDB

switch {
case c.GCSTokenDB != nil:
db, err = NewGCSTokenDB(c.GCSTokenDB.Bucket, c.GCSTokenDB.ClientSecretFile)
dbName = "GCS: " + c.GCSTokenDB.Bucket
case c.RedisTokenDB != nil:
db, err = NewRedisTokenDB(c.RedisTokenDB)
dbName = db.(*redisTokenDB).String()
default:
db, err = NewTokenDB(c.TokenDB)
}
if err != nil {
return nil, err
}
glog.Infof("Google auth token DB at %s", c.TokenDB)
glog.Infof("Google auth token DB at %s", dbName)
google_auth, _ := static.ReadFile("data/google_auth.tmpl")
return &GoogleAuth{
config: c,
Expand Down
42 changes: 29 additions & 13 deletions auth_server/authn/oidc_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,29 @@ import (
type OIDCAuthConfig struct {
// --- necessary ---
// URL of the authentication provider. Must be able to serve the /.well-known/openid-configuration
Issuer string `yaml:"issuer,omitempty"`
Issuer string `yaml:"issuer,omitempty"`
// URL of the auth server. Has to end with /oidc_auth
RedirectURL string `yaml:"redirect_url,omitempty"`
RedirectURL string `yaml:"redirect_url,omitempty"`
// ID and secret, priovided by the OIDC provider after registration of the auth server
ClientId string `yaml:"client_id,omitempty"`
ClientSecret string `yaml:"client_secret,omitempty"`
ClientSecretFile string `yaml:"client_secret_file,omitempty"`
ClientId string `yaml:"client_id,omitempty"`
ClientSecret string `yaml:"client_secret,omitempty"`
ClientSecretFile string `yaml:"client_secret_file,omitempty"`
// path where the tokendb should be stored within the container
TokenDB string `yaml:"token_db,omitempty"`
TokenDB string `yaml:"token_db,omitempty"`
GCSTokenDB *GCSStoreConfig `yaml:"gcs_token_db,omitempty"`
RedisTokenDB *RedisStoreConfig `yaml:"redis_token_db,omitempty"`
// --- optional ---
HTTPTimeout time.Duration `yaml:"http_timeout,omitempty"`
HTTPTimeout time.Duration `yaml:"http_timeout,omitempty"`
// the URL of the docker registry. Used to generate a full docker login command after authentication
RegistryURL string `yaml:"registry_url,omitempty"`
RegistryURL string `yaml:"registry_url,omitempty"`
// --- optional ---
// String claim to use for the username
UserClaim string `yaml:"user_claim,omitempty"`
UserClaim string `yaml:"user_claim,omitempty"`
// --- optional ---
// []string to add as labels.
LabelsClaims []string `yaml:"labels_claims,omitempty"`
LabelsClaims []string `yaml:"labels_claims,omitempty"`
// --- optional ---
Scopes []string `yaml:"scopes,omitempty"`
Scopes []string `yaml:"scopes,omitempty"`
}

// OIDCRefreshTokenResponse is sent by OIDC provider in response to the grant_type=refresh_token request.
Expand Down Expand Up @@ -92,11 +94,25 @@ type OIDCAuth struct {
Creates everything necessary for OIDC auth.
*/
func NewOIDCAuth(c *OIDCAuthConfig) (*OIDCAuth, error) {
db, err := NewTokenDB(c.TokenDB)
var db TokenDB
var err error
dbName := c.TokenDB

switch {
case c.GCSTokenDB != nil:
db, err = NewGCSTokenDB(c.GCSTokenDB.Bucket, c.GCSTokenDB.ClientSecretFile)
dbName = "GCS: " + c.GCSTokenDB.Bucket
case c.RedisTokenDB != nil:
db, err = NewRedisTokenDB(c.RedisTokenDB)
dbName = db.(*redisTokenDB).String()
default:
db, err = NewTokenDB(c.TokenDB)
}

if err != nil {
return nil, err
}
glog.Infof("OIDC auth token DB at %s", c.TokenDB)
glog.Infof("OIDC auth token DB at %s", dbName)
ctx := context.Background()
oidcAuth, _ := static.ReadFile("data/oidc_auth.tmpl")
oidcAuthResult, _ := static.ReadFile("data/oidc_auth_result.tmpl")
Expand Down
5 changes: 5 additions & 0 deletions auth_server/authn/tokendb_gcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ import (
"github.com/cesanta/docker_auth/auth_server/api"
)

type GCSStoreConfig struct {
Bucket string `yaml:"bucket,omitempty"`
ClientSecretFile string `yaml:"client_secret_file,omitempty"`
}

// NewGCSTokenDB return a new TokenDB structure which uses Google Cloud Storage as backend. The
// created DB uses file-per-user strategy and stores credentials independently for each user.
//
Expand Down
25 changes: 7 additions & 18 deletions auth_server/authn/tokendb_redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ import (
"github.com/go-redis/redis"
)

type RedisStoreConfig struct {
ClientOptions *redis.Options `yaml:"redis_options,omitempty"`
ClusterOptions *redis.ClusterOptions `yaml:"redis_cluster_options,omitempty"`
}

type RedisClient interface {
Get(key string) *redis.StringCmd
Set(key string, value interface{}, expiration time.Duration) *redis.StatusCmd
Expand All @@ -37,23 +42,7 @@ type RedisClient interface {

// NewRedisTokenDB returns a new TokenDB structure which uses Redis as the storage backend.
//
func NewRedisTokenDB(options *GitHubRedisStoreConfig) (TokenDB, error) {
var client RedisClient
if options.ClusterOptions != nil {
if options.ClientOptions != nil {
glog.Infof("Both redis_token_db.configs and redis_token_db.cluster_configs have been set. Only the latter will be used")
}
client = redis.NewClusterClient(options.ClusterOptions)
} else {
client = redis.NewClient(options.ClientOptions)
}

return &redisTokenDB{client}, nil
}

// NewRedisTokenDB returns a new TokenDB structure which uses Redis as the storage backend.
//
func NewRedisGitlabTokenDB(options *GitlabRedisStoreConfig) (TokenDB, error) {
func NewRedisTokenDB(options *RedisStoreConfig) (TokenDB, error) {
var client RedisClient
if options.ClusterOptions != nil {
if options.ClientOptions != nil {
Expand Down Expand Up @@ -162,4 +151,4 @@ func (db *redisTokenDB) DeleteToken(user string) error {

func (db *redisTokenDB) Close() error {
return nil
}
}
9 changes: 9 additions & 0 deletions auth_server/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ func validate(c *Config) error {
if gac.ClientId == "" || gac.ClientSecret == "" || gac.TokenDB == "" {
return errors.New("google_auth.{client_id,client_secret,token_db} are required.")
}

if gac.ClientId == "" || gac.ClientSecret == "" || (gac.GCSTokenDB != nil && (gac.GCSTokenDB.Bucket == "" || gac.GCSTokenDB.ClientSecretFile == "")) {
return errors.New("github_auth.{client_id,client_secret,gcs_token_db{bucket,client_secret_file}} are required")
}

if gac.ClientId == "" || gac.ClientSecret == "" || (gac.RedisTokenDB != nil && gac.RedisTokenDB.ClientOptions == nil && gac.RedisTokenDB.ClusterOptions == nil) {
return errors.New("github_auth.{client_id,client_secret,redis_token_db.{redis_options,redis_cluster_options}} are required")
}

if gac.HTTPTimeout <= 0 {
gac.HTTPTimeout = time.Duration(10 * time.Second)
}
Expand Down

0 comments on commit 28301af

Please sign in to comment.