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

feat(security): added the ability to use a different claim field to match against the allow-subjects list. #763

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1519,6 +1519,7 @@ security:
| `security.oidc.client-secret` | Client secret | Required `""` |
| `security.oidc.scopes` | Scopes to request. The only scope you need is `openid`. | Required `[]` |
| `security.oidc.allowed-subjects` | List of subjects to allow. If empty, all subjects are allowed. | `[]` |
| `security.oidc.claim-to-check` | Name of the field to use to match against `allowed-subjects` | `""` |

```yaml
security:
Expand All @@ -1530,6 +1531,8 @@ security:
scopes: ["openid"]
# You may optionally specify a list of allowed subjects. If this is not specified, all subjects will be allowed.
#allowed-subjects: ["[email protected]"]
# You can specify a different claim field to match against allowed-subjects. If not specified "subject" is used.
#claim-to-check: "preferred_username"
```

Confused? Read [Securing Gatus with OIDC using Auth0](https://twin.sh/articles/56/securing-gatus-with-oidc-using-auth0).
Expand Down
34 changes: 28 additions & 6 deletions security/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type OIDCConfig struct {
ClientSecret string `yaml:"client-secret"`
Scopes []string `yaml:"scopes"` // e.g. ["openid"]
AllowedSubjects []string `yaml:"allowed-subjects"` // e.g. ["[email protected]"]. If empty, all subjects are allowed
ClaimToCheck string `yaml:"claim-to-check"` // e.g. email. If empty, subject is used

oauth2Config oauth2.Config
verifier *oidc.IDTokenVerifier
Expand Down Expand Up @@ -117,14 +118,35 @@ func (c *OIDCConfig) callbackHandler(w http.ResponseWriter, r *http.Request) { /
http.Redirect(w, r, "/", http.StatusFound)
return
}
for _, subject := range c.AllowedSubjects {
if strings.ToLower(subject) == strings.ToLower(idToken.Subject) {
c.setSessionCookie(w, idToken)
http.Redirect(w, r, "/", http.StatusFound)
return

var claimToCheck = c.ClaimToCheck
if len(claimToCheck) > 0 {
var claimsMap map[string]interface{}
if err := idToken.Claims(&claimsMap); err == nil {
claimValue, ok := claimsMap[claimToCheck]
if ok {
for _, subject := range c.AllowedSubjects {
if claimValue == subject {
c.setSessionCookie(w, idToken)
http.Redirect(w, r, "/", http.StatusFound)
return
}
}
log.Printf("[security.callbackHandler] Value %s of claim %s doesn't match any element of the list of allowed subjects", claimValue, claimToCheck)
} else {
log.Printf("[security.callbackHandler] Claim doesn't contain the field %s", claimToCheck)
}
}
} else {
for _, subject := range c.AllowedSubjects {
if strings.ToLower(subject) == strings.ToLower(idToken.Subject) {
c.setSessionCookie(w, idToken)
http.Redirect(w, r, "/", http.StatusFound)
return
}
}
log.Printf("[security.callbackHandler] Subject %s is not in the list of allowed subjects", idToken.Subject)
}
log.Printf("[security.callbackHandler] Subject %s is not in the list of allowed subjects", idToken.Subject)
http.Redirect(w, r, "/?error=access_denied", http.StatusFound)
}

Expand Down
Loading