Sql Server analysis Services 2008 Dynamic dimension security using MDX expression - security

Some dimension tables in my warehouse:
DML
Site
Id bigint
Name nvarchar(256)
Primary key (Id)
DATA
SiteId Name
2 Site 2
3 Site A
DML
UserSite
Username nvarchar(256)
SiteId bigint
Primary key (Username, SiteId)
Foreign key (SiteId) referrences Site(Id)
DATA
Username SiteId
EMSUser1 2
EMSUser1 3
EMSUser2 3
My SSAS Project:
I have used these two dimension tables in one dimension in a BIDS project, created using the dimension wizard.
The usernames relate to two local windows user accounts on the SSAS Server, they are members of a local windows
group ReportBrowsers. I have created a Role for that group in BIDS and added an MDX Expression to the dimension Data tab
for this dimension in the AllowedSet box for the Username attribute:
STRTOMEMBER("[UserSiteSite].[Username].["+Trim(Mid( UserName, InStr(1, UserName, "\")+ 1,128))+"]")
This dimension is used in a cube that's all processed and deployed. I then have an SSRS Report based on that cube.
My intention:
What I'm trying to do is take the logged in user currently browsing SSRS and remove the "<domain>\" part of the string returned
effectively filtering the results to just the sites that username has a record for.
So for EMSUser1 I should see records for both sites, but it appears to be allowing the first one only ("Site 2" with Id 2)
There's no sign of "Site A" even though records exist for that site in the fact table.
I've been trawling through Analysis Services 2008 unleashed and the step by step book and all over blogs etc.
I just can't quite grok the internal workings to achieve my goal.
What am I doing wrong?

Well it's been some time now. I don't have the complete answer even now but I did get some help else where that has lead me to a solution. The details can be found here.
There are a lot of ways to solve this kind of scenario. I feel there may still be a better one for me, but I have something that at least works. Basically create a seperate class library with a static class and function that makes it's own connection to the database and selects out the allowed set. If you reference the Microsoft.AnalysisServices
and Microsoft.AnalysisServices.AdomdServer namespaces you can return a 'Set' object. You can then call this function in the Role objects Dimension data advance tab:
MyAssembly.MyMethod(UserName)

Related

Tabular Cube - Excel Filtering Doesn't Function At Node Level

I have the issue described in this post. I have two cubes with the same data backing them, one a Multi-Dimensional cube, the second a Tabular cube. If I connect to the cubes with excel and drag the top level of a hierarchy(in this example "Company" into my filter category in the Multi-Dimensional cube, then enter some text in the search bar in excel:
(Hierarchy - In Excel)
(Hierarchy - In Visual Studio)
(MultiDimensional - In Excel as a filter)
The level below will be filtered by the text and the results will be returned. However if I filter the same hierarchy in the tabular cube, the results are different:
(Tabular - In Excel as a filter)
I receive no results, the search doesn't appear to function correctly. I can get it to work if I'm looking at the leaf level of the hierarchy, but it appears as though the node level of the hierarchy search feature for tabular cubes in excel doesn't work.
Has anyone else experienced this issue before, I'd love to post the model of the cube but it's rather proprietary, I have experienced the same issue in multiple types of proprietary cubes on multiple servers and clients. Is this some sort of configuration in the model I can change? Or something in excel I can change?
Update 1
I've been doing a bit more digging, I setup SQL Profiler to run against my SSAS server while I performed the search, seems it's generating a MDX query(this time on my "item" hierarchy):
WITH MEMBER [Measures].cChildren As 'AddCalculatedMembers([Item].[I1 - Category].currentmember.children).count'
Set FilteredMembers As 'Head (Filter(AddCalculatedMembers([Item].[I1 - Category].[Category].Members), InStr(1, [Item].[I1 - Category].currentmember.member_caption, "Per")>0),10001)'
Select {[Measures].cChildren} on ROWS,
Hierarchize(Generate(FilteredMembers, Ascendants([Item].[I1 - Category].currentmember))) DIMENSION PROPERTIES PARENT_UNIQUE_NAME,
MEMBER_TYPE ON COLUMNS FROM [XXX_Test_TabularPro]
But it appears to be erroring out (would explain why I'm not getting any results in excel) when run against my cube:
Either you do not have permission to access the specified member, or
the specified member does not exist.
It's a interesting error message, I've actually never seen it before, and there's not much on the internet about it, just a few dead ends. I'm quite sure I don't have a permission issue, I can reproduce the error by running the query as an admin on that server. I think it's related to something in the query or the format of the cube but I'm not quite sure which is the issue, and I'm not super familiar with MDX. Has anybody seen this before? Is there something I can change with the cube to not have this occur? Is it a syntax issue with the query, if so why would excel generate an invalid query?
Another interesting item of note, I noticed that the search function for a leaf level hierarchy works in excel(as noted above) so I swapped out "I1 - Item Category" for "IA - Item Name" and the query runs without issue (of course we're now searching the leaf level), it's something about running this query on a non-leaf level in this case "I1 - Item Category" that is causing this error to occur.
Update 2
Ok I've made a bit of a breakthrough, I've altered my query to see if any combination of input would allow it to work, and I've found one, if I change my filter from "Per" to "GL" I get a result, it turns out that the query outlined above is actually NOT returning results from "I1 - Item Category", it's actually returning results from "[Item].[IA - Item Name].Members" which contains a distinct list of item name's.
I can actually demonstrate this in excel as well:
This makes no sense what so ever, nowhere in my query shown above(the query generated from excels search) do I mention the item name, and you clearly see what "[Item].[I1 - Category].[Category].Members" should be returning in the screenshots above(and what is returned by the multidimensional cube), it just doesn't in tabular, worst of all I captured(with SQL profiler) the query from excel on searching the item hierarchy of both my identical tabular and multidimensional versions of my cube and they generate the same exact MDX query with the only difference being the name of the cube.
I'm forced to come to the conclusion that if one generates two identical cubes(identical as possible), one being tabular, the other multidimensional, and run the above query on them(assuming this hierarchy exists), they return different results, and tabular one will return incorrect results.
Has anyone seen this issue before? I feel the tabular cube is returning a incorrect record set for the specified MDX, how would this occur, is there anything I could do to modify the query or cube to resolve this issue?
Update 3
The saga continues, one of the core questions I'd like to answer here is: Is this something specific to the cubes I generate, or does it affect all cubes, I believe I have the answer to this...
Steps To Reproduce:
Open Visual Studio, New Project, Select "Analysis Services Tabular Project", Next, Create, (A popup will display "Tabular Model Designer" I selected "Workspace Server" point it at my tabular cube server and set compatibility model 1200)
Add the following data to a CSV file or by putting it in a SQL table:
Category_Description Sub Category_Description LeafName
Professional 10 Series Filter
Performance 10 TTR GL
Professional 10 Series Series 1
Unassigned Unassigned AUTOMOTIVE
Performance 500 S RACING
Right click on "Data Sources" select "Import from Data Source", navigate through the menus to import the data source defined above.
As part of item 3 you should've imported the table listed in step 2, you should see this in your tables the new table from your data source:
Open your new table and create the following hierarchy:
Right click on your "TabularProject" in VS, select "Analyze in Excel", this should bring up a excel window
Pull the "Hierarchy1" hierarchy into "Filters", drop down this hierarchy in excel and attempt to search for "Per": You'll see that no results are displayed.
IMPORTANT Note: If I change the workspace to "Integrated", rebuild and process the cube, I no longer see the bug, it must be related to how the server is processing this model, in someway it must be different then how VS does it locally.
Ok, I think I finally understand what is occurring here, I checked my SSAS version number:
15.0.32.55
This is quite old, so I updated to "15.0.35.15" and it appears as though the issue is now resolved(search in excel now works), I believe this version upgrade introduced a fix that resolves this bug, most likely either this one, or this one.
I tested this with a slightly different environment. I used Power BI to build the model and there, it works like a charm.
I uploaded the model then to SSAS and tested again and it still works out for me. I am SQL 2019 an Power BI.
Finally, I tested with VS 2019 native developed model and workspace server. Also, this works out without any problem.

Assignment of legal entity to roles for users via dmf

I m in need to find the data entity which will help to assign legal entity to a role in bulk through dmf. The below link provides information for manual and organization hierarchy for the same process.
https://alexdmeyer.com/2020/01/07/options-for-configuring-user-legal-entity-restrictions-in-d365fo/
Kindly help.
TLDR
You are looking for entity "System security user role organization" (SystemSecurityUserRoleOrganizationEntity).
Note that there is a second entity with the technical name SystemSecurityUserRoleEntity (without Organization) that unfortunately uses the same label. Make sure you use the correct one.
Also note that this entity exists since version 10.0.11.
DIY
To find this information yourself in case you have a similar "What is the entity for x?" question in the future, here is the details of what I did to find the entity:
First, I followed the instructions from the link you provided to the form of the "Assign organizations" function. There, I checked what table is used as the data source for the grid in the lower part of the form where records are created when the "Grant" function is used. This told me that table OMUserRoleOrganization stores the data where legal entities are assigned to the roles of a user.
Next, I opened up Visual Studio, navigated to the table in the application explorer and used the context (right click) menu to find the references of the table. A bit down the list, you will notice that several entries start with dynamics://*. These are metadata references (e.g. a data source in a form) instead of code references. In this case, you are looking for a metadata reference that starts with dynamics://DataEntityView/*. This identifies data entities where the table is used, usually as a data source in the query of the entity. In this case, only one entity is found, SystemSecurityUserRoleOrganizationEntity. If you look at the fields of this entity, they match your requirement of specifying a user, a role and a legal entity.
To test the entity, I assigned an user's role to an organization (Contoso data doesn't seem to have this) and created an export project with the entity. This gives me the following result:

Kentico - WHERE condition for custom Page Types page

I have a custom page type for employees, and one of the fields is Location. I want to show/filter only employees in "San Jose" or "San Francisco" and used this WHERE condition below but it didn't work. Apparently, I missed something very basic. Could you help?
Location LIKE '%San%';
I did another test, where instead of page type, I used custom table with the exact field names and was able to filter using the same statement. On a related note, I'm new to Kentico and exploring which is more suitable for creating/maintaining a list of about 100 employees - Page Types or Custom Tables - with the ability to filter by department, location etc. Appreciated your input here as well. Best!
If you're adding the WHERE condition into a standard Kentico repeater or other data source, the syntax looks right except you do not need the semicolon ";".
You'll also want to double check the field name, and if you are limiting your query to certain columns (as is best practice especially for larger data sets) and be sure the field you are filtering on is being selected.
Regarding the management of your employee list, either method you've described will work. In that scenario it typically depends on who will be editing the content, and how frequently. It is more editor-friendly, in my opinion, to add those documents into the content tree. This also gives you quicker control over the order, and keeps it similar to how other content on the site is maintained. I also like to set up folders or other parent page types as categories if needed, so the documents can be dragged and dropped between them and it sets up a visual taxonomy that isn't possible if it's all stored in a table. Storing items in the tree also allows for workflow and versioning, as well as more granular control over permissions/access, if this is important to you.
It's awesome that you are thinking about how to best store your data in advance. There many factors to consider such as overall number of records, number of columns, the fact whether you need to use workflow, versioning, preview etc..
The best source of information regarding this would be this article which summarizes all options you have and gives clear explanations of which to use in which scenario.
And to your original question - What components are you using to display the data? Is the repeater? If so, can you make sure to set the Page types property to match the page type you are displaying? If the page types is not configured, Kentico will not load any custom fields because it doesn't know from which table it should load the data from.
Additionally make sure to either include the "Location" field in the Columns property or leave the columns blank (not recommended because then Kentico loads all columns which is like 200. when you count all from CMS_Document, CMS_Tree etc..)
Below is the framework that I use to debug whenever I wish to add a repeater and is facing some problem.
First get all the columns instead of accessing limited columns. Fetching all columns will make sure that I don't have any problem retrieving data.
If I am missing any particular column information name, then I would double check the column name.
I verify this by firing up SQL server management studio and access data from page type table or custom table.
If access to SQL server is not available(generally in Azure hosted solutions with restrictive access to DB), I would enable SQL debug from the settings and see what query repeater is generating to see if it is correct.

SSAS Dynamic Dimension Security based on another dimension attribute

In my project I have to apply security based on a dimension attribute.
I think the best way to explain my scenario is with an example, if you need more info please request me and I'll love to told you if it will help me find a solution.
I have some main dimension, the dimcustomer, dimseller, fact, data and geographic.
The fact table are related with dimseller ids, the dimcustomer is related to the dimseller based on one dimseller specific attribute(CNPJ)(another dimensions that i didnt described are related the same way).
So my goal is to apply a role security based on the dimseller CNPJ, so then when the user related with that seller trys to browse data he will be allowed to view only the data that are related to his seller CNPJ.
Table example:
DIM Seller: DIM Customer FactTable
id name cnpj id name dimseller.cnpj dimseller.id dimcustomerid measure
1 ME 1234 1 guest1 1234 1 1 50,00
2 you 5678 2 guest2 5678 2 2 100,00
So if i login as ME i will be able to se that i have the customer guest1 with one sold product that was sold by 50 bucks.
Got my point?
What is the best way of doing it?
For now I'm considering the following guide: Claim Authentication with dynamic dimension security, but at that way I should define it attribute by attribute.
Is there a way that i can define this security need? I can easy filter the data using sql statements, but i have no ideia how i can apply this kind of security in the ssas.
Thank you guys anyway!
To apply security within a dimension, you need to use roles. For each roles, you can then specify which element in the cubes/dimensions that are available to that role. So, what you got to do is to create a role by CNPJ that will be able to view only their CNPJ.

Sitecore Custom User Profile - where is it stored how can it be queried

I have created a custom User profile template and object in the core database in Sitecore (as per the Security API Cookbook).
I can select this programmatically (as per the Security API Cookbook) so that my extranet users have an extended profile, that covers all the usual suspects (Address, phone, email format etc.)
However, where is this data stored? And how do I access it if I want to query the database to return a subset of users based on this profile data.
A typical requirement for an extranet member system is to extract a list of users to contact either in an email or a phone type campaign. Can this be done with the Sitecore membership system?
UPDATE>
I'm going to take a guess and say the profile data is stored in aspnet_Profile.PropertyValuesBinary .. which would make it nigh on impossible to query and not suited to my purpose. That is unfortunate. So to extend my question, if that is the case, is it possible to get Sitecore to store those values in the text field so they are searchable?
The standard Microsoft implementation of the SqlProfileProvider (which is used in Sitecore by default) stores the user profile information in the aspnet_Profile table. All the properties are serialized into the PropertyNames / PropertyValuesString columns. The PropertyValuesBinary is used to store the binary data (images). You can find more details if you look at the code of System.Web.Profile.SqlProfileProvider, SetPropertyValues method.
Next, all the custom properties you define in the user profile, are serialized to the SerializedData property of the Profile class, and it is again serialized to the PropertyNames / PropertyValuesString columns like any other property.
Also, couple of properties are stored in aspnet_Membership table (for some reason) - Email and Comment.
So, if you are going to query the users by Email, you can use FindUsersByEmail method of MembershipProvider. Otherwise, if you plan to filter by another property value, I suppose, you'll have to get all users and filter the obtained collection.
Hope this helps.
I faced this exact problem last week, didn't come up with a permanent solution, but to solve my particular issue, I wrote a little helper page and added it as a Sitecore application to be accessed from the CMS interface. All it did was query all users, and determine if they had any of like 5-6 profile properties assigned.
var userList = Sitecore.Security.Accounts.UserManager.GetUsers();
That is the relevant line to grab the users, it returns Sitecore.Common.IFilterable
So if you need to do something where you're grabbing profile info from all users, you cn do something like this:
foreach (Sitecore.Security.Accounts.User user in userList)
{
Sitecore.Security.UserProfile profile = user.Profile;
string whatever = profile["Whatever"];
//add whatever to a list or something
}
This worked out very well for my purposes, but I don't know how feasible it will be in your situation.

Resources