Add support for a simple group filter
This commit is contained in:
parent
5e5717ded7
commit
2fd6f02cd8
3
main.go
3
main.go
|
|
@ -34,7 +34,8 @@ func main() {
|
||||||
flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path")
|
flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path")
|
||||||
flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream")
|
flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream")
|
||||||
flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream")
|
flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream")
|
||||||
flagSet.Bool("pass-groups", false, "pass user group information along with basic auth to upstream")
|
flagSet.Bool("pass-groups", false, "pass user group information in the X-Forwarded-Groups header to upstream (Azure only)")
|
||||||
|
flagSet.String("filter-groups", "", "exclude groups that do not contain this value in its 'displayName' (Azure only)")
|
||||||
flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header")
|
flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header")
|
||||||
flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header")
|
flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header")
|
||||||
flagSet.Bool("pass-host-header", true, "pass the request Host Header to upstream")
|
flagSet.Bool("pass-host-header", true, "pass the request Host Header to upstream")
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ type OAuthProxy struct {
|
||||||
SetXAuthRequest bool
|
SetXAuthRequest bool
|
||||||
PassBasicAuth bool
|
PassBasicAuth bool
|
||||||
PassGroups bool
|
PassGroups bool
|
||||||
|
FilterGroups string
|
||||||
SkipProviderButton bool
|
SkipProviderButton bool
|
||||||
PassUserHeaders bool
|
PassUserHeaders bool
|
||||||
BasicAuthPassword string
|
BasicAuthPassword string
|
||||||
|
|
@ -208,6 +209,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
|
||||||
PassBasicAuth: opts.PassBasicAuth,
|
PassBasicAuth: opts.PassBasicAuth,
|
||||||
PassUserHeaders: opts.PassUserHeaders,
|
PassUserHeaders: opts.PassUserHeaders,
|
||||||
PassGroups: opts.PassGroups,
|
PassGroups: opts.PassGroups,
|
||||||
|
FilterGroups: opts.FilterGroups,
|
||||||
BasicAuthPassword: opts.BasicAuthPassword,
|
BasicAuthPassword: opts.BasicAuthPassword,
|
||||||
PassAccessToken: opts.PassAccessToken,
|
PassAccessToken: opts.PassAccessToken,
|
||||||
SkipProviderButton: opts.SkipProviderButton,
|
SkipProviderButton: opts.SkipProviderButton,
|
||||||
|
|
@ -551,7 +553,7 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
session.IDToken = req.Form.Get("id_token")
|
session.IDToken = req.Form.Get("id_token")
|
||||||
if p.PassGroups && session.IDToken != "" {
|
if p.PassGroups && session.IDToken != "" {
|
||||||
session.Groups, err = p.provider.GetGroups(session)
|
session.Groups, err = p.provider.GetGroups(session, p.FilterGroups)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.ErrorPage(rw, 500, "Internal Error", "Internal Error")
|
p.ErrorPage(rw, 500, "Internal Error", "Internal Error")
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ type Options struct {
|
||||||
SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"`
|
SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"`
|
||||||
PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"`
|
PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"`
|
||||||
PassGroups bool `flag:"pass-groups" cfg:"pass_groups"`
|
PassGroups bool `flag:"pass-groups" cfg:"pass_groups"`
|
||||||
|
FilterGroups string `flag:"filter-groups" cfg:"filter_groups"`
|
||||||
BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password"`
|
BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password"`
|
||||||
PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token"`
|
PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token"`
|
||||||
PassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header"`
|
PassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header"`
|
||||||
|
|
@ -103,6 +104,7 @@ func NewOptions() *Options {
|
||||||
PassBasicAuth: true,
|
PassBasicAuth: true,
|
||||||
PassUserHeaders: true,
|
PassUserHeaders: true,
|
||||||
PassGroups: false,
|
PassGroups: false,
|
||||||
|
FilterGroups: "",
|
||||||
PassAccessToken: false,
|
PassAccessToken: false,
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
ApprovalPrompt: "force",
|
ApprovalPrompt: "force",
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,8 @@ func (p *AzureProvider) GetEmailAddress(s *SessionState) (string, error) {
|
||||||
return email, err
|
return email, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *AzureProvider) GetGroups(s *SessionState) (string, error) {
|
// Get list of groups user belong to. Filter the desired names of groups (in case of huge group set)
|
||||||
|
func (p *AzureProvider) GetGroups(s *SessionState, f string) (string, error) {
|
||||||
if s.AccessToken == "" {
|
if s.AccessToken == "" {
|
||||||
return "", errors.New("missing access token")
|
return "", errors.New("missing access token")
|
||||||
}
|
}
|
||||||
|
|
@ -136,36 +137,51 @@ func (p *AzureProvider) GetGroups(s *SessionState) (string, error) {
|
||||||
return "", errors.New("missing id token")
|
return "", errors.New("missing id token")
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse token, check if it has groups
|
// For future use. Right now microsoft graph don't support filter
|
||||||
// if groups, return "|".join(groups_list)
|
// http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part2-url-conventions/odata-v4.0-errata02-os-part2-url-conventions-complete.html#_Toc406398116
|
||||||
// else
|
|
||||||
// look for claim source
|
|
||||||
// GET source
|
|
||||||
// parse response
|
|
||||||
// return "|".join(response.groups_list)
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "https://graph.microsoft.com/v1.0/me/memberOf/", nil)
|
/*
|
||||||
//req, err := http.NewRequest("POST", "https://graph.microsoft.com/v1.0/me/getMemberGroups", strings.NewReader("{\"securityEnabledOnly\":true}"))
|
var request string = "https://graph.microsoft.com/v1.0/me/memberOf?$select=id,displayName,groupTypes,securityEnabled,description,mailEnabled&$top=999"
|
||||||
if err != nil {
|
if f != "" {
|
||||||
return "", err
|
request += "?$filter=contains(displayName, '"+f+"')"
|
||||||
}
|
|
||||||
req.Header = getAzureHeader(s.AccessToken)
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
|
||||||
|
|
||||||
groupData, err := api.Request(req)
|
|
||||||
|
|
||||||
groups := make([]string, 0)
|
|
||||||
for _, groupInfo := range groupData.Get("value").MustArray() {
|
|
||||||
//v, ok := groupInfo.(string)
|
|
||||||
v, ok := groupInfo.(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
dname := v["displayName"].(string)
|
*/
|
||||||
secen := v["securityEnabled"].(bool)
|
//
|
||||||
mailen := v["mailEnabled"].(bool)
|
// Filters that will be possible to use:
|
||||||
if secen == true && mailen == false {
|
// contains - unknown function | "https://graph.microsoft.com/v1.0/me/memberOf?$filter=contains(displayName,%27olm%27)"
|
||||||
groups = append(groups, dname)
|
// startswith - not supported | "https://graph.microsoft.com/v1.0/me/memberOf?$filter=startswith(displayName,%27olm%27)"
|
||||||
|
// substring - not supported | "https://graph.microsoft.com/v1.0/me/memberOf?$filter=substring(displayName,0,2)%20eq%20%27olm%27"
|
||||||
|
|
||||||
|
requestUrl := "https://graph.microsoft.com/v1.0/me/memberOf?$select=displayName"
|
||||||
|
groups := make([]string, 0)
|
||||||
|
|
||||||
|
for {
|
||||||
|
req, err := http.NewRequest("GET", requestUrl, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header = getAzureHeader(s.AccessToken)
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
groupData, err := api.Request(req)
|
||||||
|
|
||||||
|
for _, groupInfo := range groupData.Get("value").MustArray() {
|
||||||
|
v, ok := groupInfo.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dname := v["displayName"].(string)
|
||||||
|
if strings.Contains(dname, f) {
|
||||||
|
groups = append(groups, dname)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if nextlink := groupData.Get("@odata.nextLink").MustString(); nextlink != "" {
|
||||||
|
requestUrl = nextlink
|
||||||
|
} else {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ func (p *ProviderData) GetEmailAddress(s *SessionState) (string, error) {
|
||||||
return "", errors.New("not implemented")
|
return "", errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProviderData) GetGroups(s *SessionState) (string, error) {
|
func (p *ProviderData) GetGroups(s *SessionState, f string) (string, error) {
|
||||||
return "", errors.New("not implemented")
|
return "", errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
Data() *ProviderData
|
Data() *ProviderData
|
||||||
GetEmailAddress(*SessionState) (string, error)
|
GetEmailAddress(*SessionState) (string, error)
|
||||||
GetGroups(*SessionState) (string, error)
|
GetGroups(*SessionState, string) (string, error)
|
||||||
Redeem(string, string) (*SessionState, error)
|
Redeem(string, string) (*SessionState, error)
|
||||||
ValidateGroup(string) bool
|
ValidateGroup(string) bool
|
||||||
ValidateSessionState(*SessionState) bool
|
ValidateSessionState(*SessionState) bool
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue