Skip to content

Commit

Permalink
Add support for determining claims based on rules
Browse files Browse the repository at this point in the history
  • Loading branch information
halkeye committed Apr 18, 2020
1 parent 36f78dd commit f1454e0
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 11 deletions.
3 changes: 3 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ auth:
clientSecret: ""
scopes: null # list of scopes, defaults to ["openid"]
redirectURL: "" # full url you want the oidc to redirect to, example: https://vpn-admin.example.com/finish-signin
# See https://github.com/Knetic/govaluate/blob/9aa49832a739dcd78a5542ff189fb82c3e423116/MANUAL.md for how to write rules
userClaimsRules:
admin: "'WireguardAdmins' in group_membership"
# Optionally restrict login to users with an allowed email domain
# if empty or omitted, any email domain will be allowed.
emailDomains:
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ require (
google.golang.org/appengine v1.6.1 // indirect
google.golang.org/genproto v0.0.0-20200210034751-acff78025515 // indirect
google.golang.org/grpc v1.27.1
gopkg.in/Knetic/govaluate.v2 v2.3.0
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/square/go-jose.v2 v2.4.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
gopkg.in/Knetic/govaluate.v2 v2.3.0 h1:naJVc9CZlWA8rC8f5mvECJD7jreTrn7FvGXjBthkHJQ=
gopkg.in/Knetic/govaluate.v2 v2.3.0/go.mod h1:NW0gr10J8s7aNghEg6uhdxiEaBvc0+8VgJjVViHUKp4=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
64 changes: 53 additions & 11 deletions pkg/authnz/authconfig/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"net/http"
"net/url"
"strconv"
"strings"
"time"

Expand All @@ -15,16 +16,43 @@ import (
"github.com/place1/wg-access-server/pkg/authnz/authutil"
"github.com/sirupsen/logrus"
"golang.org/x/oauth2"
"gopkg.in/Knetic/govaluate.v2"
"gopkg.in/yaml.v2"
)

type ruleExpression struct {
*govaluate.EvaluableExpression
}

// MarshalYAML will encode a RuleExpression/govalidate into yaml string
func (r ruleExpression) MarshalYAML() (interface{}, error) {
return yaml.Marshal(r.String())
}

// UnmarshalYAML will decode a RuleExpression/govalidate into yaml string
func (r *ruleExpression) UnmarshalYAML(unmarshal func(interface{}) error) error {
var ruleStr string
if err := unmarshal(&ruleStr); err != nil {
return err
}
parsedRule, err := govaluate.NewEvaluableExpression(ruleStr)
if err != nil {
return errors.Wrap(err, "Unable to process oidc rule")
}
ruleExpression := &ruleExpression{parsedRule}
*r = *ruleExpression
return nil
}

type OIDCConfig struct {
Name string `yaml:"name"`
Issuer string `yaml:"issuer"`
ClientID string `yaml:"clientID"`
ClientSecret string `yaml:"clientSecret"`
Scopes []string `yaml:"scopes"`
RedirectURL string `yaml:"redirectURL"`
EmailDomains []string `yaml:"emailDomains"`
Name string `yaml:"name"`
Issuer string `yaml:"issuer"`
ClientID string `yaml:"clientID"`
ClientSecret string `yaml:"clientSecret"`
Scopes []string `yaml:"scopes"`
RedirectURL string `yaml:"redirectURL"`
EmailDomains []string `yaml:"emailDomains"`
UserClaimsRules map[string]ruleExpression `yaml:"userClaimsRules"`
}

func (c *OIDCConfig) Provider() *authruntime.Provider {
Expand Down Expand Up @@ -102,17 +130,31 @@ func (c *OIDCConfig) callbackHandler(runtime *authruntime.ProviderRuntime, oauth
return
}

var claims struct {
Name string `json:"name"`
oidcProfileData := make(map[string]interface{})
info.Claims(&oidcProfileData)

claims := &authsession.Claims{}
for claimName, rule := range c.UserClaimsRules {
result, err := rule.Evaluate(oidcProfileData)

if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if val, ok := result.(bool); ok {
claims.Add(claimName, strconv.FormatBool(val))
} else if val, ok := result.(string); ok {
claims.Add(claimName, val)
}
}
info.Claims(&claims)

runtime.SetSession(w, r, &authsession.AuthSession{
Identity: &authsession.Identity{
Provider: c.Name,
Subject: info.Subject,
Email: info.Email,
Name: claims.Name,
Name: oidcProfileData["name"].(string),
Claims: *claims,
},
})

Expand Down

0 comments on commit f1454e0

Please sign in to comment.