ServiceStack AuthProvider IsAuthorized is not called when calling service from ASP.NET code behind - authorization

I've a service operation which I marked with the Authenticate attribute
[Authenticate]
[Route("/route/to/service", "POST")]
public class OperationA: IReturn<OperationAResponse>
{
...
}
The method IsAuthorized of the AuthProvider is called correctly when I call the service using the REST URL or using JsonServiceClient inside a unit test but is not called if I call the service from ASP.NET code behind (not MVC controller).
I don't use IoC to resolve the service inside my code behind but I use this code...
MyService service = AppHostBase.Instance.Container.TryResolve<MyService>();
service.Post(operationA);
Is there something I'm missing?
Thank you for your attention.

Just to clarify:
I don't use IoC to resolve the service inside my code behind but I use this code...
MyService service = AppHostBase.Instance.Container.TryResolve<MyService>();
You are using the IOC here, i.e. resolving an auto-wired instance of MyService from ServiceStack's IOC.
If you're service doesn't make use of the HTTP Request or Response objects than you can treat it like any normal class and call C# methods. If the service does (e.g. Auth/Registration) then you will also need to inject the current HTTP Request Context as well.
The CustomAuthenticationMvc UseCase project has an example of how to do this:
var helloService = AppHostBase.Resolve<HelloService>();
helloService.RequestContext = System.Web.HttpContext.Current.ToRequestContext();
var response = (HelloResponse)helloService.Any(new Hello { Name = "World" });

Related

How to access the TelemetryClient singleton instance in startup for ASP.NET core app

I have an ASP.NET Core Web App that uses Application Insights for telemetry. I would like to wrap the TelemetryClient object with my own interface and add that instance to the services collection. To do this I need access to the singleton instance of Telemetry client in startup.cs. I can get the service information with this code:
var info = services.Where(x => x.ServiceType.Name == "TelemetryClient").Single();
That info has a ImplementationInstance that I would expect to find the instance in, but it is null. Is there any way to get the singleton instance of this item so I can create my wrapper class instance with it? My other option is to create the wrapper class in my controller constructors because there I can access it from the services container via this code:
HttpContext.RequestServices.GetService(typeof(T)) as T;
Any help would be appreciated. Thanks.
Couldn't you do this?
public class Wrapper
{
public Wrapper(TelemetryClient telemetryClient)
{
// Handle init
}
}
And register that in the service collection:
services.AddTransient<Wrapper>();
You can then get the Wrapper in your controllers through the constructor.
If this does not work for you, please leave a comment and explain why.

Access AuthenticationStateProvider in Blazor Server Side in Custom Class

Is there any general guidance on how to access AuthenticationStateProvider in Blazor Server Side in custom classes? Should AuthenticationStateProvider be added as a singleton service? Any other way to get it with DI? I'm not talking about using AuthorizeViews or through cascading parameter. I need to be able to get AuthenticationStateProvider.GetAuthenticationStateAsync() in a custom class, rather than a controller, view, etc.
Any thoughts?
Thanks for the info Isaac, but I actually was able to answer my own question. My resolution was to make sure my helper class is scoped and not singleton in order to get an instance of the authstateprovider.
services.AddScoped<Classes.GlobalHelper>();
I could then call authstateprovider the same as any other DI, for example:
public async Task<HttpClient> MyHttpClient()
{
AuthenticationState _authstate = _authStateProv.GetAuthenticationStateAsync().Result;
HttpClient http = new HttpClient();
string signedInUserID = _authstate.User.FindFirst(ClaimTypes.NameIdentifier).Value;

Can I add a service info / health check endpoint to my Identity Server 3-based service?

I have a set of AspNet WebApi-based web services and an IdentityServer3-based authentication service. All of the web services support a simple service info endpoint that we use for monitoring and diagnosis. It reports the service version and the server name. The only service that currently does not support the service info endpoint is the IdentityServer3-based authentication service.
Is there a way to add a simple endpoint to an IdentityServer3-based service? In GitHub issue 812 Brock Allen says "We have a way to add custom controllers, but it's undocumented, current unsupported, and not really done." I'd rather not take that indocumented, unsupported route.
Is there a way to modify/extend the discovery endpoint to include additional information?
Here's how I ended up coding this up. At a high level, basically I added a Controllers folder, created a AuthenticationServiceInfoController class with a single GET action method and then registered that controller during Startup. As noted in comment above, my solution had some extra complexity because my AuthenticationServiceInfoController inherited from a base ServiceInfoController defined elsewhere, but I've tried to eliminate that from this sample. So, the controller code looks like this:
[RoutePrefix("api/v1/serviceinfo")]
public class AuthencticationServiceInfoController : IServiceInfoController
{
[Route("")]
[Route("~/api/serviceinfo")]
public IHttpActionResult Get()
{
try
{
ServiceInformation serviceInfo = new ServiceInformation();
serviceInfo.ServiceVersion = Global.serviceVersion;
return Ok(serviceInfo);
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
}
It implements a simple interface:
public interface IServiceInfoController
{
IHttpActionResult Get();
}
And in my Startup.Configuration method where I configure Identity Server, I've got:
var idSrvFactory = new IdentityServerServiceFactory();
idSrvFactory.Register(new Registration<IServiceInfoController, Controllers.AuthencticationServiceInfoController>());
I think that's all that it took. It's in place and working in my Identity Server 3-based service.

WCF Task based asynchronous callback

I have created WCF service in VS2015:
[ServiceContract(CallbackContract = typeof(IMyCallback))]
public interface IMyService { }
IMyCallback looks like:
[ServiceContract]
public interface IMyCallback {
[OperationContract]
Task<string> OnServerEvent(UserAppEventData evData);
I've built the server, run it, then added service reference (by right click on solution explorer).
The client object is defined as
[CallbackBehaviorAttribute(
ConcurrencyMode = ConcurrencyMode.Reentrant,
IncludeExceptionDetailInFaults = true,
UseSynchronizationContext = true,
ValidateMustUnderstand = true
)]
public class QMyClient : IMyCallback { }
Automatically generated interface implementation made method in sync manner:
public string OnServerEvent(UserAppEventData evData) { }
This code does't work (and isn't asynchronous) and hangs client at OnServerEvent.
When I changed code manuallly to
public async Task<string> OnServerEvent(UserAppEventData evData)
and have done the same in auto generated "service references\...\Reference.cs, all works fine. But I don't want to change Referenece.cs every time I'm updating Service Reference.
Is there any method to force "Update Service Reference" make TBA OperationContractAttribute on callback?
At ordinary WCF service direction everything works OK, VS generates task based operations.
By default the service reference you've added to solution doesn't have asynchronous operations, but you can enable them and decide which option you use for your async methods - task-based or old-fashion asynchronous. This option is available in Advanced settings for service reference.
If you're using a svcutil tool, it will create the task-based methods by default, however, you can change that behavior by some flags like /async or /syncOnly.
What #VMAtm suggested will work out just fine.
I think, you could also use ChannelFactory for this scenario. It is very flexible and you can then await on the service operations from client side. Additional benefit, you don't need to modify client when there are these kind of changes on service side.
Something like:
var channelFactory = new ChannelFactory<IService>(
"WSHttpBinding_IService" // endpoint name
);
IService channel = channelFactory.CreateChannel();
string result = await channel.OnServerEvent();
Console.WriteLine(result);
Please note that for this scenario, you will have to import common interface library to client side as dll because then it will need to know about contracts and data contracts.

How can I pass parameter of type HttpContent in web api?

The back story is I have a web api that simply serves as a gateway to invoke external services. The reason for this is I don't want to expose the real business API to external services. So, in this gateway controller, it simply receives the information from the business API, calls external services and returns the response to the client, which is the business API.
In my gateway controller I have a POST action that takes a parameter of type HttpContent, something like this:
[Route("api/test")]
public void Test(HttpContent content)
{
}
but the web API infrastructure doesn't know how to serialize and deserialize HttpContent type. Is there a way to support my scenario? Thanks.
Accessing the content of the request in any controller's handler is quite natural. Just call Request.Content inside. You can't have it as a parameter because it is not a mapping as an URI segment would nor a serialized content.
Try something like:
using System.Net;
using System.Net.Http;
// namespace + controller definition...
[Route("api/test")]
public HttpResponseMessage GetTest() // This is a GET handler
{
var myRequestContext = Request.Content;
// Do something with the content e.g
if (!myRequestContext.IsMimeMultipartContent())
{
Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
}
BTW, assuming you are creating a REST API controller from what you said, don't forget to indicate the verb this handler is mapped to, either by using the [Http<REST_verb>] attribute in System.Web.Http on the handler or by prefixing the handler name by the verb.
Hope that helps!