TestOpenIDConnectImplicitFlowReuseToken ensures that requests that use the same token containing channel grants don't end up recomputing or updating the user for each use.
(t *testing.T)
| 1122 | |
| 1123 | // TestOpenIDConnectImplicitFlowReuseToken ensures that requests that use the same token containing channel grants don't end up recomputing or updating the user for each use. |
| 1124 | func TestOpenIDConnectImplicitFlowReuseToken(t *testing.T) { |
| 1125 | base.SetUpTestLogging(t, base.LevelTrace, base.KeyAll) |
| 1126 | defer db.SuspendSequenceBatching()() // allows assertions on last sequence of the database to hold true when request plus is used |
| 1127 | |
| 1128 | testProviders := auth.OIDCProviderMap{ |
| 1129 | "foo": mockProviderWith("foo", mockProviderUserPrefix{"foo"}, mockProviderChannelsClaim{"channels"}), |
| 1130 | } |
| 1131 | defaultProvider := "foo" |
| 1132 | |
| 1133 | mockAuthServer, err := newMockAuthServer() |
| 1134 | require.NoError(t, err, "Error creating mock oauth2 server") |
| 1135 | mockAuthServer.Start() |
| 1136 | defer mockAuthServer.Shutdown() |
| 1137 | mockAuthServer.options.issuer = mockAuthServer.URL + "/" + defaultProvider |
| 1138 | refreshProviderConfig(testProviders, mockAuthServer.URL) |
| 1139 | |
| 1140 | opts := auth.OIDCOptions{Providers: testProviders, DefaultProvider: &defaultProvider} |
| 1141 | restTesterConfig := RestTesterConfig{SyncFn: channels.DocChannelsSyncFunction, DatabaseConfig: &DatabaseConfig{DbConfig: DbConfig{OIDCConfig: &opts}}} |
| 1142 | |
| 1143 | // JWT claim based grants do not support named collections |
| 1144 | restTester := NewRestTesterDefaultCollection(t, &restTesterConfig) |
| 1145 | defer restTester.Close() |
| 1146 | |
| 1147 | createUser(t, restTester, "foo_noah") |
| 1148 | |
| 1149 | token, err := mockAuthServer.makeToken(claimsAuthenticWithExtraClaims(map[string]interface{}{"channels": []string{"foo"}})) |
| 1150 | require.NoError(t, err, "Error obtaining signed token from OpenID Connect provider") |
| 1151 | require.NotEmpty(t, token, "Empty token retrieved from OpenID Connect provider") |
| 1152 | |
| 1153 | // try directly using bearer token in a keyspace request |
| 1154 | resp := restTester.SendRequestWithHeaders(http.MethodPut, "/{{.keyspace}}/doc1", `{"channels":"foo"}`, map[string]string{"Authorization": BearerToken + " " + token}) |
| 1155 | RequireStatus(t, resp, http.StatusCreated) |
| 1156 | docSeq := restTester.GetDocumentSequence("doc1") |
| 1157 | |
| 1158 | restTester.WaitForPendingChanges() |
| 1159 | |
| 1160 | ctx := base.DatabaseLogCtx(base.TestCtx(t), restTester.GetDatabase().Name, nil) |
| 1161 | u, err := restTester.GetDatabase().Authenticator(ctx).GetUser("foo_noah") |
| 1162 | require.NoError(t, err) |
| 1163 | firstJWTLastUpdated := u.JWTLastUpdated() |
| 1164 | |
| 1165 | lastSeq, err := restTester.GetDatabase().LastSequence(ctx) |
| 1166 | assert.NoError(t, err) |
| 1167 | |
| 1168 | // Observing an updated user inside the changes request isn't deterministic, as it depends on the timing of the DCP feed for the principal update made during the changes request... |
| 1169 | // If we send some of these, we can at least compare JWTLastUpdated timestamps to ensure it hasn't changed. |
| 1170 | const numChanges = 10 |
| 1171 | var observedUserUpdateCount int64 |
| 1172 | for i := 0; i < numChanges; i++ { |
| 1173 | resp = restTester.SendRequestWithHeaders(http.MethodGet, fmt.Sprintf("/{{.keyspace}}/_changes?since=%d", docSeq), ``, map[string]string{"Authorization": BearerToken + " " + token}) |
| 1174 | RequireStatus(t, resp, http.StatusOK) |
| 1175 | var changesResp ChangesResults |
| 1176 | require.NoError(t, json.Unmarshal(resp.BodyBytes(), &changesResp)) |
| 1177 | if !assert.Lenf(t, changesResp.Results, 0, "Expected no changes, got %d: %v", len(changesResp.Results), changesResp) { |
| 1178 | observedUserUpdateCount++ |
| 1179 | } |
| 1180 | } |
| 1181 | assert.Equalf(t, int64(0), observedUserUpdateCount, "%d of %d changes observed user update (expected 0)", observedUserUpdateCount, numChanges) |
nothing calls this directly
no test coverage detected