git.iko.soy/typeable/oauth2-proxy
on master help sign in
fix: update code_verifier to use recommended method (#2620)

The [RFC](https://datatracker.ietf.org/doc/html/rfc7636#section-4.1) says that a code verifier just uses unreserved characters, but the recommended method is that it is a base64-urlencoded 32-octet url. Some implementations of PKCE (most notably the one used by salesforce) require that this is a valid base64 encoded string[1], so this patch switches to using the recommended approach to make it more compatible. [1]: https://help.salesforce.com/s/articleView?id=sf.remoteaccess_pkce.htm&type=5

commit4e2013e6ba170ae34f7a61a8fd16f36d0afd1640 authorVish (Ishaya) Abrams <vishvananda@gmail.com> dateWed 6 Nov 2024, 06:16 (2 years ago) parent3ceef0c
4 files changed+14−17
CHANGELOG.md+2−1 oauthproxy.go+1−1 pkg/encryption/utils.go+7−11 pkg/encryption/utils_test.go+4−4
CHANGELOG.md+2−1
@@ -12,7 +12,8 @@
1212- [#2755](https://github.com/oauth2-proxy/oauth2-proxy/pull/2755) feat: add X-Envoy-External-Address as supported header (@bjencks)
1313- [#1985](https://github.com/oauth2-proxy/oauth2-proxy/pull/1985) Add support for systemd socket (@isodude)
1414- [#2300](https://github.com/oauth2-proxy/oauth2-proxy/pull/2300) Add fix for websocket path rewrite (@rekup)
15−- [#2821](https://github.com/oauth2-proxy/oauth2-proxy/pull/2821) feat: add CF-Connecting-IP as supported real ip header
15+- [#2821](https://github.com/oauth2-proxy/oauth2-proxy/pull/2821) feat: add CF-Connecting-IP as supported real ip header (@ondrejsika)
16+- [#2620](https://github.com/oauth2-proxy/oauth2-proxy/pull/2620) fix: update code_verifier to use recommended method (@vishvananda)
1617
1718# V7.7.1
1819
oauthproxy.go+1−1
@@ -802,7 +802,7 @@ func (p *OAuthProxy) doOAuthStart(rw http.ResponseWriter, req *http.Request, ove
802802 )
803803 if p.provider.Data().CodeChallengeMethod != "" {
804804 codeChallengeMethod = p.provider.Data().CodeChallengeMethod
805− codeVerifier, err = encryption.GenerateRandomASCIIString(96)
805+ codeVerifier, err = encryption.GenerateCodeVerifierString(96)
806806 if err != nil {
807807 logger.Errorf("Unable to build random ASCII string for code verifier: %v", err)
808808 p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
pkg/encryption/utils.go+7−11
@@ -7,7 +7,7 @@ import (
77 "encoding/base64"
88 "fmt"
99 "hash"
10− "math/big"
10+ "io"
1111 "net/http"
1212 "strconv"
1313 "strings"
@@ -83,17 +83,13 @@ func SignedValue(seed string, key string, value []byte, now time.Time) (string,
8383 return cookieVal, nil
8484}
8585
86−func GenerateRandomASCIIString(length int) (string, error) {
87− b := make([]byte, length)
88− charsetLen := new(big.Int).SetInt64(int64(len(asciiCharset)))
89− for i := range b {
90− character, err := rand.Int(rand.Reader, charsetLen)
91− if err != nil {
92− return "", err
93− }
94− b[i] = asciiCharset[character.Int64()]
86+// GenerateCodeVerifierString returns a base64 encoded string of n random bytes
87+func GenerateCodeVerifierString(n int) (string, error) {
88+ data := make([]byte, n)
89+ if _, err := io.ReadFull(rand.Reader, data); err != nil {
90+ return "", err
9591 }
96− return string(b), nil
92+ return base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(data), nil
9793}
9894
9995func GenerateCodeChallenge(method, codeVerifier string) (string, error) {
pkg/encryption/utils_test.go+4−4
@@ -130,12 +130,12 @@ func TestValidate(t *testing.T) {
130130 assert.Equal(t, validValue, expectedValue)
131131}
132132
133−func TestGenerateRandomASCIIString(t *testing.T) {
134− randomString, err := GenerateRandomASCIIString(96)
133+func TestGenerateCodeVerifierString(t *testing.T) {
134+ randomString, err := GenerateCodeVerifierString(96)
135135 assert.NoError(t, err)
136136
137− // Only 8-bit characters
138− assert.Equal(t, 96, len([]byte(randomString)))
137+ // Should be 128 characters long
138+ assert.Equal(t, 128, len([]byte(randomString)))
139139
140140 // All non-ascii characters removed should still be the original string
141141 removedChars := strings.Map(func(r rune) rune {