@@ -8,10 +8,14 @@ import (
88 "encoding/json"
99 "errors"
1010 "fmt"
11+ "net/url"
1112 "strings"
1213 "testing"
1314 "time"
1415
16+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
17+ "github.com/stretchr/testify/assert"
18+
1519 "github.com/coreos/go-oidc/v3/oidc"
1620 "github.com/golang-jwt/jwt"
1721 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
@@ -498,3 +502,113 @@ func TestProviderData_checkNonce(t *testing.T) {
498502 })
499503 }
500504}
505+
506+func TestProviderData_loginURLParameters(t *testing.T) {
507+
508+ testCases := []struct {
509+ name string
510+ overrides url.Values
511+ has url.Values
512+ notHas []string
513+ }{
514+ {
515+ name: "no overrides",
516+ overrides: url.Values{},
517+ has: url.Values{
518+ "fixed": {"fixed-value"},
519+ "enum_with_default": {"default-value"},
520+ "free_with_default": {"default-value"},
521+ },
522+ notHas: []string{"enum_no_default", "free_no_default"},
523+ },
524+ {
525+ name: "attempt to override fixed value",
526+ overrides: url.Values{"fixed": {"another-value"}},
527+ has: url.Values{
528+ "fixed": {"fixed-value"},
529+ "enum_with_default": {"default-value"},
530+ "free_with_default": {"default-value"},
531+ },
532+ notHas: []string{"enum_no_default", "free_no_default"},
533+ },
534+ {
535+ name: "set one allowed and one forbidden enum",
536+ overrides: url.Values{
537+ "enum_no_default": {"allowed1", "not-allowed"},
538+ },
539+ has: url.Values{
540+ "fixed": {"fixed-value"},
541+ "enum_with_default": {"default-value"},
542+ "free_with_default": {"default-value"},
543+ "enum_no_default": {"allowed1"},
544+ },
545+ notHas: []string{"free_no_default"},
546+ },
547+ {
548+ name: "replace default value",
549+ overrides: url.Values{"free_with_default": {"something-else"}},
550+ has: url.Values{
551+ "fixed": {"fixed-value"},
552+ "enum_with_default": {"default-value"},
553+ "free_with_default": {"something-else"},
554+ },
555+ notHas: []string{"enum_no_default", "free_no_default"},
556+ },
557+ {
558+ name: "set free text value",
559+ overrides: url.Values{"free_no_default": {"some-value"}},
560+ has: url.Values{
561+ "fixed": {"fixed-value"},
562+ "enum_with_default": {"default-value"},
563+ "free_with_default": {"default-value"},
564+ "free_no_default": {"some-value"},
565+ },
566+ notHas: []string{"enum_no_default"},
567+ },
568+ {
569+ name: "attempt to set unapproved parameter",
570+ overrides: url.Values{"malicious_value": {"evil"}},
571+ has: url.Values{
572+ "fixed": {"fixed-value"},
573+ "enum_with_default": {"default-value"},
574+ "free_with_default": {"default-value"},
575+ },
576+ notHas: []string{"enum_no_default", "free_no_default"},
577+ },
578+ }
579+
580+ // fixed list of two allowed values
581+ allowed1 := "allowed1"
582+ allowed2 := "allowed2"
583+ allowEnum := []options.URLParameterRule{
584+ {Value: &allowed1},
585+ {Value: &allowed2},
586+ }
587+ // regex that will allow anything
588+ anything := "^.*$"
589+ allowAnything := []options.URLParameterRule{
590+ {Pattern: &anything},
591+ }
592+ for _, tc := range testCases {
593+ t.Run(tc.name, func(t *testing.T) {
594+ // set up LoginURLParameters for testing
595+ data := ProviderData{}
596+ data.compileLoginParams([]options.LoginURLParameter{
597+ {Name: "fixed", Default: []string{"fixed-value"}},
598+ {Name: "enum_with_default", Default: []string{"default-value"}, Allow: allowEnum},
599+ {Name: "enum_no_default", Allow: allowEnum},
600+ {Name: "free_with_default", Default: []string{"default-value"}, Allow: allowAnything},
601+ {Name: "free_no_default", Allow: allowAnything},
602+ })
603+
604+ redirectParams := data.LoginURLParams(tc.overrides)
605+ for _, k := range tc.notHas {
606+ assert.NotContains(t, redirectParams, k)
607+ }
608+ for k, vs := range tc.has {
609+ actualVals := redirectParams[k]
610+ assert.ElementsMatch(t, vs, actualVals)
611+ }
612+ })
613+ }
614+}