satellite: enable open registration (and add flag that disables it) SM-441

Change-Id: I47bfedb312089f6d2bfbab013bd74ad4b8aa5f5e
This commit is contained in:
JT Olio 2020-03-11 09:36:55 -06:00 committed by littleskunk
parent 803e2930f4
commit 051569c69f
No known key found for this signature in database
GPG Key ID: E5C6B2C94E5BB7F9
8 changed files with 68 additions and 27 deletions

View File

@ -410,9 +410,11 @@ func (planet *Planet) newSatellites(count int) ([]*SatelliteSystem, error) {
Console: consoleweb.Config{
Address: "127.0.0.1:0",
StaticDir: filepath.Join(developmentRoot, "web/satellite"),
PasswordCost: console.TestPasswordCost,
AuthToken: "very-secret-token",
AuthTokenSecret: "my-suppa-secret-key",
Config: console.Config{
PasswordCost: console.TestPasswordCost,
},
},
Marketing: marketingweb.Config{
Address: "127.0.0.1:0",

View File

@ -10,7 +10,7 @@ import (
"net/mail"
"net/smtp"
"github.com/spacemonkeygo/monkit/v3"
monkit "github.com/spacemonkeygo/monkit/v3"
"github.com/zeebo/errs"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
@ -575,7 +575,7 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB,
peer.DB.Rewards(),
peer.Marketing.PartnersService,
peer.Payments.Accounts,
consoleConfig.PasswordCost,
consoleConfig.Config,
)
if err != nil {
return nil, errs.Combine(err, peer.Close())

View File

@ -85,7 +85,7 @@ func TestGrapqhlMutation(t *testing.T) {
db.Rewards(),
partnersService,
payments.Accounts(),
console.TestPasswordCost,
console.Config{PasswordCost: console.TestPasswordCost},
)
require.NoError(t, err)

View File

@ -70,7 +70,7 @@ func TestGraphqlQuery(t *testing.T) {
db.Rewards(),
partnersService,
payments.Accounts(),
console.TestPasswordCost,
console.Config{PasswordCost: console.TestPasswordCost},
)
require.NoError(t, err)

View File

@ -23,7 +23,7 @@ import (
"github.com/graphql-go/graphql"
"github.com/graphql-go/graphql/gqlerrors"
"github.com/skyrings/skyring-common/tools/uuid"
"github.com/spacemonkeygo/monkit/v3"
monkit "github.com/spacemonkeygo/monkit/v3"
"github.com/zeebo/errs"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
@ -61,8 +61,6 @@ type Config struct {
AuthToken string `help:"auth token needed for access to registration token creation endpoint" default:""`
AuthTokenSecret string `help:"secret used to sign auth tokens" releaseDefault:"" devDefault:"my-suppa-secret-key"`
PasswordCost int `internal:"true" help:"password hashing cost (0=automatic)" default:"0"`
ContactInfoURL string `help:"url link to contacts page" default:"https://forum.storj.io"`
FrameAncestors string `help:"allow domains to embed the satellite in a frame, space separated" default:"tardigrade.io"`
LetUsKnowURL string `help:"url link to let us know page" default:"https://storjlabs.atlassian.net/servicedesk/customer/portals"`
@ -71,6 +69,8 @@ type Config struct {
SatelliteOperator string `help:"name of organization which set up satellite" default:"Storj Labs" `
TermsAndConditionsURL string `help:"url link to terms and conditions page" default:"https://storj.io/storage-sla/"`
SegmentIOPublicKey string `help:"used to initialize segment.io at web satellite console" default:""`
console.Config
}
// Server represents console web server

View File

@ -4,6 +4,7 @@
package console
import (
"bytes"
"context"
"crypto/rand"
"encoding/base64"
@ -60,6 +61,14 @@ func (secret RegistrationSecret) String() string {
return base64.URLEncoding.EncodeToString(secret[:])
}
// IsZero returns if the RegistrationSecret is not set
func (secret RegistrationSecret) IsZero() bool {
var zero RegistrationSecret
// this doesn't need to be constant-time, because we're explicitly testing
// against a hardcoded, well-known value
return bytes.Equal(secret[:], zero[:])
}
// RegistrationSecretFromBase64 creates new registration secret from base64 string
func RegistrationSecretFromBase64(s string) (RegistrationSecret, error) {
var secret RegistrationSecret

View File

@ -86,7 +86,13 @@ type Service struct {
partners *rewards.PartnersService
accounts payments.Accounts
passwordCost int
config Config
}
// Config keeps track of core console service configuration parameters
type Config struct {
PasswordCost int `help:"password hashing cost (0=automatic)" internal:"true" default:"0"`
OpenRegistrationEnabled bool `help:"enable open registration" default:"false"`
}
// PaymentsService separates all payment related functionality
@ -95,7 +101,7 @@ type PaymentsService struct {
}
// NewService returns new instance of Service.
func NewService(log *zap.Logger, signer Signer, store DB, projectAccounting accounting.ProjectAccounting, projectUsage *accounting.Service, rewards rewards.DB, partners *rewards.PartnersService, accounts payments.Accounts, passwordCost int) (*Service, error) {
func NewService(log *zap.Logger, signer Signer, store DB, projectAccounting accounting.ProjectAccounting, projectUsage *accounting.Service, rewards rewards.DB, partners *rewards.PartnersService, accounts payments.Accounts, config Config) (*Service, error) {
if signer == nil {
return nil, errs.New("signer can't be nil")
}
@ -105,8 +111,8 @@ func NewService(log *zap.Logger, signer Signer, store DB, projectAccounting acco
if log == nil {
return nil, errs.New("log can't be nil")
}
if passwordCost == 0 {
passwordCost = bcrypt.DefaultCost
if config.PasswordCost == 0 {
config.PasswordCost = bcrypt.DefaultCost
}
return &Service{
@ -118,7 +124,7 @@ func NewService(log *zap.Logger, signer Signer, store DB, projectAccounting acco
rewards: rewards,
partners: partners,
accounts: accounts,
passwordCost: passwordCost,
config: config,
}, nil
}
@ -366,6 +372,28 @@ func (paymentService PaymentsService) AddPromotionalCoupon(ctx context.Context,
return paymentService.service.accounts.Coupons().AddPromotionalCoupon(ctx, userID, duration, amount, limit)
}
// checkRegistrationSecret returns a RegistrationToken if applicable (nil if not), and an error
// if and only if the registration shouldn't proceed.
func (s *Service) checkRegistrationSecret(ctx context.Context, tokenSecret RegistrationSecret) (*RegistrationToken, error) {
if s.config.OpenRegistrationEnabled && tokenSecret.IsZero() {
// in this case we're going to let the registration happen without a token
return nil, nil
}
// in all other cases, require a registration token
registrationToken, err := s.store.RegistrationTokens().GetBySecret(ctx, tokenSecret)
if err != nil {
return nil, ErrUnauthorized.Wrap(err)
}
// if a registration token is already associated with an user ID, that means the token is already used
// we should terminate the account creation process and return an error
if registrationToken.OwnerID != nil {
return nil, errs.New(usedRegTokenErrMsg)
}
return registrationToken, nil
}
// CreateUser gets password hash value and creates new inactive User
func (s *Service) CreateUser(ctx context.Context, user CreateUser, tokenSecret RegistrationSecret, refUserID string) (u *User, err error) {
defer mon.Task()(&ctx)(&err)
@ -393,23 +421,20 @@ func (s *Service) CreateUser(ctx context.Context, user CreateUser, tokenSecret R
return nil, Error.Wrap(err)
}
// TODO: remove after vanguard release
registrationToken, err := s.store.RegistrationTokens().GetBySecret(ctx, tokenSecret)
registrationToken, err := s.checkRegistrationSecret(ctx, tokenSecret)
if err != nil {
return nil, ErrUnauthorized.Wrap(err)
}
// if a registration token is already associated with an user ID, that means the token is already used
// we should terminate the account creation process and return an error
if registrationToken.OwnerID != nil {
return nil, errs.New(usedRegTokenErrMsg)
return nil, err
}
u, err = s.store.Users().GetByEmail(ctx, user.Email)
if err == nil {
return nil, errs.New(emailUsedErrMsg)
}
if err != sql.ErrNoRows {
return nil, Error.Wrap(err)
}
hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), s.passwordCost)
hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), s.config.PasswordCost)
if err != nil {
return nil, Error.Wrap(err)
}
@ -444,9 +469,11 @@ func (s *Service) CreateUser(ctx context.Context, user CreateUser, tokenSecret R
return Error.Wrap(err)
}
err = tx.RegistrationTokens().UpdateOwner(ctx, registrationToken.Secret, u.ID)
if err != nil {
return Error.Wrap(err)
if registrationToken != nil {
err = tx.RegistrationTokens().UpdateOwner(ctx, registrationToken.Secret, u.ID)
if err != nil {
return Error.Wrap(err)
}
}
if currentReward != nil {
@ -583,7 +610,7 @@ func (s *Service) ResetPassword(ctx context.Context, resetPasswordToken, passwor
return errs.New(passwordRecoveryTokenIsExpiredErrMsg)
}
hash, err := bcrypt.GenerateFromPassword([]byte(password), s.passwordCost)
hash, err := bcrypt.GenerateFromPassword([]byte(password), s.config.PasswordCost)
if err != nil {
return err
}
@ -719,7 +746,7 @@ func (s *Service) ChangePassword(ctx context.Context, pass, newPass string) (err
return err
}
hash, err := bcrypt.GenerateFromPassword([]byte(newPass), s.passwordCost)
hash, err := bcrypt.GenerateFromPassword([]byte(newPass), s.config.PasswordCost)
if err != nil {
return Error.Wrap(err)
}

View File

@ -58,6 +58,9 @@
# url link to let us know page
# console.let-us-know-url: https://storjlabs.atlassian.net/servicedesk/customer/portals
# enable open registration
# console.open-registration-enabled: false
# used to display at web satellite console
# console.satellite-name: Storj