Commit d89c27ba authored by Sietse Ringers's avatar Sietse Ringers
Browse files

feat: add mysql support to revocation database

parent f6962dc8
......@@ -286,17 +286,24 @@ func (oi metaObjectIdentifier) Value() (driver.Value, error) {
}
func (oi *metaObjectIdentifier) Scan(src interface{}) error {
s, ok := src.(string)
if !ok {
return errors.New("cannot convert source: not a string")
switch s := src.(type) {
case string:
*oi = metaObjectIdentifier(s)
return nil
case []byte:
*oi = metaObjectIdentifier(s)
return nil
}
*oi = metaObjectIdentifier(s)
return nil
return errors.New("cannot convert source: not a string or []byte")
}
func (metaObjectIdentifier) GormDataType(dialect gorm.Dialect) string {
if dialect.GetName() == "postgres" {
switch dialect.GetName() {
case "postgres":
return "text"
case "mysql":
return "varchar(512)"
default:
return ""
}
return ""
}
......@@ -60,12 +60,16 @@ func StartRevocationServer(t *testing.T) {
irma.Logger = logger
dbstr := "host=127.0.0.1 port=5432 user=testuser dbname=test password='testpassword' sslmode=disable"
dbtype := "postgres"
//dbstr := "testuser:testpassword@tcp(127.0.0.1)/test"
//dbtype := "mysql"
cred := irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root")
settings := map[irma.CredentialTypeIdentifier]*irma.RevocationSetting{
cred: {Mode: irma.RevocationModeServer},
}
irmaconf, err := irma.NewConfiguration(filepath.Join(testdata, "irma_configuration"), irma.ConfigurationOptions{
RevocationDB: dbstr,
RevocationDBType: dbtype,
RevocationSettings: settings,
})
require.NoError(t, err)
......@@ -78,10 +82,11 @@ func StartRevocationServer(t *testing.T) {
RevocationSettings: settings,
IrmaConfiguration: irmaconf,
RevocationDB: dbstr,
RevocationDBType: dbtype,
}
// Connect to database and clear records from previous test runs
g, err := gorm.Open("postgres", conf.RevocationDB)
g, err := gorm.Open(dbtype, conf.RevocationDB)
require.NoError(t, err)
require.NoError(t, g.DropTableIfExists((*irma.EventRecord)(nil)).Error)
require.NoError(t, g.DropTableIfExists((*irma.AccumulatorRecord)(nil)).Error)
......
......@@ -93,6 +93,7 @@ func setFlags(cmd *cobra.Command, production bool) error {
flags.String("static-path", "", "Host files under this path as static files (leave empty to disable)")
flags.String("static-prefix", "/", "Host static files under this URL prefix")
flags.StringP("url", "u", defaulturl, "external URL to server to which the IRMA client connects, \":port\" being replaced by --port value")
flags.String("revocation-db-type", "", "database type for revocation database (supported: mysql, postgres)")
flags.String("revocation-db", "", "connection string for revocation database")
flags.Bool("sse", false, "Enable server sent for status updates (experimental)")
......@@ -200,6 +201,7 @@ func configureServer(cmd *cobra.Command) error {
SchemesUpdateInterval: viper.GetInt("schemes-update"),
DisableSchemesUpdate: viper.GetInt("schemes-update") == 0,
IssuerPrivateKeysPath: viper.GetString("privkeys"),
RevocationDBType: viper.GetString("revocation-db-type"),
RevocationDB: viper.GetString("revocation-db"),
URL: viper.GetString("url"),
DisableTLS: viper.GetBool("no-tls"),
......
......@@ -118,6 +118,7 @@ type ConfigurationOptions struct {
Assets string
ReadOnly bool
RevocationDB string
RevocationDBType string
RevocationSettings map[CredentialTypeIdentifier]*RevocationSetting
}
......@@ -130,7 +131,12 @@ func NewConfiguration(path string, opts ConfigurationOptions) (conf *Configurati
readOnly: opts.ReadOnly,
}
conf.Revocation = &RevocationStorage{conf: conf}
if err = conf.Revocation.Load(Logger.IsLevelEnabled(logrus.DebugLevel), opts.RevocationDB, opts.RevocationSettings); err != nil {
if err = conf.Revocation.Load(
Logger.IsLevelEnabled(logrus.DebugLevel),
opts.RevocationDBType,
opts.RevocationDB,
opts.RevocationSettings,
); err != nil {
return nil, err
}
......
......@@ -7,6 +7,7 @@ import (
"github.com/go-errors/errors"
"github.com/hashicorp/go-multierror"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/jinzhu/gorm/dialects/postgres"
"github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/big"
......@@ -73,7 +74,7 @@ type (
// IssuanceRecord contains information generated during issuance, needed for later revocation.
IssuanceRecord struct {
CredType CredentialTypeIdentifier `gorm:"primary_key"`
Key string `gorm:"primary_key"`
Key string `gorm:"primary_key;column:revocationkey"`
Attr *big.Int
Issued int64
ValidUntil int64
......@@ -186,7 +187,7 @@ func (rs *RevocationStorage) UpdateLatest(typ CredentialTypeIdentifier, count ui
return err
}
var events []*EventRecord
if err := tx.Latest(typ, "index", count, &events); err != nil {
if err := tx.Latest(typ, "eventindex", count, &events); err != nil {
return err
}
update = rs.newUpdate(acc, events)
......@@ -283,7 +284,7 @@ func (rs *RevocationStorage) Revoke(typ CredentialTypeIdentifier, key string, sk
return rs.db.Transaction(func(tx revStorage) error {
var err error
issrecord := IssuanceRecord{}
if err = tx.Get(typ, "key", key, &issrecord); err != nil {
if err = tx.Get(typ, "revocationkey", key, &issrecord); err != nil {
return err
}
issrecord.RevokedAt = time.Now().UnixNano()
......@@ -407,7 +408,7 @@ func (rs *RevocationStorage) SaveIssuanceRecord(typ CredentialTypeIdentifier, re
// Misscelaneous methods
func (rs *RevocationStorage) Load(debug bool, connstr string, settings map[CredentialTypeIdentifier]*RevocationSetting) error {
func (rs *RevocationStorage) Load(debug bool, dbtype, connstr string, settings map[CredentialTypeIdentifier]*RevocationSetting) error {
var t *CredentialTypeIdentifier
for typ, s := range settings {
......@@ -435,7 +436,7 @@ func (rs *RevocationStorage) Load(debug bool, connstr string, settings map[Crede
rs.sqlMode = false
} else {
Logger.Trace("Connecting to revocation SQL database")
db, err := newSqlStorage(debug, connstr)
db, err := newSqlStorage(debug, dbtype, connstr)
if err != nil {
return err
}
......
......@@ -124,8 +124,14 @@ func (m memRevStorage) HasRecords(typ CredentialTypeIdentifier) bool {
return len(record.r.Events) > 0
}
func newSqlStorage(debug bool, db string) (revStorage, error) {
g, err := gorm.Open("postgres", db)
func newSqlStorage(debug bool, dbtype, connstr string) (revStorage, error) {
switch dbtype {
case "postgres", "mysql":
default:
return nil, errors.New("unsupported database type")
}
g, err := gorm.Open(dbtype, connstr)
if err != nil {
return nil, err
}
......@@ -170,7 +176,7 @@ func (s sqlRevStorage) Transaction(f func(tx revStorage) error) (err error) {
}
func (s sqlRevStorage) Get(typ CredentialTypeIdentifier, col string, key interface{}, o interface{}) error {
return s.gorm.First(o, fmt.Sprintf("cred_type = ? and %s = ?", col), typ, key).Error
return s.gorm.Where(map[string]interface{}{"cred_type": typ, col: key}).First(o).Error
}
func (s sqlRevStorage) Insert(o interface{}) error {
......@@ -182,13 +188,13 @@ func (s sqlRevStorage) Save(o interface{}) error {
}
func (s sqlRevStorage) Last(typ CredentialTypeIdentifier, o interface{}) error {
return s.gorm.Last(o, "cred_type = ?", typ).Error
return s.gorm.Where(map[string]interface{}{"cred_type": typ}).Last(o).Error
}
func (s sqlRevStorage) Exists(typ CredentialTypeIdentifier, col string, key interface{}, o interface{}) (bool, error) {
var c int
s.gorm.Model(o).
Where(fmt.Sprintf("cred_type = ? and %s = ?", col), typ, key).
Where(map[string]interface{}{"cred_type": typ, col: key}).
Count(&c)
return c > 0, s.gorm.Error
}
......@@ -196,7 +202,7 @@ func (s sqlRevStorage) Exists(typ CredentialTypeIdentifier, col string, key inte
func (s sqlRevStorage) HasRecords(typ CredentialTypeIdentifier, o interface{}) (bool, error) {
var c int
s.gorm.Model(o).
Where("cred_type = ?", typ).
Where(map[string]interface{}{"cred_type": typ}).
Count(&c)
return c > 0, s.gorm.Error
}
......@@ -206,5 +212,5 @@ func (s sqlRevStorage) From(typ CredentialTypeIdentifier, col string, key interf
}
func (s sqlRevStorage) Latest(typ CredentialTypeIdentifier, col string, count uint64, o interface{}) error {
return s.gorm.Where("cred_type = ?", typ).Order(col + " asc").Limit(count).Find(o).Error
return s.gorm.Where(map[string]interface{}{"cred_type": typ}).Order(col + " asc").Limit(count).Find(o).Error
}
......@@ -54,7 +54,8 @@ type Configuration struct {
Logger *logrus.Logger `json:"-"`
// Connection string for revocation database
RevocationDB string `json:"revocation_db" mapstructure:"revocation_db"`
RevocationDB string `json:"revocation_db" mapstructure:"revocation_db"`
RevocationDBType string `json:"revocation_db_type" mapstructure:"revocation_db_type"`
// Credentials types for which revocation database should be hosted
RevocationSettings map[irma.CredentialTypeIdentifier]*irma.RevocationSetting `json:"revocation_settings" mapstructure:"revocation_settings"`
......@@ -132,6 +133,7 @@ func (conf *Configuration) verifyIrmaConf() error {
conf.Logger.WithField("schemes_path", conf.SchemesPath).Info("Determined schemes path")
conf.IrmaConfiguration, err = irma.NewConfiguration(conf.SchemesPath, irma.ConfigurationOptions{
Assets: conf.SchemesAssetsPath,
RevocationDBType: conf.RevocationDBType,
RevocationDB: conf.RevocationDB,
RevocationSettings: conf.RevocationSettings,
})
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment