Attribute-based access control with database - database

I work for a software house and I'm looking for a way to authenticate database access as follow:
Someone whose personal data are stored in a table needs to read his
personal row and he has the right to access the table.
Once the requested row has been retrieved, I need an external check
which ensures he has the right to read that specific row, checking
some table's fields which are contained in the same row.
It seems to me that the attribute-based access control is what I'm looking for, but I'm not sure. Can you confirm if it's able to do what I need?

Yes, ABAC (the model) can do that. However, the check would typically happen before you get access to the data - and that's better actually (it avoids retrieving data).
ABAC gives you two things:
a policy language to express what can and cannot happen. For instance
A user can view a record they own but not the credit card field
a request / response scheme or how to enforce the policies.
In the case of data-centric access control, policies are transformed into SQL filters. For instance, you would go from:
SELECT * FROM transactions;
to
SELECT amount, owner, CASE WHEN (0=1) THEN CREDITCARD ELSE 'xxxx' FROM transactions WHERE owner = 'Alice'
This is called dynamic data filtering and dynamic data masking. Some database vendors have had that capability e.g. Oracle and VPD or MySQL and FGAC. Lately the trend is to outsource this type of behavior to tools like Informatica DDM or Axiomatics ADAF MD (which is where I work).

Related

Get audit history records of any entity record as per CRM view

I want to display all audit history data as per MS CRM format.
I have imported all records from AuditBase table from CRM to another Database server table.
I want this table records using SQL query in Dynamics CRM format (as per above image).
I have done so far
select
AB.CreatedOn as [Created On],SUB.FullName [Changed By],
Value as Event,ab.AttributeMask [Changed Field],
AB.changeData [Old Value],'' [New Value] from Auditbase AB
inner join StringMap SM on SM.AttributeValue=AB.Action and SM.AttributeName='action'
inner join SystemUserBase SUB on SUB.SystemUserId=AB.UserId
--inner join MetadataSchema.Attribute ar on ab.AttributeMask = ar.ColumnNumber
--INNER JOIN MetadataSchema.Entity en ON ar.EntityId = en.EntityId and en.ObjectTypeCode=AB.ObjectTypeCode
--inner join Contact C on C.ContactId=AB.ObjectId
where objectid='00000000-0000-0000-000-000000000000'
Order by AB.CreatedOn desc
My problem is AttributeMask is a comma separated value that i need to compare with MetadataSchema.Attribute table's columnnumber field. And how to get New value from that entity.
I have already checked this link : Sql query to get data from audit history for opportunity entity, but its not giving me the [New Value].
NOTE : I can not use "RetrieveRecordChangeHistoryResponse", because i need to show these data in external webpage from sql table(Not CRM database).
Well, basically Dynamics CRM does not create this Audit View (the way you see it in CRM) using SQL query, so if you succeed in doing it, Microsoft will probably buy it from you as it would be much faster than the way it's currently handled :)
But really - the way it works currently, SQL is used only for obtaining all relevant Audit view records (without any matching with attributes metadata or whatever) and then, all the parsing and matching with metadata is done in .NET application. The logic is quite complex and there are so many different cases to handle, that I believe that recreating this in SQL would require not just some simple "select" query, but in fact some really complex procedure (and still that might be not enough, because not everything in CRM is kept in database, some things are simply compiled into the libraries of application) and weeks or maybe even months for one person to accomplish (of course that's my opinion, maybe some T-SQL guru will prove me wrong).
So, I would do it differently - use RetrieveRecordChangeHistoryRequest (which was already mentioned in some answers) to get all the Audit Details (already parsed and ready to use) using some kind of .NET application (probably running periodically, or maybe triggered by a plugin in CRM etc.) and put them in some Database in user-friendly format. You can then consume this database with whatever external application you want.
Also I don't understand your comment:
I can not use "RetrieveRecordChangeHistoryResponse", because i need to
show these data in external webpage from sql table(Not CRM database)
What kind of application cannot call external service (you can create a custom service, don't have to use CRM service) to get some data, but can access external database? You should not read from the db directly, better approach would be to prepare a web service returning the audit you want (using CRM SDK under the hood) and calling this service by external application. Unless of course your external app is only capable of reading databases, not running any custom web services...
It is not possible to reconstruct a complete audit history from the AuditBase tables alone. For the current values you still need the tables that are being audited.
The queries you would need to construct are complex and writing them may be avoided in case the RetrieveRecordChangeHistoryRequest is a suitable option as well.
(See also How to get audit record details using FetchXML on SO.)
NOTE
This answer was submitted before the original question was extended stating that the RetrieveRecordChangeHistoryRequest cannot be used.
As I said in comments, Audit table will have old value & new value, but not current value. Current value will be pushed as new value when next update happens.
In your OP query, ab.AttributeMask will return comma "," separated values and AB.changeData will return tilde "~" separated values. Read more
I assume you are fine with "~" separated values as Old Value column, want to show current values of fields in New Value column. This is not going to work when multiple fields are enabled for audit. You have to split the Attribute mask field value into CRM fields from AttributeView using ColumnNumber & get the required result.
I would recommend the below reference blog to start with, once you get the expected result, you can pull the current field value using extra query either in SQL or using C# in front end. But you should concatenate again with "~" for values to maintain the format.
https://marcuscrast.wordpress.com/2012/01/14/dynamics-crm-2011-audit-report-in-ssrs/
Update:
From the above blog, you can tweak the SP query with your fields, then convert the last select statement to 'select into' to create a new table for your storage.
Modify the Stored procedure to fetch the delta based on last run. Configure the sql job & schedule to run every day or so, to populate the table.
Then select & display the data as the way you want. I did the same in PowerBI under 3 days.
Pros/Cons: Obviously this requirement is for reporting purpose. Globally reporting requirements will be mirroring database by replication or other means and won't be interrupting Prod users & Async server by injecting plugins or any On demand Adhoc service calls. Moreover you have access to database & not CRM online. Better not to reinvent the wheel & take forward the available solution. This is my humble opinion & based on a Microsoft internal project implementation.

DB2 row level access control: how to pass a user Id

In our web application we want to use DB2 row level access control to control who can view what. Each table would contain a column named userId which contain the user id. We want log-in users be able to see only row's usereId column with theirs id. I have seen db2 permission examples using DB2 session_id or user, for example taking DB2 given Banking example :
CREATE PERMISSION EXAMPLEBANKING.IN_TELLER_ROW_ACCESS
ON EXAMPLEBANKING.CUSTOMER FOR ROWS WHERE BRANCH in (
SELECT HOME_BRANCH FROM EXAMPLEBANKING.INTERNAL_INFO WHERE EMP_ID = SESSION_USER
)
ENFORCED FOR ALL ACCESS
ENABLE;
Our table gets updated dynamically hence we don't know what row get added or deleted hence we don't know what are all the user Id in the table.
At any given time, different user would log-on to the web to view information retrieve from the tables, the permission declaration above only take SESSION_USER as the input, can I change it to something like Java function parameter where one can pass arbitrary id to the permission? If not then how do I handle different log-in users at arbitrary time? Or do I just keep changing SESSION_USER dynamically as new user login (using "db2 set" ??)? If so then is this the best practice for this kind use case?
Thanks in advance.
Since the user ID in question is application-provided, not originating from the database, using SESSION_USER, which equals to the DB2 authorization ID, would not be appropriate. Instead you might use the CLIENT_USERID variable, as described here.
This might become a little tricky if you use connection pooling in your application, as the variable must be set each time after obtaining a connection from the pool and reset before returning it to the pool.
Check out Trusted Contexts, this is exactly why they exist. The linked article is fairly old (you can use trusted contexts with PHP, ruby, etc. now).

User Interface to analaze date of a conventional rdbms

Currently we create Jasper PDF Reports from a single simple database table for our customers. This has been achieved programmatically. It's static. If the user wishes to change the query, he/she creates a change request, which we cannot deliver before the end of the next sprint (SCRUM).
The tool/library should be straight forward (e.g. convention over configuration) and employable from within a JavaEE container. And, open source.
Is there a dynamic tool that allows or customers to create the simple queries/reports themselves without knowing SQL? Means, they should be able to see the table and then create a query from it, execute and print (we could use Jasper Reports for the last one).
E.g. Select only data from year 2014, aggregate them by customer group and select columns x,y and z.
All of these criterias and query structure may change though, thus not just the value like year 2014.
Questions:
1) Is there a tool that presents the data in some kind of SAP-cube or something similar where the user could select the structure and attributes?
2) Can that tool save template queries (queries that the user has invoked before)?
thanks
With BIRT you could use parameters in the report... for example have one report that shows the whole data set or data cube (or at least a bit of all of the fields). Then you could add JavaScript to the report (or do all of the presentation in JavaScript for that matter), that shows the parameters a user can select from. These parameter values can then either be sent to a new report or could update the existing report. Parameters can be put into database queries too.
If that was exposed in JavaScript on a web page you could save the parameter values to an array and store them in the browser or server.

Need a clever way to get orders from all stores while each store is in a different database

The setup
I have the following database setup:
CentralDB
Table: Stores
Table: Users
Store1DB
Table: Orders
Store2DB
Table: Orders
Store3DB
Table: Orders
Store4DB
Table: Orders
... etc
CentralDB contains the users, logging and a Stores table with the name of each store database and general information about each store such as address, name, description, image, etc...
All the StoreDB's use the same structure just different data.
It is important to know that the list of stores will shrink and increase in the future.
The main client communicating with this setup is an API REST Service which gets passed a STOREID in the Header of each request telling it which database to connect to. This works flawlessly so far.
The reasoning
Whenever we need to do database maintenance on one store, we don't want all other stores to be down.
Backup management should be per store
Not having to write the WHERE storeID=x every time and for every table
Performance: each store could run on its own database server if the need arises
The goal
I need my REST API Service to somehow get all orders from all stores in one query.
Will you help me figure out a way to do this without hardcoding all storedb names? I was thinking about a stored procedure on the CentralDB but I was hoping there would be other solutions. In any case it has to be very efficient.
One option would be to have a list of databases stored in a "system" table in CentralDB.
Then you could create a stored procedure that would read the database names from the table, loop through them with cursor and generate a dynamic SQL that would UNION the results from all the databases. This way you would get a single recordset of results.
However, this database design is IMHO flawed. There is no reason for using multiple databases to store data that belongs to the same "domain". All the reasons that you have mentioned can be solved by using a single database with proper database design. Having multiple databases will create multiple problems on the long term:
you will need to change structure of all the DBs when you modify your database model
you will need to create/drop new databases when new stores are added/removed from your system
you will need to have items and other entities that are "common" to all the stores duplicated in all the DBs
what about reporting requirements (e.g. get sales data for stores 1 and 2 together, etc.) - this will require creating complex union queries...
etc...
On the long term, managing and maintaining this model will be a big pain.
I'd maintain a set of views that UNION ALL all the data. Every time a store is added or deleted those views must be updated. This can be automated.
The views provide an illusion to the application that there is only one database.
What I would not do is have each SQL query or procedure query all the database names and create dynamic SQL. That would entail lots of code duplication and an unnecessary loss of performance. This approach is error prone. Better generate code once in a central place and have all other SQL code reference that generated code.

Encryption on the fly

here is something interesting that I have been asked. It has to do with the encryption of data in a non encrypted database.
The story has as follows. We have a database, not encrypted and also none column encrypted in any of its tables. Now, we'd like to control the trafic of the data depending on who is asking for this. Let me explain more clear:
We have a table with the name: table1
This table has one column with the name: SName
We'd like to reach the following result. A user connected to the SQL Server Management Studio if runs the following query:
select * from table1
to take no result or if he/she takes a result, this result to be scrambled.
Now from inside the application the table should exchange data from/to the application in the normal mode.
Do you know if there is a setting, or an implementation or an external tool that can provide this functionality?
I think that this is quite interesting case!
Thank you.
Use permissions to stop that person reading the table at all.
Or use a VIEW to hide the table and have a WHERE clause in that that applies a filter silently: this could refer to another table with a list of approved users.
This isn't really an encryption (well, obfuscation in this case) issue.

Resources