Skip to content

Commit

Permalink
Isolating some PICS custom changes (#57)
Browse files Browse the repository at this point in the history
## Description

Isolating PICS custom changes

## Motivation and Context

It's hard to understand what are our custom changes and what is from
OAuth2-Proxy main repo

## How Has This Been Tested?

Created a local container image of the oauth-proxy from this PR and
integrated it with Reporting locally.
- run in the root of this repo
  - docker buildx build -t oauth-local .
- Updated FROM statement in pics/src/services/Oauth2Proxy/Dockerfile to 
  - FROM oauth-local

The following flows were checked:
- Login
- Audit logs
- Logout 


## Checklist:

- [x] Isolating some dunction in separated files
- [x] Creating a folder for Pics packages
  • Loading branch information
andersonvcv authored Dec 9, 2024
2 parents 2a34c87 + 519a415 commit fb0723e
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 91 deletions.
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 ",
// },
// },
// },
// }
// }

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
4 changes: 2 additions & 2 deletions pkg/audit/audit_client.go → pkg/pics/audit/audit_client.go
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.
1 change: 1 addition & 0 deletions pkg/audit/audit_event.go → pkg/pics/audit/audit_event.go
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)
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
}

0 comments on commit fb0723e

Please sign in to comment.