auth

Paddy 2014-09-19 Parent:2a6d722a2b4b Child:3a6a65ed380c

44:fb827644bfd8 Browse Files

Add support for bulk changes and for logins. Logins now get stored, listed, removed, and updated. You can select a profile by the login associated with it. Also added support for bulk changing profiles, because it may be necesary to set many profiles to compromised at the same time, and there's no sense in requiring a statement per profile.

memstore.go profile.go

     1.1 --- a/memstore.go	Thu Sep 18 22:42:02 2014 -0400
     1.2 +++ b/memstore.go	Fri Sep 19 00:05:35 2014 -0400
     1.3 @@ -24,6 +24,10 @@
     1.4  
     1.5  	profiles    map[string]Profile
     1.6  	profileLock sync.RWMutex
     1.7 +
     1.8 +	logins             map[string]Login
     1.9 +	profileLoginLookup map[string][]string
    1.10 +	loginLock          sync.RWMutex
    1.11  }
    1.12  
    1.13  func NewMemstore() *Memstore {
    1.14 @@ -36,6 +40,8 @@
    1.15  		profileClientLookup: map[string][]uuid.ID{},
    1.16  		endpoints:           map[string][]Endpoint{},
    1.17  		profiles:            map[string]Profile{},
    1.18 +		logins:              map[string]Login{},
    1.19 +		profileLoginLookup:  map[string][]string{},
    1.20  	}
    1.21  }
    1.22  
     2.1 --- a/profile.go	Thu Sep 18 22:42:02 2014 -0400
     2.2 +++ b/profile.go	Fri Sep 19 00:05:35 2014 -0400
     2.3 @@ -10,6 +10,8 @@
     2.4  var (
     2.5  	ErrProfileAlreadyExists = errors.New("profile already exists in ProfileStore")
     2.6  	ErrProfileNotFound      = errors.New("profile not found in ProfileStore")
     2.7 +	ErrLoginAlreadyExists   = errors.New("login already exists in ProfileStore")
     2.8 +	ErrLoginNotFound        = errors.New("login not found in ProfileStore")
     2.9  )
    2.10  
    2.11  type Profile struct {
    2.12 @@ -60,6 +62,12 @@
    2.13  	}
    2.14  }
    2.15  
    2.16 +func (p *Profile) ApplyBulkChange(change BulkProfileChange) {
    2.17 +	if change.Compromised != nil {
    2.18 +		p.Compromised = *change.Compromised
    2.19 +	}
    2.20 +}
    2.21 +
    2.22  type ProfileChange struct {
    2.23  	Name                   *string
    2.24  	Passphrase             *string
    2.25 @@ -78,6 +86,15 @@
    2.26  	return nil
    2.27  }
    2.28  
    2.29 +type BulkProfileChange struct {
    2.30 +	Compromised *bool
    2.31 +}
    2.32 +
    2.33 +func (b BulkProfileChange) Validate() error {
    2.34 +	// TODO: validate bulk profile changs
    2.35 +	return nil
    2.36 +}
    2.37 +
    2.38  type Login struct {
    2.39  	Type      string
    2.40  	Value     string
    2.41 @@ -88,10 +105,16 @@
    2.42  
    2.43  type ProfileStore interface {
    2.44  	GetProfileByID(id uuid.ID) (Profile, error)
    2.45 -	GetProfileByLogin(login Login) (Profile, error)
    2.46 +	GetProfileByLogin(loginType, value string) (Profile, error)
    2.47  	SaveProfile(profile Profile) error
    2.48  	UpdateProfile(id uuid.ID, change ProfileChange) error
    2.49 +	UpdateProfiles(ids []uuid.ID, change BulkProfileChange) error
    2.50  	DeleteProfile(id uuid.ID) error
    2.51 +
    2.52 +	AddLogin(login Login) error
    2.53 +	RemoveLogin(loginType, value string, profile uuid.ID) error
    2.54 +	RecordLoginUse(loginType, value string, when time.Time) error
    2.55 +	ListLogins(profile uuid.ID, num, offset int) ([]Login, error)
    2.56  }
    2.57  
    2.58  func (m *Memstore) GetProfileByID(id uuid.ID) (Profile, error) {
    2.59 @@ -104,9 +127,20 @@
    2.60  	return p, nil
    2.61  }
    2.62  
    2.63 -func (m *Memstore) GetProfileByLogin(login Login) (Profile, error) {
    2.64 -	// TODO: get profile by login
    2.65 -	return Profile{}, nil
    2.66 +func (m *Memstore) GetProfileByLogin(loginType, value string) (Profile, error) {
    2.67 +	m.loginLock.RLock()
    2.68 +	defer m.loginLock.RUnlock()
    2.69 +	login, ok := m.logins[loginType+":"+value]
    2.70 +	if !ok {
    2.71 +		return Profile{}, ErrLoginNotFound
    2.72 +	}
    2.73 +	m.profileLock.RLock()
    2.74 +	defer m.profileLock.RUnlock()
    2.75 +	profile, ok := m.profiles[login.ProfileID.String()]
    2.76 +	if !ok {
    2.77 +		return Profile{}, ErrProfileNotFound
    2.78 +	}
    2.79 +	return profile, nil
    2.80  }
    2.81  
    2.82  func (m *Memstore) SaveProfile(profile Profile) error {
    2.83 @@ -132,6 +166,21 @@
    2.84  	return nil
    2.85  }
    2.86  
    2.87 +func (m *Memstore) UpdateProfiles(ids []uuid.ID, change BulkProfileChange) error {
    2.88 +	m.profileLock.Lock()
    2.89 +	defer m.profileLock.Unlock()
    2.90 +	for id, profile := range m.profiles {
    2.91 +		for _, i := range ids {
    2.92 +			if id == i.String() {
    2.93 +				profile.ApplyBulkChange(change)
    2.94 +				m.profiles[id] = profile
    2.95 +				break
    2.96 +			}
    2.97 +		}
    2.98 +	}
    2.99 +	return nil
   2.100 +}
   2.101 +
   2.102  func (m *Memstore) DeleteProfile(id uuid.ID) error {
   2.103  	m.profileLock.Lock()
   2.104  	defer m.profileLock.Unlock()
   2.105 @@ -143,6 +192,75 @@
   2.106  	return nil
   2.107  }
   2.108  
   2.109 -// TODO: login store
   2.110 -// TODO: login delete
   2.111 -// TODO: login update
   2.112 +func (m *Memstore) AddLogin(login Login) error {
   2.113 +	m.loginLock.Lock()
   2.114 +	defer m.loginLock.Unlock()
   2.115 +	_, ok := m.logins[login.Type+":"+login.Value]
   2.116 +	if ok {
   2.117 +		return ErrLoginAlreadyExists
   2.118 +	}
   2.119 +	m.logins[login.Type+":"+login.Value] = login
   2.120 +	m.profileLoginLookup[login.ProfileID.String()] = append(m.profileLoginLookup[login.ProfileID.String()], login.Type+":"+login.Value)
   2.121 +	return nil
   2.122 +}
   2.123 +
   2.124 +func (m *Memstore) RemoveLogin(loginType, value string, profile uuid.ID) error {
   2.125 +	m.loginLock.Lock()
   2.126 +	defer m.loginLock.Unlock()
   2.127 +	l, ok := m.logins[loginType+":"+value]
   2.128 +	if !ok {
   2.129 +		return ErrLoginNotFound
   2.130 +	}
   2.131 +	if !l.ProfileID.Equal(profile) {
   2.132 +		return ErrLoginNotFound
   2.133 +	}
   2.134 +	delete(m.logins, loginType+":"+value)
   2.135 +	pos := -1
   2.136 +	for p, id := range m.profileLoginLookup[profile.String()] {
   2.137 +		if id == loginType+":"+value {
   2.138 +			pos = p
   2.139 +			break
   2.140 +		}
   2.141 +	}
   2.142 +	if pos >= 0 {
   2.143 +		m.profileLoginLookup[profile.String()] = append(m.profileLoginLookup[profile.String()][:pos], m.profileLoginLookup[profile.String()][pos+1:]...)
   2.144 +	}
   2.145 +	return nil
   2.146 +}
   2.147 +
   2.148 +func (m *Memstore) RecordLoginUse(loginType, value string, when time.Time) error {
   2.149 +	m.loginLock.Lock()
   2.150 +	defer m.loginLock.Unlock()
   2.151 +	l, ok := m.logins[loginType+":"+value]
   2.152 +	if !ok {
   2.153 +		return ErrLoginNotFound
   2.154 +	}
   2.155 +	l.LastUsed = when
   2.156 +	m.logins[loginType+":"+value] = l
   2.157 +	return nil
   2.158 +}
   2.159 +
   2.160 +func (m *Memstore) ListLogins(profile uuid.ID, num, offset int) ([]Login, error) {
   2.161 +	m.loginLock.RLock()
   2.162 +	defer m.loginLock.RUnlock()
   2.163 +	ids, ok := m.profileLoginLookup[profile.String()]
   2.164 +	if !ok {
   2.165 +		return []Login{}, nil
   2.166 +	}
   2.167 +	if len(ids) > num+offset {
   2.168 +		ids = ids[offset : num+offset]
   2.169 +	} else if len(ids) > offset {
   2.170 +		ids = ids[offset:]
   2.171 +	} else {
   2.172 +		return []Login{}, nil
   2.173 +	}
   2.174 +	logins := []Login{}
   2.175 +	for _, id := range ids {
   2.176 +		login, ok := m.logins[id]
   2.177 +		if !ok {
   2.178 +			continue
   2.179 +		}
   2.180 +		logins = append(logins, login)
   2.181 +	}
   2.182 +	return logins, nil
   2.183 +}