github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/lib/access.go (about) 1 package lib 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/qri-io/qri/auth/token" 9 qhttp "github.com/qri-io/qri/lib/http" 10 "github.com/qri-io/qri/profile" 11 ) 12 13 // AccessMethods is a group of methods for access control & user authentication 14 type AccessMethods struct { 15 d dispatcher 16 } 17 18 // Name returns the name of this method group 19 func (m AccessMethods) Name() string { 20 return "access" 21 } 22 23 // Attributes defines attributes for each method 24 func (m AccessMethods) Attributes() map[string]AttributeSet { 25 return map[string]AttributeSet{ 26 "createauthtoken": {Endpoint: qhttp.AECreateAuthToken, HTTPVerb: "POST", DefaultSource: "local"}, 27 } 28 } 29 30 // CreateAuthTokenParams are input parameters for Access().CreateAuthToken 31 type CreateAuthTokenParams struct { 32 // username to grant auth; e.g. "keyboard_cat" 33 GranteeUsername string `json:"granteeUsername"` 34 // profile Identifier to grant token for; e.g. "QmemJQrK7PTQvD3n8gmo9JhyaByyLmETiNR1Y8wS7hv4sP" 35 GranteeProfileID string `json:"granteeProfileID"` 36 // lifespan of token in nanoseconds; e.g. 2000000000000 37 TTL time.Duration `json:"ttl"` 38 } 39 40 // SetNonZeroDefaults uses default token time-to-live if one isn't set 41 func (p *CreateAuthTokenParams) SetNonZeroDefaults() { 42 if p.TTL == 0 { 43 p.TTL = token.DefaultTokenTTL 44 } 45 } 46 47 // Validate returns an error if input params are invalid 48 func (p *CreateAuthTokenParams) Validate() error { 49 if p.GranteeUsername == "" && p.GranteeProfileID == "" { 50 return fmt.Errorf("either grantee username or profile is required") 51 } 52 return nil 53 } 54 55 // CreateAuthToken constructs a JWT string token suitable for making OAuth 56 // requests as the grantee user. Creating an access token requires a stored 57 // private key for the grantee. 58 // Callers can provide either granteeUsername OR granteeProfileID 59 func (m AccessMethods) CreateAuthToken(ctx context.Context, p *CreateAuthTokenParams) (string, error) { 60 res, _, err := m.d.Dispatch(ctx, dispatchMethodName(m, "createauthtoken"), p) 61 if s, ok := res.(string); ok { 62 return s, err 63 } 64 return "", err 65 } 66 67 // accessImpl is the backing implementation for AccessMethods 68 type accessImpl struct{} 69 70 func (accessImpl) CreateAuthToken(scp scope, p *CreateAuthTokenParams) (string, error) { 71 var ( 72 grantee *profile.Profile 73 err error 74 ) 75 76 if p.GranteeProfileID != "" { 77 id, err := profile.IDB58Decode(p.GranteeProfileID) 78 if err != nil { 79 return "", err 80 } 81 if grantee, err = scp.Profiles().GetProfile(scp.Context(), id); err != nil { 82 return "", err 83 } 84 } else if p.GranteeUsername == "me" { 85 grantee = scp.ActiveProfile() 86 } else { 87 if grantee, err = profile.ResolveUsername(scp.Context(), scp.Profiles(), p.GranteeUsername); err != nil { 88 return "", err 89 } 90 } 91 92 pk := grantee.PrivKey 93 if pk == nil { 94 return "", fmt.Errorf("cannot create token for %q (id: %s), private key is required", grantee.Peername, grantee.ID.Encode()) 95 } 96 97 return token.NewPrivKeyAuthToken(pk, grantee.ID.Encode(), p.TTL) 98 }