Skip to content

Commit 8dff375

Browse files
committed
Merge branch 'pr/martindb/298'
2 parents 08abf9a + 8c46f0f commit 8dff375

8 files changed

Lines changed: 126 additions & 12 deletions

File tree

.defaults.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ vouch:
4242
redirect: X-Vouch-Requested-URI
4343
# claims:
4444
claimheader: X-Vouch-IdP-Claims-
45-
accesstoken: X-Vouch-IdP-AccessToken
46-
idtoken: X-Vouch-IdP-IdToken
45+
# https://github.com/vouch/vouch-proxy/issues/287
46+
# accesstoken: X-Vouch-IdP-AccessToken
47+
# idtoken: X-Vouch-IdP-IdToken
4748
# test_url:
4849
# post_logout_redirect_uris:
4950
# oauth:
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
vouch:
2+
testing: true
3+
logLevel: debug
4+
listen: 0.0.0.0
5+
port: 9090
6+
7+
allowAllUsers: true
8+
9+
headers:
10+
claims:
11+
- groups
12+
- boolean_claim
13+
- family_name
14+
- http://www.example.com/favorite_color
15+
accesstoken: X-Vouch-IdP-AccessToken
16+
idtoken: X-Vouch-IdP-IdToken
17+
18+
cookie:
19+
name: vouchTestingCookie
20+
21+
session:
22+
name: VouchTestingSession
23+
24+
jwt:
25+
secret: testing
26+
27+
oauth:
28+
provider: indieauth
29+
client_id: http://vouch.github.io
30+
auth_url: https://indielogin.com/auth
31+
callback_url: http://vouch.github.io:9090/auth

handlers/handlers_test.go

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ OR CONDITIONS OF ANY KIND, either express or implied.
1111
package handlers
1212

1313
import (
14+
"encoding/json"
1415
"os"
1516
"path/filepath"
1617
"testing"
@@ -30,17 +31,12 @@ var (
3031
token = &oauth2.Token{AccessToken: "123"}
3132
)
3233

34+
// setUp load config file and then call Configure() for dependent packages
3335
func setUp(configFile string) {
3436
os.Setenv("VOUCH_CONFIG", filepath.Join(os.Getenv("VOUCH_ROOT"), configFile))
3537
cfg.InitForTestPurposes()
3638

37-
// cfg.Cfg.AllowAllUsers = false
38-
// cfg.Cfg.WhiteList = make([]string, 0)
39-
// cfg.Cfg.TeamWhiteList = make([]string, 0)
40-
// cfg.Cfg.Domains = []string{"domain1"}
41-
4239
Configure()
43-
4440
domains.Configure()
4541
jwtmanager.Configure()
4642
cookie.Configure()
@@ -115,3 +111,73 @@ func TestVerifyUserNegative(t *testing.T) {
115111
assert.False(t, ok)
116112
assert.NotNil(t, err)
117113
}
114+
115+
// copied from jwtmanager_test.go
116+
// it should live there but circular imports are resolved if it lives here
117+
var (
118+
u1 = structs.User{
119+
Username: "test@testing.com",
120+
Name: "Test Name",
121+
}
122+
t1 = structs.PTokens{
123+
PAccessToken: "eyJhbGciOiJSUzI1NiIsImtpZCI6IjRvaXU4In0.eyJzdWIiOiJuZnlmZSIsImF1ZCI6ImltX29pY19jbGllbnQiLCJqdGkiOiJUOU4xUklkRkVzUE45enU3ZWw2eng2IiwiaXNzIjoiaHR0cHM6XC9cL3Nzby5tZXljbG91ZC5uZXQ6OTAzMSIsImlhdCI6MTM5MzczNzA3MSwiZXhwIjoxMzkzNzM3MzcxLCJub25jZSI6ImNiYTU2NjY2LTRiMTItNDU2YS04NDA3LTNkMzAyM2ZhMTAwMiIsImF0X2hhc2giOiJrdHFvZVBhc2praVY5b2Z0X3o5NnJBIn0.g1Jc9DohWFfFG3ppWfvW16ib6YBaONC5VMs8J61i5j5QLieY-mBEeVi1D3vr5IFWCfivY4hZcHtoJHgZk1qCumkAMDymsLGX-IGA7yFU8LOjUdR4IlCPlZxZ_vhqr_0gQ9pCFKDkiOv1LVv5x3YgAdhHhpZhxK6rWxojg2RddzvZ9Xi5u2V1UZ0jukwyG2d4PRzDn7WoRNDGwYOEt4qY7lv_NO2TY2eAklP-xYBWu0b9FBElapnstqbZgAXdndNs-Wqp4gyQG5D0owLzxPErR9MnpQfgNcai-PlWI_UrvoopKNbX0ai2zfkuQ-qh6Xn8zgkiaYDHzq4gzwRfwazaqA",
124+
PIdToken: "eyJhbGciOiJSUzI1NiIsImtpZCI6IjRvaXU4In0.eyJzdWIiOiJuZnlmZSIsImF1ZCI6ImltX29pY19jbGllbnQiLCJqdGkiOiJUOU4xUklkRkVzUE45enU3ZWw2eng2IiwiaXNzIjoiaHR0cHM6XC9cL3Nzby5tZXljbG91ZC5uZXQ6OTAzMSIsImlhdCI6MTM5MzczNzA3MSwiZXhwIjoxMzkzNzM3MzcxLCJub25jZSI6ImNiYTU2NjY2LTRiMTItNDU2YS04NDA3LTNkMzAyM2ZhMTAwMiIsImF0X2hhc2giOiJrdHFvZVBhc2praVY5b2Z0X3o5NnJBIn0.g1Jc9DohWFfFG3ppWfvW16ib6YBaONC5VMs8J61i5j5QLieY-mBEeVi1D3vr5IFWCfivY4hZcHtoJHgZk1qCumkAMDymsLGX-IGA7yFU8LOjUdR4IlCPlZxZ_vhqr_0gQ9pCFKDkiOv1LVv5x3YgAdhHhpZhxK6rWxojg2RddzvZ9Xi5u2V1UZ0jukwyG2d4PRzDn7WoRNDGwYOEt4qY7lv_NO2TY2eAklP-xYBWu0b9FBElapnstqbZgAXdndNs-Wqp4gyQG5D0owLzxPErR9MnpQfgNcai-PlWI_UrvoopKNbX0ai2zfkuQ-qh6Xn8zgkiaYDHzq4gzwRfwazaqA",
125+
}
126+
127+
lc jwtmanager.VouchClaims
128+
129+
claimjson = `{
130+
"sub": "f:a95afe53-60ba-4ac6-af15-fab870e72f3d:mrtester",
131+
"groups": ["Website Users", "Test Group"],
132+
"given_name": "Mister",
133+
"family_name": "Tester",
134+
"email": "mrtester@test.int"
135+
}`
136+
customClaims = structs.CustomClaims{}
137+
)
138+
139+
// copied from jwtmanager_test.go
140+
func init() {
141+
// log.SetLevel(log.DebugLevel)
142+
143+
lc = jwtmanager.VouchClaims{
144+
u1.Username,
145+
jwtmanager.Sites,
146+
customClaims.Claims,
147+
t1.PAccessToken,
148+
t1.PIdToken,
149+
jwtmanager.StandardClaims,
150+
}
151+
json.Unmarshal([]byte(claimjson), &customClaims.Claims)
152+
}
153+
154+
func TestParsedIdPTokens(t *testing.T) {
155+
tests := []struct {
156+
name string
157+
configFile string
158+
wantIDPTokens bool
159+
}{
160+
{"no IdP tokens", "/config/testing/handler_claims.yml", false},
161+
{"wants IdP tokens", "/config/testing/jwtmanager_has_idp_token_claims.yml", true},
162+
}
163+
164+
for _, tt := range tests {
165+
t.Run(tt.name, func(t *testing.T) {
166+
setUp(tt.configFile)
167+
uts := jwtmanager.CreateUserTokenString(u1, customClaims, t1)
168+
utsParsed, _ := jwtmanager.ParseTokenString(uts)
169+
utsPtokens, _ := jwtmanager.PTokenClaims(utsParsed)
170+
171+
if tt.wantIDPTokens {
172+
if t1.PIdToken != utsPtokens.PIdToken || t1.PAccessToken != utsPtokens.PAccessToken {
173+
t.Errorf("got PIdToken = %s, PAccessToken = %s, \nwant %s , %s", utsPtokens.PIdToken, utsPtokens.PAccessToken, t1.PIdToken, t1.PAccessToken)
174+
}
175+
} else {
176+
if utsPtokens.PIdToken != "" || utsPtokens.PAccessToken != "" {
177+
t.Errorf("PIdToken and PAccessToken = should be '' got '%s', '%s'", utsPtokens.PIdToken, utsPtokens.PAccessToken)
178+
}
179+
}
180+
})
181+
}
182+
183+
}

pkg/cfg/cfg.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,15 @@ const (
130130
minBase64Length = 44
131131
base64Bytes = 32
132132

133-
// ErrCtx set or check the http request context to see if it has errored
133+
// ErrCtxKey set or check the http request context to see if it has errored
134134
// see `responses.Error401` and `jwtmanager.JWTCacheHandler` for example
135-
ErrCtx = "isErr"
135+
ErrCtxKey ctxKey = 0
136136
)
137137

138+
// use a typed ctxKey to avoid context key collission
139+
// https://blog.golang.org/context#TOC_3.2.
140+
type ctxKey int
141+
138142
// Configure called at the very top of main()
139143
// the order of config follows the Viper conventions...
140144
//

pkg/jwtmanager/jwtcache.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ func JWTCacheHandler(next http.Handler) http.Handler {
7777
next.ServeHTTP(w, r)
7878

7979
if jwt != "" &&
80-
r.Context().Err() == nil { // r.Context().Done() is still open
80+
r.Context().Err() == nil {
81+
// see responses.addErrandCancelRequest()
82+
// r.Context().Done() is still open
8183
// cache the response headers for this jwt
8284
// log.Debug("setting cache for %+v", w.Header().Clone())
8385
Cache.SetDefault(jwt, w.Header().Clone())

pkg/jwtmanager/jwtmanager.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ func CreateUserTokenString(u structs.User, customClaims structs.CustomClaims, pt
8686
StandardClaims,
8787
}
8888

89+
// https://github.com/vouch/vouch-proxy/issues/287
90+
if cfg.Cfg.Headers.AccessToken == "" {
91+
claims.PAccessToken = ""
92+
}
93+
94+
if cfg.Cfg.Headers.IDToken == "" {
95+
claims.PIdToken = ""
96+
}
97+
8998
claims.StandardClaims.ExpiresAt = time.Now().Add(time.Minute * time.Duration(cfg.Cfg.JWT.MaxAge)).Unix()
9099

91100
// https://godoc.org/github.com/dgrijalva/jwt-go#NewWithClaims

pkg/responses/responses.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func Error403(w http.ResponseWriter, r *http.Request, e error) {
117117
// cfg.ErrCtx is tested by `jwtmanager.JWTCacheHandler`
118118
func addErrandCancelRequest(r *http.Request) {
119119
ctx, cancel := context.WithCancel(r.Context())
120-
ctx = context.WithValue(ctx, cfg.ErrCtx, true)
120+
ctx = context.WithValue(ctx, cfg.ErrCtxKey, true)
121121
*r = *r.Clone(ctx)
122122
cancel() // we're done
123123
return

pkg/structs/structs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type AzureUser struct {
5151
UPN string `json:"upn"`
5252
}
5353

54+
// PrepareUserData implement PersonalData interface
5455
func (u *AzureUser) PrepareUserData() {
5556
// AzureAD uses the 'upn' (UserPrincipleName) field to store the email address of the user
5657
// See https://docs.microsoft.com/en-us/azure/active-directory/hybrid/plan-connect-userprincipalname

0 commit comments

Comments
 (0)