git.iko.soy/typeable/oauth2-proxy
on master help sign in
Improve token pattern matching

Unit tests for token discovery

commit187960e9d884b38644aa8e015b9cec9c548c9a2e authorBrian Van Klaveren <bvan@slac.stanford.edu> dateWed 24 Apr 2019, 08:25 (8 years ago) parent8413c30
2 files changed+69−6
oauthproxy.go+6−6 oauthproxy_test.go+63
oauthproxy.go+6−6
@@ -712,7 +712,7 @@ func (p *OAuthProxy) getAuthenticatedSession(rw http.ResponseWriter, req *http.R
712712 if p.skipJwtBearerTokens && req.Header.Get("Authorization") != "" {
713713 session, err = p.GetJwtSession(req)
714714 if err != nil {
715− logger.Printf("Error validating JWT token from Authorization header: %s", err)
715+ logger.Printf("Error retrieving session from token in Authorization header: %s", err)
716716 }
717717 if session != nil {
718718 saveSession = false
@@ -938,9 +938,9 @@ func (p *OAuthProxy) findBearerToken(req *http.Request) (string, error) {
938938 if len(s) != 2 {
939939 return "", fmt.Errorf("invalid authorization header %s", auth)
940940 }
941−
941+ jwtRegex := regexp.MustCompile(`^eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]+$`)
942942 var rawBearerToken string
943− if s[0] == "Bearer" {
943+ if s[0] == "Bearer" && jwtRegex.MatchString(s[1]) {
944944 rawBearerToken = s[1]
945945 } else if s[0] == "Basic" {
946946 // Check if we have a Bearer token masquerading in Basic
@@ -955,7 +955,6 @@ func (p *OAuthProxy) findBearerToken(req *http.Request) (string, error) {
955955 user, password := pair[0], pair[1]
956956
957957 // check user, user+password, or just password for a token
958− jwtRegex := regexp.MustCompile(`^eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]+$`)
959958 if jwtRegex.MatchString(user) {
960959 // Support blank passwords or magic `x-oauth-basic` passwords - nothing else
961960 if password == "" || password == "x-oauth-basic" {
@@ -965,8 +964,9 @@ func (p *OAuthProxy) findBearerToken(req *http.Request) (string, error) {
965964 // support passwords and ignore user
966965 rawBearerToken = password
967966 }
968− } else {
969− return "", fmt.Errorf("invalid authorization header %s", auth)
967+ }
968+ if rawBearerToken == "" {
969+ return "", fmt.Errorf("no valid bearer token found in authorization header")
970970 }
971971
972972 return rawBearerToken, nil
oauthproxy_test.go+63
@@ -3,6 +3,7 @@ package main
33import (
44 "crypto"
55 "encoding/base64"
6+ "fmt"
67 "io"
78 "io/ioutil"
89 "net"
@@ -1132,3 +1133,65 @@ func TestClearSingleCookie(t *testing.T) {
11321133
11331134 assert.Equal(t, 1, len(header["Set-Cookie"]), "should have 1 set-cookie header entries")
11341135}
1136+
1137+func TestFindJwtBearerToken(t *testing.T) {
1138+ p := OAuthProxy{CookieName: "oauth2", CookieDomain: "abc"}
1139+ getReq := &http.Request{URL: &url.URL{Scheme: "http", Host: "example.com"}}
1140+
1141+ validToken := "eyJfoobar.eyJfoobar.12345asdf"
1142+ var token string
1143+
1144+ // Bearer
1145+ getReq.Header = map[string][]string{
1146+ "Authorization": {fmt.Sprintf("Bearer %s", validToken)},
1147+ }
1148+
1149+ token, _ = p.findBearerToken(getReq)
1150+ assert.Equal(t, validToken, token)
1151+
1152+ // Basic - no password
1153+ getReq.SetBasicAuth(token, "")
1154+ token, _ = p.findBearerToken(getReq)
1155+ assert.Equal(t, validToken, token)
1156+
1157+ // Basic - sentinel password
1158+ getReq.SetBasicAuth(token, "x-oauth-basic")
1159+ token, _ = p.findBearerToken(getReq)
1160+ assert.Equal(t, validToken, token)
1161+
1162+ // Basic - any username, password matching jwt pattern
1163+ getReq.SetBasicAuth("any-username-you-could-wish-for", token)
1164+ token, _ = p.findBearerToken(getReq)
1165+ assert.Equal(t, validToken, token)
1166+
1167+ failures := []string{
1168+ // Too many parts
1169+ "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1170+ // Not enough parts
1171+ "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA",
1172+ // Invalid encrypted key
1173+ "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.//////.dGVzdA.dGVzdA.dGVzdA",
1174+ // Invalid IV
1175+ "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.//////.dGVzdA.dGVzdA",
1176+ // Invalid ciphertext
1177+ "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.//////.dGVzdA",
1178+ // Invalid tag
1179+ "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.//////",
1180+ // Invalid header
1181+ "W10.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1182+ // Invalid header
1183+ "######.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1184+ // Missing alc/enc params
1185+ "e30.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1186+ }
1187+
1188+ for _, failure := range failures {
1189+ getReq.Header = map[string][]string{
1190+ "Authorization": {fmt.Sprintf("Bearer %s", failure)},
1191+ }
1192+ _, err := p.findBearerToken(getReq)
1193+ assert.Error(t, err)
1194+ }
1195+
1196+ fmt.Printf("%s", token)
1197+}