145 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			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
 | |
| }
 |