diff --git a/auth_server/authn/github_auth.go b/auth_server/authn/github_auth.go index b74d8d99..9c04a046 100644 --- a/auth_server/authn/github_auth.go +++ b/auth_server/authn/github_auth.go @@ -56,18 +56,18 @@ type ParentGitHubTeam struct { } type GitHubAuthConfig 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 *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"` + Organization string `yaml:"organization,omitempty"` + ClientId string `yaml:"client_id,omitempty"` + ClientSecret string `yaml:"client_secret,omitempty"` + ClientSecretFile string `yaml:"client_secret_file,omitempty"` + LevelTokenDB *LevelDBStoreConfig `yaml:"level_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 GitHubAuthRequest struct { @@ -158,17 +158,18 @@ func parseLinkHeader(linkLines []string) (linkHeader, error) { func NewGitHubAuth(c *GitHubAuthConfig) (*GitHubAuth, error) { var db TokenDB var err error - dbName := c.TokenDB + var dbName string switch { case c.GCSTokenDB != nil: - db, err = NewGCSTokenDB(c.GCSTokenDB.Bucket, c.GCSTokenDB.ClientSecretFile) + db, err = NewGCSTokenDB(c.GCSTokenDB) dbName = "GCS: " + c.GCSTokenDB.Bucket case c.RedisTokenDB != nil: db, err = NewRedisTokenDB(c.RedisTokenDB) dbName = db.(*redisTokenDB).String() default: - db, err = NewTokenDB(c.TokenDB) + db, err = NewTokenDB(c.LevelTokenDB) + dbName = c.LevelTokenDB.Path } if err != nil { diff --git a/auth_server/authn/gitlab_auth.go b/auth_server/authn/gitlab_auth.go index 2af8a6d3..689e56da 100644 --- a/auth_server/authn/gitlab_auth.go +++ b/auth_server/authn/gitlab_auth.go @@ -56,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 *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"` + Organization string `yaml:"organization,omitempty"` + ClientId string `yaml:"client_id,omitempty"` + ClientSecret string `yaml:"client_secret,omitempty"` + ClientSecretFile string `yaml:"client_secret_file,omitempty"` + LevelTokenDB *LevelDBStoreConfig `yaml:"level_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 { @@ -107,17 +107,18 @@ type GitlabAuth struct { func NewGitlabAuth(c *GitlabAuthConfig) (*GitlabAuth, error) { var db TokenDB var err error - dbName := c.TokenDB + var dbName string switch { case c.GCSTokenDB != nil: - db, err = NewGCSTokenDB(c.GCSTokenDB.Bucket, c.GCSTokenDB.ClientSecretFile) + db, err = NewGCSTokenDB(c.GCSTokenDB) dbName = "GCS: " + c.GCSTokenDB.Bucket case c.RedisTokenDB != nil: db, err = NewRedisTokenDB(c.RedisTokenDB) dbName = db.(*redisTokenDB).String() default: - db, err = NewTokenDB(c.TokenDB) + db, err = NewTokenDB(c.LevelTokenDB) + dbName = c.LevelTokenDB.Path } if err != nil { diff --git a/auth_server/authn/google_auth.go b/auth_server/authn/google_auth.go index c2016e65..93b080c0 100644 --- a/auth_server/authn/google_auth.go +++ b/auth_server/authn/google_auth.go @@ -33,14 +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"` - GCSTokenDB *GCSStoreConfig `yaml:"gcs_token_db,omitempty"` - RedisTokenDB *RedisStoreConfig `yaml:"redis_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"` + LevelTokenDB *LevelDBStoreConfig `yaml:"level_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 { @@ -131,17 +131,18 @@ type GoogleAuth struct { func NewGoogleAuth(c *GoogleAuthConfig) (*GoogleAuth, error) { var db TokenDB var err error - dbName := c.TokenDB + var dbName string switch { case c.GCSTokenDB != nil: - db, err = NewGCSTokenDB(c.GCSTokenDB.Bucket, c.GCSTokenDB.ClientSecretFile) + db, err = NewGCSTokenDB(c.GCSTokenDB) dbName = "GCS: " + c.GCSTokenDB.Bucket case c.RedisTokenDB != nil: db, err = NewRedisTokenDB(c.RedisTokenDB) dbName = db.(*redisTokenDB).String() default: - db, err = NewTokenDB(c.TokenDB) + db, err = NewTokenDB(c.LevelTokenDB) + dbName = c.LevelTokenDB.Path } if err != nil { return nil, err diff --git a/auth_server/authn/oidc_auth.go b/auth_server/authn/oidc_auth.go index 8ec1a205..a52e0969 100644 --- a/auth_server/authn/oidc_auth.go +++ b/auth_server/authn/oidc_auth.go @@ -48,9 +48,9 @@ type OIDCAuthConfig struct { 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"` - GCSTokenDB *GCSStoreConfig `yaml:"gcs_token_db,omitempty"` - RedisTokenDB *RedisStoreConfig `yaml:"redis_token_db,omitempty"` + LevelTokenDB *LevelDBStoreConfig `yaml:"level_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"` // the URL of the docker registry. Used to generate a full docker login command after authentication @@ -96,17 +96,18 @@ Creates everything necessary for OIDC auth. func NewOIDCAuth(c *OIDCAuthConfig) (*OIDCAuth, error) { var db TokenDB var err error - dbName := c.TokenDB + var dbName string switch { case c.GCSTokenDB != nil: - db, err = NewGCSTokenDB(c.GCSTokenDB.Bucket, c.GCSTokenDB.ClientSecretFile) + db, err = NewGCSTokenDB(c.GCSTokenDB) dbName = "GCS: " + c.GCSTokenDB.Bucket case c.RedisTokenDB != nil: db, err = NewRedisTokenDB(c.RedisTokenDB) dbName = db.(*redisTokenDB).String() default: - db, err = NewTokenDB(c.TokenDB) + db, err = NewTokenDB(c.LevelTokenDB) + dbName = c.LevelTokenDB.Path } if err != nil { diff --git a/auth_server/authn/tokendb_gcs.go b/auth_server/authn/tokendb_gcs.go index d91b1a4f..53a0d278 100644 --- a/auth_server/authn/tokendb_gcs.go +++ b/auth_server/authn/tokendb_gcs.go @@ -34,20 +34,26 @@ import ( type GCSStoreConfig struct { Bucket string `yaml:"bucket,omitempty"` ClientSecretFile string `yaml:"client_secret_file,omitempty"` + TokenHashCost int `yaml:"token_hash_cost,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. // // Note: it's not recomanded bucket to be shared with other apps or services -func NewGCSTokenDB(bucket, clientSecretFile string) (TokenDB, error) { - gcs, err := storage.NewClient(context.Background(), option.WithServiceAccountFile(clientSecretFile)) - return &gcsTokenDB{gcs, bucket}, err +func NewGCSTokenDB(options *GCSStoreConfig) (TokenDB, error) { + gcs, err := storage.NewClient(context.Background(), option.WithServiceAccountFile(options.ClientSecretFile)) + tokenHashCost := options.TokenHashCost + if tokenHashCost <= 0 { + tokenHashCost = bcrypt.DefaultCost + } + return &gcsTokenDB{gcs, options.Bucket, tokenHashCost}, err } type gcsTokenDB struct { gcs *storage.Client bucket string + tokenHashCost int } // GetValue gets token value associated with the provided user. Each user @@ -77,7 +83,7 @@ func (db *gcsTokenDB) GetValue(user string) (*TokenDBValue, error) { func (db *gcsTokenDB) StoreToken(user string, v *TokenDBValue, updatePassword bool) (dp string, err error) { if updatePassword { dp = uniuri.New() - dph, _ := bcrypt.GenerateFromPassword([]byte(dp), bcrypt.DefaultCost) + dph, _ := bcrypt.GenerateFromPassword([]byte(dp), db.tokenHashCost) v.DockerPassword = string(dph) } diff --git a/auth_server/authn/tokendb.go b/auth_server/authn/tokendb_level.go similarity index 92% rename from auth_server/authn/tokendb.go rename to auth_server/authn/tokendb_level.go index 91cec5ff..66d43444 100644 --- a/auth_server/authn/tokendb.go +++ b/auth_server/authn/tokendb_level.go @@ -36,6 +36,11 @@ const ( var ExpiredToken = errors.New("expired token") +type LevelDBStoreConfig struct { + Path string `yaml:"path,omitempty"` + TokenHashCost int `yaml:"token_hash_cost,omitempty"` +} + // TokenDB stores tokens using LevelDB type TokenDB interface { // GetValue takes a username returns the corresponding token @@ -75,8 +80,12 @@ type TokenDBValue struct { } // NewTokenDB returns a new TokenDB structure -func NewTokenDB(file string) (TokenDB, error) { - db, err := leveldb.OpenFile(file, nil) +func NewTokenDB(options *LevelDBStoreConfig) (TokenDB, error) { + db, err := leveldb.OpenFile(options.Path, nil) + tokenHashCost := options.TokenHashCost + if tokenHashCost <= 0 { + tokenHashCost = bcrypt.DefaultCost + } return &TokenDBImpl{ DB: db, }, err diff --git a/auth_server/authn/tokendb_redis.go b/auth_server/authn/tokendb_redis.go index 9b1fd528..39a4f10a 100644 --- a/auth_server/authn/tokendb_redis.go +++ b/auth_server/authn/tokendb_redis.go @@ -32,6 +32,7 @@ import ( type RedisStoreConfig struct { ClientOptions *redis.Options `yaml:"redis_options,omitempty"` ClusterOptions *redis.ClusterOptions `yaml:"redis_cluster_options,omitempty"` + TokenHashCost int `yaml:"token_hash_cost,omitempty"` } type RedisClient interface { @@ -52,12 +53,17 @@ func NewRedisTokenDB(options *RedisStoreConfig) (TokenDB, error) { } else { client = redis.NewClient(options.ClientOptions) } + tokenHashCost := options.TokenHashCost + if tokenHashCost <= 0 { + tokenHashCost = bcrypt.DefaultCost + } - return &redisTokenDB{client}, nil + return &redisTokenDB{client,tokenHashCost}, nil } type redisTokenDB struct { client RedisClient + tokenHashCost int } func (db *redisTokenDB) String() string { @@ -95,7 +101,7 @@ func (db *redisTokenDB) GetValue(user string) (*TokenDBValue, error) { func (db *redisTokenDB) StoreToken(user string, v *TokenDBValue, updatePassword bool) (dp string, err error) { if updatePassword { dp = uniuri.New() - dph, _ := bcrypt.GenerateFromPassword([]byte(dp), bcrypt.DefaultCost) + dph, _ := bcrypt.GenerateFromPassword([]byte(dp), db.tokenHashCost) v.DockerPassword = string(dph) } diff --git a/auth_server/server/config.go b/auth_server/server/config.go index 056375c5..866f65af 100644 --- a/auth_server/server/config.go +++ b/auth_server/server/config.go @@ -193,7 +193,7 @@ func validate(c *Config) error { } gac.ClientSecret = strings.TrimSpace(string(contents)) } - if gac.ClientId == "" || gac.ClientSecret == "" || (gac.TokenDB == "" && (gac.GCSTokenDB == nil && gac.RedisTokenDB == nil)) { + if gac.ClientId == "" || gac.ClientSecret == "" || (gac.LevelTokenDB != nil && (gac.GCSTokenDB == nil && gac.RedisTokenDB == nil)) { return errors.New("google_auth.{client_id,client_secret,token_db} are required") } @@ -217,7 +217,7 @@ func validate(c *Config) error { } ghac.ClientSecret = strings.TrimSpace(string(contents)) } - if ghac.ClientId == "" || ghac.ClientSecret == "" || (ghac.TokenDB == "" && (ghac.GCSTokenDB == nil && ghac.RedisTokenDB == nil)) { + if ghac.ClientId == "" || ghac.ClientSecret == "" || (ghac.LevelTokenDB != nil && (ghac.GCSTokenDB == nil && ghac.RedisTokenDB == nil)) { return errors.New("github_auth.{client_id,client_secret,token_db} are required") } @@ -245,7 +245,7 @@ func validate(c *Config) error { } oidc.ClientSecret = strings.TrimSpace(string(contents)) } - if oidc.ClientId == "" || oidc.ClientSecret == "" || oidc.Issuer == "" || oidc.RedirectURL == "" || (oidc.TokenDB == "" && (oidc.GCSTokenDB == nil && oidc.RedisTokenDB == nil)) { + if oidc.ClientId == "" || oidc.ClientSecret == "" || oidc.Issuer == "" || oidc.RedirectURL == "" || (oidc.LevelTokenDB != nil && (oidc.GCSTokenDB == nil && oidc.RedisTokenDB == nil)) { return errors.New("oidc_auth.{issuer,redirect_url,client_id,client_secret,token_db} are required") } @@ -275,7 +275,7 @@ func validate(c *Config) error { } glab.ClientSecret = strings.TrimSpace(string(contents)) } - if glab.ClientId == "" || glab.ClientSecret == "" || (glab.TokenDB == "" && (glab.GCSTokenDB == nil && glab.RedisTokenDB == nil)) { + if glab.ClientId == "" || glab.ClientSecret == "" || (glab.LevelTokenDB != nil && (glab.GCSTokenDB == nil && glab.RedisTokenDB == nil)) { return errors.New("gitlab_auth.{client_id,client_secret,token_db} are required") }