I am getting the following when trying to implement Azure Key Vault Secret from a stateless service fabric works just fine from a console app.
System.TypeLoadException
HResult=0x80131522
Message=Inheritance security rules violated by type: 'System.Net.Http.WebRequestHandler'. Derived types must either match the security accessibility of the base type or be less accessible.
Source=Microsoft.Rest.ClientRuntime
StackTrace:
at Microsoft.Rest.ServiceClient`1.CreateRootHandler
public async Task<string> GetAccessToken(string authority, string resource, string scope)
{
var clientId = MyConfig.Settings.Sections["MyConfigSection"].Parameters["AuthClientId"].Value;
var clientSecret = MyConfig.Settings.Sections["MyConfigSection"].Parameters["AuthClientSecret"].Value;
ClientCredential clientCredential = new ClientCredential(clientId, clientSecret);
var context = new AuthenticationContext(authority, TokenCache.DefaultShared);
var result = await context.AcquireTokenAsync(resource, clientCredential);
return result.AccessToken;
}
public string GetCRMConnectionString()
{
var secretvaultAddress = MyConfig.Settings.Sections["MyConfigSection"].Parameters["SecretVaultUrl"].Value;
var client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetAccessToken));
return client.GetSecretAsync(secretvaultAddress).GetAwaiter().GetResult().Value;
}
WebRequestHandler type(whose instance gets created in your case) is a part of System.Net.Http.WebRequest.dll. If you explore assembly's attributes, you'll find the next one applied to it -
[assembly: AllowPartiallyTrustedCallers]
This attribute makes the assembly being considered as SecurityTransparent. WebRequestHandler is derived from HttpClientHandler defined in another assembly - System.Net.Http.dll. So probably on the environment where you have the code deployed, System.Net.Http.dll is missing AllowPartiallyTrustedCallers which makes it security-critical, meaning that rules get violated - transparent code can not call into security-critical one.
Try to resolve it by either creating a binding rule to a specific System.Net.Http.dll version that has AllowPartiallyTrustedCallers attribute or try to create HttpClient explicitly and pass it then into KeyVaultClient ctr.
Refer to this link for more details and options - Inheritance security rules violated by type: 'System.Net.Http.WebRequestHandler'.
Related
I have a API that accepts a submission request (that when accepted to return http code 202 Accepted), for some workflow to approve, and then the caller to retrieve the result later.
The URL should be returned on successful submission and I am trying to use AcceptedAtActionResult with Azure Functions, however I do not understand how to use it as they don't have Controllers per my understanding, but this is one of the parameters.
Regardless and trying to use string.Empty, or the class name EnrollmentFunctions, or path enroll, the library is generating strange paths (in this case pointing to a different function in a different file i.e. location: http://localhost:7071/api/attest/c588484e-8e57-47f6-bf6c-973cfa5b9214?action=GetStatus&controller=enroll).
I am looking to return of the form location: http://localhost:7071/api/enroll/c588484e-8e57-47f6-bf6c-973cfa5b9214 (but avoid hardcoding URLs, both for maintenance and also running in dev mode on local machine).
I believe this would get more complicated if we used a cloud WAF (like cloudflare) on the front-end, in that case I presume would create my own class to build the URL (i.e. https://api-protected-by-waf.mydomain.com/enroll/bf920104-a630-4b58-97cb-cc3ae45c31d3)? I can see this then becoming a configuration issue was looking to avoid on the previous para.
Research points to creating my own IUrlHelper and possibly specifying key:values for retrival via Environment.GetEnvironmentVariable("your_key_here") (for use by my IUrlHelper implementation).
Thanks in advance on how to solve this issue or if i am using the libraries incorrectly and alternate best practice. Code of the Azure functions are below:
public class EnrollmentFunctions
{
[FunctionName("Enroll")]
public async Task<IActionResult> Enroll(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "enroll")] HttpRequest req)
{
var id = Guid.NewGuid();
return new AcceptedAtActionResult("GetStatus", "enroll", new { id = id }, id);
// return new AcceptedAtRouteResult("GetStatus", (new { id }, new { Result = id.ToString() }));
}
[FunctionName("GetStatus")]
public async Task<IActionResult> GetStatus(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "enroll/{id}")] HttpRequest req)
{
return new OkObjectResult("OK");
}
}
I have been developing a system which is heavily using stateless service fabric services. I thought I had a good idea how things worked however I am doing something slightly different now and it is obvious my understanding is limited.
I have a cluster of 5 nodes and all my services have an instance count of -1 for simplicity currently. With everything on every node it means I can watch a single node for basic behavior correctness.
I just added a new service which needs an instance count of 1. However it seems I am unable to resolve this service correctly. Instead SF tries to resolve the service on each machine which fails for all machines except the one where the single service exists.
It was my assumption that SF would automagically resolve a reference to a service anywhere in the cluster. If that reference fails then it would automagically resolve a new reference and so on. It appears that this is not correct at least for the way I am currently doing things.
I can find an instance using code similar to this however what happens if that instance fails. How do I get another reference?
I can resolve for every call like this however that seems like a terrible idea when I really only want to resolve a IXyzService and pass that along.
This is how I am resolving services since I am using the V2 custom serialization.
var _proxyFactory = new ServiceProxyFactory(c =>
{
return new FabricTransportServiceRemotingClientFactory(
serializationProvider: new CustomRemotingSerializationProvider(Logger)
);
});
var location = new Uri("fabric:/xyz/abcService");
var proxy = _proxyFactory.CreateServiceProxy<TService>(location);
This does actually work however it appears to only resolve a service on the same machine. So ServiceA would resolve a reference to ServiceB on the same machine. However if ServiceB doesn't exist on the machine for a valid reason then the resolution would fail.
Summary:
What is the correct way for ServiceA to use the V2 custom serialization ServiceProxyFactory to resolve an interface reference to ServiceB wherever ServiceA and ServiceB are in the cluster?
Update:
The evidence it doesn't work is the call to resolve hangs forever. According to this link that is correct behavior because the service will eventually come up. However only 1 node ever resolved it correctly and that is the node where the single instance is active. I have tried several things even waiting 30 seconds just to make sure it wasn't an init issue.
var proxy = _proxyFactory.CreateServiceProxy<TService>(location);
// Never gets here except on the one node.
SomethingElse(proxy);
Listener code
This essentially follows the V2 custom serialization tutorial almost exactly.
var listeners = new[]
{
new ServiceInstanceListener((c) =>
{
return new FabricTransportServiceRemotingListener(c, this, null,
new CustomRemotingSerializationProvider(Logger));
})
};
public class HyperspaceRemotingSerializationProvider : IServiceRemotingMessageSerializationProvider
{
#region Private Variables
private readonly ILogger _logger;
private readonly Action<RequestInfo> _requestAction;
private readonly Action<RequestInfo> _responseAction;
#endregion Private Variables
public CustomRemotingSerializationProvider(ILogger logger, Action<RequestInfo> requestAction = null, Action<RequestInfo> responseAction = null)
{
_logger = logger;
_requestAction = requestAction;
_responseAction = responseAction;
}
public IServiceRemotingRequestMessageBodySerializer CreateRequestMessageSerializer(Type serviceInterfaceType, IEnumerable<Type> requestWrappedTypes,
IEnumerable<Type> requestBodyTypes = null)
{
return new RequestMessageBodySerializer(_requestAction);
}
public IServiceRemotingResponseMessageBodySerializer CreateResponseMessageSerializer(Type serviceInterfaceType, IEnumerable<Type> responseWrappedTypes,
IEnumerable<Type> responseBodyTypes = null)
{
return new ResponseMessageBodySerializer(_responseAction);
}
public IServiceRemotingMessageBodyFactory CreateMessageBodyFactory()
{
return new MessageBodyFactory();
}
}
Connection code
_proxyFactory = new ServiceProxyFactory(c =>
{
return new FabricTransportServiceRemotingClientFactory(
serializationProvider: new CustomRemotingSerializationProvider(Logger)
);
});
// Hangs here - tried different partition keys or not specifying one.
var proxy = _proxyFactory.CreateServiceProxy<TService>(location, ServicePartitionKey.Singleton);
we keep fighting with out multi tenant application.
This is an ASP MVC EF6 Code First web application.
We initialize a list of tenants in the Application_Start, getting a pair of values:
Host
TenantId
So we can associate any host with one TenantId, and store that list in cache.
We have configured a custom filter to get the current tenant.
public class TenantActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Items.Add("TenantId", GetCurrentTenant(filterContext.HttpContext.Request.Url.Host));
base.OnActionExecuting(filterContext);
}
}
The GetCurrentTenant function just access the list in cache and get the current one based on the host passed.
Is it correct to store the current tenant in an item in the context?
After that, we have created an Interceptor to get any query and add a filter to filter by TenantId. This is done and working good, we just need to add the tenantId from the context:
The problem we have is where we get the TenantId for each request.
if (HttpContext.Current.CurrentHandler == null) return;
var clientId = Convert.ToInt32(HttpContext.Current.Items["ClientId"]);
foreach (DbParameter param in command.Parameters)
{
if (param.ParameterName != TenantAwareAttribute.TenantIdFilterParameterName)
continue;
param.Value = clientId;
}
We don't know if this is the correct approach since there is a lot of informationon the net.
Thanks.
In my experience, the persistence of the tenant Id in the HTTP context is not right, as in some cases, the HTTP context becomes null.
You can try to get the tenant Id from the claims of the current principal. Creating a static class with a tenant identifier property that reads from the claims and gives is more reliable. Assuming you are using the owin pipeline, this should be easy to do. You can take a look at the reference sample application from github here
It looks like the below block,
public static class UserContext
{
public static string TenantId
{
get
{
return Threading.Thread.CurrentPrincipal.FindFirst("tenantid");
}
}
}
I'm trying to customize an Azure Web app application that was created with Visual Studio. I've added an AccountsController to help with user registration using the Owin membership tables. I want to add Owin to the site, so I'm customizing the WebApiConfig.cs file with this method:
public static void Register(HttpConfiguration config)
{
// Use this class to set configuration options for your mobile service
var options = new ConfigOptions();
var configBuilder = new ConfigBuilder(options, (configuration, builder) =>
{
var executingAssembly = Assembly.GetExecutingAssembly();
var file = FileHelper.GetLoggingConfigFile(executingAssembly);
// startup the logging
_logger = new Logger(MethodBase.GetCurrentMethod().DeclaringType, file);
//builder.RegisterInstance(new CustomOwinAppBuilder(configuration))
// .As<IOwinAppBuilder>();
//configure the Autofac IoC container
AutofacBuilder.Configure(executingAssembly, _logger, builder, new MvcModule(),
new TaskModule());
});
var defaultConfig = ServiceConfig.Initialize(configBuilder);
// Make sure this is after ServiceConfig.Initialize
// Otherwise ServiceConfig.Initialize will overwrite your changes
StartupOwinAppBuilder.Initialize(app =>
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(TrainMobileContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// app.UseFacebookAuthentication("", "");
});
defaultConfig.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// To display errors in the browser during development, uncomment the following
// line. Comment it out again when you deploy your service for production use.
// config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
Database.SetInitializer(new MobileServiceInitializer());
}
The AutofacBuilder handles a lot of the registration with statements like so:
builder.RegisterType<RepositoryProvider>().As<IRepositoryProvider>().InstancePerHttpRequest();
builder.RegisterType<DataManager>().As<IDataManager>().InstancePerHttpRequest();
builder.RegisterType<Logger>().As<ILogger>().InstancePerLifetimeScope();
// new TrainMobileUserStore(context.Get<SpaceLinxContext>())
builder.RegisterControllers(assembly).InstancePerHttpRequest();
builder.RegisterApiControllers(assembly);
builder.RegisterModelBinders(assembly).InstancePerHttpRequest();
builder.RegisterType<LogAttribute>().PropertiesAutowired();
builder.RegisterFilterProvider();
// Needed to allow property injection in custom action filters.
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();
builder.RegisterControllers(assembly).InjectActionInvoker();
When I've made these changes however, two things happen:
Firstly, the default azure mobile app default helper page disappears and I get a default page with this:
HTTP Error 403.14 - Forbidden
The Web server is configured to not list the contents of this directory.
Secondly, when I attempt to call the Help pages or AccountsController directly, a runtime exception is raised:
System.InvalidOperationException occurred
HResult=-2146233079
Message=No service registered for type 'ITableControllerConfigProvider'.Please ensure that the dependency resolver has been configured correctly.
Source=Microsoft.WindowsAzure.Mobile.Service
StackTrace:
at System.Web.Http.DependencyScopeExtensions.GetServiceOrThrow[TService](IDependencyScope services)
at Microsoft.WindowsAzure.Mobile.Service.Tables.TableControllerConfigAttribute.Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
at System.Web.Http.Controllers.HttpControllerDescriptor.InvokeAttributesOnControllerType(HttpControllerDescriptor controllerDescriptor, Type type)
at System.Web.Http.Controllers.HttpControllerDescriptor.InvokeAttributesOnControllerType(HttpControllerDescriptor controllerDescriptor, Type type)
at System.Web.Http.Controllers.HttpControllerDescriptor..ctor(HttpConfiguration configuration, String controllerName, Type controllerType)
at System.Web.Http.Dispatcher.DefaultHttpControllerSelector.InitializeControllerInfoCache()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at System.Lazy`1.get_Value()
at System.Web.Http.Dispatcher.DefaultHttpControllerSelector.GetControllerMapping()
at System.Web.Http.Description.ApiExplorer.InitializeApiDescriptions()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at System.Lazy`1.get_Value()
at System.Web.Http.Description.ApiExplorer.get_ApiDescriptions()
at MyMobileApp.Mvc.Areas.HelpPage.Controllers.HelpController.Index() in C:\tfs\MyMobileApp\dotNET\Web\MyMobileApp.Mvc\Areas\HelpPage\Controllers\HelpController.cs:line 31
InnerException:
Does anyone know what the problem with this could be? Do I need to explicitly register the mobile service assemblies and if so, what's the best way of doing that?
This is now resolved.
Just to wrap this up, the basic problem was that I'd changed the WebApiConfig.Register method so that it was non standard. I'd changed it from this
public static void Register()
to this
public static void Register(HttpConfiguration config)
and was attempting to use it like one would a standard Mvc webapi configuration from Global.asax.cs
Once I changed it back, I was able to register objects using autofac in the method like this:
builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
builder.RegisterType<ApplicationSignInManager>().AsSelf().InstancePerRequest();
builder.Register(c => new UserStore<ApplicationUser>(c.Resolve<ApplicationContext>())).AsImplementedInterfaces().InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();
builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager>
{
DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("Application​")
});
without any problem
thanks
In Autofac one can do the following to get all registered services:
IEnumerable<MyClass> all = Context.Resolve<IEnumerable<MyClass>>()
However, this does not include those which were registered as named services.
Looking at the Autofac source it seems this is because services are queried for resolution based on either a TypedService or a KeyedService.
Is there a way to resolve all services to an IEnumerable, irrespective of whether they were registered with a name or not?
The best option here is to register the items using both the key and the regular 'typed' service:
builder.Register<CupOfT>()
.As<IBeverage>()
.Keyed<IBeverage>("someKey");
You can then just resolve IEnumerable<IBeverage> to get the result you're after, while resolving them by key (or name) is also supported.
If you're concerned about maintaining a particular default registration for IBeverage just use PreseveExistingDefaults() on the others (or make sure your intended default is registered last).
HTH!
Nick
I've written a method which appears to work; I'd appreciate feedback if there's a built-in way to do this in Autofac. In the below example, the field _context is of type IComponentContext.
public IEnumerable<T> ResolveAll<T>()
{
// We're going to find each service which was registered
// with a key, and for those which match the type T we'll store the key
// and later supplement the default output with individual resolve calls to those
// keyed services
var allKeys = new List<object>();
foreach (var componentRegistration in _context.ComponentRegistry.Registrations)
{
// Get the services which match the KeyedService type
var typedServices = componentRegistration.Services.Where(x => x is KeyedService).Cast<KeyedService>();
// Add the key to our list so long as the registration is for the correct type T
allKeys.AddRange(typedServices.Where(y => y.ServiceType == typeof (T)).Select(x => x.ServiceKey));
}
// Get the default resolution output which resolves all un-keyed services
var allUnKeyedServices = new List<T>(_context.Resolve<IEnumerable<T>>());
// Add the ones which were registered with a key
allUnKeyedServices.AddRange(allKeys.Select(key => _context.ResolveKeyed<T>(key)));
// Return the total resultset
return allUnKeyedServices;
}
It would appear that you can combine the As<T>() methods and Named<T>() methods as shown below:
[TestMethod]
public void ResolveTests()
{
var builder = new ContainerBuilder();
builder.RegisterType<ClassA1>().As<IClassA>().Named<IClassA>("1");
builder.RegisterType<ClassA2>().As<IClassA>().Named<IClassA>("2");
builder.RegisterType<ClassA3>().As<IClassA>().Named<IClassA>("3");
var container = builder.Build();
var allInstances = container.Resolve<IEnumerable<IClassA>>();
allInstances.Count().Should().Be(3);
container.ResolveNamed<IClassA>("1").Should().BeAssignableTo<ClassA1>();
container.ResolveNamed<IClassA>("2").Should().BeAssignableTo<ClassA2>();
container.ResolveNamed<IClassA>("3").Should().BeAssignableTo<ClassA3>();
}