Repository: bokeh/bokeh

Issue:
Accept server connections from any origin
I get errors like the following from my bokeh server application:

    bokeh.server.views.ws - ERROR - Refusing websocket connection from Origin 'http://127.0.0.1:8789';                       use --allow-websocket-origin=127.0.0.1:8789 to permit this; currently we allow origins {'localhost:8789'}

There may be two problems here:

1.  (minor) localhost is often synonymous with 127.0.0.1.  It might be good to whitelist 127.0.0.1 generally.
2.  (major) I have started my Bokeh server with the argument `Server(..., host=['*'])` which in previous versions ensured that my server could be accessed regardless of what the caller called my server address.  

The second point is more important to me (and to others).  It is critical in many applications to be able to robustly view a bokeh server even if we don't know, at the time of setting up the server, what that server's address will be.  This was the intent of https://github.com/bokeh/bokeh/pull/4052 

```python
In [2]: bokeh.__version__
Out[2]: '0.12.5dev15'
```


Discussion:
@mrocklin in `0.12.5` the `host` argument is no longer needed, and is now completely ignored. (It hasn't been completely removed, so as not to break people's code unnecessarily) See

https://github.com/bokeh/bokeh/pull/5979

What you may possibly need if you are running the server programmatically, and using `autoload_server` to embed the output into a page from some *other* app server (e.g. a Flask page), is to pass `relative_urls=False`:

https://github.com/bokeh/bokeh/blob/master/examples/howto/server_embed/flask_embed.py#L42

So I'm not sure what you are asking for with bullet 2? The message you are seeing is purely about ws connections, and not at all about host whitelisting (which does not happen anymore at all, we scrubbed the codebase of any use of `request.host` so it is no longer a necessary precaution)

I think adding both `localhost` and `127.0.0.1 ` could be simple and reasonable tho I am not aware of any recent change that could cause bokeh to care about the distinction. It would be good to know  what if any change in bokeh precipitated this. 
I'm not using any other system like Flask.  I'm only using Bokeh.  Here is how I start bokeh servers:

https://github.com/dask/distributed/blob/master/distributed/bokeh/core.py#L18-L25

```python
                self.server = Server(self.apps, io_loop=self.loop,
                                     port=port, address=ip, host=['*'],
                                     check_unused_sessions_milliseconds=500,
                                     )
                    self.server.start()
```

Then, when I connect to my server from a web browser using a hostname like `myhostname:myport/mypage` things fail unless myhostname is set to localhost.
@bryevdv and I chatted about this privately.  On my side I can add `allow_websocket_origin=["*"]` to my application.  Bokeh *may* dump the old `hosts=` keyword into `allow_websocket_origin=` to facilitate a smoother transition if developer time allows.

My fix in Dask is here: https://github.com/dask/distributed/pull/957
After discussion with @mrocklin the problem was discovered. Previously `--host=*` updated the host whitelist, but it *also* updated the `allow_websocket_origin` as a side effect. Now that it is completely ignored, anything that relied on `--host=whatever` to allow ws connections too, will have a probelm.

So the proposal is this:

Don't *completely* ignore `host`. But simply  immediately transfer its contents to the `allow_websocket_origin` so that old usages will not break. The deprecation message should be updated to reflect that `--allow_websocket_origin` may now be explicitly needed. 
@bokeh/dev this seems important I intend to try to make a very small PR for it 

Resolving patch:
diff --git a/bokeh/command/subcommands/serve.py b/bokeh/command/subcommands/serve.py
--- a/bokeh/command/subcommands/serve.py
+++ b/bokeh/command/subcommands/serve.py
@@ -311,6 +311,20 @@
     DEFAULT_LOG_FORMAT=DEFAULT_LOG_FORMAT
 )
 
+def _fixup_deprecated_host_args(args):
+    if args.host is not None and len(args.host) > 0:
+        if args.allow_websocket_origin is None:
+            args.allow_websocket_origin = []
+        args.allow_websocket_origin += args.host
+        args.allow_websocket_origin = list(set(args.allow_websocket_origin))
+        warnings.warn(
+            "The --host parameter is deprecated because it is no longer needed. "
+            "It will be removed and trigger an error in a future release. "
+            "Values set now will be copied to --allow-websocket-origin. "
+            "Depending on your use case, you may need to set current --host "
+            "values for 'allow_websocket_origin' instead."
+        )
+
 base_serve_args = (
     ('--port', dict(
         metavar = 'PORT',
@@ -380,7 +394,7 @@ class Serve(Subcommand):
             metavar='HOST[:PORT]',
             action='append',
             type=str,
-            help="*** IGNORED, NO LONGER USED OR NECESSARY ***",
+            help="*** DEPRECATED ***",
         )),
 
         ('--prefix', dict(
@@ -459,8 +473,8 @@ def invoke(self, args):
         log_level = getattr(logging, args.log_level.upper())
         basicConfig(level=log_level, format=args.log_format)
 
-        if args.host is not None and len(args.host) > 0:
-            warnings.warn("The --hosts parameter is no longer needed or necessary and is ignored. It will be removed and trigger an error in a future release")
+        # This should remain here until --host is removed entirely
+        _fixup_deprecated_host_args(args)
 
         if len(applications) == 0:
             # create an empty application by default
diff --git a/bokeh/server/server.py b/bokeh/server/server.py
--- a/bokeh/server/server.py
+++ b/bokeh/server/server.py
@@ -27,9 +27,10 @@ def _create_hosts_whitelist(host_list, port):
     hosts = []
     for host in host_list:
         if '*' in host:
-            log.warning('Host wildcard %r can expose the application to HTTP '
-                        'host header attacks. Host wildcard should only be '
-                        'used for testing purpose.', host)
+            log.warning(
+                "Host wildcard %r will allow websocket connections originating "
+                "from multiple (or possibly all) hostnames or IPs. Use non-wildcard "
+                "values to restrict access explicitly", host)
         if host == '*':
             # do not append the :80 port suffix in that case: any port is
             # accepted


Test patch:
diff --git a/bokeh/command/subcommands/tests/test_serve.py b/bokeh/command/subcommands/tests/test_serve.py
--- a/bokeh/command/subcommands/tests/test_serve.py
+++ b/bokeh/command/subcommands/tests/test_serve.py
@@ -94,7 +94,7 @@ def test_args():
             metavar='HOST[:PORT]',
             action='append',
             type=str,
-            help="*** IGNORED, NO LONGER USED OR NECESSARY ***",
+            help="*** DEPRECATED ***",
         )),
 
         ('--prefix', dict(
@@ -193,6 +193,49 @@ def check_error(args):
         pytest.fail("command %s unexpected successful" % (cmd,))
     return out
 
+def test__fixup_deprecated_host_args():
+    from argparse import Namespace
+
+    args = Namespace(host=None, allow_websocket_origin=None)
+    scserve._fixup_deprecated_host_args(args)
+    assert args.allow_websocket_origin == None
+
+    args = Namespace(host=[], allow_websocket_origin=None)
+    scserve._fixup_deprecated_host_args(args)
+    assert args.allow_websocket_origin == None
+
+    args = Namespace(host=[], allow_websocket_origin=[])
+    scserve._fixup_deprecated_host_args(args)
+    assert set(args.allow_websocket_origin) == set([])
+
+    args = Namespace(host=['*'], allow_websocket_origin=[])
+    scserve._fixup_deprecated_host_args(args)
+    assert set(args.allow_websocket_origin) == set(['*'])
+
+    args = Namespace(host=['*'], allow_websocket_origin=['*'])
+    scserve._fixup_deprecated_host_args(args)
+    assert set(args.allow_websocket_origin) == set(['*'])
+
+    args = Namespace(host=['*'], allow_websocket_origin=['*', 'foo'])
+    scserve._fixup_deprecated_host_args(args)
+    assert set(args.allow_websocket_origin) == set(['*', 'foo'])
+
+    args = Namespace(host=[], allow_websocket_origin=['*'])
+    scserve._fixup_deprecated_host_args(args)
+    assert set(args.allow_websocket_origin) == set(['*'])
+
+    args = Namespace(host=[], allow_websocket_origin=['*', 'foo'])
+    scserve._fixup_deprecated_host_args(args)
+    assert set(args.allow_websocket_origin) == set(['*', 'foo'])
+
+    args = Namespace(host=None, allow_websocket_origin=['*'])
+    scserve._fixup_deprecated_host_args(args)
+    assert set(args.allow_websocket_origin) == set(['*'])
+
+    args = Namespace(host=None, allow_websocket_origin=['*', 'foo'])
+    scserve._fixup_deprecated_host_args(args)
+    assert set(args.allow_websocket_origin) == set(['*', 'foo'])
+
 def test_host_not_available():
     host = "8.8.8.8"
     out = check_error(["--address", host])