Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with CORS and websockets #11

Closed
xXLokerXx opened this issue Aug 8, 2019 · 9 comments
Closed

Problem with CORS and websockets #11

xXLokerXx opened this issue Aug 8, 2019 · 9 comments

Comments

@xXLokerXx
Copy link

Describe the bug
I have an issue with cors, when i run it the example in 2 diferents ports (3000, 3001) and i try to conect a new socket from 3001 to 3000 then the console throw the next error:
WebSocket connection to 'ws://localhost:3001/echo?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjozMjEzMjF9.8waEX7-vPKACa-Soi1pQvW3Rl8QY-SUFcHKTLZI4mvU' failed: Error during WebSocket handshake: Unexpected response code: 403.

To Reproduce
Use the example server.go on the route: _examples/websocket/basic/

package main

import (
	"log"

	"github.com/kataras/iris"
	"github.com/kataras/iris/websocket"

	// Used when "enableJWT" constant is true:
	"github.com/iris-contrib/middleware/jwt"
)

// values should match with the client sides as well.
const enableJWT = true
const namespace = "default"

// if namespace is empty then simply websocket.Events{...} can be used instead.
var serverEvents = websocket.Namespaces{
	namespace: websocket.Events{
		websocket.OnNamespaceConnected: func(nsConn *websocket.NSConn, msg websocket.Message) error {
			// with `websocket.GetContext` you can retrieve the Iris' `Context`.
			ctx := websocket.GetContext(nsConn.Conn)

			log.Printf("[%s] connected to namespace [%s] with IP [%s]",
				nsConn, msg.Namespace,
				ctx.RemoteAddr())
			return nil
		},
		websocket.OnNamespaceDisconnect: func(nsConn *websocket.NSConn, msg websocket.Message) error {
			log.Printf("[%s] disconnected from namespace [%s]", nsConn, msg.Namespace)
			return nil
		},
		"chat": func(nsConn *websocket.NSConn, msg websocket.Message) error {
			// room.String() returns -> NSConn.String() returns -> Conn.String() returns -> Conn.ID()
			log.Printf("[%s] sent: %s", nsConn, string(msg.Body))

			// Write message back to the client message owner with:
			// nsConn.Emit("chat", msg)
			// Write message to all except this client with:
			nsConn.Conn.Server().Broadcast(nsConn, msg)
			return nil
		},
	},
}

func main() {
	app := iris.New()
	websocketServer := websocket.New(
		websocket.DefaultGorillaUpgrader, /* DefaultGobwasUpgrader can be used too. */
		serverEvents)

	j := jwt.New(jwt.Config{
		// Extract by the "token" url,
		// so the client should dial with ws://localhost:8080/echo?token=$token
		Extractor: jwt.FromParameter("token"),

		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
			return []byte("My Secret"), nil
		},

		// When set, the middleware verifies that tokens are signed
		// with the specific signing algorithm
		// If the signing method is not constant the
		// `Config.ValidationKeyGetter` callback field can be used
		// to implement additional checks
		// Important to avoid security issues described here:
		// https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
		SigningMethod: jwt.SigningMethodHS256,
	})

	idGen := func(ctx iris.Context) string {
		if username := ctx.GetHeader("X-Username"); username != "" {
			return username
		}

		return websocket.DefaultIDGenerator(ctx)
	}

	// serves the endpoint of ws://localhost:8080/echo
	// with optional custom ID generator.
	websocketRoute := app.Get("/echo", websocket.Handler(websocketServer, idGen))

	if enableJWT {
		// Register the jwt middleware (on handshake):
		websocketRoute.Use(j.Serve)
		// OR
		//
		// Check for token through the jwt middleware
		// on websocket connection or on any event:
		/* websocketServer.OnConnect = func(c *websocket.Conn) error {
		ctx := websocket.GetContext(c)
		if err := j.CheckJWT(ctx); err != nil {
			// will send the above error on the client
			// and will not allow it to connect to the websocket server at all.
			return err
		}

		user := ctx.Values().Get("jwt").(*jwt.Token)
		// or just: user := j.Get(ctx)

		log.Printf("This is an authenticated request\n")
		log.Printf("Claim content:")
		log.Printf("%#+v\n", user.Claims)

		log.Printf("[%s] connected to the server", c.ID())

		return nil
		} */
	}

	// serves the browser-based websocket client.
	app.Get("/", func(ctx iris.Context) {
		ctx.ServeFile("./browser/index.html", false)
	})

	// serves the npm browser websocket client usage example.
	app.HandleDir("/browserify", "./browserify")

	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

Expected behavior
I would like to make petitions from the 2 servers

Posible fix
To catch this i made a middleware function wich delete the origin header (but this will be a rellay bad practice), code above:

        app.Use(func(ctx iris.Context) {
		ctx.Request().Header.Del("Origin")
		ctx.Next()
	})
@kataras
Copy link
Owner

kataras commented Aug 11, 2019

@majidbigdeli I know that you are using websockets+cors middleware, so I have to ask you too, do you have the same issue with cors on websockets?

@majidbigdeli
Copy link

@kataras I have not issue with cors .

@majidbigdeli
Copy link

@xXLokerXx please change websocket.DefaultGorillaUpgrader to websocket.DefaultGobwasUpgrader it is work .

@majidbigdeli
Copy link

@kataras

WebSocket connection to 'ws://localhost:3001/echo?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjozMjEzMjF9.8waEX7-vPKACa-Soi1pQvW3Rl8QY-SUFcHKTLZI4mvU' failed: Error during WebSocket handshake: Unexpected response code: 403

it issue related to DefaultGorillaUpgrader in my test .
with DefaultGobwasUpgrader it is work .

@kataras
Copy link
Owner

kataras commented Aug 13, 2019

@xXLokerXx @majidbigdeli There is no issue with neffos at all, you don't need to delete a header or things like that, this happesn only on Gorilla websocket upgrader because it has a CheckOrigin field which by-default allows only same-origin. So the solution is to modify that to allow everything - you don't need to catch anything there - neffos + cors will do the job. The gorilla websocket's check origin is type of:

func (r *http.Request) bool

Example Code:

import "github.com/kataras/neffos"
import "github.com/kataras/neffos/gorilla"
import gorillaWs "github.com/gorilla/websocket"

// [...]
websocketServer := websocket.New(
	gorilla.Upgrader(gorillaWs.Upgrader{CheckOrigin: func(*http.Request) bool{return true}}),
	serverEvents)

Hope that helped!

@majidbigdeli
Copy link

@kataras yes . Gorilla websocket upgrader has a CheckOrigin field . Thank you.

@xXLokerXx
Copy link
Author

Yes, that help me a lot, i'll implement right now
thanks @kataras and @majidbigdeli
im really thankfully for help

@kataras
Copy link
Owner

kataras commented Aug 14, 2019

You are welcome @xXLokerXx of course!

@Kevinlinpr
Copy link

it works.

@xXLokerXx @majidbigdeli There is no issue with neffos at all, you don't need to delete a header or things like that, this happesn only on Gorilla websocket upgrader because it has a CheckOrigin field which by-default allows only same-origin. So the solution is to modify that to allow everything - you don't need to catch anything there - neffos + cors will do the job. The gorilla websocket's check origin is type of:

func (r *http.Request) bool

Example Code:

import "github.com/kataras/neffos"
import "github.com/kataras/neffos/gorilla"
import gorillaWs "github.com/gorilla/websocket"

// [...]
websocketServer := websocket.New(
	gorilla.Upgrader(gorillaWs.Upgrader{CheckOrigin: func(*http.Request) bool{return true}}),
	serverEvents)

Hope that helped!

it works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants