github.com/volatiletech/authboss@v2.4.1+incompatible/storage.go (about) 1 package authboss 2 3 // A concious decision was made to put all storer 4 // and user types into this file despite them truly 5 // belonging to outside modules. The reason for this 6 // is because documentation-wise, it was previously 7 // difficult to find what you had to implement or even 8 // what you could implement. 9 10 import ( 11 "context" 12 13 "github.com/pkg/errors" 14 ) 15 16 var ( 17 // ErrUserFound should be returned from Create (see ConfirmUser) 18 // when the primaryID of the record is found. 19 ErrUserFound = errors.New("user found") 20 // ErrUserNotFound should be returned from Get when the record is not found. 21 ErrUserNotFound = errors.New("user not found") 22 // ErrTokenNotFound should be returned from UseToken when the 23 // record is not found. 24 ErrTokenNotFound = errors.New("token not found") 25 ) 26 27 // ServerStorer represents the data store that's capable of loading users 28 // and giving them a context with which to store themselves. 29 type ServerStorer interface { 30 // Load will look up the user based on the passed the PrimaryID 31 Load(ctx context.Context, key string) (User, error) 32 33 // Save persists the user in the database, this should never 34 // create a user and instead return ErrUserNotFound if the user 35 // does not exist. 36 Save(ctx context.Context, user User) error 37 } 38 39 // CreatingServerStorer is used for creating new users 40 // like when Registration or OAuth2 is being done. 41 type CreatingServerStorer interface { 42 ServerStorer 43 44 // New creates a blank user, it is not yet persisted in the database 45 // but is just for storing data 46 New(ctx context.Context) User 47 // Create the user in storage, it should not overwrite a user 48 // and should return ErrUserFound if it currently exists. 49 Create(ctx context.Context, user User) error 50 } 51 52 // OAuth2ServerStorer has the ability to create users from data from the provider. 53 type OAuth2ServerStorer interface { 54 ServerStorer 55 56 // NewFromOAuth2 should return an OAuth2User from a set 57 // of details returned from OAuth2Provider.FindUserDetails 58 // A more in-depth explanation is that once we've got an access token 59 // for the service in question (say a service that rhymes with book) 60 // the FindUserDetails function does an http request to a known endpoint 61 // that provides details about the user, those details are captured in a 62 // generic way as map[string]string and passed into this function to be 63 // turned into a real user. 64 // 65 // It's possible that the user exists in the database already, and so 66 // an attempt should be made to look that user up using the details. 67 // Any details that have changed should be updated. Do not save the user 68 // since that will be done later by OAuth2ServerStorer.SaveOAuth2() 69 NewFromOAuth2(ctx context.Context, provider string, details map[string]string) (OAuth2User, error) 70 71 // SaveOAuth2 has different semantics from the typical ServerStorer.Save, 72 // in this case we want to insert a user if they do not exist. 73 // The difference must be made clear because in the non-oauth2 case, 74 // we know exactly when we want to Create vs Update. However since we're 75 // simply trying to persist a user that may have been in our database, 76 // but if not should already be (since you can think of the operation as 77 // a caching of what's on the oauth2 provider's servers). 78 SaveOAuth2(ctx context.Context, user OAuth2User) error 79 } 80 81 // ConfirmingServerStorer can find a user by a confirm token 82 type ConfirmingServerStorer interface { 83 ServerStorer 84 85 // LoadByConfirmSelector finds a user by his confirm selector field 86 // and should return ErrUserNotFound if that user cannot be found. 87 LoadByConfirmSelector(ctx context.Context, selector string) (ConfirmableUser, error) 88 } 89 90 // RecoveringServerStorer allows users to be recovered by a token 91 type RecoveringServerStorer interface { 92 ServerStorer 93 94 // LoadByRecoverSelector finds a user by his recover selector field 95 // and should return ErrUserNotFound if that user cannot be found. 96 LoadByRecoverSelector(ctx context.Context, selector string) (RecoverableUser, error) 97 } 98 99 // RememberingServerStorer allows users to be remembered across sessions 100 type RememberingServerStorer interface { 101 ServerStorer 102 103 // AddRememberToken to a user 104 AddRememberToken(ctx context.Context, pid, token string) error 105 // DelRememberTokens removes all tokens for the given pid 106 DelRememberTokens(ctx context.Context, pid string) error 107 // UseRememberToken finds the pid-token pair and deletes it. 108 // If the token could not be found return ErrTokenNotFound 109 UseRememberToken(ctx context.Context, pid, token string) error 110 } 111 112 // EnsureCanCreate makes sure the server storer supports create operations 113 func EnsureCanCreate(storer ServerStorer) CreatingServerStorer { 114 s, ok := storer.(CreatingServerStorer) 115 if !ok { 116 panic("could not upgrade ServerStorer to CreatingServerStorer, check your struct") 117 } 118 119 return s 120 } 121 122 // EnsureCanConfirm makes sure the server storer supports 123 // confirm-lookup operations 124 func EnsureCanConfirm(storer ServerStorer) ConfirmingServerStorer { 125 s, ok := storer.(ConfirmingServerStorer) 126 if !ok { 127 panic("could not upgrade ServerStorer to ConfirmingServerStorer, check your struct") 128 } 129 130 return s 131 } 132 133 // EnsureCanRecover makes sure the server storer supports 134 // confirm-lookup operations 135 func EnsureCanRecover(storer ServerStorer) RecoveringServerStorer { 136 s, ok := storer.(RecoveringServerStorer) 137 if !ok { 138 panic("could not upgrade ServerStorer to RecoveringServerStorer, check your struct") 139 } 140 141 return s 142 } 143 144 // EnsureCanRemember makes sure the server storer supports remember operations 145 func EnsureCanRemember(storer ServerStorer) RememberingServerStorer { 146 s, ok := storer.(RememberingServerStorer) 147 if !ok { 148 panic("could not upgrade ServerStorer to RememberingServerStorer, check your struct") 149 } 150 151 return s 152 } 153 154 // EnsureCanOAuth2 makes sure the server storer supports 155 // oauth2 creation and lookup 156 func EnsureCanOAuth2(storer ServerStorer) OAuth2ServerStorer { 157 s, ok := storer.(OAuth2ServerStorer) 158 if !ok { 159 panic("could not upgrade ServerStorer to OAuth2ServerStorer, check your struct") 160 } 161 162 return s 163 }