Deny node has visible - mvcsitemapprovider

When running the command #Html.MvcSiteMap().Menu(false) all nodes (even those who are denied access) are displayed.
As an example I have the controller Financeiro
[Authorize(Roles = "Financeiro")]
public class homeController : baseController
{
public ActionResult index()
{
return View();
}
}
In Mvc.sitemap
<mvcSiteMapNode title="Financeiro" roles="Financeiro" area="Financeiro" clickable="false">
<mvcSiteMapNode title="Contas" controller="contas" action="index">
<mvcSiteMapNode title="Nova conta" action="novo" changeFrequency="Never" btnClass="btn-primary" />
</mvcSiteMapNode>
<mvcSiteMapNode title="Categorias" controller="categorias" action="index" />
<mvcSiteMapNode title="A Pagar" controller="apagar" action="index" description="Contas a pagar" />
<mvcSiteMapNode title="A Receber" controller="areceber" action="index" description="Contas a receber" />
</mvcSiteMapNode>
Ninject
I use Ninject, and installed package MvcSiteMapProvider.MVC4.DI.Ninject.Modules
In file MvcSiteMapProviderModule.cs
this.Kernel.Bind<ISiteMapNodeVisibilityProviderStrategy>().To<SiteMapNodeVisibilityProviderStrategy>()
.WithConstructorArgument("defaultProviderName", "MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider");
Packages
MvcSiteMapProvider.MVC4 4.0.6
MvcSiteMapProvider.MVC4.Core 4.0.6
MvcSiteMapProvider.MVC4.DI.... 4.0.6
MvcSiteMapProvider.Web 4.0.6
When a user (with or without Financiero role) accesses the system, the node is displayed

Did you enable security trimming in your Ninject MvcSiteMapProviderModule.cs file? The default configuration has a variable at the top of the file.
bool securityTrimmingEnabled = false;
It is injected into the SiteMapBuilderSet near the end of the file:
// Configure the builder sets
this.Kernel.Bind<ISiteMapBuilderSet>().To<SiteMapBuilderSet>().Named("siteMapBuilderSet1")
.WithConstructorArgument("instanceName", "default")
.WithConstructorArgument("securityTrimmingEnabled", securityTrimmingEnabled)
.WithConstructorArgument("enableLocalization", enableLocalization)
.WithConstructorArgument("siteMapBuilder", this.Kernel.Get<ISiteMapBuilder>("compositeSiteMapBuilder"))
.WithConstructorArgument("cacheDetails", this.Kernel.Get<ICacheDetails>("cacheDetails1"));
You need to change this to true in order for the security features to function.
About the Exception:
One possible workaround is to disable the AuthorizeAttributeAclModule in your DI config, as it looks like you are only using the XmlRolesAclModule:
// Before
// Configure Security
this.Kernel.Bind<AuthorizeAttributeAclModule>().ToSelf();
this.Kernel.Bind<XmlRolesAclModule>().ToSelf();
this.Kernel.Bind<IAclModule>().To<CompositeAclModule>()
.WithConstructorArgument("aclModules",
new IAclModule[] {
this.Kernel.Get<AuthorizeAttributeAclModule>(),
this.Kernel.Get<XmlRolesAclModule>()
});
// After
// Configure Security
this.Kernel.Bind<XmlRolesAclModule>().ToSelf();
this.Kernel.Bind<IAclModule>().To<XmlRolesAclModule>();
But that is only side-stepping the problem, and you shouldn't do this if you are using the Authorize attribute or similar filters.
I have never seen a configuration that would cause AuthroizeAttributeAclModule to throw an exception before, I would really like to take a look at why this is happening. Can you build a demo and open an issue # GitHub?

Related

HazelCast configuration generates a lot members

I'm trying to add hazelcast to my project. the configuration below generates a lot of members.
What I need is only tow.
Configuration
<hz:hazelcast id="instance">
<hz:config>
<hz:group name="mass-storage-${env}" password="tomcat-${env}"></hz:group>
<hz:properties>
<hz:property name="hazelcast.merge.first.run.delay.seconds">5</hz:property>
<hz:property name="hazelcast.merge.next.run.delay.seconds">5</hz:property>
</hz:properties>
<hz:network port="${hazelcast.config-cluster.discovery-port}" port-auto-increment="false">
<hz:join>
<hz:multicast enabled="false"/>
<hz:tcp-ip>
<hz:member>${hazelcast.config-cluster.address-1}</hz:member>
<hz:member>${hazelcast.config-cluster.address-2}</hz:member>
</hz:tcp-ip>
</hz:join>
</hz:network>
<hz:map name="driveAccessTokensCache">
<hz:near-cache time-to-live-seconds="${drive.access.token.ttl.seconds}" max-idle-seconds="10" eviction-policy="LRU" invalidate-on-change="true" max-size="5000"/>
</hz:map>
<hz:map name="accessTokensCache">
<hz:near-cache time-to-live-seconds="${user.access.token.ttl.seconds}" max-idle-seconds="10" eviction-policy="LRU" invalidate-on-change="true" max-size="5000"/>
</hz:map>
</hz:config>
</hz:hazelcast>
this is what i got :
Members [2] {
Member [ecarbsul1680h11]:18934 this
Member [ecarbsul1550h11]:18934
}
03-Jun-2020 17:16:17.657 INFO [hz._hzInstance_2_dev.ServiceThread] com.hazelcast.cluster.ClusterManager.null [10.30.197.120]:5701 [dev]
Members [6] {
Member [10.30.197.223]:18934
Member [10.30.197.223]:5701
Member [10.30.197.226]:18934
Member [10.30.197.226]:5701
Member [10.30.197.120]:5701 this
Member [10.30.197.253]:5701
}
this is what i want to get :
Members [2] {
Member [ecarbsul1680h11]:18934 this
Member [ecarbsul1550h11]:18934
}
Could you please help me to know what is wrong with my configuration ?
Thanks
This line in your XML
<hz:hazelcast id="instance">
would direct Spring to create 1 #Bean of type "HazelcastInstance" with bean name "instance".
IF this file was used, you would see log messages mentioning the cluster name mass-storage-${env}.
You have a log message
03-Jun-2020 17:16:17.657 INFO [hz._hzInstance_2_dev.ServiceThread] com.hazelcast.cluster.ClusterManager.null [10.30.197.120]:5701 [dev]
that mentions a different cluster name (the default cluster name of dev).
So whatever is creating your Hazelcast instances isn't using this XML file, which is why it's not behaving as you had requested.
Try using #ImportResource("classpath:hazelcast-spring.xml") to get Spring to load the XML.
I also see mention of Tomcat. If you're using Tomcat with Hazelcast for session caching, Tomcat will create it's own Hazelcast instance unless you tell it to use an existing one. That might explain where the extra instances are coming from.

Spring Integration : How to intercept ALL spring integration component and fetch attribute values to log

I need to intercept ALL the Spring Integration components at runtime and should be able to fetch the attribute values in order to log a meaningful message.
For example:
<int-http:outbound-gateway url="someURL" http-method="GET"
request-channel="channel1"
expected-response-type="com.example.Test"
message-converters="customMessageConverters">
<int-http:uri-variable name="testId" expression="headers.testId"/>
</int-http:outbound-gateway>
In the example above, I need to intercept int-http:outbound-gateway and capture the value for url, request-channel and expected-response-type. We need to do this for all http outbound gateway.
Similarly, for all other components like int-http:inbound-gateway, int-http:inbound-channel-adapter, int:transformer, int:header-enricher, int:chain, int:router, etc.
I have tried creating a custom class implementing BeanPostProcessor - postProcessAfterInitialization method. Checked for the bean name to be matching with the component, and tried to retrieve all the details but the beans are created and this method is called at the server startup itself. My requirement is to capture the flow as and when the user navigates and any particular route is being called. Also I am not able to find Java class name for all the component apart from the below. Still finding for the rest.
org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway for int-http:inbound-gateway, org.springframework.integration.http.outbound.AbstractHttpRequestExecutingMessageHandler for int-http:outbound-gateway
Update:
I have tried the below but cant see any extra output in logs with respect to message history. Is anything missing in the above code?
<int:message-history />
<int:logging-channel-adapter id="logging"
log-full-message="true" logger-name="message.history" level="DEBUG"/>
<int:wire-tap pattern="*" order="3" channel="logging" />
or
<int:message-history />
<int:logging-channel-adapter id="logger"
log-full-message="true" logger-name="message.history" level="DEBUG"/>
<int:channel id="wiretapChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
Also, I am trying to inject LogMessage into wire-tap inorder to perform some additional tasks from MessageHistory data. But the control doesn't enter handleMessage method. Please help.
<bean id="logMessage" class="com.logging.LogMessage"/>
<int:service-activator input-channel="wiretapChannel" ref="logMessage" method="handleMessage"></int:service-activator>
public class LogMessage {
public void handleMessage(org.springframework.messaging.Message<?> message) throws MessagingException {
MessageHistory history = MessageHistory.read(message);
for (int i = 0; i < history.size(); i++) {
Properties properties = history.get(i);
getLogger().info("history: " + properties.get("name"));
}
}
}
Well, it's not so standard task, especially for the reading properties you would like to print. More over many of them are based on the SpEL expressions and the actual value depends on the request message.
There is though a component which is very close what you would like to get. It is called Message History.
All what you need is <int:message-history/> - and all the Spring Integration components will be tracked and will store they point into the MessageHistory.HEADER_NAME to show the whole path of the message over integration flow.
In addition I usually also use something like this:
<wire-tap channel="logger"/>
<logging-channel-adapter id="logger" log-full-message="true" logger-name="message.history"/>
To intercept all the channels in the application and log messages with their message history.
You may create your own POJO subscriber (<service-activator>) for the global <wire-tap> and perform some smart logic to extract a MessageHistory from the message: MessageHistory.read(Message<?>). Such a MessageHistory is a List<Properties> where, actually you can cast that Properties in the MessageHistory.Entry class and walk over its properties:
public String getName() {
return this.getProperty(NAME_PROPERTY);
}
public String getType() {
return this.getProperty(TYPE_PROPERTY);
}
public String getTimestamp() {
return this.getProperty(TIMESTAMP_PROPERTY);
}
With the name you can go to the BeanFactory to get the real component instance and already there try to extract required properties for your purpose, but again: not all of them are going to be available just because...
You also can consult with the Integration Graph for possible public properties of the IntegrationNode implementations.

MvcSiteMapProvider how to make a node match the current url

The current node is coming up null. I can't figure out how to make MvcSiteMapProvider resolve the node under this circumstance.
Here's the node it needs to match
<mvcSiteMapNode title="Policy" route="Details" typeName="Biz.ABC.ShampooMax.Policy" preservedRouteParameters="id" />
Here's the route:
routes.MapRoute(
"Details",
"Details/{id}",
new { Controller = "Object", Action = "Details" }
).RouteHandler = new ObjectRouteHandler();
The link that gets clicked:
http://localhost:36695/MyGreatWebSite/Details/121534455762071
It's hitting the route ok. Just the MvcSiteMapProvider.SiteMaps.Current.CurrentNode is null.
A null result for CurrentNode indicates the incoming request doesn't match any node in the SiteMap In your case there are 4 different problems that may be contributing to this:
The URL you are inputting http://localhost:36695/MyGreatWebSite/Details/121534455762071 does not (necessarily) match the URL pattern you specified in the route, "Details/{id}". It may if your site is hosted as an IIS application under IISROOT/MyGreatWebSite/.
Your mvcSiteMapNode doesn't specify a controller or action to match. route only acts like an additional piece of criteria (meaning only the named route will be considered in the match), but all of the parameters also need to be provided in order for there to be a match with the route.
You are passing in a custom RouteHandler, which could alter how the route matches the URL. Without seeing the code from your ObjectRouteHandler, it is impossible to tell if or how that will affect how the route matches the URL.
You have a custom attribute, typeName in your mvcSiteMapNode configuration. Unless you have specified to ignore this attribute, it will also be required in the URL to match, i.e. http://localhost:36695/MyGreatWebSite/Details/121534455762071?typeName=Biz.ABC.ShampooMax.Policy.
I recommend against using a custom RouteHandler for the purpose of matching URLs. The effect of doing so makes your incoming routes (URLs into MVC) act differently than your outgoing routes (URLs generated to link to other pages). Since MvcSiteMapProvider uses both parts of the route, it will cause URL generation problems if you only change the incoming routes without also changing the outgoing routes to match. Instead, I recommend you subclass RouteBase, where you can control both sides of the route. See this answer for an example of a custom RouteBase subclass.
However, do note that conventional routing is pretty powerful out of the box and you probably don't need to subclass RouteBase for this simple scenario.
Solution
I arrived at the answer by adding the mvc sitemap provider project into my own solution and stepping through the mvc sitemap provider code to see why my node wasn't being matched. A few things had to be changed. I fixed it by doing the following:
Mvc.sitemap
<mvcSiteMapNode title="Policy" controller="Object" action="Details" typeName="Biz.ABC.ShampootMax.Policy" preservedRouteParameters="id" roles="*"/>
RouteConfig.cs
routes.MapRoute(
name: "Details",
url: "details/{id}",
defaults: new { controller = "Object", action = "Details", typeName = "*" }
).RouteHandler = new ObjectRouteHandler();
Now at first it didn't want to work like this, but I modified the provider like so:
RouteValueDictionary.cs (added wildcard to match value)
protected virtual bool MatchesValue(string key, object value)
{
return this[key].ToString().Equals(value.ToString(), StringComparison.OrdinalIgnoreCase) || value.ToString() == "*";
}
SiteMapNode.cs (changed requestContext.RouteData.Values)
/// <summary>
/// Sets the preserved route parameters of the current request to the routeValues collection.
/// </summary>
/// <remarks>
/// This method relies on the fact that the route value collection is request cached. The
/// values written are for the current request only, after which they will be discarded.
/// </remarks>
protected virtual void PreserveRouteParameters()
{
if (this.PreservedRouteParameters.Count > 0)
{
var requestContext = this.mvcContextFactory.CreateRequestContext();
var routeDataValues = requestContext.HttpContext.Request.RequestContext.RouteData.Values;// requestContext.RouteData.Values;
I think the second modification wasn't strictly necessary because my request context wasn't cached; it would have worked if it was. I didn't know how to get it cached.
It's the first modification to make route values honor a wildcard (*) that made it work. It seems like a hack and maybe there's a built in way.
Note
Ignoring the typeName attribute with:
web.config
<add key="MvcSiteMapProvider_AttributesToIgnore" value="typeName" />
makes another node break:
Mvc.sitemap
<mvcSiteMapNode title="Policies" url="~/Home/Products/HarvestMAX/Policy/List" productType="HarvestMax" type="P" typeName="AACOBusinessModel.AACO.HarvestMax.Policy" roles="*">
so that's why I didn't do that.

TFS and MSBuild projects Logging for each project

I'm going build large number (300+) of projects on TFS. I'm considering a proj file to manage these as follows:
<ItemGroup Label="GGX_Projects" >
<MyProj Include="$(Source)Proj1.vcxproj" />
<MyProj Include="$(Source)Proj2.vcxproj" />
<MyProj Include="$(Source)Proj3.csproj" />
<MyProj Include="$(Source)Proj4.csproj" />
<MyProj Include="$(Source)Proj5.vcxproj" />
<MSBuild Projects="#(MyProj)"
Targets="ReBuid"
Properties="Configuration='$(Configuration)'"
RebaseOutputs="true"
ContinueOnError="true"
/>
This actually working fine, but one thing I'm unable to achieve i.e. to get Log for each of the projects mentioned in ItemGroup.
I need separate logs, so that if any project fails, that log can be sent via e-mail.
In addition, on msbuild command line, I tried /distributedFileLogger, but unable to understand how to use this to get log file for each project separately.
Is that a correct approach?
Can anyone please suggest some better solution which could provide separate logging for each project??
Distributed file logger is, as the name suggests, for logging from individual MSBuild nodes within a "distributed" build system, not for logging from individual projects, targets or tasks. You can try creating a simple custom logger, it is fairly trivial, I've written a sample below. Although, you might want to play around with event types for verbosity and use something like NLog rather than appending to files as you might get locks.
msbuild PerProjectLogger.sln /logger:PerProjectLogger\bin\Debug\PerProjectLogger.dll
using System.Collections.Concurrent;
using System.IO;
using Microsoft.Build.Framework;
namespace PerProjectLogger
{
public class Logger : Microsoft.Build.Utilities.Logger
{
public override void Initialize(IEventSource eventSource)
{
var loggers = new ConcurrentDictionary<string, FileInfo>();
eventSource.AnyEventRaised += (s, a) =>
{
var property = a.GetType().GetProperty("ProjectFile");
if (property == null)
return;
var project = property.GetValue(a) as string;
if (project == null)
return;
var logger = loggers.GetOrAdd(Path.GetFileName(project), name => new FileInfo(name + ".log"));
using (var writer = logger.AppendText())
writer.WriteLine(a.Message);
};
}
}
}
The simplest way to achieve this with TFS is to create a single build detention and then on the Process tab you should see an option to pick solutions to build. Here you can add each Project individually. When you do a build the default build process will do a foreach project and build them. You will get a log file in the drop location for each project.

How to register custom ISiteMapNodeUrlResolver in MvcSiteMapProviderRegistry

For the MvcSiteMapProvider v4, I've written a custom sitemap url resolver by overriding SiteMapNodeUrlResolverBase.
But I don't know how to register it in the MvcSiteMapProviderRegistry to make sure that a node's Url is always resolved using my own SiteMapNodeUrlResolver.
I expected something like:
this.For<ISiteMapNodeUrlResolver>().Use<MyUrlResolver>();
But this doesn't work, how should I do this?
The SiteMapNodeUrlResolvers (along with visibility providers and dynamic node providers) use a strategy pattern so you can wire up multiple instances and then refer to each instance by name. That name is then used by the AppliesTo() method to determine which URL resolver to use for each node.
If you inherit from SiteMapNodeUrlResolverBase rather than implement ISiteMapNodeUrlResolver, the default implementation of AppliesTo() will work in most cases. Then, this line (which is already included in the module by default) will automatically wire up all SiteMapNodeUrlResolvers:
// Multiple implementations of strategy based extension points
CommonConventions.RegisterAllImplementationsOfInterface(
(interfaceType, implementationType) => this.For(interfaceType).Singleton().Use(implementationType),
multipleImplementationTypes,
allAssemblies,
excludeTypes,
"^Composite");
By default, it only scans MvcSiteMapProvider.dll and your MVC project. If you have your URL resolver defined in a separate assembly, you will need to modify the allAssemblies variable to ensure that it includes your custom assembly.
Once it is loaded, then you need to call it by name. The default implementation uses the "ShortAssemblyQualifiedName", which is the same string that you would normally use to refer to a type in a configuration file (as long as your assembly is not strong named).
<mvcSiteMapNode title="Home" action="Index" controller="Home" urlResolver="MyNamespace.MySiteMapNodeUrlResolver, MyAssembly" />
The urlResolver property/attribute must be set on every node you wish to override the default implementation on.
If you prefer, you can implement the AppliesTo() method yourself so you can shorten the amount of configuration that is required. Note this will only work when using an external DI container because the internal DI container uses the type names from the configuration to instantiate the objects.
public override bool AppliesTo(string providerName)
{
return "myUrlResolver".Equals(providerName, StringComparison.InvariantCulture);
}
<mvcSiteMapNode title="Home" action="Index" controller="Home" urlResolver="myUrlResolver" />

Resources