// newKey realiza la generación y codificación de las claves RSA en codificación PEM. func newKey() *Key { privateKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { log.LogE("failed to generate private key", "pkg", "try6", "func", "NewKey(string) *Key", "error", err.Error()) return nil } privPEM := pem.EncodeToMemory( &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey), }, ) pubKeyPKIX, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) if err != nil { log.LogE("failed to generate DER public key", "pkg", "try6", "func", "NewKey(string) *Key", "error", err.Error()) return nil } pubPEM := pem.EncodeToMemory(&pem.Block{ Type: "RSA PUBLIC KEY", Bytes: pubKeyPKIX, }) return &Key{ PubKey: pubPEM, PrivKey: privPEM, } }
// NewKey genera una pareja de claves RSA de 2048 bits. Las clave privada se codifica como PKCS1 y la pública como PKIX. // Ambas en formato PEM. func NewKey(uid string) *Key { if uid == "" { log.LogE("new key needs an account", "pkg", "try6", "func", "NewKey(string) *Key") return nil } k := newKey() k.AccountID = uid return k }
// SaveKey persist the key data to the database func (d *DefaultStore) SaveKey(key *try6.Key) error { log.LogD("Saving Key", "pkg", "store", "func", "SaveKey(*try6.Key)", "data", key) now := time.Now().UTC() key.Updated = now if key.ID == "" { // New Key key.Created = now key.Status = "active" if err := d.C.InsertInto("keys").Blacklist("id", "deleted").Record(key).Returning("*").QueryStruct(key); err != nil { log.LogE("error saving key", "pkg", "store", "func", "SaveKey(*try6.Key)", "error", err.Error()) return err } } else { if err := d.C.Update("keys").SetBlacklist(key, "id", "created").Where("id=$1", key.ID).Returning("*").QueryStruct(key); err != nil { log.LogE("error updating key", "pkg", "store", "func", "SaveKey(*try6.Key)", "error", err.Error()) return err } } log.LogD("key inserted", "pkg", "store", "func", "SaveKey(*try6.Key)", "data", key) return nil }
// CreateTenant creates a new tenant with the data provided in try6.CreateTenantData. // The steps are: // 1. Create a new tenant in the database // 2. Create the admin directory for the tenant where the tenant admin accounts will live // 3. If an account is provided (it is created in a previous step), it will be assigned as default admin account // If no account is provide, a new one is created and made the default admin account. In this case an RSA Key pair is created for the account // 4. A default scope is created for admin purposes. As the account, it can be created prior to the call to NewTenant and be used here // 5. Maps the admin scope to the admin directory so the tenant can modify it // // It is responsability of the caller that the account and scope data are valid for the tenant administration. Usually, the account will be created // as part of a registration process and will be used here leaving the scope and directory data empty so it will be created here. func (d *DefaultStore) CreateTenant(data *try6.CreateTenantData) error { now := time.Now().UTC() if data.TData.ID != "" { log.LogE("error creating tenant", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", tryerr.ErrIDNotNull.Error()) return tryerr.ErrIDNotNull } // 1. Create Tenant log.LogD("creating tenant", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "data", data) if err := d.SaveTenant(data.TData); err != nil { log.LogE("error creating tenant", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", err.Error()) return err } // 2. Create Tenant Admin Directory. if data.Dir == nil { // directory does not exist. Create! data.Dir = &try6.Directory{ Created: now, Updated: now, } log.LogD("data directory not provided. creating new", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "directory", data.Dir) } data.Dir.TenantUID = data.TData.ID if data.Dir.Label == "" { data.Dir.Label = "Default Admin Directory" } if data.Dir.Description == "" { data.Dir.Description = "Default directory to hold administrative accounts for this tenant" } if data.Dir.Status == "" { data.Dir.Status = "active" } if err := d.SaveDirectory(data.Dir); err != nil { log.LogE("Could not create Directory", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", err) return err } // 3. Add acc to Tenant Admin Directory as default admin account if data.Acc == nil { log.LogE("nil account", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", "an admin account is needed") return tryerr.ErrAccountNotProvided } if data.Acc.ID == "" { // New account if err := data.Acc.UpdatePassword(data.Acc.Password); err != nil { log.LogW("Could not update password for admin account", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", err) } if err := d.SaveAccount(data.Dir.ID, data.Acc); err != nil { log.LogE("Could not create admin account", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", err) return err } // 4. Create RSA Keys for acc as it is new k := try6.NewKey(data.Acc.ID) if err := d.SaveKey(k); err != nil { log.LogE("Could not create rsa key for admin account", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", err) return err } } else { // account exists. Must add it to the admin directory if _, err := d.C.Upsert("directory_account").Columns("directory_id", "account_id", "created", "updated").Record(&try6.DirectoryAccount{ DirectoryID: data.Dir.ID, AccountID: data.Acc.ID, Created: now, Updated: now, }).Where("directory_id=$1 AND account_id=$2", data.Dir.ID, data.Acc.ID).Exec(); err != nil { log.LogE("error updating directory", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", err.Error()) return err } } var aki []string if err := d.C.Select("id").From("keys").Where("account_id=$1 AND deleted IS NULL", data.Acc.ID).QuerySlice(&aki); err != nil { log.LogW("account has no rsa keys", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", err.Error()) } // 5. Create the default admin scope for the tenant to give access to the tenant management) if data.Scope == nil { // directory does not exist. Create! data.Scope = &try6.Scope{ Created: now, Updated: now, } log.LogD("data scope not provided. creating new", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "scope", data.Scope) } data.Scope.TenantID = data.TData.ID if data.Scope.Label == "" { data.Scope.Label = "Default Admin Scope" } if data.Scope.Description == "" { data.Scope.Description = "Default scope to administer this tenant" } if data.Scope.Status == "" { data.Scope.Status = "active" } if err := d.SaveScope(data.Scope); err != nil { log.LogE("Could not create admin Scope", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", err) return err } // 6. Map the admin app with the admin directory created if _, err := d.C.Upsert("directory_scope").Columns("directory_id", "scope_id", "priority", "is_default_account_store", "is_default_group_store", "is_default_rbac_store", "created", "updated").Record(&try6.DirectoryScope{ DirectoryID: data.Dir.ID, ScopeID: data.Scope.ID, Priority: 1, IsDefaultAccStore: true, IsDefaultGroupStore: true, IsDefaultRBACStore: true, Created: now, Updated: now, }).Where("directory_id=$1 AND scope_id=$2", data.Dir.ID, data.Scope.ID).Exec(); err != nil { log.LogE("error updating directory_scope", "pkg", "store", "func", "CreateTenant(*try6.CreateTenantData)", "error", err.Error()) return err } log.LogD("New tenant created", "pkg", "tenant", "func", "CreateTenant(*try6.CreateTenantData)", "tenantID", data.TData.ID, "directoryID", data.Scope.ID, "adminID", data.Acc.ID, "Account Keys", aki, "ScopeID", data.Scope.ID) return nil }