Skip to content

Commit

Permalink
Merge 823af61 into ea7f705
Browse files Browse the repository at this point in the history
  • Loading branch information
bsoniam committed May 17, 2019
2 parents ea7f705 + 823af61 commit b8b58fd
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 52 deletions.
147 changes: 131 additions & 16 deletions cmd/keycloakb/keycloak_bridge.go
Expand Up @@ -11,8 +11,10 @@ import (
"net/http/pprof"
"os"
"os/signal"
"regexp"
"sort"
"strconv"
"strings"
"syscall"
"time"

Expand Down Expand Up @@ -80,6 +82,16 @@ type dbConfig struct {
ConnMaxLifetime int
}

type CloudtrustDB interface {
Exec(query string, args ...interface{}) (sql.Result, error)
Query(query string, args ...interface{}) (*sql.Rows, error)
QueryRow(query string, args ...interface{}) *sql.Row
SetMaxOpenConns(n int)
SetMaxIdleConns(n int)
SetConnMaxLifetime(d time.Duration)
Close() error
}

func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
Expand Down Expand Up @@ -124,12 +136,14 @@ func main() {
}

// Enabled units
eventsDBEnabled = c.GetBool("events-db")
configDBEnabled = c.GetBool("config-db")
influxEnabled = c.GetBool("influx")
jaegerEnabled = c.GetBool("jaeger")
sentryEnabled = c.GetBool("sentry")
pprofRouteEnabled = c.GetBool("pprof-route-enabled")
eventsDBEnabled = c.GetBool("events-db")
configDBEnabled = c.GetBool("config-db")
influxEnabled = c.GetBool("influx")
jaegerEnabled = c.GetBool("jaeger")
sentryEnabled = c.GetBool("sentry")
pprofRouteEnabled = c.GetBool("pprof-route-enabled")
auditMigrationEnabled = c.GetBool("db-audit-migration")
configMigrationEnabled = c.GetBool("db-config-migration")

// Influx
influxHTTPConfig = influx.HTTPConfig{
Expand Down Expand Up @@ -186,6 +200,41 @@ func main() {
}
)

// DB migration version
// checking that the flyway_schema_history has the minimum imposed migration version
// auditevents DB
auditMigrationVersion := c.GetString("db-audit-migration-version")
if auditMigrationEnabled {
// DB schema versioning is enabled
if auditMigrationVersion != "" {
var err error
err = checkMigrationVersion(logger, *auditRwDbParams, auditMigrationVersion)
if err != nil {
return
}
} else {
// DB schema versioning is enabled but no minimum version was given
logger.Log("msg", "Check of DB schema is enabled, but no minimum version provided", "DB", auditRoDbParams.Database)
return
}
}

// cloudtrust_configurations DB
configMigrationVersion := c.GetString("db-config-migration-version")
if configMigrationEnabled {
if configMigrationVersion != "" {
var err error
err = checkMigrationVersion(logger, *configDbParams, configMigrationVersion)
if err != nil {
return
}
} else {
// DB schema versioning is enabled but no minimum version was given
logger.Log("msg", "Check of DB schema is enabled, but no minimum version provided", "DB", configDbParams.Database)
return
}
}

// Unique ID generator
var idGenerator = idgenerator.New(ComponentName, ComponentID)

Expand Down Expand Up @@ -303,16 +352,6 @@ func main() {
defer closer.Close()
}

// Audit events DB.
type CloudtrustDB interface {
Exec(query string, args ...interface{}) (sql.Result, error)
Query(query string, args ...interface{}) (*sql.Rows, error)
QueryRow(query string, args ...interface{}) *sql.Row
SetMaxOpenConns(n int)
SetMaxIdleConns(n int)
SetConnMaxLifetime(d time.Duration)
}

var eventsDBConn CloudtrustDB = keycloakb.NoopDB{}
if eventsDBEnabled {
var err error
Expand Down Expand Up @@ -748,13 +787,17 @@ func config(logger log.Logger) *viper.Viper {
// Storage events in DB (read/write)
v.SetDefault("events-db", false)
configureDbDefault(v, "db-audit-rw")
v.SetDefault("db-audit-migration", false)
v.SetDefault("db-audit-migration-version", "")

// Storage events in DB (read only)
configureDbDefault(v, "db-audit-ro")

//Storage custom configuration in DB
v.SetDefault("config-db", true)
configureDbDefault(v, "db-config")
v.SetDefault("db-config-migration", false)
v.SetDefault("db-config-migration-version", "")

// Rate limiting (in requests/second)
v.SetDefault("rate-event", 1000)
Expand Down Expand Up @@ -836,6 +879,78 @@ func config(logger log.Logger) *viper.Viper {
return v
}

func checkMigrationVersion(logger log.Logger, dbParams dbConfig, minMigrationVersion string) error {

migrationVersionDBConn, err := dbParams.openDatabase()
if err != nil {
logger.Log("msg", "could not create DB connection in order to check the migration version", "DB", dbParams.Database, "error", err)
return err
}
defer migrationVersionDBConn.Close()

var flywayVersion string
row := migrationVersionDBConn.QueryRow(`SELECT version FROM flyway_schema_history ORDER BY installed_rank DESC LIMIT 1;`)
err = row.Scan(&flywayVersion)
if err != nil {
logger.Log("msg", "could not query the flyway_schema_history", "error", err)
return err
}

//flyway version and config migration version must match the format x.y where x and y are integers
matched, err := regexp.MatchString(`^[0-9]+\.[0-9]+$`, minMigrationVersion)
if err != nil {
return err
}
if !matched {
logger.Log("msg", "the config migration version does not match the required format")
return fmt.Errorf("The config migration version does not match the required format")
}

matched, err = regexp.MatchString(`^[0-9]+\.[0-9]+$`, flywayVersion)
if err != nil {
return err
}
if !matched {
logger.Log("msg", "the flyway migration version does not match the required format")
return fmt.Errorf("The flyway migration version does not match the required format")
}

// compare the two versions of the type x.y (major.minor)
minMajorRequired := strings.Split(minMigrationVersion, ".")
minMajorFlyway := strings.Split(flywayVersion, ".")

majorRequired, err := strconv.Atoi(minMajorRequired[0])
if err != nil {
logger.Log("msg", "could not convert string to int", "error", err)
return err
}
minorRequired, err := strconv.Atoi(minMajorRequired[1])
if err != nil {
logger.Log("msg", "could not convert string to int", "error", err)
return err
}

majorFlyway, err := strconv.Atoi(minMajorFlyway[0])
if err != nil {
logger.Log("msg", "could not convert string to int", "error", err)
return err
}
minorFlyway, err := strconv.Atoi(minMajorFlyway[1])
if err != nil {
logger.Log("msg", "could not convert string to int", "error", err)
return err
}

// it is required for the last script version of the flyway is to be "bigger" than the required version
if (majorFlyway < majorRequired) || (majorFlyway == majorRequired && minorFlyway < minorRequired) {
logger.Log("msg", "the DB schema is not up-to-date", "DB", dbParams.Database)
return fmt.Errorf("DB schema not up-to-date")
}

logger.Log("msg", "DB schema version fits the requirements")
return nil
}

func configureDbDefault(v *viper.Viper, prefix string) {
v.SetDefault(prefix+"-host-port", "")
v.SetDefault(prefix+"-username", "")
Expand Down
5 changes: 5 additions & 0 deletions configs/keycloak_bridge.yml
Expand Up @@ -44,6 +44,9 @@ db-audit-rw-protocol: tcp
db-audit-rw-max-open-conns: 10
db-audit-rw-max-idle-conns: 2
db-audit-rw-conn-max-lifetime: 3600
db-audit-migration: false
db-audit-migration-version:


# DB Audit RO
db-audit-ro-host-port: 127.0.0.1:3306
Expand All @@ -64,6 +67,8 @@ db-config-protocol: tcp
db-config-max-open-conns: 10
db-config-max-idle-conns: 2
db-config-conn-max-lifetime: 3600
db-config-migration: false
db-config-migration-version: 4.1

# audit events
events-db: false
Expand Down
4 changes: 4 additions & 0 deletions internal/keycloakb/cloudtrustdb.go
Expand Up @@ -34,6 +34,10 @@ func (NoopDB) SetConnMaxLifetime(d time.Duration) {

}

func (NoopDB) Close() error {
return nil
}

// NoopResult is a sql.Result that does nothing.
type NoopResult struct{}

Expand Down
19 changes: 0 additions & 19 deletions pkg/event/module.go
Expand Up @@ -95,24 +95,6 @@ func (sm *statisticModule) Stats(_ context.Context, m map[string]string) error {
}

const (
createTable = `CREATE TABLE IF NOT EXISTS audit (
audit_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
audit_time TIMESTAMP NULL,
origin VARCHAR(255),
realm_name VARCHAR(255),
agent_user_id VARCHAR(36),
agent_username VARCHAR(255),
agent_realm_name VARCHAR(255),
user_id VARCHAR(36),
username VARCHAR(255),
ct_event_type VARCHAR(50),
kc_event_type VARCHAR(50),
kc_operation_type VARCHAR(50),
client_id VARCHAR(255),
additional_info TEXT,
CONSTRAINT audit_pk PRIMARY KEY (audit_id)
);`

insertEvent = `INSERT INTO audit (
audit_time,
origin,
Expand Down Expand Up @@ -146,7 +128,6 @@ type eventsDBModule struct {

// NewConsoleModule returns a Console module.
func NewEventsDBModule(db DBEvents) EventsDBModule {
//db.Exec(createTable)
return &eventsDBModule{
db: db,
}
Expand Down
8 changes: 0 additions & 8 deletions pkg/export/storage.go
Expand Up @@ -7,11 +7,6 @@ import (
)

const (
createConfigTblStmt = `CREATE TABLE IF NOT EXISTS config (
component_name STRING,
version STRING,
config BYTES,
PRIMARY KEY (component_name, version))`
upsertConfigStmt = `UPSERT INTO config (
component_name,
version,
Expand All @@ -33,9 +28,6 @@ type DB interface {

// NewConfigStorageModule returns the storage module.
func NewConfigStorageModule(db DB) *StorageModule {
// Init DB: create config table.
db.Exec(createConfigTblStmt)

return &StorageModule{
db: db,
}
Expand Down
8 changes: 0 additions & 8 deletions pkg/management/module.go
Expand Up @@ -6,13 +6,6 @@ import (
)

const (
createConfigTableStmt = `CREATE TABLE IF NOT EXISTS realm_configuration(
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
realm_id VARCHAR(255) NOT NULL,
configuration JSON,
CHECK (configuration IS NULL OR JSON_VALID(configuration))
);
CREATE UNIQUE INDEX IF NOT EXISTS realm_id_idx ON realm_configuration(realm_id);`
updateConfigStmt = `INSERT INTO realm_configuration (realm_id, configuration)
VALUES (?, ?)
ON DUPLICATE KEY UPDATE configuration = ?;`
Expand All @@ -36,7 +29,6 @@ type configurationDBModule struct {

// NewConfigurationDBModule returns a ConfigurationDB module.
func NewConfigurationDBModule(db DBConfiguration) ConfigurationDBModule {
db.Exec(createConfigTableStmt)
return &configurationDBModule{
db: db,
}
Expand Down
1 change: 0 additions & 1 deletion pkg/management/module_test.go
Expand Up @@ -14,7 +14,6 @@ func TestConfigurationDBModule(t *testing.T) {
defer mockCtrl.Finish()
var mockDB = mock.NewDBConfiguration(mockCtrl)

mockDB.EXPECT().Exec(gomock.Any()).Return(nil, nil).Times(1)
mockDB.EXPECT().Exec(gomock.Any(), "realmId", gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
var configDBModule = NewConfigurationDBModule(mockDB)
var err = configDBModule.StoreOrUpdate(context.Background(), "realmId", "{}")
Expand Down

0 comments on commit b8b58fd

Please sign in to comment.