Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust tctl sso commands to new teams_to_roles field. #13463

Merged
merged 2 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,790 changes: 925 additions & 865 deletions api/types/types.pb.go

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion api/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3067,8 +3067,12 @@ message SSODiagnosticInfo {
repeated TeamMapping GithubTeamsToLogins = 31
[ (gogoproto.nullable) = false, (gogoproto.jsontag) = "github_teams_to_logins,omitempty" ];

// GithubTeamsToRoles is TeamRolesMapping mapping from Github connector used in the SSO flow.
repeated TeamRolesMapping GithubTeamsToRoles = 32
[ (gogoproto.nullable) = false, (gogoproto.jsontag) = "github_teams_to_roles,omitempty" ];

// GithubTokenInfo stores diagnostic info about Github OAuth2 token obtained during SSO flow.
GithubTokenInfo GithubTokenInfo = 32 [ (gogoproto.jsontag) = "github_token_info,omitempty" ];
GithubTokenInfo GithubTokenInfo = 33 [ (gogoproto.jsontag) = "github_token_info,omitempty" ];
Tener marked this conversation as resolved.
Show resolved Hide resolved
}

// GithubTokenInfo stores diagnostic info about Github OAuth2 token obtained during SSO flow.
Expand Down
1 change: 1 addition & 0 deletions lib/auth/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ func (a *Server) validateGithubAuthCallback(ctx context.Context, diagCtx *ssoDia
return nil, trace.Wrap(err, "Failed to get Github connector and client.")
}
diagCtx.info.GithubTeamsToLogins = connector.GetTeamsToLogins()
diagCtx.info.GithubTeamsToRoles = connector.GetTeamsToRoles()
logger.Debugf("Connector %q teams to logins: %v, roles: %v", connector.GetName(), connector.GetTeamsToLogins(), connector.GetTeamsToRoles())

// exchange the authorization code received by the callback for an access token
Expand Down
16 changes: 8 additions & 8 deletions tool/tctl/sso/configure/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ func addGithubCommand(cmd *SSOConfigureCommand) *AuthKindCommand {
sub := cmd.ConfigureCmd.Command("github", "Configure Github auth connector.")
// commonly used flags
sub.Flag("name", "Connector name.").Default("github").Short('n').StringVar(&gh.connectorName)
sub.Flag("teams-to-logins", "Sets teams-to-logins mapping using format 'organization,name,role1,role2,...'. Repeatable.").
sub.Flag("teams-to-roles", "Sets teams-to-roles mapping using format 'organization,name,role1,role2,...'. Repeatable.").
Short('r').
Required().
PlaceHolder("org,team,role1,role2,...").
SetValue(newTeamsToLoginsParser(&spec.TeamsToLogins))
SetValue(newTeamsToRolesParser(&spec.TeamsToRoles))
sub.Flag("display", "Sets the connector display name.").StringVar(&spec.Display)
sub.Flag("id", "Github app client ID.").PlaceHolder("ID").Required().StringVar(&spec.ClientID)
sub.Flag("secret", "Github app client secret.").Required().PlaceHolder("SECRET").StringVar(&spec.ClientSecret)
Expand All @@ -55,7 +55,7 @@ func addGithubCommand(cmd *SSOConfigureCommand) *AuthKindCommand {
sub.Flag("redirect-url", "Authorization callback URL.").PlaceHolder("URL").StringVar(&spec.RedirectURL)

// ignores
sub.Flag("ignore-missing-roles", "Ignore missing roles referenced in --teams-to-logins.").BoolVar(&gh.ignoreMissingRoles)
sub.Flag("ignore-missing-roles", "Ignore missing roles referenced in --teams-to-roles.").BoolVar(&gh.ignoreMissingRoles)

sub.Alias("gh")

Expand Down Expand Up @@ -133,7 +133,7 @@ func ResolveCallbackURL(logger *logrus.Entry, clt auth.ClientI, fieldName string
func specCheckRoles(ctx context.Context, logger *logrus.Entry, spec *types.GithubConnectorSpecV3, ignoreMissingRoles bool, clt auth.ClientI) error {
allRoles, err := clt.GetRoles(ctx)
if err != nil {
logger.WithError(err).Warn("unable to get roles list. Skipping teams-to-logins sanity checks.")
logger.WithError(err).Warn("unable to get roles list. Skipping teams-to-roles sanity checks.")
Tener marked this conversation as resolved.
Show resolved Hide resolved
return nil
}

Expand All @@ -144,14 +144,14 @@ func specCheckRoles(ctx context.Context, logger *logrus.Entry, spec *types.Githu
roleNames = append(roleNames, role.GetName())
}

for _, mapping := range spec.TeamsToLogins {
for _, role := range mapping.Logins {
for _, mapping := range spec.TeamsToRoles {
for _, role := range mapping.Roles {
_, found := roleMap[role]
espadolini marked this conversation as resolved.
Show resolved Hide resolved
if !found {
if ignoreMissingRoles {
logger.Warnf("teams-to-logins references non-existing role: %q. Available roles: %v.", role, roleNames)
logger.Warnf("teams-to-roles references non-existing role: %q. Available roles: %v.", role, roleNames)
} else {
return trace.BadParameter("teams-to-logins references non-existing role: %v. Correct the mapping, or add --ignore-missing-roles to ignore this error. Available roles: %v.", role, roleNames)
return trace.BadParameter("teams-to-roles references non-existing role: %v. Correct the mapping, or add --ignore-missing-roles to ignore this error. Available roles: %v.", role, roleNames)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,30 @@ import (
"github.com/gravitational/teleport/api/types"
)

// teamsToLoginsParser parsers 'name,value,role1,role2,...' values into types.AttributeMapping entries. Cumulative, can handle multiple entries.
type teamsToLoginsParser struct {
mappings *[]types.TeamMapping
// teamsToRolesParser parsers 'name,value,role1,role2,...' values into types.AttributeMapping entries. Cumulative, can handle multiple entries.
type teamsToRolesParser struct {
mappings *[]types.TeamRolesMapping
}

func (p *teamsToLoginsParser) String() string {
func (p *teamsToRolesParser) String() string {
return fmt.Sprintf("%q", p.mappings)
}

func (p *teamsToLoginsParser) Set(s string) error {
func (p *teamsToRolesParser) Set(s string) error {
splits := strings.Split(s, ",")

if len(splits) < 3 {
return trace.BadParameter("Too few elements separated with comma. use syntax: 'name,value,role1,role2,...'.")
return trace.BadParameter("Too few elements separated with comma. use syntax: 'organization,team,role1,role2,...'.")
}

name := splits[0]
value := splits[1]
org := splits[0]
team := splits[1]
roles := splits[2:]

mapping := types.TeamMapping{
Organization: name,
Team: value,
Logins: roles, // note: logins is legacy name, 'roles' is accurate now.
mapping := types.TeamRolesMapping{
Organization: org,
Team: team,
Roles: roles,
}

*p.mappings = append(*p.mappings, mapping)
Expand All @@ -56,11 +56,11 @@ func (p *teamsToLoginsParser) Set(s string) error {
}

// IsCumulative returns true if flag is repeatable. This is checked by kingpin library.
func (p *teamsToLoginsParser) IsCumulative() bool {
func (p *teamsToRolesParser) IsCumulative() bool {
return true
}

// newTeamsToLoginsParser returns a cumulative flag parser for []types.TeamMapping.
func newTeamsToLoginsParser(field *[]types.TeamMapping) kingpin.Value {
return &teamsToLoginsParser{mappings: field}
// newTeamsToRolesParser returns a cumulative flag parser for []types.TeamMapping.
func newTeamsToRolesParser(field *[]types.TeamRolesMapping) kingpin.Value {
return &teamsToRolesParser{mappings: field}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,56 +22,56 @@ import (
"github.com/gravitational/teleport/api/types"
)

func Test_teamsToLoginsParser_Set(t *testing.T) {
func Test_teamsToRolesParser_Set(t *testing.T) {
tests := []struct {
name string
parser teamsToLoginsParser
parser teamsToRolesParser
arg string
wantErr bool
wantParser teamsToLoginsParser
wantParser teamsToRolesParser
}{
{
name: "one set of correct args",
parser: teamsToLoginsParser{mappings: new([]types.TeamMapping)},
parser: teamsToRolesParser{mappings: new([]types.TeamRolesMapping)},
arg: "foo,bar,baz",
wantParser: teamsToLoginsParser{mappings: &[]types.TeamMapping{
wantParser: teamsToRolesParser{mappings: &[]types.TeamRolesMapping{
{
Organization: "foo",
Team: "bar",
Logins: []string{"baz"},
Roles: []string{"baz"},
},
}},
wantErr: false,
},
{
name: "two sets of correct args",
parser: teamsToLoginsParser{mappings: &[]types.TeamMapping{
parser: teamsToRolesParser{mappings: &[]types.TeamRolesMapping{
{
Organization: "foo",
Team: "bar",
Logins: []string{"baz"},
Roles: []string{"baz"},
},
}},
arg: "aaa,bbb,ccc,ddd",
wantParser: teamsToLoginsParser{mappings: &[]types.TeamMapping{
wantParser: teamsToRolesParser{mappings: &[]types.TeamRolesMapping{
{
Organization: "foo",
Team: "bar",
Logins: []string{"baz"},
Roles: []string{"baz"},
},
{
Organization: "aaa",
Team: "bbb",
Logins: []string{"ccc", "ddd"},
Roles: []string{"ccc", "ddd"},
},
}},
wantErr: false,
},
{
name: "one set of incorrect args",
parser: teamsToLoginsParser{mappings: new([]types.TeamMapping)},
parser: teamsToRolesParser{mappings: new([]types.TeamRolesMapping)},
arg: "abracadabra",
wantParser: teamsToLoginsParser{mappings: new([]types.TeamMapping)},
wantParser: teamsToRolesParser{mappings: new([]types.TeamRolesMapping)},
wantErr: true,
},
}
Expand Down
5 changes: 5 additions & 0 deletions tool/tctl/sso/tester/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,10 @@ func getGithubDiagInfoFields(diag *types.SSODiagnosticInfo, debug bool) []string
true,
FormatYAML("[GitHub] Connector team to logins mapping", diag.GithubTeamsToLogins),
),
GetDiagMessage(
diag.GithubTeamsToRoles != nil,
true,
FormatYAML("[GitHub] Connector team to roles mapping", diag.GithubTeamsToRoles),
),
}
}