Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query Authorization per field or property not working #22

Open
adriani10 opened this issue Apr 12, 2021 · 18 comments
Open

Query Authorization per field or property not working #22

adriani10 opened this issue Apr 12, 2021 · 18 comments
Labels
bug Something isn't working

Comments

@adriani10
Copy link

Query authorization only works for class authorization, not for field. Tested in 3.0.0

@adriani10
Copy link
Author

As of 3.1.0 class query auth also fails. Websocket message shows "Cannot find suitable method"

@morrisjdev
Copy link
Collaborator

Hi.
Thank you for reporting an issue.
Can you provide example code to reproduce the error?

Best regards
Morris

@adriani10
Copy link
Author

adriani10 commented Apr 12, 2021

Hi Morris, this is how I have the code right now. This works:

    [QueryAuth("requireAdmin")]
    public class User : IdentityUser<int>
    {
        [Key]
        [IgnoreDataMember]
        [Column("ID")]
        public override int Id { get; set; }
        [Required]
        public override string Email { get; set; }


        public static bool isSuperAdmin(HttpInformation info)
        {
            return info.User.IsInRole("Superadmin");
        }

        public static bool isAdmin(HttpInformation info)
        {
            return info.User.IsInRole("Admin") || info.User.IsInRole("Superadmin");
        }

        public static bool isMod(HttpInformation info)
        {
            return info.User.IsInRole("Mod") || info.User.IsInRole("Admin") || info.User.IsInRole("Superadmin");
        }

        public static bool isRef(HttpInformation info)
        {
            return info.User.IsInRole("Ref") || info.User.IsInRole("Mod") || info.User.IsInRole("Admin") || info.User.IsInRole("Superadmin");
        }

        public static bool isUser(HttpInformation info)
        {
            return info.User.IsInRole("User") || info.User.IsInRole("Ref") || info.User.IsInRole("Mod") || info.User.IsInRole("Admin") || info.User.IsInRole("Superadmin");
        }
    }

This doesn't, the field shows regardless if the user doesn't meet the requirement:

    public class User : IdentityUser<int>
    {
        [Key]
        [IgnoreDataMember]
        [Column("ID")]
        public override int Id { get; set; }
        [Required]
        [QueryAuth("requireAdmin")]
        public override string Email { get; set; }


        public static bool isSuperAdmin(HttpInformation info)
        {
            return info.User.IsInRole("Superadmin");
        }

        public static bool isAdmin(HttpInformation info)
        {
            return info.User.IsInRole("Admin") || info.User.IsInRole("Superadmin");
        }

        public static bool isMod(HttpInformation info)
        {
            return info.User.IsInRole("Mod") || info.User.IsInRole("Admin") || info.User.IsInRole("Superadmin");
        }

        public static bool isRef(HttpInformation info)
        {
            return info.User.IsInRole("Ref") || info.User.IsInRole("Mod") || info.User.IsInRole("Admin") || info.User.IsInRole("Superadmin");
        }

        public static bool isUser(HttpInformation info)
        {
            return info.User.IsInRole("User") || info.User.IsInRole("Ref") || info.User.IsInRole("Mod") || info.User.IsInRole("Admin") || info.User.IsInRole("Superadmin");
        }
    }

@morrisjdev
Copy link
Collaborator

Thank you for the example code.
Did you try upgrading to 3.1.7-alpha.
3.1.0 should also be an alpha version so it could probably be an already resolved issue.
The corresponding js version should be 3.1.4 (alpha).

@adriani10
Copy link
Author

I tried all the way up to 3.1.5 and the issue wasn't resolved. Above 3.1.5 I got the handshake websocket error I mentioned in the other issue.

@adriani10
Copy link
Author

I will try upgrading the clients later during the day and I will report my findings to you. Thanks

@morrisjdev
Copy link
Collaborator

Ah okay I understand.
Sorry for the inconvenience regarding the different version numbers across client and server implementation. I'll align them at the next non-alpha release.

@adriani10
Copy link
Author

adriani10 commented Apr 13, 2021

Hello Morris, I checked this with client at 3.1.4-alpha and server at 3.1.7-alpha. The issue persists, field and property auth doesn't work, however class auth Queries do work with both function and policy.

@adriani10 adriani10 changed the title Query Authorization per field not working Query Authorization per field or property not working Apr 13, 2021
@morrisjdev
Copy link
Collaborator

Ok thank you for further investigating the issue. I'll fix it soon.

@morrisjdev morrisjdev added the bug Something isn't working label Apr 13, 2021
@adriani10
Copy link
Author

Hello Morris, is there an update on this bug?

@morrisjdev
Copy link
Collaborator

Hi @adriani10.

Sorry letting you wait for so long.
I wasn't able to reproduce your problem.

I tried reproducing the issue with the following example:

public class Base
{
    [Key]
    public int Id { get; set; }

    public virtual string TestValue { get; set; } = "test";
}

public class QueryFields : Base
{
    ...

    [QueryAuth("requireAdmin")]
    public override string TestValue { get; set; } = "Test Value";
}

And this works. When not logged in as admin the result looks like this:
image
When logged in I get this:
image

Maybe you could take a look and let me know if I forgot something.

@adriani10
Copy link
Author

This is how my class looks like:

image

using JWT Token, the policy seems to be ignored when used as a property attribute, it works as a class attribute, this is what the socket message shows:

image

According to my policy, this user shouldn't get this property back due to his access level.

@morrisjdev
Copy link
Collaborator

Thanks to the screenshot you send me I was able to find the problem.
Are you using the operation first, to only query one element?
That seems to cause ignoring of the property auth.

@adriani10
Copy link
Author

Hello Morris, this is the operation I'm running on my test project in React

2021-06-13_21-25-59

@morrisjdev
Copy link
Collaborator

Hi.
I fixed the issue and added execution of auth checks after first prefilter.
Note that the result returned by the first prefilter now is an array instead of a single element.

The new version ist 3.1.8-alpha and you need to update both client and server to this version.

I hope this fixes your issue, let me know if it's working.

Best regards

Morris

@adriani10
Copy link
Author

Hello Morris, thank you for the help, I just ran some tests in the last update, it seems it works now at first sight. However, I did found another error...

2021-06-16_12-39-25

If your class contains sub-classes, on query those subclasses do not respect the policy anymore.

@morrisjdev
Copy link
Collaborator

Hi.

That's something I'm aware of. If you're using the Include-Operator the referenced classes authorize attributes will not get called. That's also described in the documentation of the Include-Operator. That's because at moment of implementing the include feature it was too complicated to handle the auth recursively, but it's already planned to come soon.

Meanwhile I would highly encourage you to not use the Include-Operator for performance reasons, because the server is not able to handle changes effectively and has to reload every related entity on change of any of the used tables entities.
I would handle multiple queries from different collections on client side and join them together on client side.

Best regards

Morris

@adriani10
Copy link
Author

adriani10 commented Jun 17, 2021

Hi Morris, ok I understand. I will try not to use includes. I found one more bug, that I was able to fix myself. It's in your "GetCustomHeader" in WebSocketHelper. Since not all clients return the header with a space (for instance Android phones using React Native) the query auth would decline access to valid tokens. This is how I fixed it:

public static string GetCustomHeader(HttpRequest request, string header)
        {
            if (request.Headers.TryGetValue("Sec-Websocket-Protocol", out StringValues customHeader) && customHeader.Count == 1)
            {
                string[] customHeaderParts = customHeader[0].Split(",");

                int keyIndex = Array.FindIndex(customHeaderParts, value => value.Trim().Equals(header, StringComparison.InvariantCultureIgnoreCase));
                if (keyIndex != -1)
                {
                    return customHeaderParts[keyIndex + 1].Trim();
                }
            }

            return null;
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants