auth
auth/profile.go
Stub out sessions. Stop using the Login type when getting profile by Login, removing Logins, or recording Login use. The Login value has to be unique, anyways, and we don't actually know the Login type when getting a profile by Login. That's sort of the point. Create the concept of Sessions and a sessionStore type to manage our authentication sessions with the server. As per OWASP, we're basically just going to use a transparent, SHA256-generated random string as an ID, and store it client-side and server-side and just pass it back and forth. Add the ProfileID to the Grant type, because we need to remember who granted access. That's sort of important. Set a defaultGrantExpiration constant to an hour, so we have that one constant when creating new Grants. Create a helper that pulls the session ID out of an auth cookie, checks it against the sessionStore, and returns the Session if it's valid. Create a helper that pulls the username and password out of a basic auth header. Create a helper that authenticates a user's login and passphrase, checking them against the profileStore securely. Stub out how the cookie checking is going to work for getting grant approval. Fix the stored Grant RedirectURI to be the passed in redirect URI, not the RedirectURI that we ultimately redirect to. This is in accordance with the spec. Store the profile ID from our session in the created Grant. Stub out a GetTokenHandler that will allow users to exchange a Grant for a Token. Set a constant for the current passphrase scheme, which we will increment for each revision to the passphrase scheme, for backwards compatibility. Change the Profile iterations property to an int, not an int64, to match the code.secondbit.org/pass library (which is matching the PBKDF2 library).
1.1 --- a/profile.go Sun Nov 09 00:22:38 2014 -0500 1.2 +++ b/profile.go Tue Nov 11 21:13:16 2014 -0500 1.3 @@ -12,6 +12,8 @@ 1.4 MinPassphraseLength = 6 1.5 // MaxPassphraseLength is the maximum length, in bytes, of a passphrase, exclusive. 1.6 MaxPassphraseLength = 64 1.7 + // CurPassphraseScheme is the current passphrase scheme. Incrememnt it when we use a different passphrase scheme 1.8 + CurPassphraseScheme = 1 1.9 ) 1.10 1.11 var ( 1.12 @@ -52,7 +54,7 @@ 1.13 ID uuid.ID 1.14 Name string 1.15 Passphrase string 1.16 - Iterations int64 1.17 + Iterations int 1.18 Salt string 1.19 PassphraseScheme int 1.20 Compromised bool 1.21 @@ -110,7 +112,7 @@ 1.22 type ProfileChange struct { 1.23 Name *string 1.24 Passphrase *string 1.25 - Iterations *int64 1.26 + Iterations *int 1.27 Salt *string 1.28 PassphraseScheme *int 1.29 Compromised *bool 1.30 @@ -183,15 +185,15 @@ 1.31 1.32 type profileStore interface { 1.33 getProfileByID(id uuid.ID) (Profile, error) 1.34 - getProfileByLogin(loginType, value string) (Profile, error) 1.35 + getProfileByLogin(value string) (Profile, error) 1.36 saveProfile(profile Profile) error 1.37 updateProfile(id uuid.ID, change ProfileChange) error 1.38 updateProfiles(ids []uuid.ID, change BulkProfileChange) error 1.39 deleteProfile(id uuid.ID) error 1.40 1.41 addLogin(login Login) error 1.42 - removeLogin(loginType, value string, profile uuid.ID) error 1.43 - recordLoginUse(loginType, value string, when time.Time) error 1.44 + removeLogin(value string, profile uuid.ID) error 1.45 + recordLoginUse(value string, when time.Time) error 1.46 listLogins(profile uuid.ID, num, offset int) ([]Login, error) 1.47 } 1.48 1.49 @@ -205,10 +207,10 @@ 1.50 return p, nil 1.51 } 1.52 1.53 -func (m *memstore) getProfileByLogin(loginType, value string) (Profile, error) { 1.54 +func (m *memstore) getProfileByLogin(value string) (Profile, error) { 1.55 m.loginLock.RLock() 1.56 defer m.loginLock.RUnlock() 1.57 - login, ok := m.logins[loginType+":"+value] 1.58 + login, ok := m.logins[value] 1.59 if !ok { 1.60 return Profile{}, ErrLoginNotFound 1.61 } 1.62 @@ -273,29 +275,29 @@ 1.63 func (m *memstore) addLogin(login Login) error { 1.64 m.loginLock.Lock() 1.65 defer m.loginLock.Unlock() 1.66 - _, ok := m.logins[login.Type+":"+login.Value] 1.67 + _, ok := m.logins[login.Value] 1.68 if ok { 1.69 return ErrLoginAlreadyExists 1.70 } 1.71 - m.logins[login.Type+":"+login.Value] = login 1.72 - m.profileLoginLookup[login.ProfileID.String()] = append(m.profileLoginLookup[login.ProfileID.String()], login.Type+":"+login.Value) 1.73 + m.logins[login.Value] = login 1.74 + m.profileLoginLookup[login.ProfileID.String()] = append(m.profileLoginLookup[login.ProfileID.String()], login.Value) 1.75 return nil 1.76 } 1.77 1.78 -func (m *memstore) removeLogin(loginType, value string, profile uuid.ID) error { 1.79 +func (m *memstore) removeLogin(value string, profile uuid.ID) error { 1.80 m.loginLock.Lock() 1.81 defer m.loginLock.Unlock() 1.82 - l, ok := m.logins[loginType+":"+value] 1.83 + l, ok := m.logins[value] 1.84 if !ok { 1.85 return ErrLoginNotFound 1.86 } 1.87 if !l.ProfileID.Equal(profile) { 1.88 return ErrLoginNotFound 1.89 } 1.90 - delete(m.logins, loginType+":"+value) 1.91 + delete(m.logins, value) 1.92 pos := -1 1.93 for p, id := range m.profileLoginLookup[profile.String()] { 1.94 - if id == loginType+":"+value { 1.95 + if id == value { 1.96 pos = p 1.97 break 1.98 } 1.99 @@ -306,15 +308,15 @@ 1.100 return nil 1.101 } 1.102 1.103 -func (m *memstore) recordLoginUse(loginType, value string, when time.Time) error { 1.104 +func (m *memstore) recordLoginUse(value string, when time.Time) error { 1.105 m.loginLock.Lock() 1.106 defer m.loginLock.Unlock() 1.107 - l, ok := m.logins[loginType+":"+value] 1.108 + l, ok := m.logins[value] 1.109 if !ok { 1.110 return ErrLoginNotFound 1.111 } 1.112 l.LastUsed = when 1.113 - m.logins[loginType+":"+value] = l 1.114 + m.logins[value] = l 1.115 return nil 1.116 } 1.117