Skip to content

Commit

Permalink
Merge pull request #443 from cwarden/standardize-refresh
Browse files Browse the repository at this point in the history
Add Session Refresh for SOAP and SFDX
  • Loading branch information
dcarroll authored Sep 28, 2017
2 parents 1d6cb19 + d0ff36b commit 9854a5d
Show file tree
Hide file tree
Showing 14 changed files with 372 additions and 230 deletions.
13 changes: 6 additions & 7 deletions command/active.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package command

import (
"encoding/json"
"fmt"
"os/exec"
"runtime"
Expand Down Expand Up @@ -39,14 +38,14 @@ func init() {

func runActive(cmd *Command, args []string) {
if account == "" {
account, _ := Config.Load("current", "account")
data, _ := Config.Load("accounts", account)
var creds ForceCredentials
json.Unmarshal([]byte(data), &creds)
creds, err := ActiveCredentials(true)
if err != nil {
ErrorAndExit(err.Error())
}
if tojson {
fmt.Printf(fmt.Sprintf("{ \"login\": \"%s\", \"instanceUrl\": \"%s\", \"namespace\":\"%s\" }", account, creds.InstanceUrl, creds.Namespace))
fmt.Printf(fmt.Sprintf("{ \"login\": \"%s\", \"instanceUrl\": \"%s\", \"namespace\":\"%s\" }", creds.SessionName(), creds.InstanceUrl, creds.UserInfo.OrgNamespace))
} else {
fmt.Println(fmt.Sprintf("%s - %s - ns:%s", account, creds.InstanceUrl, creds.Namespace))
fmt.Println(fmt.Sprintf("%s - %s - ns:%s", creds.SessionName(), creds.InstanceUrl, creds.UserInfo.OrgNamespace))
}
} else {
//account := args[0]
Expand Down
9 changes: 8 additions & 1 deletion command/apiversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,14 @@ func runApiVersion(cmd *Command, args []string) {
if !matched {
ErrorAndExit("apiversion must be in the form of nn.0.")
}
UpdateApiVersion(apiVersionNumber)
force, err := ActiveForce()
if err != nil {
ErrorAndExit(err.Error())
}
err = force.UpdateApiVersion(apiVersionNumber)
if err != nil {
ErrorAndExit("%v", err)
}
} else if len(args) == 0 {
fmt.Println(ApiVersion())
} else {
Expand Down
2 changes: 1 addition & 1 deletion command/logins.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func runLogins(cmd *Command, args []string) {

for _, account := range accounts {
if !strings.HasPrefix(account, ".") {
var creds ForceCredentials
var creds ForceSession
data, err := Config.Load("accounts", account)
json.Unmarshal([]byte(data), &creds)

Expand Down
6 changes: 3 additions & 3 deletions command/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package command

import (
"fmt"
"strings"
"io/ioutil"
"strings"

. "github.com/heroku/force/error"
. "github.com/heroku/force/lib"
. "github.com/heroku/force/error"
)

var cmdRest = &Command{
Expand Down Expand Up @@ -36,7 +36,7 @@ func runRest(cmd *Command, args []string) {
// and handle other than get
var (
data = ""
msg = ""
msg = ""
)
var err error
if strings.ToLower(args[0]) == "get" {
Expand Down
31 changes: 5 additions & 26 deletions command/usedxauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,15 @@ func runUseDXAuth(cmd *Command, args []string) {
connStatus := fmt.Sprintf("%s", auth["connectedStatus"])
username := fmt.Sprintf("%s", auth["username"])
if connStatus == "Connected" || connStatus == "Unknown" {
authData := getSFDXAuth(username)
authData, err := GetSFDXAuth(username)
if err != nil {
ErrorAndExit(err.Error())
}
if val, ok := auth["alias"]; ok {
authData.Alias = val.(string)
}
authData.Username = username
SetActiveCreds(authData)
UseSFDXSession(authData)
if len(authData.Alias) > 0 {
fmt.Printf("Now using DX credentials for %s (%s)\n", username, authData.Alias)
} else {
Expand Down Expand Up @@ -187,27 +190,3 @@ func getDefaultItem() (data map[string]interface{}, err error) {
}
return
}

func getSFDXAuth(user string) (auth UserAuth) {
cmd := exec.Command("sfdx", "force:org:display", "-u"+user, "--json")

stdout, err := cmd.StdoutPipe()
if err != nil {
ErrorAndExit(err.Error())
}
if err := cmd.Start(); err != nil {
ErrorAndExit(err.Error())
}

type authData struct {
Result UserAuth
}
var aData authData
if err := json.NewDecoder(stdout).Decode(&aData); err != nil {
ErrorAndExit(err.Error())
}
if err := cmd.Wait(); err != nil {
ErrorAndExit(err.Error())
}
return aData.Result
}
11 changes: 5 additions & 6 deletions lib/apiversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ func ApiVersionNumber() string {
return apiVersionNumber
}

func UpdateApiVersion(version string) {
apiVersion = "v" + version
apiVersionNumber = version
force, _ := ActiveForce()
force.Credentials.ApiVersion = apiVersionNumber
ForceSaveLogin(*force.Credentials, os.Stdout)
func (f *Force) UpdateApiVersion(version string) (err error) {
SetApiVersion(version)
f.Credentials.SessionOptions.ApiVersion = version
_, err = ForceSaveLogin(*f.Credentials, os.Stdout)
return
}

func SetApiVersion(version string) {
Expand Down
170 changes: 102 additions & 68 deletions lib/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,63 +10,85 @@ import (
. "github.com/heroku/force/error"
)

type UserAuth struct {
AccessToken string
Alias string
ClientId string
CreatedBy string
DevHubId string
Edition string
Id string
InstanceUrl string
OrgName string
Password string
Status string
Username string
func (f *Force) userInfo() (userinfo UserInfo, err error) {
url := fmt.Sprintf("%s/services/oauth2/userinfo", f.Credentials.InstanceUrl)
login, err := f.httpGet(url)
if err != nil {
return
}
err = json.Unmarshal([]byte(login), &userinfo)
return
}

func ForceSaveLogin(creds ForceCredentials, output *os.File) (username string, err error) {
func getUserInfo(creds ForceSession) (userinfo UserInfo, err error) {
force := NewForce(&creds)
login, err := force.Get(creds.Id)
userinfo, err = force.userInfo()
if err != nil {
return
}
me, err := force.GetRecord("User", userinfo.UserId)
if err != nil {
fmt.Fprintln(os.Stderr, "Problem getting user data, continuing...")
err = nil
}
userinfo.ProfileId = fmt.Sprintf("%s", me["ProfileId"])

body, err := json.Marshal(creds)
namespace, err := force.getOrgNamespace()
if err == nil {
userinfo.OrgNamespace = namespace
} else {
fmt.Fprintf(os.Stderr, "Your profile does not have Modify All Data enabled. Functionallity will be limited.\n")
err = nil
}
return
}

func (f *Force) getOrgNamespace() (namespace string, err error) {
describe, err := f.Metadata.DescribeMetadata()
if err != nil {
return
}
namespace = describe.NamespacePrefix
return
}

userId := login["user_id"].(string)
creds.UserId = userId
username = login["username"].(string)

me, err := force.Whoami()
// Save the credentials as the active session with the UserInfo and with the
// default current API version.
func ForceSaveLogin(creds ForceSession, output *os.File) (sessionName string, err error) {
userinfo, err := getUserInfo(creds)
if err != nil {
fmt.Fprintln(output, "Problem getting user data, continuing...")
//return
return
}
fmt.Fprintf(output, "Logged in as '%s' (API %s)\n", me["Username"], apiVersion)
title := fmt.Sprintf("\033];%s\007", me["Username"])
creds.ProfileId = fmt.Sprintf("%s", me["ProfileId"])
creds.ApiVersion = strings.TrimPrefix(apiVersion, "v")
creds.UserInfo = &userinfo
creds.SessionOptions.ApiVersion = ApiVersionNumber()

fmt.Fprintf(output, "Logged in as '%s' (API %s)\n", creds.UserInfo.UserName, ApiVersionNumber())
title := fmt.Sprintf("\033];%s\007", creds.UserInfo.UserName)
fmt.Fprintf(output, title)

describe, err := force.Metadata.DescribeMetadata()
if err = SaveLogin(creds); err != nil {
return
}
sessionName = creds.SessionName()
err = SetActiveLogin(sessionName)
return
}

if err == nil {
creds.Namespace = describe.NamespacePrefix
} else {
fmt.Fprintf(output, "Your profile does not have Modify All Data enabled. Functionallity will be limited.\n")
err = nil
func (creds *ForceSession) SessionName() string {
sessionName := creds.UserInfo.UserName
if creds.SessionOptions.Alias != "" {
sessionName = creds.SessionOptions.Alias
}
return sessionName
}

body, err = json.Marshal(creds)
func SaveLogin(creds ForceSession) (err error) {
body, err := json.Marshal(creds)
if err != nil {
return
}
Config.Save("accounts", username, string(body))
Config.Save("current", "account", username)
sessionName := creds.SessionName()
err = Config.Save("accounts", sessionName, string(body))
return
}

Expand All @@ -77,7 +99,6 @@ func ForceLoginAndSaveSoap(endpoint ForceEndpoint, user_name string, password st
}

username, err = ForceSaveLogin(creds, output)
//fmt.Printf("Creds %+v", creds)
return
}

Expand All @@ -90,12 +111,11 @@ func ForceLoginAndSave(endpoint ForceEndpoint, output *os.File) (username string
return
}

func (f *Force) UpdateCredentials(creds ForceCredentials) {
func (f *Force) UpdateCredentials(creds ForceSession) {
f.Credentials.AccessToken = creds.AccessToken
f.Credentials.IssuedAt = creds.IssuedAt
f.Credentials.InstanceUrl = creds.InstanceUrl
f.Credentials.Scope = creds.Scope
f.Credentials.Id = creds.Id
ForceSaveLogin(*f.Credentials, os.Stderr)
}

Expand All @@ -108,7 +128,37 @@ func ActiveForce() (force *Force, err error) {
return
}

func ActiveCredentials(requireCredentials bool) (creds ForceCredentials, err error) {
// Add UserInfo and SessionOptions to old ForceSession
func upgradeCredentials(creds *ForceSession) (err error) {
if creds.SessionOptions != nil && creds.UserInfo != nil {
return
}
if creds.SessionOptions == nil {
creds.SessionOptions = &SessionOptions{
ApiVersion: ApiVersionNumber(),
}
if creds.RefreshToken != "" {
creds.SessionOptions.RefreshMethod = RefreshOauth
}
}
if creds.UserInfo == nil || creds.UserInfo.UserName == "" {
force := NewForce(creds)
err = force.RefreshSession()
if err != nil {
return
}
var userinfo UserInfo
userinfo, err = getUserInfo(*creds)
if err != nil {
return
}
creds.UserInfo = &userinfo
_, err = ForceSaveLogin(*creds, os.Stderr)
}
return
}

func ActiveCredentials(requireCredentials bool) (creds ForceSession, err error) {
account, err := ActiveLogin()
if requireCredentials && (err != nil || strings.TrimSpace(account) == "") {
ErrorAndExit("Please login before running this command.")
Expand All @@ -118,10 +168,18 @@ func ActiveCredentials(requireCredentials bool) (creds ForceCredentials, err err
ErrorAndExit("Failed to load credentials. %v", err)
}
if err == nil {
_ = json.Unmarshal([]byte(data), &creds)
if creds.ApiVersion != "" {
apiVersionNumber = creds.ApiVersion
apiVersion = "v" + apiVersionNumber
err = json.Unmarshal([]byte(data), &creds)
if err != nil {
ErrorAndExit(err.Error())
}
err = upgradeCredentials(&creds)
if err != nil {
// Couldn't update the credentials. Force re-login.
err = Config.Delete("current", "account")
ErrorAndExit("Cannot update stored session. Please log in again.")
}
if creds.SessionOptions.ApiVersion != "" && creds.SessionOptions.ApiVersion != ApiVersionNumber() {
SetApiVersion(creds.SessionOptions.ApiVersion)
}
}
if !requireCredentials && err != nil {
Expand Down Expand Up @@ -154,27 +212,3 @@ func SetActiveLogin(account string) (err error) {
err = Config.Save("current", "account", account)
return
}

func SetActiveCreds(authData UserAuth) {
creds := ForceCredentials{}
creds.AccessToken = authData.AccessToken
creds.InstanceUrl = authData.InstanceUrl
creds.IsCustomEP = true
creds.ApiVersion = "40.0"
creds.ForceEndpoint = 4
creds.IsHourly = false
creds.HourlyCheck = false

body, err := json.Marshal(creds)
if err != nil {
ErrorAndExit(err.Error())
}

configName := authData.Alias
if len(configName) == 0 {
configName = authData.Username
}

Config.Save("accounts", configName, string(body))
Config.Save("current", "account", configName)
}
Loading

0 comments on commit 9854a5d

Please sign in to comment.