mirror of
https://github.com/hanzoai/commerce.git
synced 2026-10-30 15:08:42 +00:00
Multi-tenant commerce and billing: orders, subscriptions, invoices, plans, usage metering and a credit ledger. One Go binary. MIT OR Apache-2.0. Claude-Session: https://claude.ai/code/session_01SAtaDFm8VDiWrhYHNNtxMw
442 lines
12 KiB
Go
442 lines
12 KiB
Go
package test
|
|
|
|
import (
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/hanzoai/commerce/datastore"
|
|
"github.com/hanzoai/commerce/log"
|
|
"github.com/hanzoai/commerce/models/fixtures"
|
|
"github.com/hanzoai/commerce/models/oauthtoken"
|
|
"github.com/hanzoai/commerce/models/organization"
|
|
"github.com/hanzoai/commerce/models/user"
|
|
"github.com/hanzoai/commerce/util/json"
|
|
"github.com/hanzoai/commerce/util/jwt"
|
|
"github.com/hanzoai/commerce/util/test/ae"
|
|
"github.com/hanzoai/commerce/util/test/zipclient"
|
|
"github.com/hanzoai/commerce/util/zipctx"
|
|
|
|
. "github.com/hanzoai/commerce/util/test/ginkgo"
|
|
|
|
authApi "github.com/hanzoai/commerce/api/auth"
|
|
)
|
|
|
|
func Test(t *testing.T) {
|
|
Setup("api/auth", t)
|
|
}
|
|
|
|
var (
|
|
ctx ae.Context
|
|
cl *zipclient.Client
|
|
db *datastore.Datastore
|
|
org *organization.Organization
|
|
refToken *oauthtoken.Token
|
|
usr *user.User
|
|
usr2 *user.User
|
|
)
|
|
|
|
// Setup test context
|
|
var _ = BeforeSuite(func() {
|
|
// Don't need this but switching to it to avoid long timeout.
|
|
var err error
|
|
ctx = ae.NewContext()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Create mock gin context that we can use with fixtures
|
|
c := zipctx.New(ctx)
|
|
|
|
// Run fixtures
|
|
org = fixtures.Organization(c).(*organization.Organization)
|
|
|
|
// Setup client and add routes for account API tests.
|
|
cl = zipclient.New(ctx)
|
|
authApi.Route(cl.Router)
|
|
|
|
// Create organization for tests, apiKey
|
|
db = datastore.New(ctx)
|
|
|
|
usr = user.New(db)
|
|
usr.Email = "[email protected]"
|
|
usr.SetPassword("Z0rd0N")
|
|
usr.Enabled = true
|
|
usr.MustPut()
|
|
|
|
usr2 = user.New(db)
|
|
usr2.Email = "[email protected]"
|
|
usr2.SetPassword("ilikedragons")
|
|
usr2.Enabled = false
|
|
usr2.MustCreate()
|
|
|
|
refToken, err = org.ResetReferenceToken(usr, oauthtoken.Claims{})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
|
|
// Tear-down test context
|
|
var _ = AfterSuite(func() {
|
|
ctx.Close()
|
|
})
|
|
|
|
var _ = Describe("auth", func() {
|
|
Context("Password Grant JSON", func() {
|
|
It("Should allow login with password grant", func() {
|
|
req := authApi.OAuthRequest{
|
|
Username: "[email protected]",
|
|
Password: "Z0rd0N",
|
|
ClientId: org.Name,
|
|
GrantType: "password",
|
|
}
|
|
|
|
j := json.Encode(req)
|
|
log.Debug("Json %v", j)
|
|
|
|
w := cl.PostRawJSON("/auth", j)
|
|
res := authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(200))
|
|
// TODO: should deconstruct token and test if the user id is in it
|
|
Expect(res.AccessToken).ToNot(Equal(""))
|
|
aClaims := oauthtoken.Claims{}
|
|
err := jwt.Decode(res.AccessToken, org.SecretKey, oauthtoken.Algorithm, &aClaims)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(string(aClaims.Type)).To(Equal(oauthtoken.Access))
|
|
Expect(aClaims.UserId).To(Equal(refToken.Claims.UserId))
|
|
Expect(aClaims.OrganizationName).To(Equal(refToken.Claims.OrganizationName))
|
|
Expect(aClaims.Issuer).To(Equal(refToken.Id()))
|
|
|
|
Expect(res.RefreshToken).ToNot(Equal(""))
|
|
rClaims := oauthtoken.Claims{}
|
|
err = jwt.Decode(res.RefreshToken, org.SecretKey, oauthtoken.Algorithm, &rClaims)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(string(rClaims.Type)).To(Equal(oauthtoken.Refresh))
|
|
Expect(rClaims.UserId).To(Equal(refToken.Claims.UserId))
|
|
Expect(rClaims.OrganizationName).To(Equal(refToken.Claims.OrganizationName))
|
|
Expect(rClaims.Issuer).To(Equal(refToken.Id()))
|
|
Expect(int(rClaims.Permissions)).To(Equal(0))
|
|
|
|
Expect(res.ExpiresIn).ToNot(Equal(24 * 7 * 3600))
|
|
Expect(res.TokenType).To(Equal("jwt"))
|
|
})
|
|
})
|
|
|
|
Context("Password Grant Form", func() {
|
|
It("Should allow login with password grant", func() {
|
|
data := url.Values{
|
|
"username": {"[email protected]"},
|
|
"password": {"Z0rd0N"},
|
|
"client_id": {org.Name},
|
|
"grant_type": {"password"},
|
|
}
|
|
|
|
w := cl.PostForm("/auth", data)
|
|
res := authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(200))
|
|
// TODO: should deconstruct token and test if the user id is in it
|
|
Expect(res.AccessToken).ToNot(Equal(""))
|
|
aClaims := oauthtoken.Claims{}
|
|
err := jwt.Decode(res.AccessToken, org.SecretKey, oauthtoken.Algorithm, &aClaims)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(string(aClaims.Type)).To(Equal(oauthtoken.Access))
|
|
Expect(aClaims.UserId).To(Equal(refToken.Claims.UserId))
|
|
Expect(aClaims.OrganizationName).To(Equal(refToken.Claims.OrganizationName))
|
|
Expect(aClaims.Issuer).To(Equal(refToken.Id()))
|
|
|
|
Expect(res.RefreshToken).ToNot(Equal(""))
|
|
rClaims := oauthtoken.Claims{}
|
|
err = jwt.Decode(res.RefreshToken, org.SecretKey, oauthtoken.Algorithm, &rClaims)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(string(rClaims.Type)).To(Equal(oauthtoken.Refresh))
|
|
Expect(rClaims.UserId).To(Equal(refToken.Claims.UserId))
|
|
Expect(rClaims.OrganizationName).To(Equal(refToken.Claims.OrganizationName))
|
|
Expect(rClaims.Issuer).To(Equal(refToken.Id()))
|
|
Expect(int(rClaims.Permissions)).To(Equal(0))
|
|
|
|
Expect(res.ExpiresIn).ToNot(Equal(24 * 7 * 3600))
|
|
Expect(res.TokenType).To(Equal("jwt"))
|
|
})
|
|
|
|
It("Should disallow login with disabled account", func() {
|
|
data := url.Values{
|
|
"username": {"[email protected]"},
|
|
"password": {"ilikedragon"},
|
|
"client_id": {org.Name},
|
|
"grant_type": {"password"},
|
|
}
|
|
|
|
w := cl.PostForm("/auth", data)
|
|
res := authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(401))
|
|
})
|
|
|
|
It("Should disallow login with wrong password", func() {
|
|
data := url.Values{
|
|
"username": {"[email protected]"},
|
|
"password": {"z3d"},
|
|
"client_id": {org.Name},
|
|
"grant_type": {"password"},
|
|
}
|
|
|
|
w := cl.PostForm("/auth", data)
|
|
res := authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(401))
|
|
})
|
|
|
|
It("Should disallow login with wrong email", func() {
|
|
data := url.Values{
|
|
"username": {"[email protected]"},
|
|
"password": {"bloo"},
|
|
"client_id": {org.Name},
|
|
"grant_type": {"password"},
|
|
}
|
|
|
|
w := cl.PostForm("/auth", data)
|
|
res := authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(401))
|
|
})
|
|
|
|
It("Should disallow login with invalid grant", func() {
|
|
data := url.Values{
|
|
"username": {"[email protected]"},
|
|
"password": {"Z0rd0N"},
|
|
"client_id": {org.Name},
|
|
"grant_type": {"not grant"},
|
|
}
|
|
|
|
w := cl.PostForm("/auth", data)
|
|
res := authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(400))
|
|
})
|
|
})
|
|
|
|
Context("Refresh Grant JSON", func() {
|
|
It("Should allow login with refresh grant", func() {
|
|
req := authApi.OAuthRequest{
|
|
Username: "[email protected]",
|
|
Password: "Z0rd0N",
|
|
ClientId: org.Name,
|
|
GrantType: "password",
|
|
}
|
|
|
|
j := json.Encode(req)
|
|
log.Debug("Json %v", j)
|
|
|
|
w := cl.PostRawJSON("/auth", j)
|
|
res := authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(200))
|
|
|
|
// Shove the issued refresh token back in
|
|
req2 := authApi.OAuthRequest{
|
|
RefreshToken: res.RefreshToken,
|
|
GrantType: "refresh_token",
|
|
}
|
|
|
|
j = json.Encode(req2)
|
|
log.Debug("Json %v", j)
|
|
|
|
w = cl.PostRawJSON("/auth", j)
|
|
res = authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(200))
|
|
|
|
// TODO: should deconstruct token and test if the user id is in it
|
|
Expect(res.AccessToken).ToNot(Equal(""))
|
|
aClaims := oauthtoken.Claims{}
|
|
err := jwt.Decode(res.AccessToken, org.SecretKey, oauthtoken.Algorithm, &aClaims)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(string(aClaims.Type)).To(Equal(oauthtoken.Access))
|
|
Expect(aClaims.UserId).To(Equal(refToken.Claims.UserId))
|
|
Expect(aClaims.OrganizationName).To(Equal(refToken.Claims.OrganizationName))
|
|
Expect(aClaims.Issuer).To(Equal(refToken.Id()))
|
|
|
|
Expect(res.RefreshToken).ToNot(Equal(""))
|
|
rClaims := oauthtoken.Claims{}
|
|
err = jwt.Decode(res.RefreshToken, org.SecretKey, oauthtoken.Algorithm, &rClaims)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(string(rClaims.Type)).To(Equal(oauthtoken.Refresh))
|
|
Expect(rClaims.UserId).To(Equal(refToken.Claims.UserId))
|
|
Expect(rClaims.OrganizationName).To(Equal(refToken.Claims.OrganizationName))
|
|
Expect(rClaims.Issuer).To(Equal(refToken.Id()))
|
|
Expect(int(rClaims.Permissions)).To(Equal(0))
|
|
|
|
Expect(res.ExpiresIn).ToNot(Equal(24 * 7 * 3600))
|
|
Expect(res.TokenType).To(Equal("jwt"))
|
|
})
|
|
})
|
|
|
|
Context("Refresh Grant Form", func() {
|
|
It("Should allow login with refresh grant", func() {
|
|
data := url.Values{
|
|
"username": {"[email protected]"},
|
|
"password": {"Z0rd0N"},
|
|
"client_id": {org.Name},
|
|
"grant_type": {"password"},
|
|
}
|
|
|
|
w := cl.PostForm("/auth", data)
|
|
res := authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(200))
|
|
|
|
// Shove the issued refresh token back in
|
|
data = url.Values{
|
|
"refresh_token": {res.RefreshToken},
|
|
"grant_type": {"refresh_token"},
|
|
}
|
|
|
|
w = cl.PostForm("/auth", data)
|
|
res = authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(200))
|
|
|
|
// TODO: should deconstruct token and test if the user id is in it
|
|
Expect(res.AccessToken).ToNot(Equal(""))
|
|
aClaims := oauthtoken.Claims{}
|
|
err := jwt.Decode(res.AccessToken, org.SecretKey, oauthtoken.Algorithm, &aClaims)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(string(aClaims.Type)).To(Equal(oauthtoken.Access))
|
|
Expect(aClaims.UserId).To(Equal(refToken.Claims.UserId))
|
|
Expect(aClaims.OrganizationName).To(Equal(refToken.Claims.OrganizationName))
|
|
Expect(aClaims.Issuer).To(Equal(refToken.Id()))
|
|
|
|
Expect(res.RefreshToken).ToNot(Equal(""))
|
|
rClaims := oauthtoken.Claims{}
|
|
err = jwt.Decode(res.RefreshToken, org.SecretKey, oauthtoken.Algorithm, &rClaims)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(string(rClaims.Type)).To(Equal(oauthtoken.Refresh))
|
|
Expect(rClaims.UserId).To(Equal(refToken.Claims.UserId))
|
|
Expect(rClaims.OrganizationName).To(Equal(refToken.Claims.OrganizationName))
|
|
Expect(rClaims.Issuer).To(Equal(refToken.Id()))
|
|
Expect(int(rClaims.Permissions)).To(Equal(0))
|
|
|
|
Expect(res.ExpiresIn).ToNot(Equal(24 * 7 * 3600))
|
|
Expect(res.TokenType).To(Equal("jwt"))
|
|
})
|
|
|
|
It("Should disallow login with refresh grant for non-refresh token", func() {
|
|
// Shove the issued refresh token back in
|
|
data := url.Values{
|
|
"refresh_token": {refToken.String},
|
|
"grant_type": {"refresh_token"},
|
|
}
|
|
w := cl.PostForm("/auth", data)
|
|
res := authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(401))
|
|
})
|
|
})
|
|
|
|
Context("Token Revokation", func() {
|
|
It("Should deny grants if revoked", func() {
|
|
var err error
|
|
data := url.Values{
|
|
"username": {"[email protected]"},
|
|
"password": {"Z0rd0N"},
|
|
"client_id": {org.Name},
|
|
"grant_type": {"password"},
|
|
}
|
|
|
|
w := cl.PostForm("/auth", data)
|
|
res := authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(200))
|
|
|
|
refToken.Revoke()
|
|
|
|
// Shove the issued refresh token back in
|
|
data = url.Values{
|
|
"refresh_token": {res.RefreshToken},
|
|
"grant_type": {"refresh_token"},
|
|
}
|
|
|
|
w = cl.PostForm("/auth", data)
|
|
res = authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(403))
|
|
|
|
data = url.Values{
|
|
"username": {"[email protected]"},
|
|
"password": {"Z0rd0N"},
|
|
"client_id": {org.Name},
|
|
"grant_type": {"password"},
|
|
}
|
|
|
|
w = cl.PostForm("/auth", data)
|
|
res = authApi.OAuthResponse{}
|
|
|
|
log.Debug("Res %v", w.Body)
|
|
|
|
json.DecodeBuffer(w.Body, &res)
|
|
|
|
Expect(w.Code).To(Equal(403))
|
|
|
|
refToken, err = org.ResetReferenceToken(usr, oauthtoken.Claims{})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
})
|
|
})
|