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

Isolating some PICS custom changes #57

Merged
merged 8 commits into from
Dec 9, 2024
Merged
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
15 changes: 8 additions & 7 deletions oauthproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ import (
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/app/pagewriter"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/app/redirect"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/audit"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/authentication/basic"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/cookies"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
proxyhttp "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/http"
picsaudit "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/pics/audit"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"

"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
Expand Down Expand Up @@ -114,7 +114,8 @@ type OAuthProxy struct {
appDirector redirect.AppDirector

encodeState bool
AuditClient *audit.Client

picsAuditClient *picsaudit.Client
}

// NewOAuthProxy creates a new instance of OAuthProxy from the options provided
Expand Down Expand Up @@ -213,7 +214,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
Validator: redirectValidator,
})

auditClient, err := audit.NewAuditClient(&audit.ClientOpts{
picsAuditClient, err := picsaudit.NewAuditClient(&picsaudit.ClientOpts{
URL: opts.AuditURL,
Enabled: opts.EnableAudit,
ProductName: opts.AuditProductName,
Expand Down Expand Up @@ -256,7 +257,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
redirectValidator: redirectValidator,
appDirector: appDirector,
encodeState: opts.EncodeState,
AuditClient: auditClient,
picsAuditClient: picsAuditClient,
}
p.buildServeMux(opts.ProxyPrefix)

Expand Down Expand Up @@ -434,7 +435,7 @@ func buildSessionChain(opts *options.Options, provider providers.Provider, sessi
if oidcProviderSettings.CookieRefreshURL == "" {
oidcProviderSettings.CookieRefreshURL = fmt.Sprintf("%s/session/refresh", oidcProviderSettings.IssuerURL)
}
chain = chain.Append(middleware.NewCookieRefresh(&middleware.CookieRefreshOptions{CookieRefreshURL: oidcProviderSettings.CookieRefreshURL, CookieRefreshName: oidcProviderSettings.CookieRefreshName}))
chain = chain.Append(middleware.PicsNewCookieRefresh(&middleware.CookieRefreshOptions{CookieRefreshURL: oidcProviderSettings.CookieRefreshURL, CookieRefreshName: oidcProviderSettings.CookieRefreshName}))
logger.Printf("Enabling OIDC cookie refresh functionality for the cookie '%s' using the url '%s' because OIDCEnableCookieRefresh is enabled", oidcProviderSettings.CookieRefreshURL, oidcProviderSettings.CookieRefreshName)
}

Expand Down Expand Up @@ -925,7 +926,7 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
if !csrf.CheckOAuthState(nonce) {
errorMsg := "Invalid authentication via OAuth2: CSRF token mismatch, potential attack"
logger.PrintAuthf(session.Email, req, logger.AuthFailure, errorMsg)
p.AuditClient.CreateFailedLoginAuditEntry(session, appRedirect, req.Header.Get("edisp-org-id"), errorMsg)
p.picsAuditClient.CreateFailedLoginAuditEntry(session, appRedirect, req.Header.Get("edisp-org-id"), errorMsg)
p.ErrorPage(rw, req, http.StatusForbidden, "CSRF token mismatch, potential attack", "Login Failed: Unable to find a valid CSRF token. Please try again.")
return
}
Expand Down Expand Up @@ -954,7 +955,7 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
return
}
p.AuditClient.CreateSuccessfulLoginAuditEntry(session, appRedirect, req.Header.Get("edisp-org-id"))
p.picsAuditClient.CreateSuccessfulLoginAuditEntry(session, appRedirect, req.Header.Get("edisp-org-id"))
http.Redirect(rw, req, appRedirect, http.StatusFound)
} else {
logger.PrintAuthf(session.Email, req, logger.AuthFailure, "Invalid authentication via OAuth2: unauthorized")
Expand Down
59 changes: 17 additions & 42 deletions pkg/apis/options/legacy_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ func (l *LegacyHeaders) getRequestHeaders() []Header {
}

if l.PassAuthorization {
requestHeaders = append(requestHeaders, getAuthorizationHeader()...)
requestHeaders = append(requestHeaders, PicsGetAuthorizationHeader()...)
}

for i := range requestHeaders {
Expand All @@ -272,11 +272,11 @@ func (l *LegacyHeaders) getResponseHeaders() []Header {
}

if l.SetAuthorization {
responseHeaders = append(responseHeaders, getAuthorizationHeader()...)
responseHeaders = append(responseHeaders, PicsGetAuthorizationHeader()...)
}

if l.SetIntrospectionValue {
responseHeaders = append(responseHeaders, getXAuthIntrospectionValueHeaders())
responseHeaders = append(responseHeaders, PicsGetXAuthIntrospectionValueHeaders())
}
return responseHeaders
}
Expand Down Expand Up @@ -369,32 +369,20 @@ func getPassAccessTokenHeader() Header {
}
}

func getAuthorizationHeader() []Header {
headers := []Header{
{
Name: "Authorization",
Values: []HeaderValue{
{
ClaimSource: &ClaimSource{
Claim: "id_token",
Prefix: "Bearer ",
},
},
},
},
{
Name: "x-auth-request-id-token",
Values: []HeaderValue{
{
ClaimSource: &ClaimSource{
Claim: "id_token",
},
},
},
},
}
return headers
}
// PICS: changed to PicsGetAuthorizationHeader, this one is not used anywhere
// func getAuthorizationHeader() Header {
// return Header{
// Name: "Authorization",
// Values: []HeaderValue{
// {
// ClaimSource: &ClaimSource{
// Claim: "id_token",
// Prefix: "Bearer ",
// },
// },
// },
// }
// }
l-lafin marked this conversation as resolved.
Show resolved Hide resolved

func getPreferredUsernameHeader() Header {
return Header{
Expand Down Expand Up @@ -469,19 +457,6 @@ func getXAuthRequestAccessTokenHeader() Header {
}
}

func getXAuthIntrospectionValueHeaders() Header {
return Header{
Name: "X-Auth-Introspect-Value",
Values: []HeaderValue{
{
ClaimSource: &ClaimSource{
Claim: "introspect-claims",
},
},
},
}
}

type LegacyServer struct {
MetricsAddress string `flag:"metrics-address" cfg:"metrics_address"`
MetricsSecureAddress string `flag:"metrics-secure-address" cfg:"metrics_secure_address"`
Expand Down
41 changes: 41 additions & 0 deletions pkg/apis/options/pics_legacy_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package options

func PicsGetAuthorizationHeader() []Header {
headers := []Header{
{
Name: "Authorization",
Values: []HeaderValue{
{
ClaimSource: &ClaimSource{
Claim: "id_token",
Prefix: "Bearer ",
},
},
},
},
{
Name: "x-auth-request-id-token",
Values: []HeaderValue{
{
ClaimSource: &ClaimSource{
Claim: "id_token",
},
},
},
},
}
return headers
}

func PicsGetXAuthIntrospectionValueHeaders() Header {
return Header{
Name: "X-Auth-Introspect-Value",
Values: []HeaderValue{
{
ClaimSource: &ClaimSource{
Claim: "introspect-claims",
},
},
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type CookieRefreshOptions struct {
CookieRefreshURL string
}

func NewCookieRefresh(opts *CookieRefreshOptions) alice.Constructor {
func PicsNewCookieRefresh(opts *CookieRefreshOptions) alice.Constructor {
cr := &cookieRefresh{
HTTPClient: &http.Client{},
CookieRefreshName: opts.CookieRefreshName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Client struct {
func NewAuditClient(opts *ClientOpts) (*Client, error) {
if opts.Enabled {
log.Print("Audit entries will be created since OAUTH2_PROXY_ENABLE_AUDIT is true")
err := opts.Validate()
err := opts.validate()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -154,7 +154,7 @@ func (c *Client) send(msg string) error {
return nil
}

func (c *ClientOpts) Validate() error {
func (c *ClientOpts) validate() error {
err := errors.New("")
if strings.TrimSpace(c.URL) == "" {
err = errors.New("the OAUTH2_PROXY_AUDIT_URL must be set")
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ type ExtensionContent struct {
URL string `json:"url,omitempty"`
ValueString string `json:"valueString,omitempty"`
}

type Extension struct {
URL string `json:"url,omitempty"`
Extension []*ExtensionContent `json:"extension,omitempty"`
Expand Down
File renamed without changes.
File renamed without changes.
41 changes: 2 additions & 39 deletions providers/oidc.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package providers

import (
"bytes"
"context"
b64 "encoding/base64"
"errors"
"fmt"
"net/http"
"net/url"
"time"

"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"
"golang.org/x/oauth2"
)

Expand Down Expand Up @@ -98,7 +94,8 @@ func (p *OIDCProvider) Redeem(ctx context.Context, redirectURL, code, codeVerifi
// EnrichSession is called after Redeem to allow providers to enrich session fields
// such as User, Email, Groups with provider specific API calls.
func (p *OIDCProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error {
err := p.enrichFromIntrospectURL(ctx, s)

err := p.PicsEnrichFromIntrospectURL(ctx, s)
l-lafin marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
logger.Errorf("Warning: Introspect URL request failed: %v", err)
}
Expand Down Expand Up @@ -130,40 +127,6 @@ func (p *OIDCProvider) ValidateSession(ctx context.Context, s *sessions.SessionS
return true
}

// enrichFromIntrospectURL enriches a session's claims and permissions via the JSON response of
// an OIDC Introspection URL
func (p *OIDCProvider) enrichFromIntrospectURL(ctx context.Context, s *sessions.SessionState) error {
clientSecret, err := p.GetClientSecret()
if err != nil {
return err
}
params := url.Values{}
params.Add("token", s.AccessToken)
basicAuth := b64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", p.ClientID, clientSecret)))
if p.IntrospectURL == nil {
p.IntrospectURL = &url.URL{
Scheme: p.RedeemURL.Scheme,
Host: p.RedeemURL.Host,
Path: "/authorize/oauth2/v4/introspect",
}
}
logger.Printf("Requesting introspect from '%s'", p.IntrospectURL)

result := requests.New(p.IntrospectURL.String()).
WithContext(ctx).
WithMethod("POST").
WithBody(bytes.NewBufferString(params.Encode())).
SetHeader("Authorization", fmt.Sprintf("Basic %s", basicAuth)).
SetHeader("Content-Type", "application/x-www-form-urlencoded").
Do()

if result.StatusCode() != http.StatusOK {
return fmt.Errorf("error while requesting introspect claims, status code - %d", result.StatusCode())
}
s.IntrospectClaims = b64.StdEncoding.EncodeToString(result.Body())
return nil
}

// RefreshSession uses the RefreshToken to fetch new Access and ID Tokens
func (p *OIDCProvider) RefreshSession(ctx context.Context, s *sessions.SessionState) (bool, error) {
if s == nil || s.RefreshToken == "" {
Expand Down
48 changes: 48 additions & 0 deletions providers/pics_oidc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package providers

import (
"bytes"
"context"
b64 "encoding/base64"
"fmt"
"net/http"
"net/url"

"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"
)

// enrichFromIntrospectURL enriches a session's claims and permissions via the JSON response of
// an OIDC Introspection URL
func (p *OIDCProvider) PicsEnrichFromIntrospectURL(ctx context.Context, s *sessions.SessionState) error {
clientSecret, err := p.GetClientSecret()
if err != nil {
return err
}
params := url.Values{}
params.Add("token", s.AccessToken)
basicAuth := b64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", p.ClientID, clientSecret)))
if p.IntrospectURL == nil {
p.IntrospectURL = &url.URL{
Scheme: p.RedeemURL.Scheme,
Host: p.RedeemURL.Host,
Path: "/authorize/oauth2/v4/introspect",
}
}
logger.Printf("Requesting introspect from '%s'", p.IntrospectURL)

result := requests.New(p.IntrospectURL.String()).
WithContext(ctx).
WithMethod("POST").
WithBody(bytes.NewBufferString(params.Encode())).
SetHeader("Authorization", fmt.Sprintf("Basic %s", basicAuth)).
SetHeader("Content-Type", "application/x-www-form-urlencoded").
Do()

if result.StatusCode() != http.StatusOK {
return fmt.Errorf("error while requesting introspect claims, status code - %d", result.StatusCode())
}
s.IntrospectClaims = b64.StdEncoding.EncodeToString(result.Body())
return nil
}
Loading