1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2025-10-08 22:51:59 +02:00
Files
oauth2-proxy/providers/cidaas.go
Kevin Kreitner 4c86a4d574 feat: add Cidaas provider (#2273)
* Add sensible logging flag to default setup for logger

* Fix default value flag for sensitive logging

* Remove sensitive logging changes

* Add Cidaas provider

* Update CHANGELOG.md

* Add required groups scope to defaults

* Fix tests

* Remove if block with protected resource

* Fix linting

* Adjust provider sorting, fixes

* Directly handle error return

Co-authored-by: Jan Larwig <jan@larwig.com>

* Use less deep nesting

Co-authored-by: Jan Larwig <jan@larwig.com>

* Directly handle returned error

Co-authored-by: Jan Larwig <jan@larwig.com>

* Pass provider options to Cidaas provider

Co-authored-by: Jan Larwig <jan@larwig.com>

* Add import for provider options

* Fix tests

* Fix linting

* Add Cidaas doc page

* Add Cidaas provider doc page to overview

* Fix link in docs

* Fix link in docs

* Add link to Cidaas

* fix provider order in docs and changelog position

Signed-off-by: Jan Larwig <jan@larwig.com>

---------

Signed-off-by: Jan Larwig <jan@larwig.com>
Co-authored-by: Teko012 <112829523+Teko012@users.noreply.github.com>
Co-authored-by: Jan Larwig <jan@larwig.com>
Co-authored-by: Kevin Kreitner <kevinkreitner@gmail.com>
2025-08-12 17:41:45 +02:00

145 lines
3.8 KiB
Go

package providers
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/bitly/go-simplejson"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
)
type GroupsClaimList []GroupClaimEntry
type GroupClaimEntry struct {
GroupID string `json:"groupId"`
Roles []string `json:"roles"`
}
// CIDAASProvider represents an CIDAAS based Identity Provider
type CIDAASProvider struct {
*OIDCProvider
}
var _ Provider = (*CIDAASProvider)(nil)
const (
CidaasProviderName = "CIDAAS"
CidaasGroupName = "cidaas"
CidaasDefaultScope = "openid email profile roles groups"
)
// NewCIDAASProvider initiates a new CIDAASProvider
func NewCIDAASProvider(p *ProviderData, opts options.Provider) *CIDAASProvider {
p.setProviderDefaults(providerDefaults{
name: CidaasProviderName,
scope: CidaasDefaultScope,
})
return &CIDAASProvider{
OIDCProvider: NewOIDCProvider(p, opts.OIDCConfig),
}
}
// RefreshSession uses the RefreshToken to fetch new Access and ID Tokens
func (p *CIDAASProvider) RefreshSession(ctx context.Context, s *sessions.SessionState) (bool, error) {
if s == nil || s.RefreshToken == "" {
return false, nil
}
if err := p.redeemRefreshToken(ctx, s); err != nil {
return false, fmt.Errorf("unable to redeem refresh token: %w", err)
}
if err := p.EnrichSession(ctx, s); err != nil {
return false, fmt.Errorf("unable to enrich session data after refresh: %w %v", err, s)
}
return true, nil
}
// EnrichSession data to add email an groups
func (p *CIDAASProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error {
if p.ProfileURL.String() == "" && s.Email == "" {
return errors.New("id_token did not contain an email and profileURL is not defined")
} else if p.ProfileURL.String() == "" {
return nil
}
// Try to get missing emails or groups from a profileURL
if err := p.enrichFromUserinfoEndpoint(ctx, s); err != nil {
logger.Errorf("Warning: Profile URL request failed: %s", err)
}
// If a mandatory email wasn't set, error at this point.
if s.Email == "" {
return errors.New("neither the id_token nor the profileURL set an email")
}
return nil
}
// enrichFromUserinfoEndpoint enriches a session's Email & Groups via the JSON response of
// an OIDC profile URL
func (p *CIDAASProvider) enrichFromUserinfoEndpoint(ctx context.Context, s *sessions.SessionState) error {
// profile url is userinfo url in case of Cidaas
respJSON, err := requests.New(p.ProfileURL.String()).
WithContext(ctx).
WithHeaders(makeOIDCHeader(s.AccessToken)).
Do().
UnmarshalSimpleJSON()
if err != nil {
return err
}
email, err := respJSON.Get(p.EmailClaim).String()
if err == nil && s.Email == "" {
s.Email = email
}
groups, err := p.extractGroups(respJSON)
if err != nil {
return fmt.Errorf("extracting groups failed: %w", err)
}
s.Groups = groups
return nil
}
func (p *CIDAASProvider) extractGroups(respJSON *simplejson.Json) ([]string, error) {
rawGroupsClaim, err := respJSON.Get(p.GroupsClaim).MarshalJSON()
if err != nil {
return nil, err
}
var groupsClaimList GroupsClaimList
err = json.Unmarshal(rawGroupsClaim, &groupsClaimList)
if err != nil {
return nil, err
}
var groups []string
for _, group := range groupsClaimList {
for _, role := range group.Roles {
groups = append(groups, fmt.Sprintf("%s:%s", group.GroupID, role))
}
}
// Cidaas specific roles
if rolesVal, rolesClaimExists := respJSON.CheckGet("roles"); rolesClaimExists {
cidaasRoles, err := rolesVal.StringArray()
if err != nil {
return nil, fmt.Errorf("unmarshal roles failed: %w", err)
}
for _, role := range cidaasRoles {
groups = append(groups, fmt.Sprintf("%s:%s", CidaasGroupName, role))
}
}
return groups, nil
}