Browse Source

2582 Enable CORS on RPC API (#2800)

pull/2847/head
Hleb Albau 6 years ago
committed by Anton Kaliaev
parent
commit
6353862ac0
10 changed files with 82 additions and 11 deletions
  1. +2
    -0
      CHANGELOG_PENDING.md
  2. +8
    -0
      Gopkg.lock
  3. +4
    -0
      Gopkg.toml
  4. +21
    -2
      config/config.go
  5. +11
    -0
      config/toml.go
  6. +14
    -2
      node/node.go
  7. +17
    -1
      rpc/client/rpc_test.go
  8. +4
    -1
      rpc/core/doc.go
  9. +0
    -5
      rpc/lib/server/http_server.go
  10. +1
    -0
      rpc/test/helpers.go

+ 2
- 0
CHANGELOG_PENDING.md View File

@ -22,6 +22,8 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
### FEATURES:
- [rpc] [\#2582](https://github.com/tendermint/tendermint/issues/2582) Enable CORS on RPC API
### IMPROVEMENTS:
### BUG FIXES:


+ 8
- 0
Gopkg.lock View File

@ -128,6 +128,14 @@
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[[projects]]
digest = "1:b0c25f00bad20d783d259af2af8666969e2fc343fa0dc9efe52936bbd67fb758"
name = "github.com/rs/cors"
packages = ["."]
pruneopts = "UT"
revision = "9a47f48565a795472d43519dd49aac781f3034fb"
version = "v1.6.0"
[[projects]]
digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8"
name = "github.com/hashicorp/hcl"


+ 4
- 0
Gopkg.toml View File

@ -40,6 +40,10 @@
name = "github.com/gorilla/websocket"
version = "=1.2.0"
[[constraint]]
name = "github.com/rs/cors"
version = "1.6.0"
[[constraint]]
name = "github.com/pkg/errors"
version = "=0.8.0"


+ 21
- 2
config/config.go View File

@ -242,6 +242,18 @@ type RPCConfig struct {
// TCP or UNIX socket address for the RPC server to listen on
ListenAddress string `mapstructure:"laddr"`
// A list of origins a cross-domain request can be executed from.
// If the special '*' value is present in the list, all origins will be allowed.
// An origin may contain a wildcard (*) to replace 0 or more characters (i.e.: http://*.domain.com).
// Only one wildcard can be used per origin.
CORSAllowedOrigins []string `mapstructure:"cors_allowed_origins"`
// A list of methods the client is allowed to use with cross-domain requests.
CORSAllowedMethods []string `mapstructure:"cors_allowed_methods"`
// A list of non simple headers the client is allowed to use with cross-domain requests.
CORSAllowedHeaders []string `mapstructure:"cors_allowed_headers"`
// TCP or UNIX socket address for the gRPC server to listen on
// NOTE: This server only supports /broadcast_tx_commit
GRPCListenAddress string `mapstructure:"grpc_laddr"`
@ -269,8 +281,10 @@ type RPCConfig struct {
// DefaultRPCConfig returns a default configuration for the RPC server
func DefaultRPCConfig() *RPCConfig {
return &RPCConfig{
ListenAddress: "tcp://0.0.0.0:26657",
ListenAddress: "tcp://0.0.0.0:26657",
CORSAllowedOrigins: []string{},
CORSAllowedMethods: []string{"HEAD", "GET", "POST"},
CORSAllowedHeaders: []string{"Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time"},
GRPCListenAddress: "",
GRPCMaxOpenConnections: 900,
@ -300,6 +314,11 @@ func (cfg *RPCConfig) ValidateBasic() error {
return nil
}
// IsCorsEnabled returns true if cross-origin resource sharing is enabled.
func (cfg *RPCConfig) IsCorsEnabled() bool {
return len(cfg.CORSAllowedOrigins) != 0
}
//-----------------------------------------------------------------------------
// P2PConfig


+ 11
- 0
config/toml.go View File

@ -119,6 +119,17 @@ filter_peers = {{ .BaseConfig.FilterPeers }}
# TCP or UNIX socket address for the RPC server to listen on
laddr = "{{ .RPC.ListenAddress }}"
# A list of origins a cross-domain request can be executed from
# Default value '[]' disables cors support
# Use '["*"]' to allow any origin
cors_allowed_origins = "{{ .RPC.CORSAllowedOrigins }}"
# A list of methods the client is allowed to use with cross-domain requests
cors_allowed_methods = "{{ .RPC.CORSAllowedMethods }}"
# A list of non simple headers the client is allowed to use with cross-domain requests
cors_allowed_headers = "{{ .RPC.CORSAllowedHeaders }}"
# TCP or UNIX socket address for the gRPC server to listen on
# NOTE: This server only supports /broadcast_tx_commit
grpc_laddr = "{{ .RPC.GRPCListenAddress }}"


+ 14
- 2
node/node.go View File

@ -13,8 +13,9 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rs/cors"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/go-amino"
abci "github.com/tendermint/tendermint/abci/types"
bc "github.com/tendermint/tendermint/blockchain"
cfg "github.com/tendermint/tendermint/config"
@ -651,9 +652,20 @@ func (n *Node) startRPC() ([]net.Listener, error) {
wm.SetLogger(rpcLogger.With("protocol", "websocket"))
mux.HandleFunc("/websocket", wm.WebsocketHandler)
rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, coreCodec, rpcLogger)
var rootHandler http.Handler = mux
if n.config.RPC.IsCorsEnabled() {
corsMiddleware := cors.New(cors.Options{
AllowedOrigins: n.config.RPC.CORSAllowedOrigins,
AllowedMethods: n.config.RPC.CORSAllowedMethods,
AllowedHeaders: n.config.RPC.CORSAllowedHeaders,
})
rootHandler = corsMiddleware.Handler(mux)
}
listener, err := rpcserver.StartHTTPServer(
listenAddr,
mux,
rootHandler,
rpcLogger,
rpcserver.Config{MaxOpenConnections: n.config.RPC.MaxOpenConnections},
)


+ 17
- 1
rpc/client/rpc_test.go View File

@ -2,6 +2,7 @@ package client_test
import (
"fmt"
"net/http"
"strings"
"testing"
@ -11,7 +12,7 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/rpc/client"
rpctest "github.com/tendermint/tendermint/rpc/test"
"github.com/tendermint/tendermint/rpc/test"
"github.com/tendermint/tendermint/types"
)
@ -32,6 +33,21 @@ func GetClients() []client.Client {
}
}
func TestCorsEnabled(t *testing.T) {
origin := rpctest.GetConfig().RPC.CORSAllowedOrigins[0]
remote := strings.Replace(rpctest.GetConfig().RPC.ListenAddress, "tcp", "http", -1)
req, err := http.NewRequest("GET", remote, nil)
require.Nil(t, err, "%+v", err)
req.Header.Set("Origin", origin)
c := &http.Client{}
resp, err := c.Do(req)
defer resp.Body.Close()
require.Nil(t, err, "%+v", err)
assert.Equal(t, resp.Header.Get("Access-Control-Allow-Origin"), origin)
}
// Make sure status is correct (we connect properly)
func TestStatus(t *testing.T) {
for i, c := range GetClients() {


+ 4
- 1
rpc/core/doc.go View File

@ -12,7 +12,10 @@ See it here: https://github.com/tendermint/tendermint/tree/master/rpc/lib
## Configuration
Set the `laddr` config parameter under `[rpc]` table in the `$TMHOME/config/config.toml` file or the `--rpc.laddr` command-line flag to the desired protocol://host:port setting. Default: `tcp://0.0.0.0:26657`.
RPC can be configured by tuning parameters under `[rpc]` table in the `$TMHOME/config/config.toml` file or by using the `--rpc.X` command-line flags.
Default rpc listen address is `tcp://0.0.0.0:26657`. To set another address, set the `laddr` config parameter to desired value.
CORS (Cross-Origin Resource Sharing) can be enabled by setting `cors_allowed_origins`, `cors_allowed_methods`, `cors_allowed_headers` config parameters.
## Arguments


+ 0
- 5
rpc/lib/server/http_server.go View File

@ -151,11 +151,6 @@ func RecoverAndLogHandler(handler http.Handler, logger log.Logger) http.Handler
rww := &ResponseWriterWrapper{-1, w}
begin := time.Now()
// Common headers
origin := r.Header.Get("Origin")
rww.Header().Set("Access-Control-Allow-Origin", origin)
rww.Header().Set("Access-Control-Allow-Credentials", "true")
rww.Header().Set("Access-Control-Expose-Headers", "X-Server-Time")
rww.Header().Set("X-Server-Time", fmt.Sprintf("%v", begin.Unix()))
defer func() {


+ 1
- 0
rpc/test/helpers.go View File

@ -84,6 +84,7 @@ func GetConfig() *cfg.Config {
tm, rpc, grpc := makeAddrs()
globalConfig.P2P.ListenAddress = tm
globalConfig.RPC.ListenAddress = rpc
globalConfig.RPC.CORSAllowedOrigins = []string{"https://tendermint.com/"}
globalConfig.RPC.GRPCListenAddress = grpc
globalConfig.TxIndex.IndexTags = "app.creator,tx.height" // see kvstore application
}


Loading…
Cancel
Save