Permalink
Browse files

Use sub claim in JWT, not id.

  • Loading branch information...
brycekahle committed Aug 25, 2017
1 parent 9a09899 commit 0fce4a1cefb46128a4c3d8fad5130d117d345c9e
Showing with 40 additions and 37 deletions.
  1. +5 −5 api/auth.go
  2. +2 −2 api/download.go
  3. +15 −15 api/order.go
  4. +7 −7 api/order_test.go
  5. +3 −3 api/payments.go
  6. +8 −4 api/utils_test.go
  7. +0 −1 claims/claims.go
View
@@ -61,7 +61,7 @@ func withToken(w http.ResponseWriter, r *http.Request) (context.Context, error)
}
log.WithFields(logrus.Fields{
"claims_id": claims.ID,
"claims_sub": claims.Subject,
"claims_email": claims.Email,
"roles": roles,
"is_admin": isAdmin,
@@ -91,7 +91,7 @@ func adminRequired(w http.ResponseWriter, r *http.Request) (context.Context, err
return nil, unauthorizedError("Admin permissions required")
}
logEntrySetField(r, "admin_id", claims.ID)
logEntrySetField(r, "admin_id", claims.Subject)
return ctx, nil
}
@@ -101,12 +101,12 @@ func ensureUserAccess(w http.ResponseWriter, r *http.Request) (context.Context,
// ensure userID matches authenticated user OR is admin
claims := gcontext.GetClaims(ctx)
if gcontext.IsAdmin(ctx) {
logEntrySetField(r, "admin_id", claims.ID)
logEntrySetField(r, "admin_id", claims.Subject)
return ctx, nil
}
userID := gcontext.GetUserID(ctx)
if claims.ID != userID {
if claims.Subject != userID {
return nil, unauthorizedError("Can't access a different user unless you're an admin")
}
@@ -122,5 +122,5 @@ func hasOrderAccess(ctx context.Context, order *models.Order) bool {
}
claims := gcontext.GetClaims(ctx)
return claims != nil && order.UserID == claims.ID
return claims != nil && order.UserID == claims.Subject
}
View
@@ -68,7 +68,7 @@ func (a *API) DownloadURL(w http.ResponseWriter, r *http.Request) error {
tx := a.db.Begin()
tx.Model(download).Updates(map[string]interface{}{"download_count": gorm.Expr("download_count + 1")})
models.LogEvent(tx, r.RemoteAddr, claims.ID, order.ID, models.EventUpdated, []string{"download"})
models.LogEvent(tx, r.RemoteAddr, claims.Subject, order.ID, models.EventUpdated, []string{"download"})
tx.Commit()
return sendJSON(w, http.StatusOK, download)
@@ -110,7 +110,7 @@ func (a *API) DownloadList(w http.ResponseWriter, r *http.Request) error {
if order != nil {
query = query.Where("orders.id = ?", order.ID)
} else {
query = query.Where("orders.user_id = ?", claims.ID)
query = query.Where("orders.user_id = ?", claims.Subject)
}
offset, limit, err := paginate(w, r, query.Model(&models.Download{}))
View
@@ -94,12 +94,12 @@ func (a *API) ClaimOrders(w http.ResponseWriter, r *http.Request) error {
return badRequestError("Must provide an email in the token to claim orders")
}
if claims.ID == "" {
if claims.Subject == "" {
return badRequestError("Must provide a ID in the token to claim orders")
}
log = log.WithFields(logrus.Fields{
"user_id": claims.ID,
"user_id": claims.Subject,
"user_email": claims.Email,
})
@@ -121,12 +121,12 @@ func (a *API) ClaimOrders(w http.ResponseWriter, r *http.Request) error {
// create the user
user := models.User{
InstanceID: instanceID,
ID: claims.ID,
ID: claims.Subject,
Email: claims.Email,
}
if res := tx.FirstOrCreate(&user); res.Error != nil {
tx.Rollback()
return internalServerError("Failed to create user with ID %s", claims.ID).WithInternalError(res.Error).WithInternalMessage("Failed to create new user: %+v", user)
return internalServerError("Failed to create user with ID %s", claims.Subject).WithInternalError(res.Error).WithInternalMessage("Failed to create new user: %+v", user)
}
for _, o := range orders {
@@ -256,7 +256,7 @@ func (a *API) OrderList(w http.ResponseWriter, r *http.Request) error {
userID := gcontext.GetUserID(ctx)
if userID == "" {
userID = claims.ID
userID = claims.Subject
}
if userID != "all" {
query = query.Where("user_id = ?", userID)
@@ -561,10 +561,10 @@ func (a *API) OrderUpdate(w http.ResponseWriter, r *http.Request) error {
return internalServerError("Error saving order updates").WithInternalError(rsp.Error)
}
models.LogEvent(tx, r.RemoteAddr, claims.ID, existingOrder.ID, models.EventUpdated, changes)
models.LogEvent(tx, r.RemoteAddr, claims.Subject, existingOrder.ID, models.EventUpdated, changes)
if config.Webhooks.Update != "" {
// TODO should this be claims.ID or existingOrder.UserID ?
hook := models.NewHook("update", config.Webhooks.Update, claims.ID, config.Webhooks.Secret, existingOrder)
// TODO should this be claims.Subject or existingOrder.UserID ?
hook := models.NewHook("update", config.Webhooks.Update, claims.Subject, config.Webhooks.Secret, existingOrder)
tx.Save(hook)
}
if rsp := tx.Commit(); rsp.Error != nil {
@@ -586,18 +586,18 @@ func setOrderEmail(tx *gorm.DB, order *models.Order, claims *claims.JWTClaims, l
if claims == nil {
log.Debug("No claims provided, proceeding as an anon request")
} else {
if claims.ID == "" {
return badRequestError("Token had an invalid ID: %s", claims.ID)
if claims.Subject == "" {
return badRequestError("Token had an invalid ID: %s", claims.Subject)
}
log = log.WithField("user_id", claims.ID)
order.UserID = claims.ID
log = log.WithField("user_id", claims.Subject)
order.UserID = claims.Subject
user := new(models.User)
result := tx.First(user, "id = ?", claims.ID)
result := tx.First(user, "id = ?", claims.Subject)
if result.RecordNotFound() {
log.Debugf("Didn't find a user for id %s ~ going to create one", claims.ID)
user.ID = claims.ID
log.Debugf("Didn't find a user for id %s ~ going to create one", claims.Subject)
user.ID = claims.Subject
user.Email = claims.Email
tx.Create(user)
} else if result.Error != nil {
View
@@ -644,28 +644,28 @@ func validateAllOrders(t *testing.T, actual []models.Order, expected *TestData)
func validateNewUserEmail(t *testing.T, order *models.Order, claims *claims.JWTClaims, expectedUserEmail, expectedOrderEmail string) {
db, _, _, _ := db(t)
result := db.First(new(models.User), "id = ?", claims.ID)
require.True(t, result.RecordNotFound(), "Unclean test env -- user exists with ID "+claims.ID)
result := db.First(new(models.User), "id = ?", claims.Subject)
require.True(t, result.RecordNotFound(), "Unclean test env -- user exists with ID "+claims.Subject)
err := setOrderEmail(db, order, claims, testLogger)
require.NoError(t, err)
user := new(models.User)
result = db.First(user, "id = ?", claims.ID)
result = db.First(user, "id = ?", claims.Subject)
require.False(t, result.RecordNotFound())
assert := assert.New(t)
assert.Equal(claims.ID, user.ID)
assert.Equal(claims.ID, order.UserID)
assert.Equal(claims.Subject, user.ID)
assert.Equal(claims.Subject, order.UserID)
assert.Equal(expectedOrderEmail, order.Email)
assert.Equal(expectedUserEmail, user.Email)
db.Unscoped().Delete(user)
//t.Logf("Deleted user %s", claims.ID)
//t.Logf("Deleted user %s", claims.Subject)
}
func validateExistingUserEmail(t *testing.T, db *gorm.DB, order *models.Order, claims *claims.JWTClaims, expectedOrderEmail string) {
require.NoError(t, setOrderEmail(db, order, claims, testLogger))
assert.Equal(t, claims.ID, order.UserID)
assert.Equal(t, claims.Subject, order.UserID)
assert.Equal(t, expectedOrderEmail, order.Email)
}
View
@@ -66,7 +66,7 @@ func (a *API) PaymentListForOrder(w http.ResponseWriter, r *http.Request) error
}
if !hasOrderAccess(ctx, order) {
return unauthorizedError("You don't have access to this order").WithInternalMessage("Attempt to access order as %s, but order.UserID is %s", claims.ID, order.UserID)
return unauthorizedError("You don't have access to this order").WithInternalMessage("Attempt to access order as %s, but order.UserID is %s", claims.Subject, order.UserID)
}
// additional check for anonymous orders: only allow admins
@@ -131,7 +131,7 @@ func (a *API) PaymentCreate(w http.ResponseWriter, r *http.Request) error {
if order.UserID == "" {
if token != nil {
claims := token.Claims.(*claims.JWTClaims)
order.UserID = claims.ID
order.UserID = claims.Subject
tx.Save(order)
}
} else {
@@ -140,7 +140,7 @@ func (a *API) PaymentCreate(w http.ResponseWriter, r *http.Request) error {
return unauthorizedError("You must be logged in to pay for this order")
}
claims := token.Claims.(*claims.JWTClaims)
if order.UserID != claims.ID {
if order.UserID != claims.Subject {
tx.Rollback()
return unauthorizedError("You must be logged in to pay for this order")
}
View
@@ -77,26 +77,30 @@ func testConfig() (*conf.GlobalConfiguration, *conf.Configuration) {
func testToken(id, email string) *jwt.Token {
claims := &claims.JWTClaims{
ID: id,
StandardClaims: jwt.StandardClaims{
Subject: id,
},
Email: email,
}
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
}
func testExpiredToken(id, email string) *jwt.Token {
claims := &claims.JWTClaims{
ID: id,
Email: email,
StandardClaims: jwt.StandardClaims{
Subject: id,
ExpiresAt: time.Now().Add(time.Duration(-1) * time.Minute).Unix(),
},
Email: email,
}
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
}
func testAdminToken(id, email string) *jwt.Token {
claims := &claims.JWTClaims{
ID: id,
StandardClaims: jwt.StandardClaims{
Subject: id,
},
Email: email,
AppMetaData: map[string]interface{}{
"roles": []interface{}{"admin"},
View
@@ -8,7 +8,6 @@ import (
// JWTClaims represents the JWT claims information.
type JWTClaims struct {
ID string `json:"id"`
Email string `json:"email"`
AppMetaData map[string]interface{} `json:"app_metadata"`
UserMetaData map[string]interface{} `json:"user_metadata"`

0 comments on commit 0fce4a1

Please sign in to comment.