Problems using authentication with OpenID connect

Hi again,

We’re really struggling with the implementation of couchbase lite in our mobile application with authentication using OpenID (as described in the documentation here [here]). Our mobile application is built in Xamarin.Forms.

We have a ASP.NET Core backend with IdentityServer4 for handling our tokens. The CB SG is configured to use the backend for getting the tokens. It seems to work fine, here’s some rows from the SG logfile:

We have followed the guide described in the documentation (see the link above) and our authentication flow is as follows:

  1. Initialization of the Authentication object. The OIDCCallback object is created and opens a webview in a new view controller with its loginUrl as a parameter (the OIDCLoginContinuation object is stored for later use).
  2. The webview displays the login and consent form.
  3. When the callback (containing the authorization code) is obtained, the webview is closed.
  4. The initial view takes the returning redirectUrl and calls the OIDCLoginContinuation object.
  5. The redirectUrl is invoked on the OIDCLoginContinuation object (Continuation?.Invoke(new Uri(redirectUrl), null)).
  6. The flow ends.

In some point, our client receives a ID token from the SG, but it’s being printed out I raw json (see the image below).

My questions:
Our authentication flow is obviously flawed; how should this be implemented? How do we receive, and use, the ID token? Hopefully you understand our problem and can give us some pointers.

Thanks!

It looks like it is already being used. If it weren’t, then no call to _oidc_callback would have been attempted. That call contains the ID token inside of it (it is redacted in the log, but it is the part that says code=****) . The only issue seems to be the web view. You must manually close it or it will display the contents like this (there is no way for the library to tell the web view to stop this). When you passed the redirect URL to the continuation, it also fetched the contents and parsed and stored them so your job is done. Is replication failing?

Thanks for making things clear, @borrrden.

Is replication failing?

Strangely, our replication won’t pull on port 4984, but pushing works fine. We switched to port 4985 (temporarly exposed it) and both the puller and the pusher works fine on that port. I’ve seen some other threads with people with the same problem as me (no pull on port 4984). Is this a bug?
We are using couchbase through Microsoft Azure and the SG version is 1.3.

Thanks.

@priya.rajagopal, @jens maybe you know what’s up with the pull on port 4984? As I said before, pushing of locally created documents works fine. Both pulling and pushing works on port 4985.

Did you try directly posting documents to the SGW via curl or some other http client via the PUBLIC POST API ? Want to see if it’s an issue with the app or if its a port configuration issue.

And of course, please share relevant logs . Can you share both the SGW logs (enable sync logging ) and Couchbase Lite logs.

Please share your SGW configuration file as well.

We have tried some with Postman, with the same result… Here are the SGW config file, log, and a crude snippet of our client code.

Config:
{
“interface”:":4984",
“adminInterface”: “127.0.0.1:4985”,
“log”: [""],
“CORS”: {
“Origin”:["
"],
“LoginOrigin”:["*"],
“Headers”:[“Content-Type”],
“MaxAge”: 1728000
},
“databases”:{
“mydatabase”:{
“server”:"<server_host>",
“bucket”:"<bucket_name<",
“username”:"",
“password”:"",
“enable_shared_bucket_access”: true,
“continuous”:true,
“import_docs”: “continuous”,
“sync”:function(doc) { channel(doc.channels); },
“oidc”: {
“providers”: {
"": {
“issuer”:"",
“client_id”:"<client_id>",
“validation_key”:"",
“register”:true
}
}
},
“users”: {
“GUEST”: {
“disabled”:true
}
}
}
}
}

SGW Log
2018-02-05T15:22:48.996Z OIDC+: AuthenticateJWT called with token: eyJhbGciOiJSUzI1NiIsImtpZCI6IjYwNzgzNm…kNzQ2IiwiCbcA_xWgXThtP837aR-Gxw
2018-02-05T15:22:48.996Z OIDC+: JWT issuer: , audiences: [xxx]
2018-02-05T15:22:48.996Z OIDC+: Call GetProviderForIssuer w/ providers: map[xxxx:0xc4201d00c0]
2018-02-05T15:22:48.996Z OIDC+: GetProviderForIssuer with issuer: , audiences: [xxx]
2018-02-05T15:22:48.996Z OIDC+: Provider matches, returning
2018-02-05T15:22:48.996Z OIDC+: Provider for issuer: &{JWTOptions:{ValidationKey: SigningMethod:} Issuer: Register:true ClientID:0xc42000f460 ValidationKey:0xc42000f480 CallbackURL: DisableSession:false Scope:[openid email profile] IncludeAccessToken:false UserPrefix: DiscoveryURI: DisableConfigValidation:false OIDCClient: OIDCClientOnce:{m:{state:0 sema:0} done:0} IsDefault:true Name:xxxx}
2018-02-05T15:22:49.007Z OIDC: Not synchronizing provider config for issuer …
2018-02-05T15:22:49.025Z OIDC+: JWT identity: &{ID:6fb24dd3-d5c5-4124-84d1-f2c52e1bab36 Name: Email: ExpiresAt:2018-02-05 15:27:43 +0000 UTC}
2018-02-05T15:22:49.025Z OIDC+: OIDCUsername: xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf
2018-02-05T15:22:49.026Z HTTP: #001: POST /xxxx/_session (as xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-05T15:22:49.026Z WARNING: Couldn’t parse JSON in HTTP request: EOF – db.ReadJSONFromMIME() at attachment.go:224
2018-02-05T15:22:49.026Z HTTP+: #001: --> 200 (30.3 ms)
2018-02-05T15:22:51.704Z HTTP: #002: GET /xxxx/_changes?feed=websocket (as xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-05T15:22:51.704Z HTTP+: #002: --> 101 Upgraded to WebSocket protocol (0.0 ms)
2018-02-05T15:22:51.816Z Changes+: Int sequence multi changes feed…
2018-02-05T15:22:51.816Z Changes: MultiChangesFeed(channels: {}, options: {Since:0 Limit:0 Conflicts:true IncludeDocs:false Wait:true Continuous:true Terminator:0xc4203f0d20 HeartbeatMs:300000 TimeoutMs:300000 ActiveOnly:true}) … (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-05T15:22:51.817Z Changes+: MultiChangesFeed: channels expand to “!:1” … (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-05T15:22:51.817Z Cache: Initialized cache for channel “!” with options: &{ChannelCacheMinLength:50 ChannelCacheMaxLength:500 ChannelCacheAge:1m0s}
2018-02-05T15:22:51.817Z Cache: getCachedChanges("!", 0) --> 0 changes valid from #36
2018-02-05T15:22:51.817Z Cache: Querying ‘channels’ view for “!” (start=#1, end=#36, limit=0)
2018-02-05T15:22:51.884Z Cache: Got no rows from view for “!“
2018-02-05T15:22:51.884Z Cache: GetChangesInChannel(”!”) --> 0 rows
2018-02-05T15:22:51.884Z Changes+: [changesFeed] Found 0 changes for channel !
2018-02-05T15:22:51.884Z Changes+: MultiChangesFeed waiting… (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-05T15:22:51.884Z Changes+: No new changes to send to change listener. Waiting for “xxxx”'s count to pass 5
2018-02-05T15:22:57.143Z HTTP: #003: GET /xxxx/_changes?feed=websocket (as xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-05T15:22:57.143Z HTTP+: #003: --> 101 Upgraded to WebSocket protocol (0.0 ms)
2018-02-05T15:22:57.212Z Changes+: Int sequence multi changes feed…
2018-02-05T15:22:57.213Z Changes: MultiChangesFeed(channels: {
}, options: {Since:0 Limit:0 Conflicts:true IncludeDocs:false Wait:true Continuous:true Terminator:0xc420374fc0 HeartbeatMs:300000 TimeoutMs:300000 ActiveOnly:false}) … (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-05T15:22:57.213Z Changes+: MultiChangesFeed: channels expand to “!:1” … (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-05T15:22:57.213Z Cache: getCachedChanges("!", 0) --> 0 changes valid from #1
2018-02-05T15:22:57.213Z Changes+: [changesFeed] Found 0 changes for channel !
2018-02-05T15:22:57.213Z Changes+: MultiChangesFeed waiting… (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-05T15:22:57.213Z Changes+: No new changes to send to change listener. Waiting for “xxxx”'s count to pass 5

Client code snippet

PullReplication = _database.CreatePullReplication(_sgUri);
PullReplication.SetCookie(“SyncGatewaySession”, session.Id, session.Path, session.ExpiresAt, false, false);
PullReplication.Continuous = true;
PullReplication.Changed += OnChanged;

PushReplication = _database.CreatePushReplication(_sgUri);
PushReplication.SetCookie("SyncGatewaySession", session.Id, session.Path, session.ExpiresAt, false, false);
PushReplication.Continuous = true;
PushReplication.Changed += OnChanged;


PushReplication.Start();
PullReplication.Start();

Here’s the result from Postman:

{
    "authentication_handlers": [
        "default",
        "cookie"
    ],
    "ok": true,
    "userCtx": {
        "channels": {
            "!": 1
        },
        "name": "xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf"
    }
}

Sorry for the bad formatting in the previous post…

Seems like something may be amiss when creating the user session but from that postman response, it seems like you got a 200 OK for this . Can you share the exact request that was attempted

What was the request and what was the response ?

Maybe it’s a bug in CBL .Net? (WARNING: Couldn’t parse JSON in HTTP request: EOF – db.ReadJSONFromMIME() at attachment.go:224). I saw @borrrden mention this in another thread: Replication with Custom Auth in CB Lite.net 2.0 DB020

A little update; it seems I can avoid the warning by sending an empty Json body in the session post request (instead of null).

var response = await httpClient.PostAsync(sessionUri, new StringContent(""));

The problem remains however… Nothing is pulled.

Well - your entire endpoint is redacted so I don’t know what you were attempting to do. Are you trying to create a document ?

I’m trying to create an OpenID Connect session with Couchbase and then pull my documents… I don’t know how to be clearer than this (I have no more logs/code to show).

What do you mean by redacted? I have only masked the private parts of the data. Here’s the endpoint (altough masked):
http://vm0.syncgateway-xxxx.northeurope.cloudapp.azure.com:4984/mydatabase/_session

Well- I had suggested that you try to create the document via the the SGW REST POST API and see if you are able to do that over port 4984.

Your entire request endpoint was redacted . I couldn’t see what you were attempting to do. Looks like you are creating a _session. Did you try using the REST API to post a document as suggested ?

Ok, I’ve created a new document by using the REST API post method. It works as expected.
Here’s the response:

{
    "id": "f2dbc791dd6b6af4f6d41f5dc739c547",
    "ok": true,
    "rev": "1-b4b791d6357739e981ab1679e98fe0b6"
}

This was done with the following endpoint:
http://vm0.syncgateway-xxxx.northeurope.cloudapp.azure.com:4984/mydatabase/

Documents created by my application gets pushed as well, it’s just not pulling anything.

And what does _changes API on 4984 give you. I am basically trying to get the CBL client out of the picture to narrow down the cause. Also see what the SGW logs show when you make the request

In general, things to look for when you are troubleshooting pull replication issues -
Check the filter criteria on the replicator to ensure that the changes meet that criteria
Make sure that user has access to relevant channels

In your case, per your sync function, it seems like you are assigning doc to the public channel, so it should automatically be available to all users so I wouldn’t expect that to be an issue.

Everything seems OK (I’ve checked the _changes API, matched the replication filters with the channels, observed the log etc.).

Just to make sure that I had the correct filter and channels; I switched to the admin port (4985) and the documents was pulled as expected. I then changed the channel to a certain value only a few documents had (and updated the channels accordingly). It worked too - the few documents were pulled.

My understanding is that the admin REST API don’t require any user authentication (hence, the reason why it shouldn’t be open to the Internet). If this is the case, could it be some problem with my OpenID connection? I don’t see any indication of this in the log, but I’m just trying to narrow down what the differences between the admin (4985) api and public (4984) api calls.

Interesting. So _changes API over port 4984 with the specified token works just fin? . So that would imply that the token is ok. I would expect that if you removed that token from your request, it would return an error- can you try?.

Right. I would have expected a 403 unauthorized or 401 error. I am not seeing that in the logs so would appear to me that the tokenId is fine.

One other thing to note is that when request comes in over 4985, all the access control restrictions specified in the sync function are effectively NOPs/ ignored .
Did you to try assigning document to specific channel and giving the user explicit access to that channel ? (Again public channel should be available to all but trying to see if its some odd access control issue here)

Just to make sure what users I had to try this with, I made a call to the user Admin REST API. I have chosen in my SGW configuration file to have my SGW users created automatically when a successful authentication is done. The user I got back was this: xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf. Is this correct? I mean, is this a representation of the unique user that authenticated through my OpenID connect server, or will it always be this SGW user, no matter which user authenticates through my OpenID connect server?

Anyway, I configured access specifically for that user (i.e.:xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf) and that doesn’t work either (no doc’s pulled)… Here’s the SGW log for this attempt:

2018-02-08T08:46:34.048Z OIDC+: OIDCUsername: xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf
2018-02-08T08:46:34.049Z HTTP:  #003: POST /xxxx/_session  (as xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-08T08:46:34.050Z HTTP+: #003:     --> 200   (432.0 ms)
2018-02-08T08:46:35.794Z HTTP:  #004: GET /xxxx/_changes?feed=websocket  (as xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-08T08:46:35.794Z HTTP+: #004:     --> 101 Upgraded to WebSocket protocol  (0.0 ms)
2018-02-08T08:46:35.956Z Changes+: Int sequence multi changes feed...
2018-02-08T08:46:35.956Z Changes: MultiChangesFeed(channels: {TestChannel1}, options: {Since:0 Limit:0 Conflicts:true IncludeDocs:false Wait:true Continuous:true Terminator:0xc4203c9860 HeartbeatMs:300000 TimeoutMs:300000 ActiveOnly:true}) ...   (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-08T08:46:35.957Z Changes+: MultiChangesFeed: channels expand to "" ...   (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-08T08:46:35.957Z Changes+: MultiChangesFeed waiting...   (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-08T08:46:35.957Z Changes+: No new changes to send to change listener.  Waiting for "xxxx"'s count to pass 4
2018-02-08T08:46:41.293Z HTTP:  #005: GET /xxxx/_changes?feed=websocket  (as xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-08T08:46:41.295Z HTTP+: #005:     --> 101 Upgraded to WebSocket protocol  (0.0 ms)
2018-02-08T08:46:41.365Z Changes+: Int sequence multi changes feed...
2018-02-08T08:46:41.365Z Changes: MultiChangesFeed(channels: {TestChannel1}, options: {Since:0 Limit:0 Conflicts:true IncludeDocs:false Wait:true Continuous:true Terminator:0xc420251560 HeartbeatMs:300000 TimeoutMs:300000 ActiveOnly:false}) ...   (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-08T08:46:41.366Z Changes+: MultiChangesFeed: channels expand to "" ...   (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-08T08:46:41.366Z Changes+: MultiChangesFeed waiting...   (to xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf)
2018-02-08T08:46:41.366Z Changes+: No new changes to send to change listener.  Waiting for "xxxx"'s count to pass 4

Edit:

Strange… The user isn’t given to the access to the specified channel. I’m calling the user admin REST API. See below:

SGW config sync function:

“sync”: function(doc) { access("xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf", "*"); channel("*"); },

Postman result:
{"name":"xxxx.azurewebsites.net_ab123-defgc5-4124-wd34-54jfgrbrtsSf","all_channels":["!"]}