Skip to content
This repository has been archived by the owner on May 18, 2021. It is now read-only.

Commit

Permalink
feat: sort roles listed in roles prompt (#229)
Browse files Browse the repository at this point in the history
  • Loading branch information
badie authored and nickatsegment committed Oct 17, 2019
1 parent 47e49fc commit 5ea3811
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
10 changes: 9 additions & 1 deletion lib/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,15 @@ func (p *Provider) getSamlSessionCreds() (sts.Credentials, error) {
} else {
profileARN, ok = p.profiles[source]["role_arn"]
if !ok {
return sts.Credentials{}, errors.New("Source profile must provide `role_arn`")
// profile does not have a role_arn. This is ok as the user will be promted
// to choose a role from all available roles
// Support profiles similar to below
// [profile my-profile]
// output = json
// aws_saml_url = /home/some_saml_url
// mfa_provider = FIDO
// mfa_factor_type = u2f
log.Debugf("Profile '%s' does not have role_arn", source)
}
}

Expand Down
36 changes: 35 additions & 1 deletion lib/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/xml"
"errors"
"fmt"
"regexp"
"sort"
"strconv"
"strings"

Expand All @@ -13,6 +15,10 @@ import (
"golang.org/x/net/html"
)

// Role arn format => arn:${Partition}:iam::${Account}:role/${RoleNameWithPath}
// https://docs.aws.amazon.com/IAM/latest/UserGuide/list_identityandaccessmanagement.html
var awsRoleARNRegex = regexp.MustCompile(`arn:[a-z-]+:iam::(\d{12}):role/(.*)`)

func GetRoleFromSAML(resp *saml.Response, profileARN string) (string, string, error) {

roles, err := GetAssumableRolesFromSAML(resp)
Expand Down Expand Up @@ -91,9 +97,23 @@ func GetRole(roleList saml.AssumableRoles, profileARN string) (saml.AssumableRol
return roleList[0], nil
}

// Sort the roles in alphabetical order
sort.Slice(roleList, func(i, j int) bool {
return roleList[i].Role < roleList[j].Role
})

var roleName, previousAccountID, currentAccountID string

for i, arole := range roleList {
fmt.Printf("%d - %s\n", i, arole.Role)
currentAccountID, roleName = accountIDAndRoleFromRoleARN(arole.Role)
if currentAccountID != previousAccountID {
fmt.Printf("\nAccount: %s\n", currentAccountID)
}
previousAccountID = currentAccountID

fmt.Printf("%4d - %s\n", i, roleName)
}
fmt.Println("")

i, err := Prompt("Select Role to Assume", false)
if err != nil {
Expand Down Expand Up @@ -160,3 +180,17 @@ func GetNode(n *html.Node, name string) (val string, node *html.Node) {
}
return
}

func accountIDAndRoleFromRoleARN(roleARN string) (string, string) {
matches := awsRoleARNRegex.FindStringSubmatch(roleARN)

// matches will contain ("roleARN", "accountID", "roleName")
if len(matches) == 3 {
return matches[1], matches[2]
}

// Getting here means we failed to extract accountID and roleName from
// roleARN. It should "not" happen, but if it does, return empty string
// as accountID and roleARN as roleName instead.
return "", roleARN
}

0 comments on commit 5ea3811

Please sign in to comment.