Restricting users' access when using the Accelerator

Open
Lukas Navratil asked on July 26, 2017

Hi guys,
even if I went through the documentation for Accelrator and authentication, I'm probably not able to fully understand the authentication concept when accelerator for SSAS is used...
Our application is working in this way:

  • Windows authentication on web site that hosts the Flexmonster pivot. Our custom authorization which says which users can access the web
  • Flexmonster accelerator running on the web server
  • Web server is able to connect to SSAS using windows credentials - in flexmonster.config. I'm not supplying any credentials right now

Ideal case would be if we could use the end user authentication for accessing the SSAS. But I do not expect it is possible because of double hop issue - the web server can be on different machine than the SSAS. So I expect that Accelerator is using the account under which is the service running when no credentials are specified, is it right?
Also I expect that anybody who has access to the web server where accelerator is running can read the data from the accelerator unless it is restricted on firewall level.
Assume that we e.g. have 100 users in domain, 20 with access to the SSAS using Windows authentication (same 20 users have access to the web page), but all can access the Accelerator's endpoint via http. How can we manage that only 20 authenticated users can access the cube? It does not have to be necessary based on Windows authentication, we can implement user/password authentication on the web site, but still I don't know how to restrict the access on Accelerator side. The only think I would like to avoid is that we have to manually set allowed users in the firewall, because it would be another place where we have to keep and synchronize users.
In documentation at https://www.flexmonster.com/doc/configuring-authentication-process/ there is "In general, Accelerator will use these credentials if client-side report does not contain own credentials". How can I pass my own credentials in the report?
BTW, the main purpose of using Accelerator is that we want to avoid setting up the data pump on SSAS server.
Thanks in advance for any explanation or hints.
Regards,
Lukas
 

18 answers

Public
Dmytro Zvazhii Dmytro Zvazhii Flexmonster July 26, 2017

Hello Lukas,
Thank you for the detailed explanation.
Since the user authorization for Accelerator only works through IIS and data pump we want to recommend you another approach.
Accelerator can be integrated into your website backend as a separate ASP.NET controller. In this case, Accelerator endpoint will be on the same host as a website (i.e. http://example.com/api/FlexmonsterProxy/). It will give you the full control over the endpoint access management. For instance, if the end user has an open session he will be redirected to the Accelerator URL. Otherwise, it will be redirected to the authentication page.
We are ready to provide you with the Flexmonster Accelerator DLL file and with the examples of how to implement a separate controller. It will allow managing the security the way you want and also avoid setting up the data pump on SSAS server.
Please let us know if it works for you.
Best regards,
Dmytro.

Public
Lukas Navratil July 26, 2017

Hello Dmytro,
thanks for your answer, build a proxy in my MVC/WebAPI and just redirect authenticated requests to Accelerator endpoint which will be available only locally was one on mine ideas. If you have integration of endpoint to ASP.NET it would be great if you could provide me the DLL, otherwise I think I will manage to write my own solution...
Regards,
Lukas

Public
Ian Sadovy Ian Sadovy Flexmonster July 27, 2017

Hello Lukas,
 
Thank you for the answer, glad to hear that WebAPI solution can help.
As promised, we have prepared MVC/WebAPI sample.
Please find Flexmonster.Accelerator.Core.dll inside.
Also, connection string can be modified in the App_Start/FlexmonsterConfig.cs file.
 
Please let me know if you have any additional questions.
 
Regards,
Ian

Public
Lukas Navratil July 27, 2017

Hi Guys,
This is absolutely amazing, thanks a lot! I think this way - a DLL that can be referenced directly from the ASP.NET project and used without Accelerator installation - should be preferred way how to distribute the Accelerator. It makes our live much easier - no checking if prerequisites are installed, no running of Accelerator installers, easy update to newest version, no firewall settings, no service dependencies etc.
Thanks a lot once again!
Regards,
Lukas

Public
Lukas Navratil July 28, 2017

I have just found one issue, which is probably also exists when I use Accelerator as a service...
When I open the Connect -> To OLAP dialog, it sends a request to my API endpoint which contains SOAP body. There are two issues - there is no defined default action for /api/endpoint/ , I have tried to set default to Handshake, but still it does not expect SOAP content and fails on some NullReferenceException.
But even when I have accelerator running and I fill http://localhost:50005 to the Proxy URL, it does not load list of Catalogs/Cubes, the HTTP response just returns a message that accelerator is running.
It's low priority, ideal case would be if we could change just the cube - catalog and Proxy URL should be hardcoded. For now we can do our custom function for that... 

Public
Tanya Gryshko Tanya Gryshko Flexmonster July 28, 2017

Hello Lukas,
Thank you for writing. Currently, our Toolbar supports only OLAP connection via XMLA protocol. This step by step connection is supported by such API calls as getXMLADataSourcesgetXMLACatalogs and getXMLACubes. There are no such API calls for Accelerator. We may consider adding these API calls in our future minor releases. Please let us know how important this would be for your project.
Regards,
Tanya

Public
Lukas Navratil July 30, 2017

Hello Tanya, 
Thanks for the reply. Adding API calls would be nice, however it's just a medium priority for now and adding support for Accelerator in the dialog is a low priority - we can write custom dialog for that.
Regards,
Lukas

Public
Lukas Navratil August 9, 2017

Hi,
I have found one issue that causes us occasional errors - FlexmonsterProxyController is not thread safe. You have there static dictionaries like cachedAllMembers which can be accessed from multiple threads (multiple controllers - one per each request) and you are using regular Dictionary without locking. It can be quite easily fixed by changing it to ConcurrentDictionary...
If you want, I can rewrite it for you, if you send me the source code of FlexmonsterProxyController. Right now I have just decompiled version. I can fix it there, because I will have to fix it anyways before our go-live, but the merge to your version would be more complicated for you from decompiled version.
Regards,
Lukas

Public
Tanya Gryshko Tanya Gryshko Flexmonster August 9, 2017

Hello Lukas,
We would like to thank you for pointing out this issue about FlexmonsterProxyController. It's a really good idea, and we will implement it quickly. But it will take some time to run all necessary tests. We will send you the updated version right after we finish testing.
Regards,
Tanya

Public
Lukas Navratil August 9, 2017

Hello Tanya,
Ok, thank you.
Regards,
Lukas

Public
Lukas Navratil August 21, 2017

Hello guys,
Any chance that this issue will be fixed until 28th August? Our release is coming, so I would just like to know if we can count with the fix or not...
Regards,
Lukas

Public
Tanya Gryshko Tanya Gryshko Flexmonster August 22, 2017

Hi Lukas,

ConcurrentDictionary is already added to version 2.401 and available to download. We just published this build on Monday.
Please download update from here http://www.flexmonster.com/download-page/ 

Does it work for you?

Regards,
  Tanya

Public
Lukas Navratil August 23, 2017

Hi Tanya,
Sorry for late reply, I did not get notification that you have replied...
Awesome, I would just need to get a Flexmonster.Accelerator.Core.dll which is not part of standard distribution - previously Ian added it to the sample that is linked above. 
The second thing I'm worried about is if 2.4 accelerator is working with 2.3 component - we do not plan to upgrade to 2.4 for this our release.
Regards,
Lukas

Public
Ian Sadovy Ian Sadovy Flexmonster August 24, 2017

Hello Lukas,
 
Thank you for the answer.
We have prepared Accelerator DLL that will work with 2.3 and includes the above fix.
It is available for download here.
 
Please let me know if it works for you.
 
Regards,
Ian

Public
Lukas Navratil August 24, 2017

Hi Ian,
Thank you for DLL. However there are still issues and it's not fully working for me. I have looked yesterday into the code of FlexmonsterProxyController and I have probably understood how it works and applied an intermediary fix to the decompiled version...

  • There are still normal Dictionaries in the controller, it has been fixed just for CacheManager, but it's probably not a big deal, the main issue I had was somewhere else...
  • The dictionaries dataChunkFromIndex and dataChunkTotalRows are used to hold data between requests (to allow chunk processing), but the key can't distinguish the requests, imaging this scenario:
    • Two clients are requesting same report which is currently not in the cache (or cache is not used at all)
    • First request manages to process chunk 0 and 1 and starts processing chunk 2
    • Second request comes, data are not in the cache yet. Second request is starting the main part of Execute method and is processing chunk 0. It puts in these dictionaries data for chunk 0
    • First request while processing chunk 2 is trying to read data which stored in the dictionary in chunk 1, however they have been overwritten by second request and it reads data for chunk 0 instead.
    • In that case I was getting empty report body, in the worst case this incorrect result make it to the cache and we are getting empty reports forever.

The solution I have applied to your decompiled code is that in these dictionaries I'm using two keys:

  • keyWithPrevuiousChunk = key + (args.chunkIndex-1) for reading
  • keyWithCurrentChunk = key +args.chunkIndex for writing

So I have there e.g. 
dataChunkFromIndex[keyWithCurrentChunk] = dataChunkFromIndex[keyWithPrevuiousChunk] + num2;
Assuming that the data stored in these dictionaries are the same for the same chunks from different requests, the requests are potentially still overwriting the data across requests but with the same values. I'm just not removing these values when the processing is finished because I don't know if another request that is still being processed will need them or not. Also while writing this post it brings me to the question if the order of chunks (that chunk 0 is always processed before chunk 1 etc.) is guaranteed for one request, but I expect it is...
Also I have one suggestion for improvement in CacheManager. You have there method ContainsKey, which enumerates the whole dictionary and uses Equals on each item:
public bool ContainsKey(object key)
{
foreach (object key1 in (IEnumerable<object>) this.cache.Keys)
{
if (key1.Equals(key))
return true;
}
return false;
}
Which is pretty inefficient from performance point of view, you are loosing the advantage of dictionary that it can get item by the key very fast. If you would just pass it to underlying dictionary 
public bool ContainsKey(object key)
{
this.cache.ContainsKey(key);
}
It will behave the same, but it will be just much faster on large dictionaries. Or you can use TryAdd/TryGet methods on (Concurrent)Dictionary and you don't need ContainsKey at all and also you will get rid of dictionary double lookup issue.
Regards,
Lukas

Public
Ian Sadovy Ian Sadovy Flexmonster August 25, 2017

Hello Lukas,
 
Thank you for such detailed investigation.
Could you please share updated FlexmonsterProxyController class so we can review and apply all changes made by you?
I think it will be very useful to include this fix in our main version.
 
Thanks,
Ian
 

Public
Lukas Navratil August 28, 2017

Hello Ian,
You can find the FlexmonsterProxyController and CacheManager here - https://vistaentertainment-my.sharepoint.com/personal/lukas_navratil_vista_co/_layouts/15/guestaccess.aspx?folderid=113885a50d4f64a87a8756cb354d74262-fm&authkey=AfmeE0rEfLeMuL9uj-emQ1M . But it's from decompiled code (without having corresponding PDB file), so it can be quite difficult for you to apply the same changes - there are dummy variable names, there are strange casts and other constructs that decompiler has produced. I believe I can do the same changes again if I would give me the original code, it can be from 2.4 branch.
In the CacheManager I have removed the ContainsKey method and I have modified little bit the Cache limit - changed it from amount of memory to number of items. I just wanted to avoid so many calls of GC.Collect in our solution, because your controller is now sharing the same memory space with our app, and there can be a lot of memory allocated. It's just an interim solution... Ideal case would be if you could make the cacheManager as protected in the controller and change it to interface. In that case we could change the implementation of the cache in our controller which inherits from your controller. But probably we could still live with your CacheManager... 
Regards,
Lukas

Public
Ian Sadovy Ian Sadovy Flexmonster August 29, 2017

Hello Lukas,
 
Thank you for giving us some time.
We have sent a package with Accelerator's code by e-mail.
Looking forward to hearing from you.
 
Regards,
Ian

Please login or Register to Submit Answer