Add more API and config stuff and add basic FETokens
This commit is contained in:
parent
f682d44244
commit
cfeafebd68
18 changed files with 959 additions and 89 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
/config.yaml
|
||||
/.WROOF_KEYS.json
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
|
|
60
cmd/addUser.go
Normal file
60
cmd/addUser.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.1in9.net/raider/wroofauth/internal/database"
|
||||
"git.1in9.net/raider/wroofauth/internal/entities"
|
||||
"git.1in9.net/raider/wroofauth/internal/entities/user"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// addUserCmd represents the generateKeys command
|
||||
var addUserCmd = &cobra.Command{
|
||||
Use: "add-user [username]",
|
||||
Short: "Creates a user",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) < 1 {
|
||||
cmd.Usage()
|
||||
return
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
database.MongoConnect(ctx)
|
||||
database.RedisConnect(ctx)
|
||||
|
||||
entities.SetupEntityDatabases()
|
||||
|
||||
newUser := user.New()
|
||||
|
||||
newUser.Username = &args[0]
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
fmt.Printf("Password for %s: ", args[0])
|
||||
|
||||
password, _, err := reader.ReadLine()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
passwordString := string(password)
|
||||
|
||||
newUser.SetPassword(passwordString)
|
||||
|
||||
newUser.Persist(context.Background())
|
||||
|
||||
fmt.Printf("User \"%s\" created. ID: %s\n", args[0], newUser.ID)
|
||||
|
||||
database.MongoDisconnect(ctx)
|
||||
database.RedisDisconnect()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(addUserCmd)
|
||||
}
|
63
cmd/generateKeys.go
Normal file
63
cmd/generateKeys.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"git.1in9.net/raider/wroofauth/internal/keystore"
|
||||
"github.com/lestrrat-go/jwx/jwk"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// generateKeysCmd represents the generateKeys command
|
||||
var generateKeysCmd = &cobra.Command{
|
||||
Use: "generate-keys",
|
||||
Short: "Generates a new keys",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
public, private, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
cmd.PrintErrln(err)
|
||||
return
|
||||
}
|
||||
|
||||
key, err := jwk.New(private)
|
||||
if err != nil {
|
||||
cmd.PrintErrln(err)
|
||||
return
|
||||
}
|
||||
|
||||
keyPublic, err := jwk.New(public)
|
||||
if err != nil {
|
||||
cmd.PrintErrln(err)
|
||||
return
|
||||
}
|
||||
|
||||
kid, err := keystore.GenerateKeyID()
|
||||
if err != nil {
|
||||
cmd.PrintErrln(err)
|
||||
return
|
||||
}
|
||||
|
||||
key.Set(jwk.KeyIDKey, kid)
|
||||
keyPublic.Set(jwk.KeyIDKey, kid)
|
||||
key.Set(jwk.AlgorithmKey, "EdDSA")
|
||||
keyPublic.Set(jwk.AlgorithmKey, "EdDSA")
|
||||
|
||||
keystore.Global.Add(key)
|
||||
keystore.Global.Add(keyPublic)
|
||||
|
||||
buf, err := json.MarshalIndent(keystore.Global, "", " ")
|
||||
if err != nil {
|
||||
fmt.Printf("failed to marshal key into JSON: %s\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%s\n", buf)
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(generateKeysCmd)
|
||||
}
|
10
cmd/root.go
10
cmd/root.go
|
@ -4,7 +4,9 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"git.1in9.net/raider/wroofauth/internal/keystore"
|
||||
"git.1in9.net/raider/wroofauth/internal/logger"
|
||||
"github.com/lestrrat-go/jwx/jwk"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
|
@ -68,10 +70,10 @@ func init() {
|
|||
viper.BindEnv("http.wyrd_url", "WYRD_URL")
|
||||
viper.BindEnv("http.frontend_url", "WYRD_FRONTEND_URL")*/
|
||||
|
||||
/*viper.SetDefault("crypto.keys", jwk.NewSet())
|
||||
viper.SetDefault("crypto.keys", jwk.NewSet())
|
||||
viper.SetDefault("crypto.keyfile", nil)
|
||||
viper.SetDefault("crypto.use_key", "")
|
||||
viper.BindEnv("crypto.keyfile", "WYRD_KEYFILE")*/
|
||||
viper.SetDefault("crypto.use_key.frontend", "")
|
||||
viper.BindEnv("crypto.keyfile", "WROOF_KEYS")
|
||||
|
||||
viper.SetDefault("totp.issuer", "WroofAuth") // Used for 2fa issuer value
|
||||
|
||||
|
@ -122,4 +124,6 @@ func loadConfig() {
|
|||
logger.StartLogger() // Restart Logger, as we may have changed our loglevel
|
||||
|
||||
logger.Sugar.Info("Using config file:", viper.ConfigFileUsed())
|
||||
|
||||
keystore.LoadKeystore()
|
||||
}
|
||||
|
|
9
go.mod
9
go.mod
|
@ -8,6 +8,7 @@ require (
|
|||
github.com/bsm/redislock v0.9.4
|
||||
github.com/go-chi/chi/v5 v5.0.10
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/lestrrat-go/jwx v1.2.26
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.4.0
|
||||
github.com/redis/go-redis/v9 v9.2.1
|
||||
|
@ -26,9 +27,11 @@ require (
|
|||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-chi/chi v1.5.5 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.3 // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
|
@ -37,11 +40,17 @@ require (
|
|||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.17.0 // indirect
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.1 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.9.1 // indirect
|
||||
github.com/prometheus/procfs v0.0.8 // indirect
|
||||
|
|
30
go.sum
30
go.sum
|
@ -114,6 +114,9 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
|
||||
|
@ -151,6 +154,8 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
|
@ -298,6 +303,19 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
|
||||
github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
|
||||
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
|
||||
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
||||
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
||||
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
||||
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
||||
github.com/lestrrat-go/jwx v1.2.26 h1:4iFo8FPRZGDYe1t19mQP0zTRqA7n8HnJ5lkIiDvJcB0=
|
||||
github.com/lestrrat-go/jwx v1.2.26/go.mod h1:MaiCdGbn3/cckbOFSCluJlJMmp9dmZm5hDuIkx8ftpQ=
|
||||
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
||||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
|
@ -341,6 +359,7 @@ github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6
|
|||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
|
@ -481,6 +500,7 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y
|
|||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
@ -522,6 +542,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -568,6 +589,8 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -597,6 +620,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -670,10 +694,14 @@ golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -685,6 +713,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -746,6 +775,7 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -66,7 +66,7 @@ resolver:
|
|||
# gqlgen will search for any type names in the schema in these go packages
|
||||
# if they match it will use them, otherwise it will generate them.
|
||||
autobind:
|
||||
# - "git.1in9.net/raider/wroofauth/graph/model"
|
||||
- "git.1in9.net/raider/wroofauth/graph/model"
|
||||
|
||||
# This section declares type mapping between the GraphQL and go type systems
|
||||
#
|
||||
|
|
|
@ -44,6 +44,7 @@ type ResolverRoot interface {
|
|||
}
|
||||
|
||||
type DirectiveRoot struct {
|
||||
FeToken func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error)
|
||||
Internal func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error)
|
||||
Self func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error)
|
||||
}
|
||||
|
@ -56,11 +57,12 @@ type ComplexityRoot struct {
|
|||
|
||||
Mutation struct {
|
||||
AuthFeSessionCreate func(childComplexity int) int
|
||||
AuthFeSessionIdentify func(childComplexity int, identification string) int
|
||||
AuthFeSessionLock func(childComplexity int) int
|
||||
AuthFeSessionLogout func(childComplexity int) int
|
||||
AuthFeSessionPassword func(childComplexity int, password string) int
|
||||
AuthFeSessionTotp func(childComplexity int, totp string) int
|
||||
AuthFeSessionIdentify func(childComplexity int, session string, identification string) int
|
||||
AuthFeSessionLock func(childComplexity int, session string) int
|
||||
AuthFeSessionLogout func(childComplexity int, session string) int
|
||||
AuthFeSessionPassword func(childComplexity int, session string, password string) int
|
||||
AuthFeSessionTotp func(childComplexity int, session string, totp string) int
|
||||
AuthFeTokenCreate func(childComplexity int) int
|
||||
}
|
||||
|
||||
Query struct {
|
||||
|
@ -86,11 +88,12 @@ type ComplexityRoot struct {
|
|||
|
||||
type MutationResolver interface {
|
||||
AuthFeSessionCreate(ctx context.Context) (*model.FeSession, error)
|
||||
AuthFeSessionIdentify(ctx context.Context, identification string) (*model.FeSession, error)
|
||||
AuthFeSessionPassword(ctx context.Context, password string) (*model.FeSession, error)
|
||||
AuthFeSessionTotp(ctx context.Context, totp string) (*model.FeSession, error)
|
||||
AuthFeSessionLock(ctx context.Context) (*model.FeSession, error)
|
||||
AuthFeSessionLogout(ctx context.Context) (*model.FeSession, error)
|
||||
AuthFeSessionIdentify(ctx context.Context, session string, identification string) (*model.FeSession, error)
|
||||
AuthFeSessionPassword(ctx context.Context, session string, password string) (*model.FeSession, error)
|
||||
AuthFeSessionTotp(ctx context.Context, session string, totp string) (*model.FeSession, error)
|
||||
AuthFeSessionLock(ctx context.Context, session string) (*model.FeSession, error)
|
||||
AuthFeSessionLogout(ctx context.Context, session string) (*model.FeSession, error)
|
||||
AuthFeTokenCreate(ctx context.Context) (string, error)
|
||||
}
|
||||
type QueryResolver interface {
|
||||
Self(ctx context.Context) (model.Actor, error)
|
||||
|
@ -149,21 +152,31 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.AuthFeSessionIdentify(childComplexity, args["identification"].(string)), true
|
||||
return e.complexity.Mutation.AuthFeSessionIdentify(childComplexity, args["session"].(string), args["identification"].(string)), true
|
||||
|
||||
case "Mutation.authFeSessionLock":
|
||||
if e.complexity.Mutation.AuthFeSessionLock == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.AuthFeSessionLock(childComplexity), true
|
||||
args, err := ec.field_Mutation_authFeSessionLock_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.AuthFeSessionLock(childComplexity, args["session"].(string)), true
|
||||
|
||||
case "Mutation.authFeSessionLogout":
|
||||
if e.complexity.Mutation.AuthFeSessionLogout == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.AuthFeSessionLogout(childComplexity), true
|
||||
args, err := ec.field_Mutation_authFeSessionLogout_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.AuthFeSessionLogout(childComplexity, args["session"].(string)), true
|
||||
|
||||
case "Mutation.authFeSessionPassword":
|
||||
if e.complexity.Mutation.AuthFeSessionPassword == nil {
|
||||
|
@ -175,7 +188,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.AuthFeSessionPassword(childComplexity, args["password"].(string)), true
|
||||
return e.complexity.Mutation.AuthFeSessionPassword(childComplexity, args["session"].(string), args["password"].(string)), true
|
||||
|
||||
case "Mutation.authFeSessionTOTP":
|
||||
if e.complexity.Mutation.AuthFeSessionTotp == nil {
|
||||
|
@ -187,7 +200,14 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.AuthFeSessionTotp(childComplexity, args["totp"].(string)), true
|
||||
return e.complexity.Mutation.AuthFeSessionTotp(childComplexity, args["session"].(string), args["totp"].(string)), true
|
||||
|
||||
case "Mutation.authFeTokenCreate":
|
||||
if e.complexity.Mutation.AuthFeTokenCreate == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.AuthFeTokenCreate(childComplexity), true
|
||||
|
||||
case "Query.authFeSession":
|
||||
if e.complexity.Query.AuthFeSession == nil {
|
||||
|
@ -408,14 +428,53 @@ func (ec *executionContext) field_Mutation_authFeSessionIdentify_args(ctx contex
|
|||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 string
|
||||
if tmp, ok := rawArgs["identification"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("identification"))
|
||||
arg0, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if tmp, ok := rawArgs["session"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("session"))
|
||||
arg0, err = ec.unmarshalNID2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["identification"] = arg0
|
||||
args["session"] = arg0
|
||||
var arg1 string
|
||||
if tmp, ok := rawArgs["identification"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("identification"))
|
||||
arg1, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["identification"] = arg1
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_authFeSessionLock_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 string
|
||||
if tmp, ok := rawArgs["session"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("session"))
|
||||
arg0, err = ec.unmarshalNID2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["session"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_authFeSessionLogout_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 string
|
||||
if tmp, ok := rawArgs["session"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("session"))
|
||||
arg0, err = ec.unmarshalNID2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["session"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
|
@ -423,14 +482,23 @@ func (ec *executionContext) field_Mutation_authFeSessionPassword_args(ctx contex
|
|||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 string
|
||||
if tmp, ok := rawArgs["password"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password"))
|
||||
arg0, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if tmp, ok := rawArgs["session"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("session"))
|
||||
arg0, err = ec.unmarshalNID2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["password"] = arg0
|
||||
args["session"] = arg0
|
||||
var arg1 string
|
||||
if tmp, ok := rawArgs["password"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password"))
|
||||
arg1, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["password"] = arg1
|
||||
return args, nil
|
||||
}
|
||||
|
||||
|
@ -438,14 +506,23 @@ func (ec *executionContext) field_Mutation_authFeSessionTOTP_args(ctx context.Co
|
|||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 string
|
||||
if tmp, ok := rawArgs["totp"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("totp"))
|
||||
arg0, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if tmp, ok := rawArgs["session"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("session"))
|
||||
arg0, err = ec.unmarshalNID2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["totp"] = arg0
|
||||
args["session"] = arg0
|
||||
var arg1 string
|
||||
if tmp, ok := rawArgs["totp"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("totp"))
|
||||
arg1, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["totp"] = arg1
|
||||
return args, nil
|
||||
}
|
||||
|
||||
|
@ -658,8 +735,14 @@ func (ec *executionContext) _Mutation_authFeSessionCreate(ctx context.Context, f
|
|||
}
|
||||
return ec.directives.Internal(ctx, nil, directive0)
|
||||
}
|
||||
directive2 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.FeToken == nil {
|
||||
return nil, errors.New("directive feToken is not implemented")
|
||||
}
|
||||
return ec.directives.FeToken(ctx, nil, directive1)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
tmp, err := directive2(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
@ -720,7 +803,7 @@ func (ec *executionContext) _Mutation_authFeSessionIdentify(ctx context.Context,
|
|||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().AuthFeSessionIdentify(rctx, fc.Args["identification"].(string))
|
||||
return ec.resolvers.Mutation().AuthFeSessionIdentify(rctx, fc.Args["session"].(string), fc.Args["identification"].(string))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.Internal == nil {
|
||||
|
@ -728,8 +811,14 @@ func (ec *executionContext) _Mutation_authFeSessionIdentify(ctx context.Context,
|
|||
}
|
||||
return ec.directives.Internal(ctx, nil, directive0)
|
||||
}
|
||||
directive2 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.FeToken == nil {
|
||||
return nil, errors.New("directive feToken is not implemented")
|
||||
}
|
||||
return ec.directives.FeToken(ctx, nil, directive1)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
tmp, err := directive2(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
@ -801,7 +890,7 @@ func (ec *executionContext) _Mutation_authFeSessionPassword(ctx context.Context,
|
|||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().AuthFeSessionPassword(rctx, fc.Args["password"].(string))
|
||||
return ec.resolvers.Mutation().AuthFeSessionPassword(rctx, fc.Args["session"].(string), fc.Args["password"].(string))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.Internal == nil {
|
||||
|
@ -809,8 +898,14 @@ func (ec *executionContext) _Mutation_authFeSessionPassword(ctx context.Context,
|
|||
}
|
||||
return ec.directives.Internal(ctx, nil, directive0)
|
||||
}
|
||||
directive2 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.FeToken == nil {
|
||||
return nil, errors.New("directive feToken is not implemented")
|
||||
}
|
||||
return ec.directives.FeToken(ctx, nil, directive1)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
tmp, err := directive2(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
@ -882,7 +977,7 @@ func (ec *executionContext) _Mutation_authFeSessionTOTP(ctx context.Context, fie
|
|||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().AuthFeSessionTotp(rctx, fc.Args["totp"].(string))
|
||||
return ec.resolvers.Mutation().AuthFeSessionTotp(rctx, fc.Args["session"].(string), fc.Args["totp"].(string))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.Internal == nil {
|
||||
|
@ -890,8 +985,14 @@ func (ec *executionContext) _Mutation_authFeSessionTOTP(ctx context.Context, fie
|
|||
}
|
||||
return ec.directives.Internal(ctx, nil, directive0)
|
||||
}
|
||||
directive2 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.FeToken == nil {
|
||||
return nil, errors.New("directive feToken is not implemented")
|
||||
}
|
||||
return ec.directives.FeToken(ctx, nil, directive1)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
tmp, err := directive2(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
@ -963,7 +1064,7 @@ func (ec *executionContext) _Mutation_authFeSessionLock(ctx context.Context, fie
|
|||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().AuthFeSessionLock(rctx)
|
||||
return ec.resolvers.Mutation().AuthFeSessionLock(rctx, fc.Args["session"].(string))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.Internal == nil {
|
||||
|
@ -971,8 +1072,14 @@ func (ec *executionContext) _Mutation_authFeSessionLock(ctx context.Context, fie
|
|||
}
|
||||
return ec.directives.Internal(ctx, nil, directive0)
|
||||
}
|
||||
directive2 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.FeToken == nil {
|
||||
return nil, errors.New("directive feToken is not implemented")
|
||||
}
|
||||
return ec.directives.FeToken(ctx, nil, directive1)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
tmp, err := directive2(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
@ -1015,6 +1122,17 @@ func (ec *executionContext) fieldContext_Mutation_authFeSessionLock(ctx context.
|
|||
return nil, fmt.Errorf("no field named %q was found under type FeSession", field.Name)
|
||||
},
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = ec.Recover(ctx, r)
|
||||
ec.Error(ctx, err)
|
||||
}
|
||||
}()
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
if fc.Args, err = ec.field_Mutation_authFeSessionLock_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return fc, err
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
|
@ -1033,7 +1151,7 @@ func (ec *executionContext) _Mutation_authFeSessionLogout(ctx context.Context, f
|
|||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().AuthFeSessionLogout(rctx)
|
||||
return ec.resolvers.Mutation().AuthFeSessionLogout(rctx, fc.Args["session"].(string))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.Internal == nil {
|
||||
|
@ -1041,8 +1159,14 @@ func (ec *executionContext) _Mutation_authFeSessionLogout(ctx context.Context, f
|
|||
}
|
||||
return ec.directives.Internal(ctx, nil, directive0)
|
||||
}
|
||||
directive2 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.FeToken == nil {
|
||||
return nil, errors.New("directive feToken is not implemented")
|
||||
}
|
||||
return ec.directives.FeToken(ctx, nil, directive1)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
tmp, err := directive2(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
@ -1085,6 +1209,61 @@ func (ec *executionContext) fieldContext_Mutation_authFeSessionLogout(ctx contex
|
|||
return nil, fmt.Errorf("no field named %q was found under type FeSession", field.Name)
|
||||
},
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = ec.Recover(ctx, r)
|
||||
ec.Error(ctx, err)
|
||||
}
|
||||
}()
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
if fc.Args, err = ec.field_Mutation_authFeSessionLogout_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return fc, err
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_authFeTokenCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Mutation_authFeTokenCreate(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().AuthFeTokenCreate(rctx)
|
||||
})
|
||||
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.(string)
|
||||
fc.Result = res
|
||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Mutation_authFeTokenCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
|
@ -1220,8 +1399,14 @@ func (ec *executionContext) _Query_authFeSession(ctx context.Context, field grap
|
|||
}
|
||||
return ec.directives.Internal(ctx, nil, directive0)
|
||||
}
|
||||
directive2 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.FeToken == nil {
|
||||
return nil, errors.New("directive feToken is not implemented")
|
||||
}
|
||||
return ec.directives.FeToken(ctx, nil, directive1)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
tmp, err := directive2(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
@ -3723,6 +3908,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
|||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "authFeTokenCreate":
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_authFeTokenCreate(ctx, field)
|
||||
})
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
|
|
18
graph/model/fesession.go
Normal file
18
graph/model/fesession.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package model
|
||||
|
||||
import "git.1in9.net/raider/wroofauth/internal/machines/fesession"
|
||||
|
||||
type FeSession struct {
|
||||
ID string `json:"id"`
|
||||
State SessionState `json:"state"`
|
||||
}
|
||||
|
||||
func (FeSession) IsNode() {}
|
||||
func (this FeSession) GetID() string { return this.ID }
|
||||
|
||||
func FeSessionFromDb(fesession fesession.FeSession) FeSession {
|
||||
return FeSession{
|
||||
ID: fesession.ID.Hex(),
|
||||
State: SessionState(fesession.State),
|
||||
}
|
||||
}
|
|
@ -17,14 +17,6 @@ type Node interface {
|
|||
GetID() string
|
||||
}
|
||||
|
||||
type FeSession struct {
|
||||
ID string `json:"id"`
|
||||
State SessionState `json:"state"`
|
||||
}
|
||||
|
||||
func (FeSession) IsNode() {}
|
||||
func (this FeSession) GetID() string { return this.ID }
|
||||
|
||||
type SecondFactor struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Name string `json:"name"`
|
||||
|
|
|
@ -5,6 +5,12 @@ api clients.
|
|||
"""
|
||||
directive @internal on FIELD_DEFINITION
|
||||
|
||||
"""
|
||||
Fields with @feToken require an frontend token
|
||||
to be submitted with the request.
|
||||
"""
|
||||
directive @feToken on FIELD_DEFINITION
|
||||
|
||||
"""
|
||||
Fields with @self may only be queried when queried
|
||||
directly by the actor represented by the object.
|
||||
|
@ -52,18 +58,20 @@ type Query {
|
|||
self: Actor!
|
||||
|
||||
user(id: ID!): User!
|
||||
authFeSession(id: ID!): FeSession! @internal
|
||||
authFeSession(id: ID!): FeSession! @internal @feToken
|
||||
|
||||
node(id: ID!): Node!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
authFeSessionCreate: FeSession! @internal
|
||||
authFeSessionIdentify(identification: String!): FeSession! @internal
|
||||
authFeSessionPassword(password: String!): FeSession! @internal
|
||||
authFeSessionTOTP(totp: String!): FeSession! @internal
|
||||
authFeSessionLock: FeSession! @internal
|
||||
authFeSessionLogout: FeSession! @internal
|
||||
authFeSessionCreate: FeSession! @internal @feToken
|
||||
authFeSessionIdentify(session: ID!, identification: String!): FeSession! @internal @feToken
|
||||
authFeSessionPassword(session: ID!, password: String!): FeSession! @internal @feToken
|
||||
authFeSessionTOTP(session: ID!, totp: String!): FeSession! @internal @feToken
|
||||
authFeSessionLock(session: ID!): FeSession! @internal @feToken
|
||||
authFeSessionLogout(session: ID!): FeSession! @internal @feToken
|
||||
|
||||
authFeTokenCreate: String!
|
||||
}
|
||||
|
||||
interface Node {
|
||||
|
|
|
@ -6,39 +6,235 @@ package graph
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.1in9.net/raider/wroofauth/graph/model"
|
||||
"git.1in9.net/raider/wroofauth/internal/keystore"
|
||||
"git.1in9.net/raider/wroofauth/internal/logger"
|
||||
"git.1in9.net/raider/wroofauth/internal/machines/fesession"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/lestrrat-go/jwx/jwa"
|
||||
"github.com/lestrrat-go/jwx/jwt"
|
||||
redis "github.com/redis/go-redis/v9"
|
||||
"github.com/spf13/viper"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// AuthFeSessionCreate is the resolver for the authFeSessionCreate field.
|
||||
func (r *mutationResolver) AuthFeSessionCreate(ctx context.Context) (*model.FeSession, error) {
|
||||
panic(fmt.Errorf("not implemented: AuthFeSessionCreate - authFeSessionCreate"))
|
||||
// TODO: Check auth
|
||||
|
||||
feSession := fesession.NewSession(ctx, primitive.NilObjectID) // TODO: Put actual object here
|
||||
err := feSession.Persist(ctx)
|
||||
if err != nil {
|
||||
logger.Logger.Warn("failed to create fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
modSession := model.FeSessionFromDb(*feSession)
|
||||
return &modSession, nil
|
||||
}
|
||||
|
||||
// AuthFeSessionIdentify is the resolver for the authFeSessionIdentify field.
|
||||
func (r *mutationResolver) AuthFeSessionIdentify(ctx context.Context, identification string) (*model.FeSession, error) {
|
||||
panic(fmt.Errorf("not implemented: AuthFeSessionIdentify - authFeSessionIdentify"))
|
||||
func (r *mutationResolver) AuthFeSessionIdentify(ctx context.Context, session string, identification string) (*model.FeSession, error) {
|
||||
// TODO: Check auth
|
||||
|
||||
sessionId, err := primitive.ObjectIDFromHex(session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
feSession, err := fesession.GetById(ctx, sessionId)
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
return nil, errors.New("session not found")
|
||||
}
|
||||
logger.Logger.Warn("failed to load fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
err = feSession.HandleIdentification(ctx, identification)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = feSession.Persist(ctx)
|
||||
if err != nil {
|
||||
logger.Logger.Warn("failed to persist fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
modSession := model.FeSessionFromDb(*feSession)
|
||||
return &modSession, nil
|
||||
}
|
||||
|
||||
// AuthFeSessionPassword is the resolver for the authFeSessionPassword field.
|
||||
func (r *mutationResolver) AuthFeSessionPassword(ctx context.Context, password string) (*model.FeSession, error) {
|
||||
panic(fmt.Errorf("not implemented: AuthFeSessionPassword - authFeSessionPassword"))
|
||||
func (r *mutationResolver) AuthFeSessionPassword(ctx context.Context, session string, password string) (*model.FeSession, error) {
|
||||
// TODO: Check auth
|
||||
|
||||
sessionId, err := primitive.ObjectIDFromHex(session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
feSession, err := fesession.GetById(ctx, sessionId)
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
return nil, errors.New("session not found")
|
||||
}
|
||||
logger.Logger.Warn("failed to load fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
err = feSession.HandlePassword(ctx, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = feSession.Persist(ctx)
|
||||
if err != nil {
|
||||
logger.Logger.Warn("failed to persist fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
modSession := model.FeSessionFromDb(*feSession)
|
||||
return &modSession, nil
|
||||
}
|
||||
|
||||
// AuthFeSessionTotp is the resolver for the authFeSessionTOTP field.
|
||||
func (r *mutationResolver) AuthFeSessionTotp(ctx context.Context, totp string) (*model.FeSession, error) {
|
||||
panic(fmt.Errorf("not implemented: AuthFeSessionTotp - authFeSessionTOTP"))
|
||||
func (r *mutationResolver) AuthFeSessionTotp(ctx context.Context, session string, totp string) (*model.FeSession, error) {
|
||||
// TODO: Check auth
|
||||
|
||||
sessionId, err := primitive.ObjectIDFromHex(session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
feSession, err := fesession.GetById(ctx, sessionId)
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
return nil, errors.New("session not found")
|
||||
}
|
||||
logger.Logger.Warn("failed to load fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
err = feSession.HandleTOTP(ctx, totp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = feSession.Persist(ctx)
|
||||
if err != nil {
|
||||
logger.Logger.Warn("failed to persist fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
modSession := model.FeSessionFromDb(*feSession)
|
||||
return &modSession, nil
|
||||
}
|
||||
|
||||
// AuthFeSessionLock is the resolver for the authFeSessionLock field.
|
||||
func (r *mutationResolver) AuthFeSessionLock(ctx context.Context) (*model.FeSession, error) {
|
||||
panic(fmt.Errorf("not implemented: AuthFeSessionLock - authFeSessionLock"))
|
||||
func (r *mutationResolver) AuthFeSessionLock(ctx context.Context, session string) (*model.FeSession, error) {
|
||||
// TODO: Check auth
|
||||
|
||||
sessionId, err := primitive.ObjectIDFromHex(session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
feSession, err := fesession.GetById(ctx, sessionId)
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
return nil, errors.New("session not found")
|
||||
}
|
||||
logger.Logger.Warn("failed to load fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
err = feSession.HandleLock(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = feSession.Persist(ctx)
|
||||
if err != nil {
|
||||
logger.Logger.Warn("failed to persist fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
modSession := model.FeSessionFromDb(*feSession)
|
||||
return &modSession, nil
|
||||
}
|
||||
|
||||
// AuthFeSessionLogout is the resolver for the authFeSessionLogout field.
|
||||
func (r *mutationResolver) AuthFeSessionLogout(ctx context.Context) (*model.FeSession, error) {
|
||||
panic(fmt.Errorf("not implemented: AuthFeSessionLogout - authFeSessionLogout"))
|
||||
func (r *mutationResolver) AuthFeSessionLogout(ctx context.Context, session string) (*model.FeSession, error) {
|
||||
// TODO: Check auth
|
||||
|
||||
sessionId, err := primitive.ObjectIDFromHex(session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
feSession, err := fesession.GetById(ctx, sessionId)
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
return nil, errors.New("session not found")
|
||||
}
|
||||
logger.Logger.Warn("failed to load fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
err = feSession.HandleLogout(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = feSession.Persist(ctx)
|
||||
if err != nil {
|
||||
logger.Logger.Warn("failed to persist fesession", zap.Error(err), zap.String("request-id", middleware.GetReqID(ctx)))
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
modSession := model.FeSessionFromDb(*feSession)
|
||||
return &modSession, nil
|
||||
}
|
||||
|
||||
// AuthFeTokenCreate is the resolver for the authFeTokenCreate field.
|
||||
func (r *mutationResolver) AuthFeTokenCreate(ctx context.Context) (string, error) {
|
||||
id := primitive.NewObjectID()
|
||||
|
||||
t := jwt.NewBuilder()
|
||||
t.Issuer(viper.GetString("wroofauth.url"))
|
||||
t.IssuedAt(time.Now())
|
||||
t.Audience([]string{
|
||||
viper.GetString("wroofauth.url"),
|
||||
})
|
||||
t.Claim("is_frontend_token", true)
|
||||
t.JwtID(id.Hex())
|
||||
|
||||
token, err := t.Build()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
kid := viper.GetString("crypto.use_key.frontend")
|
||||
|
||||
key, found := keystore.Global.LookupKeyID(kid)
|
||||
if !found {
|
||||
logger.Logger.Error("Keystore doesn't contain key to use for frontend!")
|
||||
return "", errors.New("misconfigured server")
|
||||
}
|
||||
|
||||
signed, err := jwt.Sign(token, jwa.EdDSA, key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(signed), nil
|
||||
}
|
||||
|
||||
// Self is the resolver for the self field.
|
||||
|
@ -53,7 +249,19 @@ func (r *queryResolver) User(ctx context.Context, id string) (*model.User, error
|
|||
|
||||
// AuthFeSession is the resolver for the authFeSession field.
|
||||
func (r *queryResolver) AuthFeSession(ctx context.Context, id string) (*model.FeSession, error) {
|
||||
panic(fmt.Errorf("not implemented: AuthFeSession - authFeSession"))
|
||||
sessionId, err := primitive.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session, err := fesession.GetById(ctx, sessionId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
obj := model.FeSessionFromDb(*session)
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
// Node is the resolver for the node field.
|
||||
|
|
|
@ -45,6 +45,12 @@ type User struct {
|
|||
SecondFactorOverride bool `bson:"secondFactorOverride,omitempty"` // Can be used to temporarily disable 2fa
|
||||
}
|
||||
|
||||
func New() User {
|
||||
return User{
|
||||
ID: primitive.NewObjectID(),
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) GetType() string {
|
||||
return "user"
|
||||
}
|
||||
|
|
93
internal/helpers/fetoken/fetoken.go
Normal file
93
internal/helpers/fetoken/fetoken.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
package fetoken
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.1in9.net/raider/wroofauth/internal/keystore"
|
||||
"git.1in9.net/raider/wroofauth/internal/logger"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/lestrrat-go/jwx/jwa"
|
||||
"github.com/lestrrat-go/jwx/jwt"
|
||||
"github.com/spf13/viper"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type FeToken struct {
|
||||
ID primitive.ObjectID
|
||||
}
|
||||
|
||||
type feTokenCtxKeyType = string
|
||||
|
||||
const feTokenCtxKey = feTokenCtxKeyType("feToken")
|
||||
|
||||
func getFeToken(r *http.Request) *FeToken {
|
||||
header := r.Header.Get("Authorization")
|
||||
if !strings.HasPrefix(header, "Bearer ") {
|
||||
logger.Logger.Info("FeToken - Authorization is not Bearer", zap.String("requestId", middleware.GetReqID(r.Context())))
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenString := strings.TrimPrefix(header, "Bearer ")
|
||||
|
||||
kid := viper.GetString("crypto.use_key.frontend")
|
||||
|
||||
key, found := keystore.Global.LookupKeyID(kid)
|
||||
if !found {
|
||||
logger.Logger.Error("Keystore doesn't contain key to use for frontend!")
|
||||
return nil
|
||||
}
|
||||
|
||||
public, err := key.PublicKey()
|
||||
if err != nil {
|
||||
logger.Logger.Error("Failed to make key into public key!", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
|
||||
token, err := jwt.Parse([]byte(tokenString), jwt.WithVerify(jwa.EdDSA, public))
|
||||
if err != nil {
|
||||
logger.Logger.Info("FeToken - Could not parse token", zap.Error(err), zap.String("requestId", middleware.GetReqID(r.Context())))
|
||||
return nil
|
||||
}
|
||||
|
||||
err = jwt.Validate(token)
|
||||
if err != nil {
|
||||
logger.Logger.Info("FeToken - Could not validate token", zap.Error(err), zap.String("requestId", middleware.GetReqID(r.Context())))
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenId := token.JwtID()
|
||||
|
||||
id, err := primitive.ObjectIDFromHex(tokenId)
|
||||
if err != nil {
|
||||
logger.Logger.Info("FeToken - Could not parse token ID", zap.Error(err), zap.String("requestId", middleware.GetReqID(r.Context())))
|
||||
return nil
|
||||
}
|
||||
|
||||
feToken := FeToken{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
return &feToken
|
||||
}
|
||||
|
||||
func ForContext(ctx context.Context) *FeToken {
|
||||
raw, _ := ctx.Value(feTokenCtxKey).(*FeToken)
|
||||
return raw
|
||||
}
|
||||
|
||||
func Middleware() func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
feToken := getFeToken(r)
|
||||
// feToken is a pointer.
|
||||
|
||||
ctx := context.WithValue(r.Context(), feTokenCtxKey, feToken)
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
76
internal/keystore/keystore.go
Normal file
76
internal/keystore/keystore.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
package keystore
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"os"
|
||||
|
||||
"git.1in9.net/raider/wroofauth/internal/logger"
|
||||
"github.com/lestrrat-go/jwx/jwk"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
Global jwk.Set
|
||||
)
|
||||
|
||||
func GenerateRandomBytes(n uint32) ([]byte, error) {
|
||||
b := make([]byte, n)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func GenerateKeyID() (string, error) {
|
||||
random, err := GenerateRandomBytes(64)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
kid := base64.StdEncoding.EncodeToString(random)
|
||||
|
||||
return kid, nil
|
||||
}
|
||||
|
||||
func LoadKeystore() {
|
||||
if viper.GetString("crypto.keyfile") != "" {
|
||||
keystoreContent, err := os.ReadFile(viper.GetString("crypto.keyfile"))
|
||||
if err != nil {
|
||||
logger.Logger.Fatal("Unable to load keyfile", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
fileKeyStore, err := jwk.Parse(keystoreContent)
|
||||
if err != nil {
|
||||
logger.Logger.Fatal("Unable to load keyfile", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
Global = fileKeyStore
|
||||
|
||||
if key, found := Global.Get(0); found {
|
||||
viper.SetDefault("crypto.use_key", key.KeyID())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
configKeyStore := jwk.NewSet()
|
||||
err := viper.UnmarshalKey("crypto.keys", &configKeyStore)
|
||||
|
||||
if err != nil {
|
||||
logger.Logger.Fatal("Unable to load keys", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
Global = configKeyStore
|
||||
|
||||
if key, found := Global.Get(0); found {
|
||||
viper.SetDefault("crypto.use_key", key.KeyID())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
70
internal/machines/fesession/db.go
Normal file
70
internal/machines/fesession/db.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
package fesession
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
|
||||
"git.1in9.net/raider/wroofauth/internal/database"
|
||||
"git.1in9.net/raider/wroofauth/internal/logger"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
const (
|
||||
PREFIX = "fe_session_"
|
||||
)
|
||||
|
||||
func (s *FeSession) Persist(ctx context.Context) error {
|
||||
return Persist(ctx, s)
|
||||
}
|
||||
|
||||
func Persist(ctx context.Context, session *FeSession) error {
|
||||
if session == nil {
|
||||
logger.Logger.Panic("trying to persist null-pointer")
|
||||
}
|
||||
|
||||
err := session.Validate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
marshaled, err := bson.Marshal(session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encoded := base64.StdEncoding.EncodeToString(marshaled)
|
||||
|
||||
status := database.Redis.Set(ctx, PREFIX+session.ID.Hex(), encoded, 0)
|
||||
if status.Err() != nil {
|
||||
return status.Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetById(ctx context.Context, id primitive.ObjectID) (*FeSession, error) {
|
||||
encoded, err := database.Redis.Get(ctx, PREFIX+id.Hex()).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
marshaled, err := base64.StdEncoding.DecodeString(encoded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var session FeSession
|
||||
|
||||
err = bson.Unmarshal(marshaled, &session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = session.Hydrate(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &session, nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package machines
|
||||
package fesession
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -42,19 +42,22 @@ const (
|
|||
SecondFactor_TOTP = "TOTP"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
ID primitive.ObjectID
|
||||
type FeSession struct {
|
||||
ID primitive.ObjectID `bson:"_id"`
|
||||
LinkedToken primitive.ObjectID `bson:"token"`
|
||||
|
||||
State SessionState
|
||||
State SessionState `bson:"state"`
|
||||
|
||||
AuthenticationMethod AuthenticationMethod
|
||||
SecondFactor SecondFactor
|
||||
AuthenticationMethod AuthenticationMethod `bson:"auth_method"`
|
||||
SecondFactor SecondFactor `bson:"second_factor"`
|
||||
|
||||
User *user.User
|
||||
User *user.User `bson:"-"`
|
||||
UserId *primitive.ObjectID `bson:"user"`
|
||||
}
|
||||
|
||||
func NewSession(ctx context.Context) *Session {
|
||||
return &Session{
|
||||
func NewSession(ctx context.Context, token primitive.ObjectID) *FeSession {
|
||||
return &FeSession{
|
||||
ID: primitive.NewObjectID(),
|
||||
State: SessionState_EMPTY,
|
||||
AuthenticationMethod: AuthenticationMethod_NONE,
|
||||
SecondFactor: SecondFactor_NONE,
|
||||
|
@ -62,7 +65,7 @@ func NewSession(ctx context.Context) *Session {
|
|||
}
|
||||
|
||||
// s.Validate checks if the session is in a valid state
|
||||
func (s *Session) Validate(ctx context.Context) error {
|
||||
func (s *FeSession) Validate(ctx context.Context) error {
|
||||
if s.IsAnyAuthenticated() {
|
||||
if s.User == nil {
|
||||
// We can only be here if a user is set
|
||||
|
@ -84,11 +87,11 @@ func (s *Session) Validate(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) IsAnyAuthenticated() bool {
|
||||
func (s *FeSession) IsAnyAuthenticated() bool {
|
||||
return strings.HasPrefix(string(s.State), "AUTHENTICATED_")
|
||||
}
|
||||
|
||||
func (s *Session) performPreflight(ctx context.Context) error {
|
||||
func (s *FeSession) performPreflight(ctx context.Context) error {
|
||||
// TODO: Do Preflight Checks.
|
||||
|
||||
// TODO: Do PASSWORD_EXPIRED check
|
||||
|
@ -107,7 +110,19 @@ func (s *Session) performPreflight(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) HandleIdentification(ctx context.Context, identification string) error {
|
||||
func (s *FeSession) Hydrate(ctx context.Context) error {
|
||||
if s.UserId != nil {
|
||||
var err error
|
||||
s.User, err = user.GetById(ctx, *s.UserId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *FeSession) HandleIdentification(ctx context.Context, identification string) error {
|
||||
if s.State != SessionState_EMPTY {
|
||||
return ErrIllegalStateAction // This step may only run on EMPTY sessions
|
||||
}
|
||||
|
@ -122,6 +137,7 @@ func (s *Session) HandleIdentification(ctx context.Context, identification strin
|
|||
}
|
||||
|
||||
s.User = user
|
||||
s.UserId = &user.ID
|
||||
|
||||
//TODO: Check for SAML
|
||||
|
||||
|
@ -130,7 +146,7 @@ func (s *Session) HandleIdentification(ctx context.Context, identification strin
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) HandlePassword(ctx context.Context, password string) error {
|
||||
func (s *FeSession) HandlePassword(ctx context.Context, password string) error {
|
||||
if s.State != SessionState_UNAUTHENTICATED {
|
||||
return ErrIllegalStateAction // This step may only run on UNAUTHENTICATED sessions
|
||||
}
|
||||
|
@ -155,7 +171,7 @@ func (s *Session) HandlePassword(ctx context.Context, password string) error {
|
|||
|
||||
// TODO: Passkey action
|
||||
|
||||
func (s *Session) HandleTOTP(ctx context.Context, otp string) error {
|
||||
func (s *FeSession) HandleTOTP(ctx context.Context, otp string) error {
|
||||
if s.State != SessionState_AWAITING_FACTOR {
|
||||
return ErrIllegalStateAction
|
||||
}
|
||||
|
@ -173,7 +189,7 @@ func (s *Session) HandleTOTP(ctx context.Context, otp string) error {
|
|||
return s.performPreflight(ctx)
|
||||
}
|
||||
|
||||
func (s *Session) HandleLock(ctx context.Context) error {
|
||||
func (s *FeSession) HandleLock(ctx context.Context) error {
|
||||
if !s.IsAnyAuthenticated() {
|
||||
return ErrIllegalStateAction
|
||||
}
|
||||
|
@ -181,7 +197,7 @@ func (s *Session) HandleLock(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) HandleLogout(ctx context.Context) error {
|
||||
func (s *FeSession) HandleLogout(ctx context.Context) error {
|
||||
if !s.IsAnyAuthenticated() {
|
||||
return ErrIllegalStateAction
|
||||
}
|
||||
|
@ -189,7 +205,7 @@ func (s *Session) HandleLogout(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) Destroy(ctx context.Context) error {
|
||||
func (s *FeSession) Destroy(ctx context.Context) error {
|
||||
// TODO: Destroy Session
|
||||
return nil
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"git.1in9.net/raider/wroofauth/graph"
|
||||
"git.1in9.net/raider/wroofauth/internal/helpers/fetoken"
|
||||
chiprometheus "github.com/766b/chi-prometheus"
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/99designs/gqlgen/graphql/playground"
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
@ -25,7 +29,8 @@ func SetupAPI() chi.Router {
|
|||
|
||||
m := chiprometheus.NewMiddleware("api")
|
||||
router.Use(m)
|
||||
//router.Use(decodeAuthMiddleware)
|
||||
|
||||
router.Use(fetoken.Middleware())
|
||||
|
||||
router.NotFound(notFoundHandler)
|
||||
router.MethodNotAllowed(methodNotAllowedHandler)
|
||||
|
@ -34,6 +39,25 @@ func SetupAPI() chi.Router {
|
|||
|
||||
c := graph.Config{Resolvers: &graph.Resolver{}}
|
||||
|
||||
c.Directives.FeToken = func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
|
||||
feToken := fetoken.ForContext(ctx)
|
||||
if feToken == nil {
|
||||
return nil, errors.New("FeToken is invalid")
|
||||
}
|
||||
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
c.Directives.Internal = func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
|
||||
// TODO
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
c.Directives.Self = func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
|
||||
// TODO
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
srv := handler.NewDefaultServer(graph.NewExecutableSchema(c))
|
||||
router.Handle("/query", srv)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue