Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Auth0 integration_V2 #703

Merged
merged 24 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
85f5785
add separate auth0 file for beckend
sanjsingh07 Apr 11, 2021
d289150
revert commit
sanjsingh07 Apr 11, 2021
b6029ff
Merge branch 'master' of https://github.com/stellar/kelp
sanjsingh07 Jun 4, 2021
9b75668
configured auth0 on GUI
sanjsingh07 Jun 4, 2021
eb09550
added interceptor
sanjsingh07 Jun 4, 2021
4c75879
added support for accepting GUI config file through CLI on server com…
sanjsingh07 Jun 6, 2021
93a94df
fixed not rendering component on async token call
sanjsingh07 Jun 9, 2021
c378e9e
finalize Auth0 Implementation
sanjsingh07 Jun 9, 2021
eb6574b
removed unused code
sanjsingh07 Jun 9, 2021
ef1b06b
fixing xdg-open not found bug on some linux-machine
sanjsingh07 Jun 9, 2021
96fad7b
trying to fix continuous reloading issue when deploying on k8s
sanjsingh07 Jun 9, 2021
c325878
auth0-implemention
sanjsingh07 Jun 9, 2021
65499e7
auth0-implemention
sanjsingh07 Jun 9, 2021
0584f93
updated readme.md
sanjsingh07 Jun 9, 2021
939863e
Merge branch 'master' of https://github.com/stellar/kelp
Jun 9, 2021
5002d86
Merge branch 'auth0-integration' of https://github.com/orunpay/kelp i…
Jun 9, 2021
1d182dd
auth0-integration
Jun 9, 2021
157408c
Delete auth0-config.json
sanjsingh07 Jun 9, 2021
4120425
Auth0 Implementation
sanjsingh07 Jun 18, 2021
8b3b33a
Merge branch 'master' of https://github.com/orunpay/kelp
Jun 18, 2021
3b55fbd
Auth0 integration V2
Jun 19, 2021
9f721e0
Updated interceptor.js
sanjsingh07 Jun 29, 2021
aecf3e4
Update serverMetadata.js
sanjsingh07 Jun 29, 2021
26fdb7d
Update version.js
sanjsingh07 Jun 29, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Your use of Kelp is governed by the Apache 2.0 open-source license. Please note
* [Running Kelp](#running-kelp)
* [Using CCXT](#using-ccxt)
* [Using Postgres](#using-postgres)
* [Using Auth0](#using-auth0)
* [Examples](#examples)
* [Walkthrough Guides](#walkthrough-guides)
* [Configuration Files](#configuration-files)
Expand Down Expand Up @@ -184,6 +185,11 @@ You can find more details on the [CCXT_REST github page][ccxt-rest].

[Postgres][postgres] v12.1 or later must be installed for Kelp to automatically write trades to a sql database along with updating the trader config file.

### Using Auth0

A [auth0](https://auth0.com/) account is required. To use it, uncomment \[AUTH0] section in [Sample GUI config file](examples/configs/trader/sample_GUI_config.cfg) and enter your auth0 crendentials in required fields.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 thanks!

Note: AUTH0 is only applicable for Kelp GUI or Kaas Mode. Intructions of how to configure your auth0 account can be found [here](https://auth0.com/docs/quickstart/spa/react/01-login#configure-auth0)

## Examples

It's easier to learn with examples! Take a look at the walkthrough guides and sample configuration files below.
Expand All @@ -208,6 +214,7 @@ The following reference config files are in the [examples folder](examples/confi
- [Sample Balanced strategy config file](examples/configs/trader/sample_balanced.cfg)
- [Sample Pendulum strategy config file](examples/configs/trader/sample_pendulum.cfg)
- [Sample Mirror strategy config file](examples/configs/trader/sample_mirror.cfg)
- [Sample GUI(auth0 and other stuff) config file](examples/configs/trader/sample_GUI_config.cfg)

### Winning Educational Content from StellarBattle

Expand Down Expand Up @@ -403,6 +410,7 @@ See the [Code of Conduct](CODE_OF_CONDUCT.md).
[ccxt-rest]: https://github.com/franz-see/ccxt-rest
[docker]: https://www.docker.com/
[postgres]: https://www.postgresql.org/
[auth0]: https://auth0.com/
[kelp-battle-1]: https://stellarbattle.com/kelp-overview-battle/
[kelp-battle-1-winners]: https://medium.com/stellar-community/announcing-the-winners-of-the-first-kelpbot-stellarbattle-a6f28fef7776
[kraken]: https://www.kraken.com/
Expand Down
32 changes: 32 additions & 0 deletions cmd/server_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import (
"github.com/stellar/kelp/support/prefs"
"github.com/stellar/kelp/support/sdk"
"github.com/stellar/kelp/support/utils"
"github.com/stellar/kelp/support/guiconfig"
"github.com/stellar/go/support/config"
)

const kelpAssetsPath = "/assets"
Expand Down Expand Up @@ -72,6 +74,15 @@ type serverInputOptions struct {
enableKaas *bool
tlsCertFile *string
tlsKeyFile *string
guiConfigPath *string
}

// checks for required flag on CLI
func requiredFlags(flag string) {
e := serverCmd.MarkFlagRequired(flag)
if e != nil {
panic(e)
}
}

// String is the stringer method impl.
Expand All @@ -80,6 +91,19 @@ func (o serverInputOptions) String() string {
*o.port, *o.dev, *o.devAPIPort, *o.horizonTestnetURI, *o.horizonPubnetURI, *o.noHeaders, *o.verbose, *o.noElectron, *o.disablePubnet, *o.enableKaas)
}

// function for reading custom config file and returning config struct with intilized value
func readGUIConfig(options serverInputOptions) guiconfig.GUIConfig {
var guiConfigInFunc guiconfig.GUIConfig
e := config.Read(*options.guiConfigPath, &guiConfigInFunc)
utils.CheckConfigError(guiConfigInFunc, e, *options.guiConfigPath)
if e != nil {
panic(fmt.Errorf("could not read GUI config file '%s': %s", *options.guiConfigPath, e))
}
return guiConfigInFunc
}
// customConfigVar Variable with its equivalent struct #used to inject config values to jwt config var and to configure route
var auth0ConfigVar guiconfig.GUIConfig

func init() {
options := serverInputOptions{}
options.port = serverCmd.Flags().Uint16P("port", "p", 8000, "port on which to serve HTTP")
Expand All @@ -95,6 +119,9 @@ func init() {
options.enableKaas = serverCmd.Flags().Bool("enable-kaas", false, "enable kelp-as-a-service (KaaS) mode, which does not bring up browser or electron")
options.tlsCertFile = serverCmd.Flags().String("tls-cert-file", "", "path to TLS certificate file")
options.tlsKeyFile = serverCmd.Flags().String("tls-key-file", "", "path to TLS key file")
options.guiConfigPath = serverCmd.Flags().StringP("guiconfig", "c", "", "(required) gui-config for auth0 and other basic config file path")

requiredFlags("guiconfig")

serverCmd.Run = func(ccmd *cobra.Command, args []string) {
isLocalMode := env == envDev
Expand Down Expand Up @@ -143,6 +170,10 @@ func init() {

log.Printf("initialized server with cli flag inputs: %s", options)

//calliing readGUIConfig func and then inject values into JWT_middleware customconfigvar
auth0ConfigVar = readGUIConfig(options)
backend.Auth0ConfigVarJWT = auth0ConfigVar

if runtime.GOOS == "windows" {
if !*options.noElectron {
log.Printf("input options had specified noElectron=false for windows, but electron is not supported on windows yet. force setting noElectron=true for windows.\n")
Expand Down Expand Up @@ -382,6 +413,7 @@ func init() {
*options.noHeaders,
quit,
metricsTracker,
auth0ConfigVar,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for fitting into the existing serverMetadata pattern! 🎉

)
if e != nil {
panic(e)
Expand Down
11 changes: 11 additions & 0 deletions examples/configs/trader/sample_GUI_config.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Sample UI config file for the kelp bot

# uncomment the AUTH0 section below to enable
# [AUTH0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

# AUTH0_ENABLED=false
# #auth0 domain
# DOMAIN= #"domain_goes_here" #example "dev-*******.eu.auth0.com"
# #auth0 clientID
# CLIENT_ID= #"Client_id_goes_here" #examples "7I47ob2************XKF29hY5"
# #auth0 audience
# AUDIENCE= #"Audience/Identifier goes_here"
4 changes: 4 additions & 0 deletions glide.lock

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

4 changes: 4 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import:
- clients/horizonclient
- support/config
- support/errors
- package: github.com/auth0/go-jwt-middleware
version: v1.0.0
- package: github.com/form3tech-oss/jwt-go
version: 5b2d2b5f6c34ccb3b6b65f77f4706558067690ef
##############################################################
# manually added dependencies to fix glide import resolution
##############################################################
Expand Down
4 changes: 4 additions & 0 deletions gui/backend/api_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/stellar/go/clients/horizonclient"
"github.com/stellar/kelp/plugins"
"github.com/stellar/kelp/support/kelpos"
"github.com/stellar/kelp/support/guiconfig"
)

// UserData is the json data passed in to represent a user
Expand Down Expand Up @@ -59,6 +60,7 @@ type APIServer struct {
kelpErrorsByUserLock *sync.Mutex

cachedOptionsMetadata metadata
guiConfig guiconfig.GUIConfig
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

// MakeAPIServer is a factory method
Expand All @@ -76,6 +78,7 @@ func MakeAPIServer(
noHeaders bool,
quitFn func(),
metricsTracker *plugins.MetricsTracker,
guiConfig guiconfig.GUIConfig,
) (*APIServer, error) {
kelpBinPath := kos.GetBinDir().Join(filepath.Base(os.Args[0]))

Expand All @@ -102,6 +105,7 @@ func MakeAPIServer(
metricsTracker: metricsTracker,
kelpErrorsByUser: map[string]kelpErrorDataForUser{},
kelpErrorsByUserLock: &sync.Mutex{},
guiConfig: guiConfig,
}, nil
}

Expand Down
88 changes: 88 additions & 0 deletions gui/backend/jwt_middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package backend

import (
"encoding/json"
"errors"
"net/http"
"fmt"

jwtmiddleware "github.com/auth0/go-jwt-middleware"
"github.com/form3tech-oss/jwt-go"
"github.com/stellar/kelp/support/guiconfig"
)

type Response struct {
Message string `json:"message"`
}

type Jwks struct {
Keys []JSONWebKeys `json:"keys"`
}

type JSONWebKeys struct {
Kty string `json:"kty"`
Kid string `json:"kid"`
Use string `json:"use"`
N string `json:"n"`
E string `json:"e"`
X5c []string `json:"x5c"`
}

var Auth0ConfigVarJWT guiconfig.GUIConfig

var JWTMiddlewareVar = jwtmiddleware.New(jwtmiddleware.Options{
ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
// Verify 'iss' claim
iss := "https://" + Auth0ConfigVarJWT.Auth0Config.Domain + "/"
checkIss := token.Claims.(jwt.MapClaims).VerifyIssuer(iss, false)
if !checkIss {
return token, errors.New("Invalid issuer.")
}

// Verify 'aud' claim
aud := Auth0ConfigVarJWT.Auth0Config.Audience
checkAud := token.Claims.(jwt.MapClaims).VerifyAudience(aud, false)
if !checkAud {
return token, errors.New("Invalid audience.")
}

cert, err := getPemCert(token)
if err != nil {
return nil, fmt.Errorf("error when getting PEM certificate: %s", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

result, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(cert))
return result, nil
},
SigningMethod: jwt.SigningMethodRS256,
})

func getPemCert(token *jwt.Token) (string, error) {
cert := ""
resp, err := http.Get("https://" + Auth0ConfigVarJWT.Auth0Config.Domain + "/.well-known/jwks.json")

if err != nil {
return cert, err
}
defer resp.Body.Close()

var jwks = Jwks{}
err = json.NewDecoder(resp.Body).Decode(&jwks)

if err != nil {
return cert, err
}

for k, _ := range jwks.Keys {
if token.Header["kid"] == jwks.Keys[k].Kid {
cert = "-----BEGIN CERTIFICATE-----\n" + jwks.Keys[k].X5c[0] + "\n-----END CERTIFICATE-----"
}
}

if cert == "" {
err := errors.New("Unable to find appropriate key.")
return cert, err
}

return cert, nil
}
37 changes: 21 additions & 16 deletions gui/backend/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,27 @@ func SetRoutes(r *chi.Mux, s *APIServer) {
r.Get("/serverMetadata", http.HandlerFunc(s.serverMetadata))
r.Get("/newSecretKey", http.HandlerFunc(s.newSecretKey))
r.Get("/optionsMetadata", http.HandlerFunc(s.optionsMetadata))
var router chi.Router = r
if s.guiConfig.Auth0Config != nil && s.guiConfig.Auth0Config.Auth0Enabled {
// setting the router to use the JWT middleware to handle auth0 style JWT tokens
router = r.With(JWTMiddlewareVar.Handler)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

much better, thank you!! 💯 🎉

}

r.Post("/listBots", http.HandlerFunc(s.listBots))
r.Post("/genBotName", http.HandlerFunc(s.generateBotName))
r.Post("/getNewBotConfig", http.HandlerFunc(s.getNewBotConfig))
r.Post("/autogenerate", http.HandlerFunc(s.autogenerateBot))
r.Post("/fetchKelpErrors", http.HandlerFunc(s.fetchKelpErrors))
r.Post("/removeKelpErrors", http.HandlerFunc(s.removeKelpErrors))
r.Post("/start", http.HandlerFunc(s.startBot))
r.Post("/stop", http.HandlerFunc(s.stopBot))
r.Post("/deleteBot", http.HandlerFunc(s.deleteBot))
r.Post("/getState", http.HandlerFunc(s.getBotState))
r.Post("/getBotInfo", http.HandlerFunc(s.getBotInfo))
r.Post("/getBotConfig", http.HandlerFunc(s.getBotConfig))
r.Post("/fetchPrice", http.HandlerFunc(s.fetchPrice))
r.Post("/upsertBotConfig", http.HandlerFunc(s.upsertBotConfig))
r.Post("/sendMetricEvent", http.HandlerFunc(s.sendMetricEvent))
router.Post("/listBots", http.HandlerFunc(s.listBots))
router.Post("/genBotName", http.HandlerFunc(s.generateBotName))
router.Post("/getNewBotConfig", http.HandlerFunc(s.getNewBotConfig))
router.Post("/autogenerate", http.HandlerFunc(s.autogenerateBot))
router.Post("/fetchKelpErrors", http.HandlerFunc(s.fetchKelpErrors))
router.Post("/removeKelpErrors", http.HandlerFunc(s.removeKelpErrors))
router.Post("/start", http.HandlerFunc(s.startBot))
router.Post("/stop", http.HandlerFunc(s.stopBot))
router.Post("/deleteBot", http.HandlerFunc(s.deleteBot))
router.Post("/getState", http.HandlerFunc(s.getBotState))
router.Post("/getBotInfo", http.HandlerFunc(s.getBotInfo))
router.Post("/getBotConfig", http.HandlerFunc(s.getBotConfig))
router.Post("/fetchPrice", http.HandlerFunc(s.fetchPrice))
router.Post("/upsertBotConfig", http.HandlerFunc(s.upsertBotConfig))
router.Post("/sendMetricEvent", http.HandlerFunc(s.sendMetricEvent))
})
r.Get("/ping", http.HandlerFunc(s.ping))
}
}
3 changes: 3 additions & 0 deletions gui/backend/serverMetadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ import (
"encoding/json"
"fmt"
"net/http"
"github.com/stellar/kelp/support/guiconfig"
)

// ServerMetadataResponse is the response from the /serverMetadata endpoint
type ServerMetadataResponse struct {
DisablePubnet bool `json:"disable_pubnet"`
EnableKaas bool `json:"enable_kaas"`
GuiConfig guiconfig.GUIConfig `json:"guiconfig"`
}

func (s *APIServer) serverMetadata(w http.ResponseWriter, r *http.Request) {
metadata := ServerMetadataResponse{
DisablePubnet: s.disablePubnet,
EnableKaas: s.enableKaas,
GuiConfig: s.guiConfig,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perfect! 👍

}

b, e := json.Marshal(metadata)
Expand Down
2 changes: 2 additions & 0 deletions gui/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@auth0/auth0-react": "^1.5.0",
"classnames": "^2.2.6",
"fetch-intercept": "^2.4.0",
"node-sass": "^4.11.0",
"react": "^16.8.4",
"react-dom": "^16.8.4",
Expand Down
Loading