Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent Authentication popup 401 with CouchDB PouchDB

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?!

like image 347
sleidig Avatar asked Sep 19 '15 16:09

sleidig


2 Answers

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.

like image 170
sleidig Avatar answered Sep 28 '22 08:09

sleidig


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.

like image 31
TylerDurden Avatar answered Sep 28 '22 07:09

TylerDurden