Search code examples
ioscouchbase-lite

What is proper way to setup auth layer for CouchbaseLite (CBLListener and CBLReplication) for p2p database replication?


I am trying to configure basic login / password authentication for p2p replication.
Replication works fine with no authentication. So I pretty sure my issue relates to authentication configuration.

CBListener configuration:

login = "my_login"
password = "my_password"

listener = CBLListener(manager: CBLManager.sharedInstance(), port: 55555)
listener.setBonjourName(netServiceName, type: netServiceType)
listener.readOnly = true
listener.setPasswords([login : password])
try! listener.start()

CBLReplication configuration:

let netService: NetService = ... // Got from NetServiceBrowserDelegate and NetServiceDelegate

let components = NSURLComponents()
components.scheme = "http"
components.host = netService.hostName
components.port = NSNumber(value: 55555)
components.path = "/" + database.name
components.user = login
components.password = password    

let newReplication = database.createPullReplication(components.url!)
newReplication.continuous = true
newReplication.start()

Here is what I am getting in Xcode console:

CBLRestPuller[http://my_login:*****@Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Going online

CBLRestPuller[http://my_login:*****@Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: No local checkpoint; not getting remote one

CBLRestPuller[http://my_login:*****@Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net] Progress: set active = 1

CBLReplication[from http://my_login:*****@Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: active, progress = 0 / 0, err: (null) nil

CBLRestPuller[http://my_login:*****@Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Reachability state = :reachable (20002), suspended=0

: HTTP auth failed; sent Authorization: Basic bXlfbG9naW46bXlfcGFzc3dvcmQ= ; got WWW-Authenticate: Digest realm="CouchbaseLite", qop="auth", nonce="69773230-683C-4DCC-AB40-A21527A1F911"

CBLSocketChangeTracker[0x127d63810 sg_to_firstfoundry_net]: Can't connect, giving up: CBLHTTP[401, http://my_login:*****@Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_changes?feed=normal&heartbeat=300000&style=all_docs]<--NSURLError[-1013, http://my_login:*****@Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_changes?feed=normal&heartbeat=300000&style=all_docs]

CBLRestPuller[http://my_login:*****@Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: ChangeTracker stopped; error=CBLHTTP[401, http://my_login:*****@Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_changes?feed=normal&heartbeat=300000&style=all_docs]<--NSURLError[-1013, http://my_login:*****@Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_changes?feed=normal&heartbeat=300000&style=all_docs]

I think the most important log here is this line:

: HTTP auth failed; sent Authorization: Basic bXlfbG9naW46bXlfcGFzc3dvcmQ= ; got WWW-Authenticate: Digest realm="CouchbaseLite", qop="auth", nonce="69773230-683C-4DCC-AB40-A21527A1F911"

Alternatively I tried to use CBLAuthenticator instead of injecting login/password into url. Still doesn't work, however I am getting different error messages in log:
What is changed:

// Added:
newReplication.authenticator = CBLAuthenticator.basicAuthenticator(withName: login, password: password)

// Removed:
components.user = login 
components.password = password

Here is what I am getting in Xcode console after updating the code:

CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Going online

CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net] Progress: set active = 1

CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Successfully logged in!

RemoteRequest: Added Authorization header for CBLPasswordAuthorizer[my_login/****]

CBLRemoteJSONRequest[GET http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]: Starting...

DEALLOC CBLRemoteLogin[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net] 2017-02-20 16:51:28.335 Union Dev[1922:1702832] RemoteRequest: CBLRemoteSession starting CBLRemoteJSONRequest[GET http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]

Sync: CBLReplication[from http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: active, progress = 0 / 0, err: (null) nil

CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Reachability state = :reachable (20002), suspended=0

RemoteRequest: Got challenge for CBLRemoteJSONRequest[GET http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]: method=NSURLAuthenticationMethodHTTPDigest, err=(null)

RemoteRequest: challenge: (phase 3) continueWithoutCredential

Sync: CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Server is (null)

RemoteRequest: CBLRemoteJSONRequest[GET http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]: Got response, status 401

CBLRemoteJSONRequest[GET http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]: Got error CBLHTTP[401, "unauthorized", http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]

Sync: CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Error fetching last sequence: CBLHTTP[401, "unauthorized", http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]

Sync: CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net] Progress: set error = CBLHTTP[401, "unauthorized", http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]

Could anybody point me to place where I am doing something wrong?


Solution

  • After having conversation with Couchbase engineers it was decided that the best solution here is to enable secure http connection, since it doesn't make sense to send login / password through insecure http request.

    The easiest (not most secure) way to enable https is to do next:

    // Change url to https
    components.scheme = "https"
    
    // Inject self-signed generated on the fly certificate into CBLListener
    try listener.setAnonymousSSLIdentityWithLabel("use_any_string_here")
    

    More information about configuring https connection for p2p replication is available here.