Prevent Authentication popup 401 with CouchDB PouchDB
Asked Answered
B

3

5

For a JavaScript web app (AngularJS based) I am using PouchDB replicating a CouchDB database on my server. Authentication in PouchDB works nicely with pouchdb-authentication. I want to manage this through a html/js login screen.

However, if the user enters wrong credentials, I receive a 401 Unauthorized from the CouchDB server that causes a browser popup asking for credentials.

How can I prevent this ugly Authentication popup and just handle everything from my javascript?!

Byrdie answered 19/9, 2015 at 16:29 Comment(1)
would you mind marking one of the answers as accepted solution?Inwrap
B
5

I finally found the solution:

Edit the CouchDB config local.ini and change the HTTP Header sent in response:

WWW-Authenticate = Other realm="app"

Originally this is

WWW-Authenticate = Basic realm="administrator"

or if it is commented, that's what is sent out anyway. The WWW-Authenticate = Basic apparently causes the browser to handle (failed) authentication by showing its modal. Changing Basic to anything else makes the browser ignore it and you can deal with the login yourself.

Byrdie answered 19/9, 2015 at 16:29 Comment(2)
Although this doesn't cause the modal to show up, you can't login to fauxton anymore, it seems.Dimorphous
Yes, you are right - I also had problems using futon with those changes. After logging in on my own app, I was also authenticated for Futon howeverByrdie
I
4

Update 2015.12.18

After a lot of testing I arrived at the second solution outlined. All you need to do is install nginx with the headers-more-module. Add the following to your nginx-config:

location / {

    # forward all request headers to backend
    proxy_pass_request_headers on;

    # these settings come from the CouchDB wiki
    proxy_set_header    Host               $host;
    proxy_set_header    X-Real-IP          $remote_addr;
    proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;

    # your CouchDB backend
    proxy_pass http://127.0.0.1:5984;

    # replace WWW-Authenticate header in response if authorization failed
    more_set_headers -s 401 'WWW-Authenticate: Other realm="App"';
}

# location to handle access to Futon
location /_utils/ {

    # forward all request headers to backend
    proxy_pass_request_headers on;

    # these settings come from the CouchDB wiki
    proxy_set_header    Host               $host;
    proxy_set_header    X-Real-IP          $remote_addr;
    proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;

    # your CouchDB backend
    proxy_pass http://127.0.0.1:5984;

    # DO NOT replace WWW-Authenticate header in response if authorization failed
    # more_set_headers -s 401 'WWW-Authenticate: Other realm="App"';

    # Handle redirects
    proxy_redirect default;
}

And your are set. You can continue using pouchdb-authentication or write your own login handler.

Original Post

Sorry to answer, but I cannot comment (yet).

I suffer from the same problem, even worse that on OS X the WWW-Authenticate parameter is lower-cased on every restart of CouchDB and therefore not recognized any more. Therefore it has to be set after EACH restart using Futon/Fauxton or the API.

You could try and play with the next parameter (see http://docs.couchdb.org/en/1.6.1/api/server/authn.html). In principle you send your auth-request to (example in angular2):

// assuming you bootstrapped HTTP_PROVIDERS and injected Http

// configure headers
let headers: Headers = new Headers()
headers.append('Content-Type', 'application/json')
headers.append('Accept', 'application/json')
headers.append('Authorization', 'Basic ' + window.btoa(username + ':' + password))

// using the injected Http instance
this.http
// post to _session specifying next and the redirect
.post(
  'http://localhost:5984/_session?next=/successfullyLoggedInPage'
  , JSON.stringify({'name': username, 'password': password})
  , {headers: headers}
)
.map((res: Response) => res.json())
.subscribe(
  (res) => {
    // successful auth
  },
  (err) => {
    if (err.status === 401) // failed auth
  }
)

In my setup the web-app and CouchDB are served from two different origins. I can only get this working if I disable web-security in Chrome due to cross-origin restrictions. I believe a reverse proxy could rewrite the redirect response, e. g. using nginx's proxy_redirect (http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect).

I believe the best solution is to modify the response headers by a reverse proxy. For nginx there is a module called ngx_headers_more (see https://github.com/openresty/headers-more-nginx-module#readme) which should be able to do this. One could check for 401 responses and then modify the header from Authentication: Basic to Authentication: Other, therefore disabling the modal. In principle Futon/Fauxton should still work then, no? I haven't tried this approach yet but in the location block of nginx you need to specify

more_set_headers -s 401 'WWW-Authenticate: Other realm="App"'

I hope someone more qualified can add his/her two cents.

Inwrap answered 17/12, 2015 at 23:55 Comment(0)
C
1

I was having more or less the same problem. Though I am using a reverse proxy with the 'proxy' authentication handler of CouchDB. When the user tries to do something that he is not allowed to (creating a DB while he is not an admin), a 401 response was returned by CouchDB, triggering HTTP basic auth. Not so nice, as the reverse proxy handles authentication based on X509 client certificates. I actually think that CouchDB should return a 403 response, but that's a different discussion.

To fix it, I used your answers, but I am not so eager to use an external Nginx module (ngx_headers_more) and actually am not so fond of changing the header to a 'nonsense' value. Instead, with the existing proxy module in Nginx, you can just remove the WWW-Authenticate all together:

proxy_pass              http://${COUCHDB_HOSTNAME}:${COUCHDB_PORT};
proxy_hide_header       WWW-Authenticate;

Seems to be working fine. See https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header for its documentation.

Coats answered 20/5, 2017 at 14:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.