github.com/versent/saml2aws@v2.17.0+incompatible/aws_account.go (about)

     1  package saml2aws
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"net/url"
     8  
     9  	"fmt"
    10  
    11  	"github.com/PuerkitoBio/goquery"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  const awsURL = "https://signin.aws.amazon.com/saml"
    16  
    17  // AWSAccount holds the AWS account name and roles
    18  type AWSAccount struct {
    19  	Name  string
    20  	Roles []*AWSRole
    21  }
    22  
    23  // ParseAWSAccounts extract the aws accounts from the saml assertion
    24  func ParseAWSAccounts(samlAssertion string) ([]*AWSAccount, error) {
    25  
    26  	res, err := http.PostForm(awsURL, url.Values{"SAMLResponse": {samlAssertion}})
    27  	if err != nil {
    28  		return nil, errors.Wrap(err, "error retrieving AWS login form")
    29  	}
    30  
    31  	data, err := ioutil.ReadAll(res.Body)
    32  	if err != nil {
    33  		return nil, errors.Wrap(err, "error retrieving AWS login body")
    34  	}
    35  
    36  	return ExtractAWSAccounts(data)
    37  }
    38  
    39  // ExtractAWSAccounts extract the accounts from the AWS html page
    40  func ExtractAWSAccounts(data []byte) ([]*AWSAccount, error) {
    41  	accounts := []*AWSAccount{}
    42  
    43  	doc, err := goquery.NewDocumentFromReader(bytes.NewBuffer(data))
    44  	if err != nil {
    45  		return nil, errors.Wrap(err, "failed to build document from response")
    46  	}
    47  
    48  	doc.Find("fieldset > div.saml-account").Each(func(i int, s *goquery.Selection) {
    49  		account := new(AWSAccount)
    50  		account.Name = s.Find("div.saml-account-name").Text()
    51  		s.Find("label").Each(func(i int, s *goquery.Selection) {
    52  			role := new(AWSRole)
    53  			role.Name = s.Text()
    54  			role.RoleARN, _ = s.Attr("for")
    55  			account.Roles = append(account.Roles, role)
    56  		})
    57  		accounts = append(accounts, account)
    58  	})
    59  
    60  	return accounts, nil
    61  }
    62  
    63  // AssignPrincipals assign principal from roles
    64  func AssignPrincipals(awsRoles []*AWSRole, awsAccounts []*AWSAccount) {
    65  
    66  	awsPrincipalARNs := make(map[string]string)
    67  	for _, awsRole := range awsRoles {
    68  		awsPrincipalARNs[awsRole.RoleARN] = awsRole.PrincipalARN
    69  	}
    70  
    71  	for _, awsAccount := range awsAccounts {
    72  		for _, awsRole := range awsAccount.Roles {
    73  			awsRole.PrincipalARN = awsPrincipalARNs[awsRole.RoleARN]
    74  		}
    75  	}
    76  
    77  }
    78  
    79  // LocateRole locate role by name
    80  func LocateRole(awsRoles []*AWSRole, roleName string) (*AWSRole, error) {
    81  	for _, awsRole := range awsRoles {
    82  		if awsRole.RoleARN == roleName {
    83  			return awsRole, nil
    84  		}
    85  	}
    86  
    87  	return nil, fmt.Errorf("Supplied RoleArn not found in saml assertion: %s", roleName)
    88  }