I have different Active Directory groups and one BO universe.
Different active directory groups should have different restricted access on data in the universe.
How can I implement that? (unfortunately I did not found corresponding tutorial or documentation on the net.)
If there are more than one ways to implement data access, what is the best practice?
Thanks.
There are two main ways to implement row-level security in a universe. One is via a Security Profile; the other is via #variable('BOUSER').
If the security is to be applied at a group level (that is, all members of a group should have the same condition applied), then a Security Profile is appropriate. This is covered in Chapter 17 of the IDT User Guide. At a high level, the steps are:
From IDT, launch the Security Editor
Select the universe, and create either a Data Security Profile or a Business Security Profile (read the docs for the differences between the two, but one is that with the DSP, you will write a WHERE condition; with the BSP, you select objects and define a condition)
Once the Security Profile is created, select the group or groups that it should apply to
Repeat the above for each group that should have a restriction applied
The other method for applying row-level security is only applicable when the data source includes a table that has a mapping of BO user IDs to the values that they may have access to. For example, let's say you have a security table in your data source that looks like this:
user_id region
------- ------
U123 NE
U123 SE
U321 W
and your fact table looks like:
pk region value
__ ______ _____
1 NE 3
2 W 4
You can apply security such that user U123 only sees the "NE" row, and user U321 only sees the "W" row. You would join the two tables on region (security.region=fact.region), then create a new mandatory filter on security.user_id=#variable('BOUSER'). This will force the filter to be applied to all queries.
Note that both of the above methods work by adding conditions to the query's WHERE condition. If your users have permission to view and edit the query's SQL, they will be above to override the filtering logic. To ensure security, users should be denied this right.
Related
I'm learning how to design a DB structure for assigning users permission to access certain pages
if the user is an admin that user would have access to crud operations
if the user is an editor that user would have access to only edit
user can have custom permission then access it would vary depending on the config
I have two schema designs and both seems good, one requires simple queries and the other can hold more description about each role and permission.
Design 1
role id is stored in a table called user and i will need to lookup role_has_permission table get all the permission ids then lookup permission table to get the permission_name column. comparatively longer query with more data being fetched, but i can have description column in permission table
Design 2
role id stored in table user, i can simply make a single query and check for permission. eg: role.canEdit is set to true user is allowed to edit. smaller and faster query.
why cant i go with the second design? and why do many articles go with the first design?
Design 1 lets you add permissions dynamically without changing the software. If you need a new permission, say can order lunch for entire team, you just add a record in the permission table and as many in the role_has_permission as needed, and you're done. In design 2 you'd have to add an operation canOrderLunchForEntireTeam. So design 1 is more flexible.
However, the flexibility of design 1 has a price. It's not enough to define and assign these permissions, but the software shall probably also check them when a function is performed. Adding a function for ordering lunch is a software change anyway, so adding an attribute to your design 2 class might be tolerable. The generic way of defining permissions in design 1 will therefore only pay out if you implement a similarly generic way of applying them.
I've been trying to develop an internal staff portal for our company. There are departments, job grades, working areas, roles (user, editor, admin, super admin, etc...) and special groups (executives, etc) for user grouping.
User must have one (only one) department.
User must have one (only one) job grades.
User must work in minimum one area.
User must have one (only one) roles.
User may have one or more special groups.
Job grades and roles are hierarchical (an grade or role may be inherited of another one) but other ones not.
Users will see only allowed menus and access permitted routes.
User will also select which users can view it when posting a new content.
e.g:
Combination 1: (IT or Finance department) and (Job Grade is one of 9,10,11) and (Area is one of 1,5,8) and (Exclusive special group is one of 1,5,8) except user id=1
Combination 2: (HR department) and (Job Grade is 11) and user_id=3,4,5
Combinations can be related as AND/OR among themselves like Combination 1 AND combination 2
So, there will be lots of contents and every content will have different group permissions. I try to create a DB schema but it's very hard to get all contents that is visible to logged in user. Serialized data would be good for saving combination sets in db but it looks like impossible with serialized data. Is there an advantage to using MongoDB for this issue? How can i save combinations of group/user permissions in tables also?
I researched lots of ACL and RBAC examples but can't find the optimal solution. Please help.
Btw, i use Laravel Framework.
Thanks.
You need to look into attribute-based access control (ABAC - Wikipedia) and the eXtensible Access Control Markup Language (XACML). NIST, the National Institute of Science & Technology gives a great intro to ABAC here.
XACML will give you the ability to express fine-grained access control policies that use you attributes. In your question you have:
user attributes
department
job grade
working area
role
group
object (resource) attributes
content type
content location
content classification
With XACML you can write rules such as:
A user with grade==1 can do the action==edit on content of type==post
if content.department==user.department.
You can have as many rules as you like including conflicting rules or environment rules (deny access before 9am).
Have a look at the ALFA plugin for Eclipse to write your own policies (Wikipedia | Download).
HTH,
David
I'm building an stock exchange simulation game. I have a table called 'Market_data' and in the game players simulate being in particular dates and are allowed to use SQL queries to retrieve the historical data and plan their course of action. My difficulty is that I need to limit the rows they can access based on the current date they are playing on so they cant see rows with a date greater than the current date.
Eg: An user is running the game and is currently in the year 2010, if he does a simple select like "SELECT * FROM market_data" I don't want him to see rows with Date > 'x-x-2010'
The only soution that I know of is to parse the user's SQL and add WHERE clauses to remove newer dates but it seems time consuming and prone to errors and I wasn't sure whether there were better alternatives. Any ideas on how to do this right will be thanked.
Solution is SQL Views, Views are used for several different reasons:
*1.*To hide data complexity. Instead of forcing your users to learn the T-SQL JOIN syntax you might wish to provide a view that runs a commonly requested SQL statement.
*2.*To protect the data. If you have a table containing sensitive data in certain columns, you might wish to hide those columns from certain groups of users. For instance, customer names, addresses and their social security numbers might all be stored in the same table; however, for lower level employees like shipping clerks, you can create a view that only displays customer name and address. You can grant permissions to a view without allowing users to query the underlying tables. There are a couple of ways you might want to secure your data:
a.Create a view to allow reading of only certain columns from a table. A common example of this would be the salary column in the employee table. You might not want all personnel to be able to read manager's or each other's salary. This is referred to as partitioning a table vertically and is accomplished by specifying only the appropriate columns in the CREATE VIEW statement.
b.Create a view to allow reading only certain rows from a table. For instance, you might have a view for department managers. This way, each manager can provide raises only to the employees of his or her department. This is referred to as horizontal partitioning and is accomplished by providing a WHERE clause in the SELECT statement that creates a view.
*3.*Enforcing some simple business rules. For example, if you wish to generate a list of customers that need to receive the fall catalog, you can create a view of customers that have previously bought your shirts during the fall.
*4.*Data exports with BCP. If you are using BCP to export your SQL Server data into text files, you can format the data through views since BCP's formatting ability is quite limited.
*5.*Customizing data. If you wish to display some computed values or column names formatted differently than the base table columns, you can do so by creating views.
reference taken from http://sqlserverpedia.com.
1)You can use mysql proxy http://dev.mysql.com/downloads/mysql-proxy/ with custom rules restricting access.
2)You can use stored procedures/functions
3)You can use views
The basic way would be :
-> Prevent that user (or group) from accessing the base table.
-> Define a view on top of that table that shows only the rows these users are supposed to see.
-> Give those users SELECT permission on the view.
-> And you can also use SQL Encryption,Decryption and Hashing concept.
Encryption & Decryption examples can be found here:
http://msdn.microsoft.com/en-us/library/ms179331.aspx
Hashing example can be found here:
http://msdn.microsoft.com/en-us/library/ms174415.aspx
Let us suppose I have a site with a certain number of users with the following three distinguishing characteristics:
1) The user is part of a network. (The site contains multiple networks.)
2) The user is a 'contact' of a certain number of other site members.
3) Individual documents uploaded by a user may be shared with certain contacts (excluding other contacts).
In this way, a user's document search is unique for each user based upon his or her network, contacts, and additional documents that have been shared with that user. What would be possible ways to address this -- would I need to append a long unique SQL query for each user for each of his or her searches? I am currently using MySQL as a database -- would using this be sufficient, or would I need to move towards a NoSQL option here to maintain the performance of a similar non-filtered search?
A few questions come to mind to help answer this question:
How many documents do you think the average user will have access to? Will many documents in the network be shared for all to see?
How will users be able to find documents and what do the documents look like? Will they only be able to search by the contact that shared it? By a simple title match? Will they be able to run a full text search against the document's contents?
Depending on the answer to those two questions, a relational system could work just fine, which I'm guessing is preferable since you are already using MySql. I think you could locate the documents for an individual user in a relational system with a few very reasonable queries.
Here is a potential bare bones schema
User
--all users in the system
UserId int
NetworkId int (Not sure if this is a 1 to many relationship)
Document
--all documents in the system
DocumentId int
UserId int -- the author
Name varchar
StatusId -- perhaps a flag to indicate whether it is public or not, e.g. shared with everyone in the same network or shared with all contacts
UserDocumentLink
--Linking between a document and the contacts a user has shared the document with
DocumentId
ContactId
UserContact
--A link between a user and all of their contacts
ContactId -- PK identity to represent a link between two users
UserId -- User who owns the contact
ContactUserId --The contact user
Here is a potential "search" query:
--documents owned by me
SELECT DocumentId
from Document where UserId = #userId
UNION
--documents shared with me explicitly
SELECT DocumentId
From UserContact uc
InnerJoin UserDocumentLink ucl on uc.ContactId = ucl.ContactId
Where
uc.ContactUserId = #userId
UNION
--documents shared with me via some public status, using a keyword filter
Select DocumentId
From Document d
inner join User u on d.UserId = u.UserId
where
u.NetworkId = #userNetworkId
and d.status in ()
and d.Name like '%' + #keyword + '%'
I think what might be a more influential requirement for schema design is one that is not mentioned in your question - how will users be able to search through documents? And what kind of documents are we talking about here? MySql is not a good option for full text search.
It rather depends on what you mean by a "certain number" of users. If you mean a few tens of thousands, then almost any solution can be made to perform adequately. If you mean many millions, then a NoSQL solution may scale up more cheaply and easily.
I suspect that a more general SQL query can be used, rather than a unique one for each user, e.g. selecting documents that belong to users that know the current user, that are marked as being shared with the current user, and match the search string.
Denormalisation can probably be used (as is common in NoSQL approaches) to improve performance.
However, a graph database (as Peter Neubauer suggests) possibly in combination with a document store (CouchDB, MongoDB or Cassandra) would work very well for this type of problem and would scale well.
I would take a look at some of the NOSQL solutions, for this interconnected dataset possibly Neo4j, a Graph Database. It's even pretty straightforward to query it through Cypher so that you get tabular results back.
As others have pointed out the number of users and the frequency of requests (traffic volume) must be looked at. Also, how important is redundancy? How likely are people to work on same documents simultaneously? Are most documents created once and distributed for "readonly" purposes?
NoSQL can help you scale and get redundancy in a much easier way compared to rdbms for this particular scenario. I am assuming that at some point you will want tagging etc. to be enabled on the documents.
Now, I am wondering if there is any particular reason why you are not looking at off the shelf document management and CMS system for this? I am sure there is a good reason, but it might be worth looking at all the those options too.
I hope this helps. Good luck!
Denormalization will give you better read-search performance in this
case.
Don't normalize users, keep frequently joined entities like owner and
text, in one table
e.g. keep names of the owners as FK on text table, to keep their
names on the text table and decrease number of joins, then you can
use sql freely.
I've managed this using long unique queries in MySQL as you suggest for a small-scale social networking project. Nowadays I would suggest using solr and keeping permission information as a denormalized array of interchangeable keywords on each document. Say each network has a unique recognizable code (ie 100N-20000N), similar for users and special permission grants. You can store an array of permission keys, like "5515N 43243N 2342N 603U 203PG 44321PG" and treat those as keywords when searching.
I would address it with a simple business process solution, which will lead to a simple data schema, a simple query and so performances and scalabilty:
Each User has a list of documents... Period.
This list is in fact a list of references to documents in a document table (with owner/security informations...)
When sharing a document to another user this document reference is added to the user's document list (Tagged as a shared one if you want), user is added to the document security list (with permission level for example).
sql query to get documents is a simple: select documentid from userdocument where userid=#userid
With a join on document table, proper indexes and sql tuning it will run with all needed informations and it will run fast.
I hope i understood well what you try to do.
-< = one to many
>-< = many to many (will require link table)
Network -< user -< documents >-< contact(user)
v
|
^
contacts(user,user)
This is relational, I don't see a good reason to go NoSQL unless you have a billion users
Network (unless you can belong to more than one) is an attribute of user
contacts will be maitained in the link table user_contact(user,user)
tables
documents(doc_id,user_id)
user(user_id)
contacts(user_id,c_user_id) with foreign keys on users
document_contact(doc_id,c_user_id) where a trigger constrains the c_user_id
then you get a view for all docs owners and subscribers (contacts)
CREATE OR REPLACE VIEW user_docs AS
SELECT d.user_id, d.doc_id, 'owner' AS role
FROM documents d
JOIN users u ON d.user_id = u.user_id
UNION
SELECT c.user_id, d.doc_id, 'subscriber' AS role
FROM documents d
JOIN contacts c ON d.user_id = c.c_user_id;
you can then filter the view against the document contacts,
select * from user_docs ud
where
(ud.role = 'originator'
or
ud.doc_id in (select doc_id from document_contact dc where ud.doc_id = dc.doc_id)
) and ud.user_id = 'me'
I would trade off immediateness with performance when it comes to full text searching.
I would create a hash table of the user combinations with the documents on a separate thread usually triggered by an asynchronous call when user associations change.
I then query the hash value + other search criteria. This will eliminate the need for the long SQL that appears at the end which may cause a lock.
I want to create a schema for a ACL; however, I'm torn between a couple of ways of implementing it.
I am pretty sure I don't want to deal with cascading permissions as that leads to a lot of confusion on the backend and for site administrators.
I think I can also live with users only being in one role at a time. A setup like this will allow roles and permissions to be added as needed as the site grows without affecting existing roles/rules.
At first I was going to normalize the data and have three tables to represent the relations.
ROLES { id, name }
RESOURCES { id, name }
PERMISSIONS { id, role_id, resource_id }
A query to figure out whether a user was allowed somewhere would look like this:
SELECT id FROM resources WHERE name = ?
SELECT * FROM permissions WHERE role_id = ? AND resource_id = ? ($user_role_id, $resource->id)
Then I realized that I will only have about 20 resources, each with up to 5 actions (create, update, view, etc..) and perhaps another 8 roles. This means that I can exercise blatant disregard for data normalization as I will never have more than a couple of hundred possible records.
So perhaps a schema like this would make more sense.
ROLES { id, name }
PERMISSIONS { id, role_id, resource_name }
which would allow me to lookup records in a single query
SELECT * FROM permissions WHERE role_id = ? AND permission = ? ($user_role_id, 'post.update')
So which of these is more correct? Are there other schema layouts for ACL?
In my experience, the real question mostly breaks down to whether or not any amount of user-specific access-restriction is going to occur.
Suppose, for instance, that you're designing the schema of a community and that you allow users to toggle the visibility of their profile.
One option is to stick to a public/private profile flag and stick to broad, pre-emptive permission checks: 'users.view' (views public users) vs, say, 'users.view_all' (views all users, for moderators).
Another involves more refined permissions, you might want them to be able to configure things so they can make themselves (a) viewable by all, (b) viewable by their hand-picked buddies, (c) kept private entirely, and perhaps (d) viewable by all except their hand-picked bozos. In this case you need to store owner/access-related data for individual rows, and you'll need to heavily abstract some of these things in order to avoid materializing the transitive closure of a dense, oriented graph.
With either approach, I've found that added complexity in role editing/assignment is offset by the resulting ease/flexibility in assigning permissions to individual pieces of data, and that the following to worked best:
Users can have multiple roles
Roles and permissions merged in the same table with a flag to distinguish the two (useful when editing roles/perms)
Roles can assign other roles, and roles and perms can assign permissions (but permissions cannot assign roles), from within the same table.
The resulting oriented graph can then be pulled in two queries, built once and for all in a reasonable amount of time using whichever language you're using, and cached into Memcache or similar for subsequent use.
From there, pulling a user's permissions is a matter of checking which roles he has, and processing them using the permission graph to get the final permissions. Check permissions by verifying that a user has the specified role/permission or not. And then run your query/issue an error based on that permission check.
You can extend the check for individual nodes (i.e. check_perms($user, 'users.edit', $node) for "can edit this node" vs check_perms($user, 'users.edit') for "may edit a node") if you need to, and you'll have something very flexible/easy to use for end users.
As the opening example should illustrate, be wary of steering too much towards row-level permissions. The performance bottleneck is less in checking an individual node's permissions than it is in pulling a list of valid nodes (i.e. only those that the user can view or edit). I'd advise against anything beyond flags and user_id fields within the rows themselves if you're not (very) well versed in query optimization.
This means that I can exercise blatant
disregard for data normalization as I
will never have more than a couple
hundred possible records.
The number of rows you expect isn't a criterion for choosing which normal form to aim for.
Normalization is concerned with data integrity. It generally increases data integrity by reducing redundancy.
The real question to ask isn't "How many rows will I have?", but "How important is it for the database to always give me the right answers?" For a database that will be used to implement an ACL, I'd say "Pretty danged important."
If anything, a low number of rows suggests you don't need to be concerned with performance, so 5NF should be an easy choice to make. You'll want to hit 5NF before you add any id numbers.
A query to figure out if a user was
allowed somewhere would look like
this:
SELECT id FROM resources WHERE name = ?
SELECT * FROM permissions
WHERE role_id = ? AND resource_id = ? ($user_role_id, $resource->id)
That you wrote that as two queries instead of using an inner join suggests that you might be in over your head. (That's an observation, not a criticism.)
SELECT p.*
FROM permissions p
INNER JOIN resources r ON (r.id = p.resource_id AND
r.name = ?)
You can use a SET to assign the roles.
CREATE TABLE permission (
id integer primary key autoincrement
,name varchar
,perm SET('create', 'edit', 'delete', 'view')
,resource_id integer );