microsoft: option for group UUIDs instead of name and group whitelist

This commit is contained in:
Maxime Desrosiers
2019-05-08 16:06:19 -04:00
parent 20a858da3b
commit 458585008b
2 changed files with 65 additions and 29 deletions

View File

@@ -19,35 +19,50 @@ import (
"github.com/dexidp/dex/pkg/log"
)
// GroupNameFormat represents the format of the group identifier
// we use type of string instead of int because it's easier to
// marshall/unmarshall
type GroupNameFormat string
// Possible values for GroupNameFormat
const (
GroupID GroupNameFormat = "id"
GroupName GroupNameFormat = "name"
)
const (
apiURL = "https://graph.microsoft.com"
// Microsoft requires this scope to access user's profile
scopeUser = "user.read"
// Microsoft requires this scope to list groups the user is a member of
// and resolve their UUIDs to groups names.
// and resolve their ids to groups names.
scopeGroups = "directory.read.all"
)
// Config holds configuration options for microsoft logins.
type Config struct {
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
Tenant string `json:"tenant"`
OnlySecurityGroups bool `json:"onlySecurityGroups"`
Groups []string `json:"groups"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
Tenant string `json:"tenant"`
OnlySecurityGroups bool `json:"onlySecurityGroups"`
Groups []string `json:"groups"`
GroupNameFormat GroupNameFormat `json:"groupNameFormat"`
UseGroupsAsWhitelist bool `json:"useGroupsAsWhitelist"`
}
// Open returns a strategy for logging in through Microsoft.
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
m := microsoftConnector{
redirectURI: c.RedirectURI,
clientID: c.ClientID,
clientSecret: c.ClientSecret,
tenant: c.Tenant,
onlySecurityGroups: c.OnlySecurityGroups,
groups: c.Groups,
logger: logger,
redirectURI: c.RedirectURI,
clientID: c.ClientID,
clientSecret: c.ClientSecret,
tenant: c.Tenant,
onlySecurityGroups: c.OnlySecurityGroups,
groups: c.Groups,
groupNameFormat: c.GroupNameFormat,
useGroupsAsWhitelist: c.UseGroupsAsWhitelist,
logger: logger,
}
// By default allow logins from both personal and business/school
// accounts.
@@ -55,6 +70,15 @@ func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error)
m.tenant = "common"
}
// By default, use group names
switch m.groupNameFormat {
case "":
m.groupNameFormat = GroupName
case GroupID, GroupName:
default:
return nil, fmt.Errorf("invalid groupNameFormat: %s", m.groupNameFormat)
}
return &m, nil
}
@@ -70,13 +94,15 @@ var (
)
type microsoftConnector struct {
redirectURI string
clientID string
clientSecret string
tenant string
onlySecurityGroups bool
groups []string
logger log.Logger
redirectURI string
clientID string
clientSecret string
tenant string
onlySecurityGroups bool
groupNameFormat GroupNameFormat
groups []string
useGroupsAsWhitelist bool
logger log.Logger
}
func (c *microsoftConnector) isOrgTenant() bool {
@@ -300,24 +326,28 @@ type group struct {
Name string `json:"displayName"`
}
func (c *microsoftConnector) getGroups(ctx context.Context, client *http.Client, userID string) (groups []string, err error) {
ids, err := c.getGroupIDs(ctx, client)
func (c *microsoftConnector) getGroups(ctx context.Context, client *http.Client, userID string) ([]string, error) {
userGroups, err := c.getGroupIDs(ctx, client)
if err != nil {
return groups, err
return nil, err
}
groups, err = c.getGroupNames(ctx, client, ids)
if err != nil {
return
if c.groupNameFormat == GroupName {
userGroups, err = c.getGroupNames(ctx, client, userGroups)
if err != nil {
return nil, err
}
}
// ensure that the user is in at least one required group
filteredGroups := groups_pkg.Filter(groups, c.groups)
filteredGroups := groups_pkg.Filter(userGroups, c.groups)
if len(c.groups) > 0 && len(filteredGroups) == 0 {
return nil, fmt.Errorf("microsoft: user %v not in any of the required groups", userID)
} else if c.useGroupsAsWhitelist {
return filteredGroups, nil
}
return
return userGroups, nil
}
func (c *microsoftConnector) getGroupIDs(ctx context.Context, client *http.Client) (ids []string, err error) {