From 6dfd65f26e95619274754cc8434abdf9c1dfd8f5 Mon Sep 17 00:00:00 2001 From: Umputun Date: Thu, 22 Aug 2019 19:57:56 -0500 Subject: [PATCH] promote aud to user level In some cases access to the standard claim's aud can be useful for consumer. For example to reject tokens made for different, but allowed aud passed verification just fine. However, the full claim is not avail, just User part of it. The change sets Audience field from std claim aud. In other words the goal is to prevent valid token issued for subsystem A to be used in subsystem B. The package doesn't provide such a rejection but allow user to handle it on application level. --- middleware/auth_test.go | 4 +++- token/jwt.go | 3 +++ token/jwt_test.go | 9 ++++++--- token/user.go | 7 ++++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/middleware/auth_test.go b/middleware/auth_test.go index dfd7041..5cbad65 100644 --- a/middleware/auth_test.go +++ b/middleware/auth_test.go @@ -34,7 +34,9 @@ func TestAuthJWTCookie(t *testing.T) { handler := func(w http.ResponseWriter, r *http.Request) { u, err := token.GetUserInfo(r) assert.NoError(t, err) - assert.Equal(t, token.User{Name: "name1", ID: "id1", Picture: "http://example.com/pic.png", IP: "127.0.0.1", Email: "me@example.com", Attributes: map[string]interface{}{"boola": true, "stra": "stra-val"}}, u) + assert.Equal(t, token.User{Name: "name1", ID: "id1", Picture: "http://example.com/pic.png", + IP: "127.0.0.1", Email: "me@example.com", Audience: "test_sys", + Attributes: map[string]interface{}{"boola": true, "stra": "stra-val"}}, u) w.WriteHeader(201) } mux.Handle("/auth", a.Auth(http.HandlerFunc(handler))) diff --git a/token/jwt.go b/token/jwt.go index b89e307..ab17d92 100644 --- a/token/jwt.go +++ b/token/jwt.go @@ -259,6 +259,9 @@ func (j *Service) Get(r *http.Request) (Claims, string, error) { return Claims{}, "", errors.New("xsrf mismatch") } } + if claims.User != nil { + claims.User.Audience = claims.Audience + } return claims, tokenString, nil } diff --git a/token/jwt_test.go b/token/jwt_test.go index c58c66e..7a4ac59 100644 --- a/token/jwt_test.go +++ b/token/jwt_test.go @@ -264,7 +264,8 @@ func TestJWT_GetFromHeader(t *testing.T) { assert.Equal(t, testJwtValid, token) assert.False(t, j.IsExpired(claims)) assert.Equal(t, &User{Name: "name1", ID: "id1", Picture: "http://example.com/pic.png", IP: "127.0.0.1", - Email: "me@example.com", Attributes: map[string]interface{}{"boola": true, "stra": "stra-val"}}, claims.User) + Email: "me@example.com", Audience: "test_sys", + Attributes: map[string]interface{}{"boola": true, "stra": "stra-val"}}, claims.User) assert.Equal(t, "remark42", claims.Issuer) req = httptest.NewRequest("GET", "/", nil) @@ -295,7 +296,8 @@ func TestJWT_GetFromQuery(t *testing.T) { assert.Equal(t, testJwtValid, token) assert.False(t, j.IsExpired(claims)) assert.Equal(t, &User{Name: "name1", ID: "id1", Picture: "http://example.com/pic.png", IP: "127.0.0.1", - Email: "me@example.com", Attributes: map[string]interface{}{"boola": true, "stra": "stra-val"}}, claims.User) + Email: "me@example.com", Audience: "test_sys", + Attributes: map[string]interface{}{"boola": true, "stra": "stra-val"}}, claims.User) assert.Equal(t, "remark42", claims.Issuer) req = httptest.NewRequest("GET", "/blah?token="+testJwtExpired, nil) @@ -349,7 +351,8 @@ func TestJWT_SetAndGetWithCookies(t *testing.T) { r, _, err := j.Get(req) assert.Nil(t, err) assert.Equal(t, &User{Name: "name1", ID: "id1", Picture: "http://example.com/pic.png", IP: "127.0.0.1", - Email: "me@example.com", Attributes: map[string]interface{}{"boola": true, "stra": "stra-val"}}, r.User) + Email: "me@example.com", Audience: "test_sys", + Attributes: map[string]interface{}{"boola": true, "stra": "stra-val"}}, r.User) assert.Equal(t, "remark42", claims.Issuer) assert.Equal(t, true, claims.SessionOnly) t.Log(resp.Cookies()) diff --git a/token/user.go b/token/user.go index f23f966..c78648e 100644 --- a/token/user.go +++ b/token/user.go @@ -21,9 +21,10 @@ const adminAttr = "admin" // predefined attribute key for bool isAdmin status // User is the basic part of oauth data provided by service type User struct { // set by service - Name string `json:"name"` - ID string `json:"id"` - Picture string `json:"picture"` + Name string `json:"name"` + ID string `json:"id"` + Picture string `json:"picture"` + Audience string `json:"aud,omitempty"` // set by client IP string `json:"ip,omitempty"`