Skip to content

Commit

Permalink
feat(auth): introduce @auth directive on submit gentx
Browse files Browse the repository at this point in the history
The directive implementation required the http retrieved token to equals
to static one configured when starting the application
  • Loading branch information
amimart committed Dec 5, 2022
1 parent 1271293 commit dec14b9
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 18 deletions.
6 changes: 4 additions & 2 deletions app/actor/graphql/actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@ type Actor struct {
mongoURI string
dbName string
eventStore *actor.PID
bearer *string
srv *server
}

func NewActor(httpAddr, mongoURI, dbName string, eventStore *actor.PID) *Actor {
func NewActor(httpAddr, mongoURI, dbName string, eventStore *actor.PID, bearer *string) *Actor {
return &Actor{
addr: httpAddr,
mongoURI: mongoURI,
dbName: dbName,
eventStore: eventStore,
bearer: bearer,
}
}

Expand All @@ -35,7 +37,7 @@ func (a *Actor) Receive(ctx actor.Context) {
}

func (a *Actor) handleStart(ctx actor.Context) {
graphqlServer, err := NewGraphQLServer(context.Background(), ctx, a.mongoURI, a.dbName, a.eventStore)
graphqlServer, err := NewGraphQLServer(context.Background(), ctx, a.mongoURI, a.dbName, a.eventStore, a.bearer)
if err != nil {
log.Fatal().Err(err).Str("db", a.dbName).Msg("❌ Couldn't create graphql server")
}
Expand Down
41 changes: 39 additions & 2 deletions app/actor/graphql/graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,63 @@ package graphql

import (
"context"
"fmt"

"okp4/nemeton-leaderboard/app/keybase"

"okp4/nemeton-leaderboard/app/nemeton"
"okp4/nemeton-leaderboard/graphql"
"okp4/nemeton-leaderboard/graphql/generated"

graphql2 "github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/asynkron/protoactor-go/actor"
)

func NewGraphQLServer(ctx context.Context, actorCTX actor.Context, mongoURI, db string, eventStore *actor.PID) (*handler.Server, error) {
var ErrUnauthorized = fmt.Errorf("unauthorized")

const bearerCTXKey = "bearer"

func NewGraphQLServer(
ctx context.Context,
actorCTX actor.Context,
mongoURI, db string,
eventStore *actor.PID,
bearer *string,
) (*handler.Server, error) {
store, err := nemeton.NewStore(ctx, mongoURI, db)
if err != nil {
return nil, err
}

cfg := generated.Config{Resolvers: graphql.NewResolver(actorCTX, store, keybase.NewClient(), eventStore)}
cfg.Directives.Auth = func(ctx context.Context, obj interface{}, next graphql2.Resolver) (interface{}, error) {
if err := Authorize(ctx, bearer); err != nil {
return nil, err
}
return next(ctx)
}
return handler.NewDefaultServer(
generated.NewExecutableSchema(
generated.Config{Resolvers: graphql.NewResolver(actorCTX, store, keybase.NewClient(), eventStore)},
cfg,
),
), nil
}

func Authorize(ctx context.Context, expectedBearer *string) error {
if expectedBearer == nil {
return nil
}

if b := GetBearerFrom(ctx); b == nil || *expectedBearer != *b {
return ErrUnauthorized
}
return nil
}

func GetBearerFrom(ctx context.Context) *string {
if bearer, ok := ctx.Value(bearerCTXKey).(string); ok {
return &bearer
}
return nil
}
4 changes: 1 addition & 3 deletions app/actor/graphql/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@ package graphql
import (
"net/http"

"okp4/nemeton-leaderboard/graphql"

"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/playground"
)

func makeRouter(graphqlServer *handler.Server) *http.ServeMux {
router := http.NewServeMux()
router.Handle("/graphiql", playground.Handler("GraphiQL", "/graphql"))
router.Handle("/graphql", NewBearerMiddleware(graphql.BearerCTXKey, graphqlServer))
router.Handle("/graphql", NewBearerMiddleware(bearerCTXKey, graphqlServer))

return router
}
9 changes: 6 additions & 3 deletions app/system/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ type App struct {
init *actor.PID
}

func Bootstrap(listenAddr, mongoURI, dbName, grpcAddr, twitterToken, twitterAccount string,
func Bootstrap(
listenAddr, mongoURI, dbName, grpcAddr, twitterToken, twitterAccount string,
tls credentials.TransportCredentials,
accessToken *string,
) *App {
initProps := actor.PropsFromFunc(func(ctx actor.Context) {
if _, ok := ctx.Message().(*actor.Started); ok {
boot(ctx, listenAddr, mongoURI, dbName, grpcAddr, twitterToken, twitterAccount, tls)
boot(ctx, listenAddr, mongoURI, dbName, grpcAddr, twitterToken, twitterAccount, tls, accessToken)
}
})

Expand All @@ -45,6 +47,7 @@ func (app *App) Stop() error {

func boot(ctx actor.Context, listenAddr, mongoURI, dbName, grpcAddr, twitterToken, twitterAccount string,
tls credentials.TransportCredentials,
accessToken *string,
) {
grpcClientProps := actor.PropsFromProducer(func() actor.Actor {
grpcClient, err := cosmos.NewGrpcClient(grpcAddr, tls)
Expand Down Expand Up @@ -88,7 +91,7 @@ func boot(ctx actor.Context, listenAddr, mongoURI, dbName, grpcAddr, twitterToke
}

graphqlProps := actor.PropsFromProducer(func() actor.Actor {
return graphql.NewActor(listenAddr, mongoURI, dbName, eventStorePID)
return graphql.NewActor(listenAddr, mongoURI, dbName, eventStorePID, accessToken)
})
if _, err := ctx.SpawnNamed(graphqlProps, "graphql"); err != nil {
log.Panic().Err(err).Str("actor", "graphql").Msg("❌ Could not create actor")
Expand Down
22 changes: 21 additions & 1 deletion cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,27 @@ var (
tlsSkipVerify bool
twitterToken string
twitterAccount string
accessToken string

startCmd = &cobra.Command{
Use: "start",
Short: "Start the leaderboard service",
Run: func(cmd *cobra.Command, args []string) {
app := system.Bootstrap(graphqlAddr, mongoURI, dbName, grpcAddress, twitterToken, twitterAccount, getTransportCredentials())
var accessTokenOpt *string
if len(accessToken) > 0 {
accessTokenOpt = &accessToken
}

app := system.Bootstrap(
graphqlAddr,
mongoURI,
dbName,
grpcAddress,
twitterToken,
twitterAccount,
getTransportCredentials(),
accessTokenOpt,
)

kill := make(chan os.Signal, 1)
signal.Notify(kill, syscall.SIGINT, syscall.SIGTERM)
Expand Down Expand Up @@ -70,6 +85,11 @@ func init() {
FlagTwitterAccount,
"@OKP4_Protocol",
"Set the twitter account that should be mentioned on tweet to be accepted for twitter task")
startCmd.PersistentFlags().StringVar(
&accessToken,
"access-token",
"",
"The required access token for authenticated operations, an empty value = no auth")
}

func getTransportCredentials() credentials.TransportCredentials {
Expand Down
35 changes: 31 additions & 4 deletions graphql/generated/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion graphql/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ type Resolver struct {
eventStore *actor.PID
}

func NewResolver(ctx actor.Context, store *nemeton.Store, keybaseClient *keybase.Client, eventStore *actor.PID) *Resolver {
func NewResolver(
ctx actor.Context,
store *nemeton.Store,
keybaseClient *keybase.Client,
eventStore *actor.PID,
) *Resolver {
return &Resolver{
actorCTX: ctx,
store: store,
Expand Down
7 changes: 6 additions & 1 deletion graphql/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ Represents a Javascript Object Notation format.
"""
scalar JSON

"""
Authorization needed to perform operation.
"""
directive @auth on FIELD_DEFINITION

directive @goField(
forceResolver: Boolean
name: String
Expand Down Expand Up @@ -139,7 +144,7 @@ type Mutation {
The gentx carrying the `MsgCreateValidator` related to this validator.
"""
gentx: JSON!
): Void
): Void @auth
}

"""
Expand Down
1 change: 0 additions & 1 deletion graphql/schema.resolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

"okp4/nemeton-leaderboard/app/event"
"okp4/nemeton-leaderboard/app/message"

"okp4/nemeton-leaderboard/app/nemeton"
"okp4/nemeton-leaderboard/graphql/generated"
"okp4/nemeton-leaderboard/graphql/model"
Expand Down

0 comments on commit dec14b9

Please sign in to comment.