Authentication Exception swallowed and ignored

I have a situation where an Authentication exception is being swallowed and ignored.

NOTE: This is ServiceStack v5.7.

I have a RequestFilterAttribute against the Service Class instance, and the AuthorizeAttribute against the individual methods in the class.

This seems to be causing the RequestFilterAttribute to be executed prior to any Authentication, via an Authorize Attribute.

When running the Execute of the RequestFilterAttribute is called first.
This calls req.SessionAs<>(),
which in turn causes the ApiKeyAuthProvider.Authenticate to be called.

This throws an authorization exception, but the code still returns to code after the req.SessionAs with an empty session and continues, the exception is swallowed up and ignored.

I assume the offending code is the following:

    public static IAuthSession GetSession(this IRequest httpReq, bool reload = false)
    {
        ...
            try
            {
                HostContext.AppHost.ApplyPreAuthenticateFilters(httpReq, httpReq.Response);
                httpReq.Items.TryGetValue(Keywords.Session, out oSession);
            }
            catch (Exception ex)
            {
                Log.Error("Error in GetSession() when ApplyPreAuthenticateFilters", ex);
                /*treat errors as non-existing session*/
            }
        }

My Service looks like this

[SolcastProductUsage] // RequestFilterAttribute
public class HistoricalService : Service
{
    ...


    [AuthenticateSolcastProduct] // AuthenticateAttribute descendant
    [SolcastProduct(SolcastProductId.TmyP50)]
    public async Task<object> Get(ApiGetHistoricalRadiationTmy request)
    {
        InitSession<TmyData>(request);

        return await GetTmy(request);
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AuthenticateSolcastProductAttribute : AuthenticateAttribute
{
    public AuthenticateSolcastProductAttribute()
    {
    }

    public override Task ExecuteAsync(IRequest req, IResponse res, object requestDto)
    {
        req.Items[SolcastProductId.ItemKey] = SolcastProductMap.Instance.GetProduct(requestDto.GetType());

        return base.ExecuteAsync(req, res, requestDto);
    }

}

   public class SolcastProductUsageAttribute: RequestFilterAttribute
{
    public SolcastProductUsageAttribute() : base() { }

    public override void Execute(IRequest req, IResponse res, object requestDto)
    {
        var product = SolcastProductMap.Instance.GetProduct(requestDto.GetType());
        req.Items[SolcastProductId.ItemKey] = product;
        var session = req.SessionAs<SolcastAuthUserSession>();
        if (session == null)
        {
            throw new Exception("Unable to resolve session.");
        }

NOTE: If i move the RequestFilterAttribute onto the method calls, instead of against the class, then the situation does NOT occur, and the Authentication occurs prior to the RequestFilter

The code comment explains the behavior, it treats any exception during the application of PreAuthenticate* APIs the same as an unauthenticated user session.

But as I said, Authentication has NOT occurred, prior to the RequestFilter being run, which I would have thought, would be a pre-requisite.

Is it an issue or concern that Authorization has NOT occurerd, when a filter is being executed.

Refer to the Order of Operations to find out the order which different filters are run, i.e. Action Request Filters are always executed after Global Request Filters and Request Filter Attributes.

Authentication is validated (i.e. asserts that the request has an authenticated User Session) with one of the Authentication Attributes. The attributes themselves are just Request Filter Attributes with a low priority (-100) so that they’re run before other Request Filter Attributes and Global Request Filters.

If the attributes are applied as an Action Filter Attribute it gets executed after all Request Filter Attributes & Global Request Filters. If your service doesn’t have any Authentication attributes, they don’t get executed at all.

Your Services can still access the Users Session within an Service that’s not validated with an Authentication attribute in which case it will execute the PreAuthenticate* APIs of any registered IAuthWithRequest Auth Providers which will populate a Users Session for authenticated requests. But accessing the Users Session doesn’t assert validation, (i.e. as it were validated with an Authentication attribute and short-circuit the request and return a HTTP Error response if the User isn’t authenticated), if the User isn’t authenticated it returns an empty UnAuthenticated User Session that your Service can check its session.IsAuthenticated to decide what to do.

Thanks for the detailed response and links to your documentation.

Unfortunately, it doesn’t clear up the issue I am having in relation to the location of the various attributes.

There is no information in the “Order of Operations” that states that RequestFilter attributes associated with a Service class object will be executed prior to any RequestFilter attributes associated with the method of the service object, regardless of their priority.

My issue is
the class has a RequestFilter object on it (normal priority)
the method has a Authenticate attribute on it (-ve priority)

But when calling the method, the class level attribute is executed prior to the method level attribute.

This doesn’t match the explanation from the Order of Operation, as it doesn’t define any distinction between where an attribute maybe attached and how that may effect ordering.

If i don’t touch the session in the RequestFilter object, then it works successfully, and then the authenticate is also executed correctly, with authentication exceptions being returned to the client as expected.

What you call a “Class Level” Request Filter Attribute is called a Request Filter Attribute. Applying them to methods is what makes them Action Request Filters which are always executed immediately before and after the Service implementation, so they’re always executed after Global Request Filters (& attrs) and always before Global Response filters (& attrs).

Their execution should intuitively follow how they’re visually located with their proximity to their Service implementation. i.e. class level functionality is executed before action level functionality for inputs (requests) whose execution order is reversed for outputs (responses), i.e. response action filters are executed before class response filter attributes.

Likewise class filter attributes are applied to all API methods within their Service class whilst Action filter attributes are only applied to the implementation they’re annotated on.

Because accessing the session forces the execution of the IAuthWithRequest PreAuthenticate* APIs, which are only executed once per request, which will return an empty unauthenticated session for unauthenticated requests.

Thanks, that clears it up and lets me know we need to be careful about how attributes are placed and what effect they have on the order of processing.

I apologize for my mis-understanding.

Perhaps the “Action Request Filters” and “Action Response Filters” could be highlighted links in the “Order of Operation”, and then they’d look as clear and as important as the others listed.

Because accessing the session forces the execution of the IAuthWithRequest PreAuthenticate* APIs, which are only executed once per request, which will return an empty unauthenticated session for unauthenticated requests.

I thought this was great, that it would cause authentication, because it hadn’t yet occured, but unfortunately, as commented, any authentication failures (as opposed to it being an un-authenticated request) are swallowed and ignored.

I was trying to follow the 90/10 rule, of using attributes where most appropriate (90% of the time needed, 10% not), so i only needed one instance, but this doesn’t work in this scenario.

A similar situation could be where you want 90% authenticated methods, and 10% un-authenticated, but there is no way of doing this (like an [Ignore…] attribute for DTO’s.

The more we learn, the more we understand and the less we really know.

thanks again
Steve

Why aren’t you having separate classes for Authenticated vs Public Services? Seems it would be the most logical layout structure so you could immediately tell which Requests are Authenticated or Public that would require fewer attributes/effort to maintain and be less error prone from accidentally forgetting to annotate a protected service or protect against if the attribute was accidentally lost during a refactor.

If you still want to maintain services with mixed accessibility in the same class you can use Declarative Validation where you can use Auth Type Validator attributes to mark individual Services on your Request DTOs, e.g:

[ValidateIsAuthenticated] 
public class Secured { ... }

Its not really a public service, but an un-authorized, un-logged, un-monitored endpoint that is part of the service.

We integrate with a third party, and they requested an “is it available” endpoint to determine whether a authenticated/purchased call would succeed or fail. (thus can grey out the option to their client if not available)

Seeing all code was available in the existing class, simplest to add call there.

In your suggestion, we’d have to create another service, which internally called the existing service for the operation anyway.

6 of 1, half dozen of the other. Learning more about the intricacies of the product, helps sway methodology one way or the other

You can use the [ValidateIsAuthenticated] attribute without adding any additional services.

Although even if you have to add more than 1 authentication action attribute it would approach the char boilerplate count creating an additional service would take, which (if preferred) could also be placed aside other Services in the same file. Regardless, I personally wouldn’t factor key strokes as rationale for maintaining Services with mixed behavior/accessibility, IMO it adds unnecessary confusion and sets a up pit of failure where eventually a protected Service will be added with the wrong accessibility.

NOTE: This is just a philosophical discussion about choices made and how they effect operations and usage patterns. Ramblings based on my experiences.

I guess to me the whole issue is around the precedence of associated attributes against functionality and how it is decided the order of execution.

You have two orders of execution, the priority (< 0 >0 and I assume within these as well), then separately depending on which object/method the attribute decoration occurs.

And we have 3 levels (DTO, Class, Method)

Thus the options available are:

  1. collapse all levels to single set (the old flatten hierarchy) and decide all precedence by Priority
  2. Choose the level priorities, then priorities within the levels

SS implements (2), but with the level priorities hard coded, and not user configurable, whereas the priority level are user configurable.

Personally, I would have thought priority order of interpreting attribute based rules would be

  1. RequestDto
  2. chosen Method for URL
  3. class hosting said method

Thus lowest common denominator (most shared) is at class level and a catch all for default functionality.
Attribute once, covers everything, unless otherwise overridden at a method or DTO level

This would also covers inheritance situations.

Then we can override this “default” at either the method level, or RequestDto level

Thus an [IgnoreAuthentication] attribute can be easily added at Method or DTO level, to bypass a default “everything” autheticated at the class level, or vis-a-versa.

This same functionality would work in option (1) as well, we’d just have to make sure the IgnoreAuthentication is higher priority then Authentication (so it can pseudo authenticate)

I guess I’m also a little concerned, but understand all the reasons, that RequestDTO pre-filters, bindings and convertors all happen prior to authentication, and if you associate the attributes incorrectly, even request filters can occur prior to authentication.