auth
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.
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 +}