Add _admin_signup mutation

This commit is contained in:
Lakhan Samani 2022-01-09 17:35:37 +05:30
parent 91c35aa381
commit 9d08d6c672
24 changed files with 297 additions and 66 deletions

View File

@ -1,6 +1,7 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
@ -17,7 +18,7 @@ func adminLogoutTests(s TestSetup, t *testing.T) {
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
assert.Nil(t, err)
req.Header.Add("Authorization", "Bearer "+h)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
_, err = resolvers.AdminLogout(ctx)
assert.Nil(t, err)

View File

@ -1,6 +1,7 @@
package test
import (
"fmt"
"log"
"testing"
@ -19,7 +20,7 @@ func adminSessionTests(s TestSetup, t *testing.T) {
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
assert.Nil(t, err)
req.Header.Add("Authorization", "Bearer "+h)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
res, err := resolvers.AdminSession(ctx)
assert.Nil(t, err)

View File

@ -0,0 +1,32 @@
package test
import (
"log"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)
func adminSignupTests(s TestSetup, t *testing.T) {
t.Run(`should complete admin login`, func(t *testing.T) {
_, ctx := createContext(s)
_, err := resolvers.AdminSignupResolver(ctx, model.AdminLoginInput{
AdminSecret: "admin",
})
log.Println("err", err)
assert.NotNil(t, err)
// reset env for test to pass
constants.EnvData.ADMIN_SECRET = ""
res, err := resolvers.AdminSignupResolver(ctx, model.AdminLoginInput{
AdminSecret: uuid.New().String(),
})
assert.Nil(t, err)
assert.Greater(t, len(res.AccessToken), 0)
})
}

View File

@ -1,6 +1,7 @@
package test
import (
"fmt"
"log"
"testing"
@ -19,7 +20,7 @@ func configTests(s TestSetup, t *testing.T) {
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
assert.Nil(t, err)
req.Header.Add("Authorization", "Bearer "+h)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
res, err := resolvers.ConfigResolver(ctx)
assert.Nil(t, err)

View File

@ -1,11 +1,13 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
@ -24,7 +26,10 @@ func deleteUserTest(s TestSetup, t *testing.T) {
})
assert.NotNil(t, err, "unauthorized")
req.Header.Add("x-authorizer-admin-secret", constants.EnvData.ADMIN_SECRET)
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
_, err = resolvers.DeleteUser(ctx, model.DeleteUserInput{
Email: email,
})

View File

@ -1,8 +1,10 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
@ -25,7 +27,7 @@ func logoutTests(s TestSetup, t *testing.T) {
})
token := *verifyRes.AccessToken
req.Header.Add("Authorization", "Bearer "+token)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token))
_, err = resolvers.Logout(ctx)
assert.Nil(t, err)
_, err = resolvers.Profile(ctx)

View File

@ -1,8 +1,10 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
@ -26,7 +28,7 @@ func magicLinkLoginTests(s TestSetup, t *testing.T) {
})
token := *verifyRes.AccessToken
req.Header.Add("Authorization", "Bearer "+token)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token))
_, err = resolvers.Profile(ctx)
assert.Nil(t, err)

View File

@ -1,8 +1,10 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
@ -30,7 +32,7 @@ func profileTests(s TestSetup, t *testing.T) {
})
token := *verifyRes.AccessToken
req.Header.Add("Authorization", "Bearer "+token)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token))
profileRes, err := resolvers.Profile(ctx)
assert.Nil(t, err)

View File

@ -13,8 +13,8 @@ import (
func TestResolvers(t *testing.T) {
databases := map[string]string{
enum.Sqlite.String(): "../../data.db",
enum.Arangodb.String(): "http://root:root@localhost:8529",
enum.Mongodb.String(): "mongodb://localhost:27017",
// enum.Arangodb.String(): "http://root:root@localhost:8529",
// enum.Mongodb.String(): "mongodb://localhost:27017",
}
for dbType, dbURL := range databases {
@ -35,6 +35,19 @@ func TestResolvers(t *testing.T) {
log.Println("EnvData:", constants.EnvData)
t.Run("should pass tests for "+dbType, func(t *testing.T) {
// admin tests
adminSignupTests(s, t)
verificationRequestsTest(s, t)
usersTest(s, t)
deleteUserTest(s, t)
updateUserTest(s, t)
adminLoginTests(s, t)
adminLogoutTests(s, t)
adminSessionTests(s, t)
updateConfigTests(s, t)
configTests(s, t)
// user tests
loginTests(s, t)
signupTests(s, t)
forgotPasswordTest(s, t)
@ -47,17 +60,6 @@ func TestResolvers(t *testing.T) {
magicLinkLoginTests(s, t)
logoutTests(s, t)
metaTests(s, t)
// admin tests
verificationRequestsTest(s, t)
usersTest(s, t)
deleteUserTest(s, t)
updateUserTest(s, t)
adminLoginTests(s, t)
adminLogoutTests(s, t)
adminSessionTests(s, t)
updateConfigTests(s, t)
configTests(s, t)
})
}
}

View File

@ -1,8 +1,10 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
@ -30,7 +32,8 @@ func sessionTests(s TestSetup, t *testing.T) {
})
token := *verifyRes.AccessToken
req.Header.Add("Authorization", "Bearer "+token)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token))
sessionRes, err := resolvers.Session(ctx, []string{})
assert.Nil(t, err)

View File

@ -1,6 +1,7 @@
package test
import (
"fmt"
"log"
"testing"
@ -23,7 +24,8 @@ func updateConfigTests(s TestSetup, t *testing.T) {
assert.NotNil(t, err)
h, _ := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
req.Header.Add("Authorization", "Bearer "+h)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
newURL := "https://test.com"
data = model.UpdateConfigInput{
AppURL: &newURL,

View File

@ -1,8 +1,10 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
@ -33,7 +35,7 @@ func updateProfileTests(s TestSetup, t *testing.T) {
})
token := *verifyRes.AccessToken
req.Header.Add("Authorization", "Bearer "+token)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token))
_, err = resolvers.UpdateProfile(ctx, model.UpdateProfileInput{
FamilyName: &fName,
})

View File

@ -1,11 +1,13 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
@ -29,7 +31,9 @@ func updateUserTest(s TestSetup, t *testing.T) {
})
assert.NotNil(t, err, "unauthorized")
req.Header.Add("x-authorizer-admin-secret", constants.EnvData.ADMIN_SECRET)
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
_, err = resolvers.UpdateUser(ctx, model.UpdateUserInput{
ID: user.ID,
Roles: newRoles,

View File

@ -1,11 +1,13 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
@ -22,7 +24,9 @@ func usersTest(s TestSetup, t *testing.T) {
users, err := resolvers.Users(ctx)
assert.NotNil(t, err, "unauthorized")
req.Header.Add("x-authorizer-admin-secret", constants.EnvData.ADMIN_SECRET)
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
users, err = resolvers.Users(ctx)
assert.Nil(t, err)
rLen := len(users)

View File

@ -1,11 +1,13 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
@ -23,7 +25,9 @@ func verificationRequestsTest(s TestSetup, t *testing.T) {
requests, err := resolvers.VerificationRequests(ctx)
assert.NotNil(t, err, "unauthorizer")
req.Header.Add("x-authorizer-admin-secret", constants.EnvData.ADMIN_SECRET)
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
requests, err = resolvers.VerificationRequests(ctx)
assert.Nil(t, err)

View File

@ -119,21 +119,7 @@ func PersistEnv() error {
}
if hasChanged {
jsonBytes, err := json.Marshal(jsonData)
if err != nil {
return err
}
err = json.Unmarshal(jsonBytes, &constants.EnvData)
if err != nil {
return err
}
configData, err := json.Marshal(constants.EnvData)
if err != nil {
return err
}
encryptedConfig, err := utils.EncryptAES(configData)
encryptedConfig, err := utils.EncryptConfig(jsonData)
if err != nil {
return err
}

View File

@ -29,7 +29,7 @@ require (
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/mail.v2 v2.3.1 // indirect
gopkg.in/mail.v2 v2.3.1
gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/mysql v1.2.1
gorm.io/driver/postgres v1.2.3

View File

@ -109,6 +109,7 @@ type ComplexityRoot struct {
Mutation struct {
AdminLogin func(childComplexity int, params model.AdminLoginInput) int
AdminLogout func(childComplexity int) int
AdminSignup func(childComplexity int, params model.AdminLoginInput) int
DeleteUser func(childComplexity int, params model.DeleteUserInput) int
ForgotPassword func(childComplexity int, params model.ForgotPasswordInput) int
Login func(childComplexity int, params model.LoginInput) int
@ -180,6 +181,7 @@ type MutationResolver interface {
ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error)
DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error)
UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error)
AdminSignup(ctx context.Context, params model.AdminLoginInput) (*model.AdminLoginResponse, error)
AdminLogin(ctx context.Context, params model.AdminLoginInput) (*model.AdminLoginResponse, error)
AdminLogout(ctx context.Context) (*model.Response, error)
UpdateConfig(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error)
@ -564,6 +566,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.AdminLogout(childComplexity), true
case "Mutation._admin_signup":
if e.complexity.Mutation.AdminSignup == nil {
break
}
args, err := ec.field_Mutation__admin_signup_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.AdminSignup(childComplexity, args["params"].(model.AdminLoginInput)), true
case "Mutation._delete_user":
if e.complexity.Mutation.DeleteUser == nil {
break
@ -1231,6 +1245,7 @@ type Mutation {
# admin only apis
_delete_user(params: DeleteUserInput!): Response!
_update_user(params: UpdateUserInput!): User!
_admin_signup(params: AdminLoginInput!): AdminLoginResponse!
_admin_login(params: AdminLoginInput!): AdminLoginResponse!
_admin_logout: Response!
_update_config(params: UpdateConfigInput!): Response!
@ -1269,6 +1284,21 @@ func (ec *executionContext) field_Mutation__admin_login_args(ctx context.Context
return args, nil
}
func (ec *executionContext) field_Mutation__admin_signup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 model.AdminLoginInput
if tmp, ok := rawArgs["params"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params"))
arg0, err = ec.unmarshalNAdminLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminLoginInput(ctx, tmp)
if err != nil {
return nil, err
}
}
args["params"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation__delete_user_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@ -3529,6 +3559,48 @@ func (ec *executionContext) _Mutation__update_user(ctx context.Context, field gr
return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation__admin_signup(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Mutation",
Field: field,
Args: nil,
IsMethod: true,
IsResolver: true,
}
ctx = graphql.WithFieldContext(ctx, fc)
rawArgs := field.ArgumentMap(ec.Variables)
args, err := ec.field_Mutation__admin_signup_args(ctx, rawArgs)
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
fc.Args = args
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().AdminSignup(rctx, args["params"].(model.AdminLoginInput))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*model.AdminLoginResponse)
fc.Result = res
return ec.marshalNAdminLoginResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminLoginResponse(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation__admin_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@ -7062,6 +7134,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
invalids++
}
case "_admin_signup":
out.Values[i] = ec._Mutation__admin_signup(ctx, field)
if out.Values[i] == graphql.Null {
invalids++
}
case "_admin_login":
out.Values[i] = ec._Mutation__admin_login(ctx, field)
if out.Values[i] == graphql.Null {

View File

@ -233,6 +233,7 @@ type Mutation {
# admin only apis
_delete_user(params: DeleteUserInput!): Response!
_update_user(params: UpdateUserInput!): User!
_admin_signup(params: AdminLoginInput!): AdminLoginResponse!
_admin_login(params: AdminLoginInput!): AdminLoginResponse!
_admin_logout: Response!
_update_config(params: UpdateConfigInput!): Response!

View File

@ -55,6 +55,10 @@ func (r *mutationResolver) UpdateUser(ctx context.Context, params model.UpdateUs
return resolvers.UpdateUser(ctx, params)
}
func (r *mutationResolver) AdminSignup(ctx context.Context, params model.AdminLoginInput) (*model.AdminLoginResponse, error) {
return resolvers.AdminSignupResolver(ctx, params)
}
func (r *mutationResolver) AdminLogin(ctx context.Context, params model.AdminLoginInput) (*model.AdminLoginResponse, error) {
return resolvers.AdminLoginResolver(ctx, params)
}
@ -101,5 +105,7 @@ func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResol
// Query returns generated.QueryResolver implementation.
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
type (
mutationResolver struct{ *Resolver }
queryResolver struct{ *Resolver }
)

View File

@ -0,0 +1,78 @@
package resolvers
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils"
)
func AdminSignupResolver(ctx context.Context, params model.AdminLoginInput) (*model.AdminLoginResponse, error) {
gc, err := utils.GinContextFromContext(ctx)
var res *model.AdminLoginResponse
if err != nil {
return res, err
}
if strings.TrimSpace(params.AdminSecret) == "" {
err = fmt.Errorf("please select secure admin secret")
return res, err
}
if len(params.AdminSecret) < 6 {
err = fmt.Errorf("admin secret must be at least 6 characters")
return res, err
}
if constants.EnvData.ADMIN_SECRET != "" {
err = fmt.Errorf("admin sign up already completed")
return res, err
}
constants.EnvData.ADMIN_SECRET = params.AdminSecret
// consvert EnvData to JSON
var jsonData map[string]interface{}
jsonBytes, err := json.Marshal(constants.EnvData)
if err != nil {
return res, err
}
if err := json.Unmarshal(jsonBytes, &jsonData); err != nil {
return res, err
}
config, err := db.Mgr.GetConfig()
if err != nil {
return res, err
}
configData, err := utils.EncryptConfig(jsonData)
if err != nil {
return res, err
}
config.Config = configData
if _, err := db.Mgr.UpdateConfig(config); err != nil {
return res, err
}
hashedKey, err := utils.HashPassword(params.AdminSecret)
if err != nil {
return res, err
}
utils.SetAdminCookie(gc, hashedKey)
res = &model.AdminLoginResponse{
AccessToken: hashedKey,
Message: "admin signed up successfully",
}
return res, nil
}

View File

@ -72,21 +72,7 @@ func UpdateConfigResolver(ctx context.Context, params model.UpdateConfigInput) (
return res, err
}
jsonBytes, err := json.Marshal(updatedData)
if err != nil {
return res, err
}
err = json.Unmarshal(jsonBytes, &constants.EnvData)
if err != nil {
return res, err
}
configData, err := json.Marshal(constants.EnvData)
if err != nil {
return res, err
}
encryptedConfig, err := utils.EncryptAES(configData)
encryptedConfig, err := utils.EncryptConfig(updatedData)
if err != nil {
return res, err
}

View File

@ -134,13 +134,13 @@ func GetAdminAuthToken(gc *gin.Context) (string, error) {
token, err := GetAdminCookie(gc)
if err != nil || token == "" {
// try to check in auth header for cookie
auth := gc.Request.Header.Get("Authorization")
if auth == "" {
return "", fmt.Errorf(`unauthorized`)
}
token = strings.TrimPrefix(auth, "Bearer ")
// auth := gc.Request.Header.Get("Authorization")
// if auth == "" {
// return "", fmt.Errorf(`unauthorized`)
// }
// token = strings.TrimPrefix(auth, "Bearer ")
return "", fmt.Errorf("unauthorized")
}
// cookie escapes special characters like $

View File

@ -0,0 +1,30 @@
package utils
import (
"encoding/json"
"github.com/authorizerdev/authorizer/server/constants"
)
func EncryptConfig(data map[string]interface{}) ([]byte, error) {
jsonBytes, err := json.Marshal(data)
if err != nil {
return []byte{}, err
}
err = json.Unmarshal(jsonBytes, &constants.EnvData)
if err != nil {
return []byte{}, err
}
configData, err := json.Marshal(constants.EnvData)
if err != nil {
return []byte{}, err
}
encryptedConfig, err := EncryptAES(configData)
if err != nil {
return []byte{}, err
}
return encryptedConfig, nil
}