github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/lib/dbaccessor.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package lib
    18  
    19  import (
    20  	"encoding/json"
    21  	"strings"
    22  
    23  	"github.com/hyperledger/fabric-ca/lib/attr"
    24  
    25  	"github.com/pkg/errors"
    26  
    27  	"github.com/cloudflare/cfssl/log"
    28  	"github.com/hyperledger/fabric-ca/api"
    29  	"github.com/hyperledger/fabric-ca/lib/spi"
    30  	"golang.org/x/crypto/bcrypt"
    31  	"golang.org/x/crypto/ocsp"
    32  
    33  	"github.com/jmoiron/sqlx"
    34  	"github.com/kisielk/sqlstruct"
    35  	_ "github.com/mattn/go-sqlite3" // Needed to support sqlite
    36  )
    37  
    38  // Match to sqlx
    39  func init() {
    40  	sqlstruct.TagName = "db"
    41  }
    42  
    43  const (
    44  	insertUser = `
    45  INSERT INTO users (id, token, type, affiliation, attributes, state, max_enrollments, level)
    46  	VALUES (:id, :token, :type, :affiliation, :attributes, :state, :max_enrollments, :level);`
    47  
    48  	deleteUser = `
    49  DELETE FROM users
    50  	WHERE (id = ?);`
    51  
    52  	updateUser = `
    53  UPDATE users
    54  	SET token = :token, type = :type, affiliation = :affiliation, attributes = :attributes, state = :state, max_enrollments = :max_enrollments, level = :level
    55  	WHERE (id = :id);`
    56  
    57  	getUser = `
    58  SELECT * FROM users
    59  	WHERE (id = ?)`
    60  
    61  	insertAffiliation = `
    62  INSERT INTO affiliations (name, prekey, level)
    63  	VALUES (?, ?, ?)`
    64  
    65  	deleteAffiliation = `
    66  DELETE FROM affiliations
    67  	WHERE (name = ?)`
    68  
    69  	getAffiliationQuery = `
    70  SELECT * FROM affiliations
    71  	WHERE (name = ?)`
    72  
    73  	getAllAffiliationsQuery = `
    74  SELECT * FROM affiliations
    75  	WHERE ((name = ?) OR (name LIKE ?))`
    76  )
    77  
    78  // UserRecord defines the properties of a user
    79  type UserRecord struct {
    80  	Name           string `db:"id"`
    81  	Pass           []byte `db:"token"`
    82  	Type           string `db:"type"`
    83  	Affiliation    string `db:"affiliation"`
    84  	Attributes     string `db:"attributes"`
    85  	State          int    `db:"state"`
    86  	MaxEnrollments int    `db:"max_enrollments"`
    87  	Level          int    `db:"level"`
    88  }
    89  
    90  // AffiliationRecord defines the properties of an affiliation
    91  type AffiliationRecord struct {
    92  	Name   string `db:"name"`
    93  	Prekey string `db:"prekey"`
    94  	Level  int    `db:"level"`
    95  }
    96  
    97  // Accessor implements db.Accessor interface.
    98  type Accessor struct {
    99  	db *sqlx.DB
   100  }
   101  
   102  // NewDBAccessor is a constructor for the database API
   103  func NewDBAccessor(db *sqlx.DB) *Accessor {
   104  	return &Accessor{
   105  		db: db,
   106  	}
   107  }
   108  
   109  func (d *Accessor) checkDB() error {
   110  	if d.db == nil {
   111  		return errors.New("Failed to correctly setup database connection")
   112  	}
   113  	return nil
   114  }
   115  
   116  // SetDB changes the underlying sql.DB object Accessor is manipulating.
   117  func (d *Accessor) SetDB(db *sqlx.DB) {
   118  	d.db = db
   119  }
   120  
   121  // InsertUser inserts user into database
   122  func (d *Accessor) InsertUser(user *spi.UserInfo) error {
   123  	if user == nil {
   124  		return errors.New("User is not defined")
   125  	}
   126  	log.Debugf("DB: Add identity %s", user.Name)
   127  
   128  	err := d.checkDB()
   129  	if err != nil {
   130  		return err
   131  	}
   132  
   133  	attrBytes, err := json.Marshal(user.Attributes)
   134  	if err != nil {
   135  		return err
   136  	}
   137  
   138  	// Hash the password before storing it
   139  	pwd := []byte(user.Pass)
   140  	pwd, err = bcrypt.GenerateFromPassword(pwd, bcrypt.DefaultCost)
   141  	if err != nil {
   142  		return errors.Wrap(err, "Failed to hash password")
   143  	}
   144  
   145  	// Store the user record in the DB
   146  	res, err := d.db.NamedExec(insertUser, &UserRecord{
   147  		Name:           user.Name,
   148  		Pass:           pwd,
   149  		Type:           user.Type,
   150  		Affiliation:    user.Affiliation,
   151  		Attributes:     string(attrBytes),
   152  		State:          user.State,
   153  		MaxEnrollments: user.MaxEnrollments,
   154  		Level:          user.Level,
   155  	})
   156  
   157  	if err != nil {
   158  		return errors.Wrapf(err, "Error adding identity '%s' to the database", user.Name)
   159  	}
   160  
   161  	numRowsAffected, err := res.RowsAffected()
   162  	if err != nil {
   163  		return err
   164  	}
   165  
   166  	if numRowsAffected == 0 {
   167  		return errors.Errorf("Failed to add identity %s to the database", user.Name)
   168  	}
   169  
   170  	if numRowsAffected != 1 {
   171  		return errors.Errorf("Expected to add one record to the database, but %d records were added", numRowsAffected)
   172  	}
   173  
   174  	log.Debugf("Successfully added identity %s to the database", user.Name)
   175  
   176  	return nil
   177  
   178  }
   179  
   180  // DeleteUser deletes user from database
   181  func (d *Accessor) DeleteUser(id string) (spi.User, error) {
   182  	log.Debugf("DB: Delete identity %s", id)
   183  
   184  	result, err := d.doTransaction(d.deleteUserTx, id, ocsp.CessationOfOperation) // 5 (cessationofoperation) reason for certificate revocation
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  
   189  	userRec := result.(*UserRecord)
   190  	user := d.newDBUser(userRec)
   191  
   192  	return user, nil
   193  }
   194  
   195  func (d *Accessor) deleteUserTx(tx *sqlx.Tx, args ...interface{}) (interface{}, error) {
   196  	id := args[0].(string)
   197  	reason := args[1].(int)
   198  
   199  	var userRec UserRecord
   200  	err := tx.Get(&userRec, tx.Rebind(getUser), id)
   201  	if err != nil {
   202  		return nil, getError(err, "User")
   203  	}
   204  
   205  	_, err = tx.Exec(tx.Rebind(deleteUser), id)
   206  	if err != nil {
   207  		return nil, newHTTPErr(500, ErrDBDeleteUser, "Error deleting identity '%s': %s", id, err)
   208  	}
   209  
   210  	record := &CertRecord{
   211  		ID: id,
   212  	}
   213  	record.Reason = reason
   214  
   215  	_, err = tx.NamedExec(tx.Rebind(updateRevokeSQL), record)
   216  	if err != nil {
   217  		return nil, newHTTPErr(500, ErrDBDeleteUser, "Error encountered while revoking certificates for identity '%s' that is being deleted: %s", id, err)
   218  	}
   219  
   220  	return &userRec, nil
   221  }
   222  
   223  // UpdateUser updates user in database
   224  func (d *Accessor) UpdateUser(user *spi.UserInfo, updatePass bool) error {
   225  	if user == nil {
   226  		return errors.New("User is not defined")
   227  	}
   228  
   229  	log.Debugf("DB: Update identity %s", user.Name)
   230  	err := d.checkDB()
   231  	if err != nil {
   232  		return err
   233  	}
   234  
   235  	attributes, err := json.Marshal(user.Attributes)
   236  	if err != nil {
   237  		return errors.Wrap(err, "Failed to marshal user attributes")
   238  	}
   239  
   240  	// Hash the password before storing it
   241  	pwd := []byte(user.Pass)
   242  	if updatePass {
   243  		pwd, err = bcrypt.GenerateFromPassword(pwd, bcrypt.DefaultCost)
   244  		if err != nil {
   245  			return errors.Wrap(err, "Failed to hash password")
   246  		}
   247  	}
   248  
   249  	// Store the updated user entry
   250  	res, err := d.db.NamedExec(updateUser, &UserRecord{
   251  		Name:           user.Name,
   252  		Pass:           pwd,
   253  		Type:           user.Type,
   254  		Affiliation:    user.Affiliation,
   255  		Attributes:     string(attributes),
   256  		State:          user.State,
   257  		MaxEnrollments: user.MaxEnrollments,
   258  		Level:          user.Level,
   259  	})
   260  
   261  	if err != nil {
   262  		return errors.Wrap(err, "Failed to update identity record")
   263  	}
   264  
   265  	numRowsAffected, err := res.RowsAffected()
   266  
   267  	if numRowsAffected == 0 {
   268  		return errors.New("Failed to update any identity records")
   269  	}
   270  
   271  	if numRowsAffected != 1 {
   272  		return errors.Errorf("Expected one identity record to be updated, but %d records were updated", numRowsAffected)
   273  	}
   274  
   275  	return err
   276  
   277  }
   278  
   279  // GetUser gets user from database
   280  func (d *Accessor) GetUser(id string, attrs []string) (spi.User, error) {
   281  	log.Debugf("DB: Getting identity %s", id)
   282  
   283  	err := d.checkDB()
   284  	if err != nil {
   285  		return nil, err
   286  	}
   287  
   288  	var userRec UserRecord
   289  	err = d.db.Get(&userRec, d.db.Rebind(getUser), id)
   290  	if err != nil {
   291  		return nil, getError(err, "User")
   292  	}
   293  
   294  	return d.newDBUser(&userRec), nil
   295  }
   296  
   297  // InsertAffiliation inserts affiliation into database
   298  func (d *Accessor) InsertAffiliation(name string, prekey string, level int) error {
   299  	log.Debugf("DB: Add affiliation %s", name)
   300  	err := d.checkDB()
   301  	if err != nil {
   302  		return err
   303  	}
   304  	dbType := d.db.DriverName()
   305  	// InnoDB store engine for MySQL does not allow more than 767 bytes
   306  	// in a 'UNIQUE' column. To work around this, the UNIQUE constraint was removed
   307  	// from the 'name' column in the affiliations table for MySQL to allow for up to 1024
   308  	// characters to be stored. In doing this, a check is needed on MySQL to check
   309  	// if the affiliation exists before adding it to prevent duplicate entries.
   310  	if dbType == "mysql" {
   311  		aff, _ := d.GetAffiliation(name)
   312  		if aff != nil {
   313  			log.Debugf("Affiliation '%s' already exists", name)
   314  			return nil
   315  		}
   316  	}
   317  	_, err = d.db.Exec(d.db.Rebind(insertAffiliation), name, prekey, level)
   318  	if err != nil {
   319  		if (!strings.Contains(err.Error(), "UNIQUE constraint failed") && dbType == "sqlite3") || (!strings.Contains(err.Error(), "duplicate key value") && dbType == "postgres") {
   320  			return err
   321  		}
   322  		log.Debugf("Affiliation '%s' already exists", name)
   323  		return nil
   324  	}
   325  	log.Debugf("Affiliation '%s' added", name)
   326  
   327  	return nil
   328  }
   329  
   330  // DeleteAffiliation deletes affiliation from database. Using the force option with identity removal allowed
   331  // this will also delete the identities associated with removed affiliations, and also delete the certificates
   332  // for the identities removed
   333  func (d *Accessor) DeleteAffiliation(name string, force, identityRemoval, isRegistrar bool) (*spi.DbTxResult, error) {
   334  	log.Debugf("DB: Delete affiliation %s", name)
   335  
   336  	_, err := d.GetAffiliation(name)
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  
   341  	result, err := d.doTransaction(d.deleteAffiliationTx, name, force, identityRemoval, isRegistrar)
   342  	if err != nil {
   343  		return nil, err
   344  	}
   345  
   346  	deletedInfo := result.(*spi.DbTxResult)
   347  
   348  	return deletedInfo, nil
   349  }
   350  
   351  func (d *Accessor) deleteAffiliationTx(tx *sqlx.Tx, args ...interface{}) (interface{}, error) {
   352  	var err error
   353  
   354  	name := args[0].(string)
   355  	force := args[1].(bool)
   356  	identityRemoval := args[2].(bool)
   357  	isRegistar := args[3].(bool)
   358  
   359  	query := "SELECT * FROM users WHERE (affiliation = ?)"
   360  	ids := []UserRecord{}
   361  	err = tx.Select(&ids, tx.Rebind(query), name)
   362  	if err != nil {
   363  		return nil, newHTTPErr(500, ErrRemoveAffDB, "Failed to select users with affiliation '%s': %s", name, err)
   364  	}
   365  
   366  	subAffName := name + ".%"
   367  	query = "SELECT * FROM users WHERE (affiliation LIKE ?)"
   368  	subAffIds := []UserRecord{}
   369  	err = tx.Select(&subAffIds, tx.Rebind(query), subAffName)
   370  	if err != nil {
   371  		return nil, newHTTPErr(500, ErrRemoveAffDB, "Failed to select users with sub-affiliation of '%s': %s", name, err)
   372  	}
   373  
   374  	ids = append(ids, subAffIds...)
   375  	idNames := []string{}
   376  	for _, id := range ids {
   377  		idNames = append(idNames, id.Name)
   378  	}
   379  	idNamesStr := strings.Join(idNames, ",")
   380  
   381  	if len(ids) > 0 {
   382  		if !isRegistar {
   383  			return nil, newAuthErr(ErrUpdateConfigRemoveAff, "Removing affiliation affects identities, but caller is not a registrar")
   384  		}
   385  
   386  		// Force enabled, delete any associated identities and certificates
   387  		if force {
   388  			log.Debugf("IDs '%s' to removed based on affiliation '%s' removal", idNamesStr, name)
   389  
   390  			if !identityRemoval {
   391  				return nil, newAuthErr(ErrUpdateConfigRemoveAff, "Identity removal is not allowed on server")
   392  			}
   393  
   394  			// Delete all the identities in one database request
   395  			query := "DELETE FROM users WHERE (id IN (?))"
   396  			inQuery, args, err := sqlx.In(query, idNames)
   397  			if err != nil {
   398  				return nil, newHTTPErr(500, ErrRemoveAffDB, "Failed to construct query '%s': %s", query, err)
   399  			}
   400  			_, err = tx.Exec(tx.Rebind(inQuery), args...)
   401  			if err != nil {
   402  				return nil, newHTTPErr(500, ErrRemoveAffDB, "Failed to execute query '%s' for multiple identity removal: %s", query, err)
   403  			}
   404  
   405  			// Revoke all the certificates associated with the removed identities above with reason of "affiliationchange" (3)
   406  			query = "UPDATE certificates SET status='revoked', revoked_at=CURRENT_TIMESTAMP, reason = ? WHERE (id IN (?) AND status != 'revoked')"
   407  			inQuery, args, err = sqlx.In(query, ocsp.AffiliationChanged, idNames)
   408  			if err != nil {
   409  				return nil, newHTTPErr(500, ErrRemoveAffDB, "Failed to construct query '%s': %s", query, err)
   410  			}
   411  			_, err = tx.Exec(tx.Rebind(inQuery), args...)
   412  			if err != nil {
   413  				return nil, newHTTPErr(500, ErrRemoveAffDB, "Failed to execute query '%s' for multiple certificate removal: %s", query, err)
   414  			}
   415  		} else {
   416  			// If force option is not specified, only delete affiliation if there are no identities that have that affiliation
   417  			return nil, newAuthErr(ErrUpdateConfigRemoveAff, "The request to remove affiliation '%s' has the following identities associated: %s. Need to use 'force' to remove identities and affiliation", name, idNamesStr)
   418  		}
   419  	}
   420  
   421  	aff := AffiliationRecord{}
   422  	err = tx.Get(&aff, tx.Rebind(getAffiliationQuery), name)
   423  	if err != nil {
   424  		return nil, getError(err, "Affiliation")
   425  	}
   426  	// Getting all the sub-affiliations that are going to be deleted
   427  	allAffs := []AffiliationRecord{}
   428  	err = tx.Select(&allAffs, tx.Rebind("Select * FROM affiliations where (name LIKE ?)"), subAffName)
   429  	if err != nil {
   430  		return nil, newHTTPErr(500, ErrRemoveAffDB, "Failed to select sub-affiliations of '%s': %s", allAffs, err)
   431  	}
   432  	allAffs = append(allAffs, aff)
   433  	log.Debug("All affiliations to be removed: ", allAffs)
   434  
   435  	// Delete the requested affiliation
   436  	_, err = tx.Exec(tx.Rebind(deleteAffiliation), name)
   437  	if err != nil {
   438  		return nil, newHTTPErr(500, ErrRemoveAffDB, "Failed to delete affiliation '%s': %s", name, err)
   439  	}
   440  	// Delete all the sub-affiliations
   441  	_, err = tx.Exec(tx.Rebind("DELETE FROM affiliations where (name LIKE ?)"), subAffName)
   442  	if err != nil {
   443  		return nil, newHTTPErr(500, ErrRemoveAffDB, "Failed to delete affiliations: %s", err)
   444  	}
   445  
   446  	// Return the identities and affiliations that were removed
   447  	result := d.getResult(ids, allAffs)
   448  
   449  	return result, nil
   450  }
   451  
   452  // GetAffiliation gets affiliation from database
   453  func (d *Accessor) GetAffiliation(name string) (spi.Affiliation, error) {
   454  	log.Debugf("DB: Get affiliation %s", name)
   455  	err := d.checkDB()
   456  	if err != nil {
   457  		return nil, err
   458  	}
   459  
   460  	var affiliationRecord AffiliationRecord
   461  
   462  	err = d.db.Get(&affiliationRecord, d.db.Rebind(getAffiliationQuery), name)
   463  	if err != nil {
   464  		return nil, getError(err, "Affiliation")
   465  	}
   466  
   467  	affiliation := spi.NewAffiliation(affiliationRecord.Name, affiliationRecord.Prekey, affiliationRecord.Level)
   468  
   469  	return affiliation, nil
   470  }
   471  
   472  // GetAffiliationTree returns the requested affiliation and affiliations below
   473  func (d *Accessor) GetAffiliationTree(name string) (*spi.DbTxResult, error) {
   474  	log.Debugf("DB: Get affiliation tree for '%s'", name)
   475  
   476  	if name != "" {
   477  		_, err := d.GetAffiliation(name)
   478  		if err != nil {
   479  			return nil, err
   480  		}
   481  	}
   482  
   483  	result, err := d.doTransaction(d.getAffiliationTreeTx, name)
   484  	if err != nil {
   485  		return nil, err
   486  	}
   487  
   488  	getResult := result.(*spi.DbTxResult)
   489  
   490  	return getResult, nil
   491  }
   492  
   493  // GetAffiliation gets affiliation from database
   494  func (d *Accessor) getAffiliationTreeTx(tx *sqlx.Tx, args ...interface{}) (interface{}, error) {
   495  	name := args[0].(string)
   496  
   497  	log.Debugf("DB: Get affiliation tree for %s", name)
   498  	err := d.checkDB()
   499  	if err != nil {
   500  		return nil, err
   501  	}
   502  
   503  	// Getting affiliations
   504  	allAffs := []AffiliationRecord{}
   505  	if name == "" { // Requesting all affiliations
   506  		err = tx.Select(&allAffs, tx.Rebind("SELECT * FROM affiliations"))
   507  		if err != nil {
   508  			return nil, newHTTPErr(500, ErrGettingAffiliation, "Failed to get affiliation tree for '%s': %s", name, err)
   509  		}
   510  	} else {
   511  		err = tx.Select(&allAffs, tx.Rebind("Select * FROM affiliations where (name LIKE ?) OR (name = ?)"), name+".%", name)
   512  		if err != nil {
   513  			return nil, newHTTPErr(500, ErrGettingAffiliation, "Failed to get affiliation tree for '%s': %s", name, err)
   514  		}
   515  	}
   516  
   517  	ids := []UserRecord{} // TODO: Return identities associated with these affiliations
   518  	result := d.getResult(ids, allAffs)
   519  	return result, nil
   520  }
   521  
   522  // GetProperties returns the properties from the database
   523  func (d *Accessor) GetProperties(names []string) (map[string]string, error) {
   524  	log.Debugf("DB: Get properties %s", names)
   525  	err := d.checkDB()
   526  	if err != nil {
   527  		return nil, err
   528  	}
   529  
   530  	type property struct {
   531  		Name  string `db:"property"`
   532  		Value string `db:"value"`
   533  	}
   534  
   535  	properties := []property{}
   536  
   537  	query := "SELECT * FROM properties WHERE (property IN (?))"
   538  	inQuery, args, err := sqlx.In(query, names)
   539  	if err != nil {
   540  		return nil, errors.Wrapf(err, "Failed to construct query '%s' for properties '%s'", query, names)
   541  	}
   542  	err = d.db.Select(&properties, d.db.Rebind(inQuery), args...)
   543  	if err != nil {
   544  		return nil, getError(err, "Properties")
   545  	}
   546  
   547  	propertiesMap := make(map[string]string)
   548  	for _, prop := range properties {
   549  		propertiesMap[prop.Name] = prop.Value
   550  	}
   551  
   552  	return propertiesMap, nil
   553  }
   554  
   555  // GetUserLessThanLevel returns all identities that are less than the level specified
   556  // Otherwise, returns no users if requested level is zero
   557  func (d *Accessor) GetUserLessThanLevel(level int) ([]spi.User, error) {
   558  	if level == 0 {
   559  		return []spi.User{}, nil
   560  	}
   561  
   562  	rows, err := d.db.Queryx(d.db.Rebind("SELECT * FROM users WHERE (level < ?) OR (level IS NULL)"), level)
   563  	if err != nil {
   564  		return nil, errors.Wrap(err, "Failed to get identities that need to be updated")
   565  	}
   566  
   567  	allUsers := []spi.User{}
   568  
   569  	for rows.Next() {
   570  		var user UserRecord
   571  		rows.StructScan(&user)
   572  		dbUser := d.newDBUser(&user)
   573  		allUsers = append(allUsers, dbUser)
   574  	}
   575  
   576  	return allUsers, nil
   577  }
   578  
   579  // GetAllAffiliations gets the requested affiliation and any sub affiliations from the database
   580  func (d *Accessor) GetAllAffiliations(name string) (*sqlx.Rows, error) {
   581  	log.Debugf("DB: Get affiliation %s", name)
   582  	err := d.checkDB()
   583  	if err != nil {
   584  		return nil, err
   585  	}
   586  
   587  	if name == "" { // Requesting all affiliations
   588  		rows, err := d.db.Queryx(d.db.Rebind("SELECT * FROM affiliations"))
   589  		if err != nil {
   590  			return nil, err
   591  		}
   592  		return rows, nil
   593  	}
   594  
   595  	rows, err := d.db.Queryx(d.db.Rebind(getAllAffiliationsQuery), name, name+".%")
   596  	if err != nil {
   597  		return nil, err
   598  	}
   599  
   600  	return rows, nil
   601  }
   602  
   603  // GetFilteredUsers returns all identities that fall under the affiliation and types
   604  func (d *Accessor) GetFilteredUsers(affiliation, types string) (*sqlx.Rows, error) {
   605  	log.Debugf("DB: Get all identities per affiliation '%s' and types '%s'", affiliation, types)
   606  	err := d.checkDB()
   607  	if err != nil {
   608  		return nil, err
   609  	}
   610  
   611  	typesArray := strings.Split(types, ",")
   612  	for i := range typesArray {
   613  		typesArray[i] = strings.TrimSpace(typesArray[i])
   614  	}
   615  
   616  	if affiliation == "" {
   617  		query := "SELECT * FROM users WHERE (type IN (?))"
   618  		query, args, err := sqlx.In(query, typesArray)
   619  		if err != nil {
   620  			return nil, errors.Wrapf(err, "Failed to construct query '%s' for affiliation '%s' and types '%s'", query, affiliation, types)
   621  		}
   622  		rows, err := d.db.Queryx(d.db.Rebind(query), args...)
   623  		if err != nil {
   624  			return nil, errors.Wrapf(err, "Failed to execute query '%s' for affiliation '%s' and types '%s'", query, affiliation, types)
   625  		}
   626  		return rows, nil
   627  	}
   628  
   629  	subAffiliation := affiliation + ".%"
   630  	query := "SELECT * FROM users WHERE ((affiliation = ?) OR (affiliation LIKE ?)) AND (type IN (?))"
   631  	inQuery, args, err := sqlx.In(query, affiliation, subAffiliation, typesArray)
   632  	if err != nil {
   633  		return nil, errors.Wrapf(err, "Failed to construct query '%s' for affiliation '%s' and types '%s'", query, affiliation, types)
   634  	}
   635  	rows, err := d.db.Queryx(d.db.Rebind(inQuery), args...)
   636  	if err != nil {
   637  		return nil, errors.Wrapf(err, "Failed to execute query '%s' for affiliation '%s' and types '%s'", query, affiliation, types)
   638  	}
   639  
   640  	return rows, nil
   641  
   642  }
   643  
   644  // ModifyAffiliation renames the affiliation and updates all identities to use the new affiliation depending on
   645  // the value of the "force" parameter
   646  func (d *Accessor) ModifyAffiliation(oldAffiliation, newAffiliation string, force, isRegistrar bool) (*spi.DbTxResult, error) {
   647  	log.Debugf("DB: Modify affiliation from '%s' to '%s'", oldAffiliation, newAffiliation)
   648  	err := d.checkDB()
   649  	if err != nil {
   650  		return nil, err
   651  	}
   652  
   653  	// Check to see if the affiliation being modifies exists in the affiliation table
   654  	_, err = d.GetAffiliation(oldAffiliation)
   655  	if err != nil {
   656  		return nil, err
   657  	}
   658  
   659  	// Check to see if the new affiliation being requested exists in the affiliation table
   660  	_, err = d.GetAffiliation(newAffiliation)
   661  	if err == nil {
   662  		return nil, newHTTPErr(400, ErrUpdateConfigModifyAff, "Affiliation '%s' already exists", newAffiliation)
   663  	}
   664  
   665  	result, err := d.doTransaction(d.modifyAffiliationTx, oldAffiliation, newAffiliation, force, isRegistrar)
   666  	if err != nil {
   667  		return nil, err
   668  	}
   669  
   670  	modifiedInfo := result.(*spi.DbTxResult)
   671  
   672  	return modifiedInfo, nil
   673  }
   674  
   675  func (d *Accessor) modifyAffiliationTx(tx *sqlx.Tx, args ...interface{}) (interface{}, error) {
   676  	oldAffiliation := args[0].(string)
   677  	newAffiliation := args[1].(string)
   678  	force := args[2].(bool)
   679  	isRegistar := args[3].(bool)
   680  
   681  	// Get the affiliation record
   682  	query := "SELECT name, prekey FROM affiliations WHERE (name = ?)"
   683  	var oldAffiliationRecord AffiliationRecord
   684  	err := tx.Get(&oldAffiliationRecord, tx.Rebind(query), oldAffiliation)
   685  	if err != nil {
   686  		return nil, err
   687  	}
   688  
   689  	// Get the affiliation records for all sub affiliations
   690  	query = "SELECT name, prekey FROM affiliations WHERE (name LIKE ?)"
   691  	var allOldAffiliations []AffiliationRecord
   692  	err = tx.Select(&allOldAffiliations, tx.Rebind(query), oldAffiliation+".%")
   693  	if err != nil {
   694  		return nil, err
   695  	}
   696  
   697  	allOldAffiliations = append(allOldAffiliations, oldAffiliationRecord)
   698  
   699  	log.Debugf("Affiliations to be modified %+v", allOldAffiliations)
   700  
   701  	// Iterate through all the affiliations found and update to use new affiliation path
   702  	idsUpdated := []string{}
   703  	for _, affiliation := range allOldAffiliations {
   704  		var idsWithOldAff []UserRecord
   705  		oldPath := affiliation.Name
   706  		oldParentPath := affiliation.Prekey
   707  		newPath := strings.Replace(oldPath, oldAffiliation, newAffiliation, 1)
   708  		newParentPath := strings.Replace(oldParentPath, oldAffiliation, newAffiliation, 1)
   709  		log.Debugf("oldPath: %s, newPath: %s, oldParentPath: %s, newParentPath: %s", oldPath, newPath, oldParentPath, newParentPath)
   710  
   711  		// Select all users that are using the old affiliation
   712  		query = "SELECT * FROM users WHERE (affiliation = ?)"
   713  		err = tx.Select(&idsWithOldAff, tx.Rebind(query), oldPath)
   714  		if err != nil {
   715  			return nil, err
   716  		}
   717  		if len(idsWithOldAff) > 0 {
   718  			if !isRegistar {
   719  				return nil, newAuthErr(ErrMissingRegAttr, "Modifying affiliation affects identities, but caller is not a registrar")
   720  			}
   721  			// Get the list of names of the identities that need to be updated to use new affiliation
   722  			ids := []string{}
   723  			for _, id := range idsWithOldAff {
   724  				ids = append(ids, id.Name)
   725  			}
   726  
   727  			if force {
   728  				log.Debugf("Identities %s to be updated to use new affiliation of '%s' from '%s'", ids, newPath, oldPath)
   729  
   730  				query := "Update users SET affiliation = ? WHERE (id IN (?))"
   731  				inQuery, args, err := sqlx.In(query, newPath, ids)
   732  				if err != nil {
   733  					return nil, errors.Wrapf(err, "Failed to construct query '%s'", query)
   734  				}
   735  				_, err = tx.Exec(tx.Rebind(inQuery), args...)
   736  				if err != nil {
   737  					return nil, errors.Wrapf(err, "Failed to execute query '%s' for multiple certificate removal", query)
   738  				}
   739  
   740  				// If user's affiliation is being updated, need to also update 'hf.Affiliation' attribute of user
   741  				for _, userRec := range idsWithOldAff {
   742  					user := d.newDBUser(&userRec)
   743  					currentAttrs, _ := user.GetAttributes(nil)                            // Get all current user attributes
   744  					userAff := GetUserAffiliation(user)                                   // Get the current affiliation
   745  					newAff := strings.Replace(userAff, oldAffiliation, newAffiliation, 1) // Replace old affiliation with new affiliation
   746  					userAttrs := getNewAttributes(currentAttrs, []api.Attribute{          // Generate the new set of attributes for user
   747  						api.Attribute{
   748  							Name:  attr.Affiliation,
   749  							Value: newAff,
   750  						},
   751  					})
   752  
   753  					attrBytes, err := json.Marshal(userAttrs)
   754  					if err != nil {
   755  						return nil, err
   756  					}
   757  
   758  					// Update attributes
   759  					query := "UPDATE users SET attributes = ? where (id = ?)"
   760  					id := user.GetName()
   761  					res, err := tx.Exec(tx.Rebind(query), string(attrBytes), id)
   762  					if err != nil {
   763  						return nil, err
   764  					}
   765  
   766  					numRowsAffected, err := res.RowsAffected()
   767  					if err != nil {
   768  						return nil, errors.Wrap(err, "Failed to get number of rows affected")
   769  					}
   770  
   771  					if numRowsAffected == 0 {
   772  						return nil, errors.Errorf("No rows were affected when updating the state of identity %s", id)
   773  					}
   774  
   775  					if numRowsAffected != 1 {
   776  						return nil, errors.Errorf("%d rows were affected when updating the state of identity %s", numRowsAffected, id)
   777  					}
   778  				}
   779  			} else {
   780  				// If force option is not specified, can only modify affiliation if there are no identities that have that affiliation
   781  				idNamesStr := strings.Join(ids, ",")
   782  				return nil, newHTTPErr(400, ErrUpdateConfigModifyAff, "The request to modify affiliation '%s' has the following identities associated: %s. Need to use 'force' to remove identities and affiliation", oldAffiliation, idNamesStr)
   783  			}
   784  
   785  			idsUpdated = append(idsUpdated, ids...)
   786  		}
   787  
   788  		// Update the affiliation record in the database to use new affiliation path
   789  		query = "Update affiliations SET name = ?, prekey = ? WHERE (name = ?)"
   790  		res := tx.MustExec(tx.Rebind(query), newPath, newParentPath, oldPath)
   791  		numRowsAffected, err := res.RowsAffected()
   792  		if err != nil {
   793  			return nil, errors.Errorf("Failed to get number of rows affected")
   794  		}
   795  		if numRowsAffected == 0 {
   796  			return nil, errors.Errorf("Failed to update any affiliation records for '%s'", oldPath)
   797  		}
   798  	}
   799  
   800  	// Generate the result set that has all identities with their new affiliation and all renamed affiliations
   801  	var idsWithNewAff []UserRecord
   802  	if len(idsUpdated) > 0 {
   803  		query = "Select * FROM users WHERE (id IN (?))"
   804  		inQuery, args, err := sqlx.In(query, idsUpdated)
   805  		if err != nil {
   806  			return nil, errors.Wrapf(err, "Failed to construct query '%s'", query)
   807  		}
   808  		err = tx.Select(&idsWithNewAff, tx.Rebind(inQuery), args...)
   809  		if err != nil {
   810  			return nil, errors.Wrapf(err, "Failed to execute query '%s' for getting users with new affiliation", query)
   811  		}
   812  	}
   813  
   814  	allNewAffs := []AffiliationRecord{}
   815  	err = tx.Select(&allNewAffs, tx.Rebind("Select * FROM affiliations where (name LIKE ?) OR (name = ?)"), newAffiliation+".%", newAffiliation)
   816  	if err != nil {
   817  		return nil, newHTTPErr(500, ErrGettingAffiliation, "Failed to get affiliation tree for '%s': %s", newAffiliation, err)
   818  	}
   819  
   820  	// Return the identities and affiliations that were modified
   821  	result := d.getResult(idsWithNewAff, allNewAffs)
   822  
   823  	return result, nil
   824  }
   825  
   826  func (d *Accessor) doTransaction(doit func(tx *sqlx.Tx, args ...interface{}) (interface{}, error), args ...interface{}) (interface{}, error) {
   827  	err := d.checkDB()
   828  	if err != nil {
   829  		return nil, err
   830  	}
   831  	tx := d.db.MustBegin()
   832  	result, err := doit(tx, args...)
   833  	if err != nil {
   834  		err2 := tx.Rollback()
   835  		if err2 != nil {
   836  			log.Errorf("Error encounted while rolling back transaction: %s", err2)
   837  			return nil, err
   838  		}
   839  		return nil, err
   840  	}
   841  
   842  	err = tx.Commit()
   843  	if err != nil {
   844  		return nil, errors.Wrap(err, "Error encountered while committing transaction")
   845  	}
   846  
   847  	return result, nil
   848  }
   849  
   850  // Returns the identities and affiliations that were modified
   851  func (d *Accessor) getResult(ids []UserRecord, affs []AffiliationRecord) *spi.DbTxResult {
   852  	// Collect all the identities that were modified
   853  	identities := []spi.User{}
   854  	for _, id := range ids {
   855  		identities = append(identities, d.newDBUser(&id))
   856  	}
   857  
   858  	// Collect the name of all affiliations that were modified
   859  	affiliations := []spi.Affiliation{}
   860  	for _, aff := range affs {
   861  		newAff := spi.NewAffiliation(aff.Name, aff.Prekey, aff.Level)
   862  		affiliations = append(affiliations, newAff)
   863  	}
   864  
   865  	return &spi.DbTxResult{
   866  		Affiliations: affiliations,
   867  		Identities:   identities,
   868  	}
   869  }
   870  
   871  // Creates a DBUser object from the DB user record
   872  func (d *Accessor) newDBUser(userRec *UserRecord) *DBUser {
   873  	var user = new(DBUser)
   874  	user.Name = userRec.Name
   875  	user.pass = userRec.Pass
   876  	user.State = userRec.State
   877  	user.MaxEnrollments = userRec.MaxEnrollments
   878  	user.Affiliation = userRec.Affiliation
   879  	user.Type = userRec.Type
   880  	user.Level = userRec.Level
   881  
   882  	var attrs []api.Attribute
   883  	json.Unmarshal([]byte(userRec.Attributes), &attrs)
   884  	user.Attributes = attrs
   885  
   886  	user.attrs = make(map[string]api.Attribute)
   887  	for _, attr := range attrs {
   888  		user.attrs[attr.Name] = api.Attribute{
   889  			Name:  attr.Name,
   890  			Value: attr.Value,
   891  			ECert: attr.ECert,
   892  		}
   893  	}
   894  
   895  	user.db = d.db
   896  	return user
   897  }
   898  
   899  // DBUser is the databases representation of a user
   900  type DBUser struct {
   901  	spi.UserInfo
   902  	pass  []byte
   903  	attrs map[string]api.Attribute
   904  	db    *sqlx.DB
   905  }
   906  
   907  // GetName returns the enrollment ID of the user
   908  func (u *DBUser) GetName() string {
   909  	return u.Name
   910  }
   911  
   912  // GetType returns the type of the user
   913  func (u *DBUser) GetType() string {
   914  	return u.Type
   915  }
   916  
   917  // GetMaxEnrollments returns the max enrollments of the user
   918  func (u *DBUser) GetMaxEnrollments() int {
   919  	return u.MaxEnrollments
   920  }
   921  
   922  // GetLevel returns the level of the user
   923  func (u *DBUser) GetLevel() int {
   924  	return u.Level
   925  }
   926  
   927  // SetLevel sets the level of the user
   928  func (u *DBUser) SetLevel(level int) error {
   929  	query := "UPDATE users SET level = ? where (id = ?)"
   930  	id := u.GetName()
   931  	res, err := u.db.Exec(u.db.Rebind(query), level, id)
   932  	if err != nil {
   933  		return err
   934  	}
   935  	numRowsAffected, err := res.RowsAffected()
   936  	if err != nil {
   937  		return errors.Wrap(err, "Failed to get number of rows affected")
   938  	}
   939  
   940  	if numRowsAffected == 0 {
   941  		return errors.Errorf("No rows were affected when updating the state of identity %s", id)
   942  	}
   943  
   944  	if numRowsAffected != 1 {
   945  		return errors.Errorf("%d rows were affected when updating the state of identity %s", numRowsAffected, id)
   946  	}
   947  	return nil
   948  }
   949  
   950  // Login the user with a password
   951  func (u *DBUser) Login(pass string, caMaxEnrollments int) error {
   952  	log.Debugf("DB: Login user %s with max enrollments of %d and state of %d", u.Name, u.MaxEnrollments, u.State)
   953  
   954  	// Check the password by comparing to stored hash
   955  	err := bcrypt.CompareHashAndPassword(u.pass, []byte(pass))
   956  	if err != nil {
   957  		return errors.Wrap(err, "Password mismatch")
   958  	}
   959  
   960  	if u.MaxEnrollments == 0 {
   961  		return errors.Errorf("Zero is an invalid value for maximum enrollments on identity '%s'", u.Name)
   962  	}
   963  
   964  	if u.State == -1 {
   965  		return errors.Errorf("User %s is revoked; access denied", u.Name)
   966  	}
   967  
   968  	// If max enrollment value of user is greater than allowed by CA, using CA max enrollment value for user
   969  	if caMaxEnrollments != -1 && (u.MaxEnrollments > caMaxEnrollments || u.MaxEnrollments == -1) {
   970  		log.Debugf("Max enrollment value (%d) of identity is greater than allowed by CA, using CA max enrollment value of %d", u.MaxEnrollments, caMaxEnrollments)
   971  		u.MaxEnrollments = caMaxEnrollments
   972  	}
   973  
   974  	// If maxEnrollments is set to -1, user has unlimited enrollment
   975  	// If the maxEnrollments is set (i.e. >= 1), make sure we haven't exceeded this number of logins.
   976  	// The state variable keeps track of the number of previously successful logins.
   977  	if u.MaxEnrollments != -1 && u.State >= u.MaxEnrollments {
   978  		return errors.Errorf("The identity %s has already enrolled %d times, it has reached its maximum enrollment allowance", u.Name, u.MaxEnrollments)
   979  	}
   980  
   981  	log.Debugf("DB: identity %s successfully logged in", u.Name)
   982  
   983  	return nil
   984  
   985  }
   986  
   987  // LoginComplete completes the login process by incrementing the state of the user
   988  func (u *DBUser) LoginComplete() error {
   989  	var stateUpdateSQL string
   990  	var args []interface{}
   991  	var err error
   992  
   993  	state := u.State + 1
   994  	args = append(args, u.Name)
   995  	if u.MaxEnrollments == -1 {
   996  		// unlimited so no state check
   997  		stateUpdateSQL = "UPDATE users SET state = state + 1 WHERE (id = ?)"
   998  	} else {
   999  		// state must be less than max enrollments
  1000  		stateUpdateSQL = "UPDATE users SET state = state + 1 WHERE (id = ? AND state < ?)"
  1001  		args = append(args, u.MaxEnrollments)
  1002  	}
  1003  	res, err := u.db.Exec(u.db.Rebind(stateUpdateSQL), args...)
  1004  	if err != nil {
  1005  		return errors.Wrapf(err, "Failed to update state of identity %s to %d", u.Name, state)
  1006  	}
  1007  
  1008  	numRowsAffected, err := res.RowsAffected()
  1009  	if err != nil {
  1010  		return errors.Wrap(err, "db.RowsAffected failed")
  1011  	}
  1012  
  1013  	if numRowsAffected == 0 {
  1014  		return errors.Errorf("No rows were affected when updating the state of identity %s", u.Name)
  1015  	}
  1016  
  1017  	if numRowsAffected != 1 {
  1018  		return errors.Errorf("%d rows were affected when updating the state of identity %s", numRowsAffected, u.Name)
  1019  	}
  1020  
  1021  	log.Debugf("Successfully incremented state for identity %s to %d", u.Name, state)
  1022  	return nil
  1023  
  1024  }
  1025  
  1026  // GetAffiliationPath returns the complete path for the user's affiliation.
  1027  func (u *DBUser) GetAffiliationPath() []string {
  1028  	affiliationPath := strings.Split(u.Affiliation, ".")
  1029  	return affiliationPath
  1030  }
  1031  
  1032  // GetAttribute returns the value for an attribute name
  1033  func (u *DBUser) GetAttribute(name string) (*api.Attribute, error) {
  1034  	value, hasAttr := u.attrs[name]
  1035  	if !hasAttr {
  1036  		return nil, errors.Errorf("User does not have attribute '%s'", name)
  1037  	}
  1038  	return &value, nil
  1039  }
  1040  
  1041  // GetAttributes returns the requested attributes. Return all the user's
  1042  // attributes if nil is passed in
  1043  func (u *DBUser) GetAttributes(attrNames []string) ([]api.Attribute, error) {
  1044  	var attrs []api.Attribute
  1045  	if attrNames == nil {
  1046  		for _, value := range u.attrs {
  1047  			attrs = append(attrs, value)
  1048  		}
  1049  		return attrs, nil
  1050  	}
  1051  
  1052  	for _, name := range attrNames {
  1053  		value, hasAttr := u.attrs[name]
  1054  		if !hasAttr {
  1055  			return nil, errors.Errorf("User does not have attribute '%s'", name)
  1056  		}
  1057  		attrs = append(attrs, value)
  1058  	}
  1059  	return attrs, nil
  1060  }
  1061  
  1062  // Revoke will revoke the user, setting the state of the user to be -1
  1063  func (u *DBUser) Revoke() error {
  1064  	stateUpdateSQL := "UPDATE users SET state = -1 WHERE (id = ?)"
  1065  
  1066  	res, err := u.db.Exec(u.db.Rebind(stateUpdateSQL), u.GetName())
  1067  	if err != nil {
  1068  		return errors.Wrapf(err, "Failed to update state of identity %s to -1", u.Name)
  1069  	}
  1070  
  1071  	numRowsAffected, err := res.RowsAffected()
  1072  	if err != nil {
  1073  		return errors.Wrap(err, "db.RowsAffected failed")
  1074  	}
  1075  
  1076  	if numRowsAffected == 0 {
  1077  		return errors.Errorf("No rows were affected when updating the state of identity %s", u.Name)
  1078  	}
  1079  
  1080  	if numRowsAffected != 1 {
  1081  		return errors.Errorf("%d rows were affected when updating the state of identity %s", numRowsAffected, u.Name)
  1082  	}
  1083  
  1084  	log.Debugf("Successfully incremented state for identity %s to -1", u.Name)
  1085  
  1086  	return nil
  1087  }
  1088  
  1089  // ModifyAttributes adds a new attribute, modifies existing attribute, or delete attribute
  1090  func (u *DBUser) ModifyAttributes(newAttrs []api.Attribute) error {
  1091  	log.Debugf("Modify Attributes: %+v", newAttrs)
  1092  	currentAttrs, _ := u.GetAttributes(nil)
  1093  	userAttrs := getNewAttributes(currentAttrs, newAttrs)
  1094  
  1095  	attrBytes, err := json.Marshal(userAttrs)
  1096  	if err != nil {
  1097  		return err
  1098  	}
  1099  
  1100  	query := "UPDATE users SET attributes = ? where (id = ?)"
  1101  	id := u.GetName()
  1102  	res, err := u.db.Exec(u.db.Rebind(query), string(attrBytes), id)
  1103  	if err != nil {
  1104  		return err
  1105  	}
  1106  
  1107  	numRowsAffected, err := res.RowsAffected()
  1108  	if err != nil {
  1109  		return errors.Wrap(err, "Failed to get number of rows affected")
  1110  	}
  1111  
  1112  	if numRowsAffected == 0 {
  1113  		return errors.Errorf("No rows were affected when updating the state of identity %s", id)
  1114  	}
  1115  
  1116  	if numRowsAffected != 1 {
  1117  		return errors.Errorf("%d rows were affected when updating the state of identity %s", numRowsAffected, id)
  1118  	}
  1119  	return nil
  1120  }
  1121  
  1122  func getError(err error, getType string) error {
  1123  	if err.Error() == "sql: no rows in result set" {
  1124  		return newHTTPErr(404, ErrDBGet, "Failed to get %s: %s", getType, err)
  1125  	}
  1126  	return newHTTPErr(504, ErrConnectingDB, "Failed to process database request: %s", err)
  1127  }