Authentication exception

I’ve getting exception while trying to check whether login is correct:

cluster.Authenticate(Login_TextBox.Text, Password_TextBox.Text);

        User This_User;
        try
        {
            This_User = cluster.CreateManager().GetUser(AuthenticationDomain.Local, Login_TextBox.Text).Value;
            Console.WriteLine(Login_TextBox.Text);
            Console.WriteLine(This_User.Name);
            Console.WriteLine(This_User.Domain);
            Console.WriteLine(This_User.Roles);
        }
        catch
        {
            Console.WriteLine(Login_TextBox.Text);
            Console.WriteLine("Not entered");
            return;
        }

What is the exception that you are getting? Which line?

Hello. Thankth for reply.
The program is going to “catch” block, on any login, whatever login is correct or not.
So “try … catch…” catching something wrong.

And when i comment the “try catch” construction it says:

the exception was not processed
System.NullReferenceException: “object Reference does not point to an instance of an object.”
This_User was null.

@Enlighted,

I figured it was a null reference exception. What I would recommend is attaching a debugger, stepping through, and figuring out what is null when you don’t expect it to be.

Ok, i’ve debugged that. And the string:

cluster.CreateManager().GetUser(AuthenticationDomain.Local, Login_TextBox.Text).Value;

returns NULL. But the Login_TextBox.Text is a name of existing user.
I’ve also tried to check

cluster.CreateManager().GetUser(AuthenticationDomain.External , Login_TextBox.Text).Value;

The result is same it returns NULL.

I’ve tried to do the same as in couchbase documentation put:
cluster.CreateManager().GetUsers().Value
without any arguments inside brackets but it doesn’t even want to compile

Ok. i just want to get logged in user permissions and it doesn’t returns it to me. I think the problem is in string: AuthenticationDomain… but how can i not to use this construction?

And another question would user be able to log in on another server if domain selected “AuthenticationDomain.Local”?

@Enlighted,

I just ran this small snippet of code after creating a “testuser” on my cluster, and it seems to work as expected without throwing an exception.

static void Main(string[] args)
{
    var cluster = new Cluster(new ClientConfiguration
    {
        Servers = new List<Uri> { new Uri("http://localhost:8091") }
    });
    cluster.Authenticate("Administrator", "password");

    var manager = cluster.CreateManager();
    var userResult = manager.GetUser(AuthenticationDomain.Local, "testuser");
    var user = userResult.Value;

    Console.WriteLine(user.Name);
    Console.WriteLine(user.Domain);
    Console.WriteLine(user.Roles);

    cluster.Dispose();
}

Are you sure Login_TextBox.Text contains a valid name of a user? It is case sensitive, you may want to double check. Also “Username” and “Full Name” are different things: GetUser is looking for the Username, so you may want to double check that as well.

I don’t quite understand your second question “And another question would user be able to log in on another server if domain selected “AuthenticationDomain.Local”?” - I would recommend starting a new forum question with more details.

Thank you for the replies. Now i see that the login is correct. Login is ok, i see that it doesn’t returns user… user is null. I’ve inserted your code and it shows null in user variable.

private void button1_Click(object sender, EventArgs e)
        {
            var cluster = new Cluster(new ClientConfiguration
            {
                Servers = new List<Uri> { new Uri("http://localhost:8091") }
            });

            Console.WriteLine("*************************************");
            cluster.Authenticate(Login_TextBox.Text, Password_TextBox.Text);
            
            var manager = cluster.CreateManager();
            var userResult = manager.GetUser(AuthenticationDomain.Local, "Auditor");
            var user = userResult.Value;

            Console.WriteLine(user.Name); - "here is error "System.NullReferenceException: "object Reference does not point to an instance of an object." user was null.""
            Console.WriteLine(user.Domain);
            Console.WriteLine(user.Roles);

            cluster.Dispose();

The user “Auditor” is exist and also loged in with cluster.Authenticate(Login_TextBox.Text, Password_TextBox.Text);

Also i’ve added “testuser” via webui, and tried to look at it’s properties with
var userResult = manager.GetUser(AuthenticationDomain.Local, “testuser”);
still user. returns NULL

But when i create user with C# code and retrieve that user’s properties the couchbase returns them and no exception is appearing.

So the problem is that i cannot se the users properties while it is integrated Admin or created via webUI.

@Enlighted,

It appears that GetUser will only work if the credentials you are using to connect to the cluster has access to get RBAC users. What roles/permissions have you given the “Auditor” account?

By the way, instead waiting for a NullReferenceException, you can check userResult.Success and show an error message instead.

Ok. Today i’ve found that the user “Administrator” can get data about user “Auditor”, but cannot get data about himself, the same thing is aboute “Auditor” can not get data aboute himself.

The code:

Program.gl_cluster.Authenticate(Login_TextBox.Text, Password_TextBox.Text);
            var manager = Program.gl_cluster.CreateManager();
            var userResult = manager.GetUser(AuthenticationDomain.Local, "Auditor").Success;
            Console.WriteLine(userResult);
            Console.WriteLine(manager.GetUser(AuthenticationDomain.Local, "Auditor").Value.Name);

returns success and “Auditor” name while login as Administrator, but returns null while login as “Auditor”

so the code:

Program.gl_cluster.Authenticate(Login_TextBox.Text, Password_TextBox.Text);
            var manager = Program.gl_cluster.CreateManager();
            var userResult = manager.GetUser(AuthenticationDomain.Local, Login_TextBox.Text).Success;
            Console.WriteLine(userResult);
            Console.WriteLine(manager.GetUser(AuthenticationDomain.Local, Login_TextBox.Text).Value.Name);

shows null and exception.

so how can i get data about logged in user if it doesn’t return any data about logged in user?

Thank you for your replys.

It appears to be the case that if the logged-in user does not have permission to get user information, they cannot get user information, even about themselves.

What information about the logged in user do you want to retrieve?

Maybe i’m doing not right. Let me explain what do i need. I need to check the logged in user permissions for the specific bucket, and if it is write permitted, there will be a special form loaded, otherwise another form will be loaded. And if user doesn’t exist in couchbase server program will be closed. So maybe there is a more elegant solution in couchbase .net than the one that i’m trying to realize.

@Enlighted,

I don’t see any way to do this from the .NET SDK. However, there is a REST endpoint “whoami” which might work for you.

I don’t see any documentation; if there isn’t any, then this is likely an unsupported endpoint, and therefore there may be breaking changes in the future without any warning.

GET /whoami

And use basic auth with the given credentials. Something like this should work from .NET Core:

   public class Program
    {
        static async Task Main(string[] args)
        {
            var buckets = await GetAuthorizedBucketsForUser("Auditor", "password");

            Console.WriteLine("Buckets that this user has SOME access to:");
            foreach (var bucket in buckets)
            {
                Console.WriteLine(bucket);
            }
        }

        public static async Task<List<string>> GetAuthorizedBucketsForUser(string username, string password)
        {
            var encoding = new ASCIIEncoding();
            var basicAuthCredentials = Convert.ToBase64String(encoding.GetBytes($"{username}:{password}"));
            var authHeader = new AuthenticationHeaderValue("Basic", basicAuthCredentials);
            var http = new HttpClient();
            http.DefaultRequestHeaders.Authorization = authHeader;

            var response = await http.GetAsync("http://localhost:8091/whoami");
            var rawJson = await response.Content.ReadAsStringAsync();

            var results = JsonConvert.DeserializeObject<WhoAmIResponse>(rawJson);
            
            http.Dispose();
            
            return results.Roles.Select(x => x.Bucket_Name)
                .Distinct()
                .ToList();
        }

        public class WhoAmIResponse
        {
            public List<RolesResponse> Roles { get; set; }
        }

        public class RolesResponse
        {
            public string Role { get; set; }
            public string Bucket_Name { get; set; }
        }
    }

Note that this code completely ignores which roles the user has to a bucket. If the user has ANY role in a bucket, it counts it as bucket access. I’m also throwing away any information in the response except for Roles, doing no error checking or validation. And I must stress again that I can’t find any documentation for the “whoami” endpoint. Your needs may vary; your method of making HTTP requests may vary, but the general principle is here.

Hi @Enlighted, @matthew.groves - have filed doc ticket to track adding this REST endpoint: https://issues.couchbase.com/browse/DOC-6199

-dave

1 Like

Thanks everybody for your answers, i’ll try them.
I didn’t knew that it is unsupported. I thought to retrieve logged user .Role and check has it write privileges to specific bucket or not.

@Enlighted,

Good luck, and just to recap: the REST endpoint actually IS supported, it’s just not in the documentation. But it soon will be.

I’ve beent testing for some time, and found that:
.GetUsers(AuthenticationDomain.Local).Value;
doesn’t returns the security admins accounts, and maybe any admin accounts.
So the next trouble is how to get all users in system while logged in as security admin?

Thanks.

And we can probably add SDK support through the management interface. This use case hadn’t been considered before, but it does make sense. Thanks for bringing it up @Enlighted.

1 Like