TryGetAsync possibly broken in IUserProfileAdmin/IUserProfileSelfService #634
|
I've been scratching my head all day trying to figure out if this is a me-problem or a problem with I'm creating an "invite-only" registration flow for my local users doing the following:
Later, when the user wishes to log in again I first do a check if the user exists, with the intention of only allowing existing users to log on. For this I use the To do a sanity check and see if // userAdmin is IUserProfileAdmin in this example
var schema = await userAdmin.GetSchemaAsync(cancellationToken);
var attributes = new AttributeValueCollection(schema);
attributes.Set(OidcStandardAttributes.Email, request.Email);
attributes.Set(OidcStandardAttributes.Name, request.Name);
attributes.Set(OidcStandardAttributes.PreferredUserName, request.Username);
// request.SubjectId is from otpSuccess.UserSubjectId
var profile = await userAdmin.TryAddAsync(request.SubjectId, attributes.Validate(), cancellationToken);
if (profile is null)
{
return RegisterUserResult.ProfileAlreadyExists();
}
// allUsers returns one profile (the one just created, which is correct)
var allUsers = await userAdmin.QueryAsync(QueryRequest.Create(), cancellationToken);
var user = allUsers[0];
// getting on SubjectId works fine, returns the same user that is returned in allUsers
var viaSub = await userAdmin.TryGetAsync(user.SubjectId, cancellationToken);
// not found
var viaEmail = await userAdmin.TryGetAsync(user.Attributes[OidcStandardAttributes.Email].Code, user.Attributes[OidcStandardAttributes.Email].UntypedValue, cancellationToken);
// not found
var viaName = await userAdmin.TryGetAsync(user.Attributes[OidcStandardAttributes.Name].Code, user.Attributes[OidcStandardAttributes.Name].UntypedValue, cancellationToken);
// not found
var viaUsername = await userAdmin.TryGetAsync(user.Attributes[OidcStandardAttributes.PreferredUserName].Code, user.Attributes[OidcStandardAttributes.PreferredUserName].UntypedValue, cancellationToken);As you can see, I'm even using attribute values from the actual profile just created just to confirm that there aren't any equality shenanigans holding me back. The simpler version of the call ( So far I believe this is a bug where some sort of equality comparison is wrong, either in the code or the resulting SQL. |
Replies: 2 comments 2 replies
|
Hi @iseneirik ! Thanks for the detailed report, and good instinct to compare against You're not holding it wrong. The API should make this much clearer. We've filed an internal issue, and we'll update the docs. In the meantime, you have two options:
var result = await schemaAdmin.GetAsync(SchemaId.UserProfile, ct);
var schema = result.Item!;
var email = schema.AttributeDefinitions.Single(d => d.Code == OidcStandardAttributes.Email.Code);
schema.AttributeDefinitions.Remove(email);
schema.AttributeDefinitions.Add(email with { IsUnique = true });
await schemaAdmin.UpdateAsync(SchemaId.UserProfile, schema, result.Version!.Value, ct);After that,
|
|
We will address this in an upcoming release |

Hi @iseneirik ! Thanks for the detailed report, and good instinct to compare against
QueryAsyncandTryGetAsync(subjectId). That made this easy to reproduce.You're not holding it wrong.
TryGetAsync(AttributeCode, object, ct)only works for attributes that are marked unique in the user profile schema. Under the hood it isn't a value search. It looks up a storage key, and those keys are only written for attributes whose definition hasIsUnique = true. The built-inOidcStandardAttributes(Email,Name,PreferredUserName, ...) are all non-unique by default, which matches the OIDC spec. So there's never a key to find, and the call quietly returnsnull.The API should make this much clearer. We…