Migrate Plone users and groups to relational data - plone

I have a Plone 4 site which contains a lot of users and groups which are stored in the ZODB. Over time, we added some functionality which uses relational data (in a PostgreSQL database); some tables have fields which contain user or group ids.
However, currently the users and groups are defined in ZODB rather than the RDB, so we don't have proper foreign keys here. Thus, the obvious idea is to migrate the user and groups data to the RDB - those who/which are used by the Plone site, at least; I assume emergency users need to be an exception to this (but those are no members of any groups anyway).
Would this be a good thing to do?
Are there reasons to do it only partly, or should I transfer everything including group memberships? (Since memberships are stored as lists of users (and/or groups) with the containing group, I could imagine a reverse table which holds all groups a user is member of, and which is maintained by a trigger function.)
Are there any special tools to use?
Thank you!

imho it's based on what you want to achieve. In Plone you have PAS, so technically it doesn't really matter, where you put users, groups and user group relationships.
You can store users/groups in:
Plone (by default)
SQL - pas.plugins.sqlalchemy
LDAP/AD - Products.PloneLDAP
There are also many other plugins for AUTH, like RPX, Goolge+, etc.
You can enable, disable and modify the behabvior of every plugin thru PAS.
Does it make sense, to NOT use Plone users?
Of course, if you want to share user credentials (Example LDAP), or if you need the user informations in other Apps, etc.
Migration
Should be very simple if the PAS plugins you are using supports "Properties" and "User enumeration".
Get the data from one plugin and put the data into another one with a simple python script. Both supports the same API.

the tool you're looking for is https://pypi.python.org/pypi/pas.plugins.sqlalchemy/0.3
I've used this in a webportal where users are "shared" with a newsletter system.
I've 200 users and any problem.
I think the only "good reason" to store users in an external DB rather in zodb/plone is in a use-case like mine.
Have you ever think about "extend" plone users (ex. https://plone.org/products/collective.examples.userdata)? With plone.api you can easly manipulate users' properties in your code.

Related

Oracle APEX User Rights and Previleges

I do not have much experience and I would like to know if there is an easy way to create user rights and privileges, so that each user can access only specific records from the database tables, based on the level he belongs to.
More specifically, suppose we have a group of companies where this group has some companies and these companies have some branches and the branches have some users.
I want the user belonging to the "group of companies" level to have access to and view all the entries in the database related to that group and what is below it (its companies and the branches of these companies).
The user who belongs to the "company" level should have access and see only the files of this company and the branches that this company may have in the database.
The user belonging to the "Branch" level should only be able to access and view this barnch records in the database.
And finally the user belonging to the "End User" level to have access and see only the records created by the user in the database.
Of course level "administrator" will have access to all records in the database.
I thought of creating a user table with a field "User_Level" and in each table to enter USER_ID where based on this I can find the level of a user but how can I restrict access based on the Group of Companies or the Company or the Branch where it belongs?
In APEX you can create authorization schemes to determine what components a user has access to within an application - but that is just a part of the answer to this question. Your question is about filtering the data that is showed to a user based on certain criteria.
There are a couple of possible solutions to this. Since this is a very broad question I'm just going to give you pointers/concepts to start your research. Up to you to determine what solution/combination is most suitable for your implementation.
Concept: Multi-Tenancy
If the data is used by multiple tenants then add a tenant_id to each table that has tenant specific data. In your case a tenant should be a branch. A simple design could be a groups table (to hold branch - companies - company groups), a group_members table (to define relationship between branch - companies - company groups OR between any group and a user) and a users table.
Concept: VPD This is a feature in the oracle database that allows a transparent implementation of security rules. In the application you'll define a simple select like
SELECT * FROM emp
But the VPD implementation will automatically add a where clause to the query to only show the records defined in the VPD policy. This makes developing the application a lot easier since there is less room for errors. Note that this database option could not be included for your licence. There is also something called "Poor Man's VPD" that does not use the VPD option. Google on how to implement this in your apex application.
Just do it all by hand: This is the least preferred option but it can be done. For every component where a select is done, manually add a where clause to restrict the returned rows. However this is very maintenance intensive and there is a ton of room for errors - obiously the data model will still have to support the striping of the data.
This blog post by Jeffrey Kemp might give you some pointers as well: https://jeffkemponoracle.com/2017/11/convert-an-apex-application-to-multi-tenant/ - go through the "further reading" section at the bottom.
you can create a procedure or function and in your app's shared components -> authorization scheme use that such as pl/sql function/procedure returning boolean and return true for the users you want to see the things and false for hiding.
In Apex components, select this authorization scheme like in items, pages etc.

Best approach to having multiple users in one app

This is mobile app which can have different kind of users. I'm using realm only for the offline storage. Say I have two users A and B and a have a List Class. This class wont ever be shared, so different data for each user. How would i go in designing the schema? Considering versioning and migration.
A. Add a primary key for the List and assign it differently to user A and B.
B. Use two different realms
There is no one good way of defining your Realm schema and the solution to choose completely depends on the exact scenario.
If you want your users data to be completely independent of each other and you will never need to use a single query to retrieve both users data or to access some common data, then using separate Realm instances for each use seems like a good approach. It provides complete separation between your users data.
However, if your users might have some shared data or if you might end up making some statistics about all of your users even though their data is independent, using a single Realm instance is the way to go. In this case you should just create a one-to-many relationship between each of your users and whatever objects you want to store in your lists like this:
class User:Object {
let stuff = List<Stuff>()
}

Best Practices in User Privileges/Session Variables in MVC3

Hi Stack Community Members,
I am developing an application under MVC3 where users have department-specific CRUD privileges. In other words, all users can view data for all departments, but only certain users can make changes to the data for any one given department. User-department privilege data is held in a join table in a database.
What I typically do in this kind of situation (in PHP) is to create a Session variable (an array) on login which is populated with the id's of the departments which the user is allowed to edit. When a user then goes to access the editing feature a drop-down list is populated with only these specific departments. I also populate a few other session variables which are used frequently like the user's name and the id of the current time period (business quarter).
Is this type of approach a good way to go in MVC3, or is some alternative approach better? While I figure that I'm going to use Forms Authentication and some specific roles (employee, admin, etc.) these types of roles are just too broad to be able to target department-by-department access, and I'm not sure that MVC3 has an out-of-the-box method which is better than what I'm planning to do.
Your guidance is appreciated!
I'm using Forms Authentication, add specific roles, and combine them if needed. I don't mind being specific for the roles, as they can be combined anyway I want. I can still have broad roles for more general actions.
I store similar data (UserId, DepartmentId, etc) in session since it does not change for the user and it is a small amount of data. It is my opinion that session state would be a good approach for you also.

Use ASP.NET Profile or not?

I need to store a few attributes of an authenticated user (I am using Membership API) and I need to make a choice between using Profiles or adding a new table with UserId as the PK. It appears that using Profiles is quick and needs less work upfront. However, I see the following downsides:
The profile values are squished into a single ntext column. At some point in the future, I will have SQL scripts that may update user's attributes. Querying a ntext column and trying to update a value sounds a little buggy to me.
If I choose to add a new user specific property and would like to assign a default for all the existing users, would it be possible?
My first impression has been that using profiles may cause maintainance headaches in the long run. Thoughts?
There was an article on MSDN (now on ASP.NET http://www.asp.net/downloads/sandbox/table-profile-provider-samples) that discusses how to make a Profile Table Provider. The idea is to store the Profile data in a table versus a row, making it easier to query with just SQL.
More onto that point, SQL Server 2005/2008 provides support for getting data via services and CLR code. You could conceivably access the Profile data via the API instead of the underlying tables directly.
As to point #2, you can set defaults to properties, and while this will not update other profiles immediately, the profile would be updated when next it is accessed.
Seems to me you have answered your own question. If your point 1 is likely to happen, then a SQL table is the only sensible option.
Check out this question...
ASP.NET built in user profile vs. old stile user class/tables
The first hint that the built-in profiles are badly designed is their use of delimited data in a relational database. There are a few cases that delimited data in a RDBMS makes sense, but this is definitely not one of them.
Unless you have a specific reason to use ASP.Net Profiles, I'd suggest you go with the separate tables instead.

Granting a Drupal role to all users that have a certain role

I need to automatically apply a role, Role X, to all Drupal users that have been granted a separate role, Role Y. In other words, I wish for Role X to be a subset of Role Y. How can I do this?
You could implement hook_user() in a custom module. On the 'insert' and/or 'update' action, you'd check for role Y in the $account->roles array. If present, add role X if not already there. This would ensure that your rule gets applied every time a user account gets created and/or changed.
For a bootstrapping/one time operation, take a look at user_multiple_role_edit(). It lets you add or remove roles for an array of user ids. Alternatively, you could do it directly in the database:
INSERT INTO users_roles (uid, rid)
SELECT uid, [roleX_ID] AS rid FROM users_roles
WHERE uid IN
(SELECT uid FROM users_roles WHERE rid = [roleY_ID])
AND uid NOT IN
(SELECT uid FROM users_roles WHERE rid = [roleX_ID])
;
I agree with Henrik Opel on using hook_user in a custom module would be a good solution to maintain the users and make sure they are up to date all the time.
Normally I wouldn't mind writing SQL or something alike, but in this case, since it's on a production site, I would prefer a different route, since if something can easily go wrong when writing raw SQL, a little typo can cause big troubles. Another good point is that you can run into problems as drupal wont be aware of what raw SQL you run on your database and might get out of sync with some processes, hooks and other processes that's normally run when you do things through the Drupal API.
Instead you can use the drupal user admin interface. I actually think that in this case, it is the easiest way to do what you want. Simply filter all users that are students. Click all the users and give them the member role. This is done with a few clicks in no time, and is very secure since Drupal will handle all the SQL for you.
Updated
With that many users, I'm surprised that you don't have a custom user and content managing page setup using views_bulk_operations. Using a few minutes, you can setup a admin page which you can use to preform bulk operations like changing user status, roles, or perform similar tasks for nodes. You can create your own filters using exposed views filters. So with a few clicks you can select all the users with role of student and that isn't member, select them all and add the member roll to them. The advantage doing this is not only that it's quick and safe, but you can create some nice managing pages for your site administrators, content creators etc. You should consider looking into this module.
The LDAP module allows you to dynamically assign roles based on DN. I actually had to write my own module that is tailored specifically to our system, otherwise I would be more than happy to share it.
link text

Resources