One of our clients wants to restrict several client accounts to be able to login only from work. (Fixed Ip)
This can not be solved through htaccess and Im not a Magento expert by no means. I have not found something usefull in google so any help would be so much appreciated.
Best Regards.
I like the idea, feel weird when you think about the use cases, but the implementation is perfectly doable.
In case we are talking about Customers, you can use customer_customer_authenticated event. Once triggered, it means that user is trying to login with correct credentials.
At this point you have to check the remote address validate it agains list of whitelisted/blacklisted IPs and throw exception (Mage::throwException('..')) with message in case you want to prevent user from logging in.
One of a parameters passed to the event observer is customer model instance, so that's cool...
If you are talking about admin users, you can do quite similar thing with admin_user_authenticate_after event.
In both cases you should have custom attribute per customer/admin where store admins can list whitelisted/blacklisted IPs.
Careful not to lock yourself out. ;)
I am adding ACL to an nodejs/express application. I have already read the documentation for the modules acl and express-acl but there is a something missing.
They don't provide examples on how to handle access to single resources.
Typical example: users can edit their own comments but can only read other users comments. So having a role that either grants or deny edit permissions to the resource comment/edit is not good enough. The permission depends on which comment the user is accessing.
Is there a way to achieve that with one of the module provided on npm or is it something that one must implement in the controller after the acl module has provided access to the resource?
Thanks
We searched a lot, but found no good ACL for Node for this kind of stuff.
However in Node.js, it is really easy to just write the method as middleware, which checks the rights on specific resource and allow/deny user to it. If you do not write something really big, this is reasonable approach.
I'm in the process of making a portal website and I wanted to include an iframe which would route people to an intranet. Is there any downsides to this as far as security is concerned?
I think that maybe there's a misunderstanding on your side regarding the function of IFrames: An <iframe> will not route anything. It just tells the user's browser which URL to fetch and show inside it. This means that
People need access to the intranet to actually load the contents of the <iframe>, which might not be what you expected.
It's not a security risk per se.
It is no more or less secure than giving those people direct web access to that intranet.
If you really want to know whether something is "secure" or not, you need to specify the types of threat that you need to protect against, what your tolerance is for breaks in that security, and what additional mechanisms that you have taken to secure your site (for example password authentication, NTLM, SSL, etc).
CONTEXT
I have just been reading about Zend ACL
http://framework.zend.com/manual/en/zend.acl.html
QUESTION
I'm running three Zend applications on one server.
My Front End App
My Front End-Members App
My Back End App (Site Owner's Admin)
Within the applications I'm considering having two types of ACL.
Application Wide ACL - ''app ACL's'' permissions are just - "access" (or maybe call it "read", (or even "SendHTTPRequests"))
Account Wide - leaving all other permissions to individual ''account ACL's''
I'm thinking this would make it easier to block spammers and other attackers
if (UserActivityScoresHighProbabilityOfHacking_Specification->IsSatisfiedBy(User))
{
User->addrole(Attacker)
}
Perhaps with rules something like this:
My Front End App Access Controls
Name = Attacker
Unique Permissions = NONE
Inherit Permissions From = N/A
Name = Guest
Unique Permissions = SendHTTPRequests
Inherit Permissions From = N/A
Name = Member
Unique Permissions = SendHTTPRequests
Inherit Permissions From = Guest
Name = Admin
Unique Permissions = (ALL Permissions)
Inherit Permissions From = N/A
The other apps would have more stringent rules to deny access to guests, etc
So the question to answer is:
Does assigning the role of 'Attacker' (a negative role) to a user strike you as being a sensible thing to do.
Or this contrary to general best practice?
There are basically two philosophies in using ACL:
deny all at startup and give access to resources only after checking black lists/white lists/ permission and all the check you want.
allow all at startup and then deny access to the sensitive area, where you will allow access only after checks.
I prefer to go with the first one usually.
The second one is better when you have small areas to protect and mostly public zones. Doing check for each call adds some weight to your application.
After a couple of days of pondering...here's my answer to my question above:
Does assigning the role of 'Attacker' (a negative role) to a user strike you as being a sensible thing to do.
My answer:
No, its a very silly thing to do.
Why
Aside from the issues outlined by koen and Robert Harvey..
The ACL allows for roles to be inherited and so having positive AND negative roles would cause more chance of complexity and conflict if two roles become applicable to a situation.
I mean 'positive' in the sense of :
'only let someone do something if they are this role'
As opposed to 'negative' in the sense of:
'only let someone do something if they are NOT this role'
Therefore, if you were going to add a role to define 'a hacker', it would be better to keep it in the positive (by negating the negative) - i.e. 'NOT a hacker'.
Or to rephrase that rolename: ''FriendlyUser''
All positive :
+ Role1: FriendlyUser
+ Role2: Guest
+ Role3: Member
+ Role4: Admin
As opposed to mixed:
- Role1: Hacker
+ Role2: Guest
+ Role3: Member
+ Role4: Admin
The second role list is much more confusing.
It's not uncommon for users to share a common IP address, so I'm not sure how practical it is to ban users by IP.
If it is fill-out forms type stuff, spammers are best stopped with a Captcha.
The problem I see with assigning a role based on what a user does/has is that it hardcodes rules in your code. The implicit rule in your example is:
deny user access when user has property/behavior X
A way to see this is hardcoded is to ask yourself what would happen if you wanted to adjust it. Suppose you found the suspicious behaviour a bit too strict and want to tolerate some more, then you would have to go into the file.php and change it.
I think your best bet is to look into the assertion part of the rules:
http://framework.zend.com/manual/en/zend.acl.advanced.html
Depending on your specific needs these can be a good solution.
edit: answer to comment ->
I appreciate the point you make. I think it points to why RBAC will be replaced by more powerful access controls like attribute based access control. This will allow rules based one the attributes of users and objects/resources under control.
Ideally you want the access control to have as much permission decision logic in it as possible. When you assign roles to users implicitly some of the decision making will be outside of the access control (eg what user will be administrator is mostly determined by things like who owns the website). But you want to minimize the decision making outside of the acl because it adds a layer of access that is not controled by the acl. Thus deciding who will have a particular role is often implied and outside the acl. But still it is the are of access control, determined by some logic, and it's best to keep as much logic inside the program that has the responsability to handle this domain.
Hope this rambling makes sense :-)
I'm trying to come up with a good way to do authentication and authorization. Here is what I have. Comments are welcome and what I am hoping for.
I have php on a mac server.
I have Microsoft AD for user accounts.
I am using LDAP to query the AD when the user logs in to the Intranet.
My design question concerns what to do with that AD information. It was suggested by a co-worker to use a naming convention in the AD to avoid an intermediary database. For example, I have a webpage, personnel_payroll.php. I get the url and with the URL and the AD user query the AD for the group personnel_payroll. If the logged in user is in that group they are authorized to view the page. I would have to have a group for every page or at least user domain users for the generic authentication.
It gets more tricky with controls on a page. For example, say there is a button on a page or a grid, only managers can see this. I would need personnel_payroll_myButton as a group in my AD. If the user is in that group, they get the button. I could have many groups if a page had several different levels of authorizations.
Yes, my AD would be huge, but if I don't do this something else will, whether it is MySQL (or some other db), a text file, the httpd.conf, etc.
I would have a generic php funciton IsAuthorized for the various items that passes the url or control name and the authenticated user.
Is there something inherently wrong with using a naming convention for security like this and using the AD as that repository? I have to keep is somewhere. Why not AD?
Thank you for comments.
EDIT: Do you think this scheme would result in super slow pages because of the LDAP calls?
EDIT: I cannot be the first person to ever think of this. Any thoughts on this are appreciated.
EDIT: Thank you to everyone. I am sorry that I could not give you all more points for answering. I had to choose one.
I wonder if there might be a different way of expressing and storing the permissions that would work more cleanly and efficiently.
Most applications are divided into functional areas or roles, and permissions are assigned based on those [broad] areas, as opposed to per-page permissions. So for example, you might have permissions like:
UseApplication
CreateUser
ResetOtherUserPassword
ViewPayrollData
ModifyPayrollData
Or with roles, you could have:
ApplicationUser
ApplicationAdmin
PayrollAdmin
It is likely that the roles (and possibly the per-functionality permissions) may already map to data stored in Active Directory, such as existing AD Groups/Roles. And if it doesn't, it will still be a lot easier to maintain than per-page permissions. The permissions can be maintained as user groups (a user is either in a group, so has the permission, or isn't), or alternately as a custom attribute:
dn: cn=John Doe,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: webAppUser
cn: John Doe
givenName: John
...
myApplicationPermission: UseApplication
myApplicationPermission: ViewPayrollData
This has the advantage that the schema changes are minimal. If you use groups, AD (and every other LDAP server on the planet) already has that functionality, and if you use a custom attribute like this, only a single attribute (and presumably an objectClass, webAppUser in the above example) would need to be added.
Next, you need to decide how to use the data. One possibility would be to check the user's permissions (find out what groups they are in, or what permissions they have been granted) when they log in and store them on the webserver-side in their session. This has the problem that permissions changes only take effect at user-login time and not immediately. If you don't expect permissions to change very often (or while a user is concurrently using the system) this is probably a reasonable way to go. There are variations of this, such as reloading the user's permissions after a certain amount of time has elapsed.
Another possibility, but with more serious (negative) performance implications is to check permissions as needed. In this case you end up hitting the AD server more frequently, causing increased load (both on the web server and AD server), increased network traffic, and higher latency/request times. But you can be sure that the permissions are always up-to-date.
If you still think that it would be useful to have individual pages and buttons names as part of the permissions check, you could have a global "map" of page/button => permission, and do all of your permissions lookups through that. Something (completely un-tested, and mostly pseudocode):
$permMap = array(
"personnel_payroll" => "ViewPayroll",
"personnel_payroll_myButton" => "EditPayroll",
...
);
function check_permission($elementName) {
$permissionName = $permMap[$elementName];
return isUserInLdapGroup($user,$permissionName);
}
The idea of using AD for permissions isn't flawed unless your AD can't scale. If using a local database would be faster/more reliable/flexible, then use that.
Using the naming convention for finding the correct security roles is pretty fragile, though. You will inevitably run into situations where your natural mapping doesn't correspond to the real mapping. Silly things like you want the URL to be "finbiz", but its already in AD as "business-finance" - do you duplicate the group and keep them synchronized, or do you do the remapping within your application...? Sometimes its as simple as "FinBiz" vs "finbiz".
IMO, its best to avoid that sort of problem to begin with, e.g, use group "185" instead of "finbiz" or "business-finance", or some other key that you have more control over.
Regardless of how your getting your permissions, if end up having to cache it, you'll have to deal with stale cache data.
If you have to use ldap, it would make more sense to create a permissions ou (or whatever the AD equivalent of "schema" is) so that you can map arbitrary entities to those permissions. Cache that data, and you should ok.
Edit:
Part of the question seems to be to avoid an intermediary database - why not make the intermediary the primary? Sync the local permissions database to AD regularly (via a hook or polling), and you can avoid two important issues 1) fragile naming convention, 2) external datasource going down.
You will have very slow pages this way (it sounds to me like you'll be re-querying AD LDAP every time a user navigates to figure out what he can do), unless you implement caching of some kind, but then you may run into volatile permission issues (revoked/added permissions on AD while you didn't know about it).
I'd keep permissions and such separate and not use AD as the repository to manage your application specific authorization. Instead use a separate storage provider which will be much easier to maintain and extend as necessary.
Is there something inherently wrong with using a naming convention for security like
this and using the AD as that repository? I have to keep is somewhere. Why not AD?
Logically, using groups for authorization in LDAP/AD is just what it was designed for. An LDAP query of a specific user should be reasonably fast.
In practice, AD can be very unpredictable about how long data changes take to replicate between servers. If someday your app ends up in a big forest with domain controllers distributed all over the continent, you will really regret putting fine-grained data into there. Seriously, it can take an hour for that stuff to replicate for some customers I've worked with. Mysterious situations arise where things magically start working after servers are rebooted and the like.
It's fine to use a directory for 'myapp-users', 'managers', 'payroll' type groups. Try to avoid repeated and wasteful LDAP lookups.
If you were on Windows, one possibility is to create a little file on the local disk for each authorized item. This gives you 'securable objects'. Your app can then impersonate the user and try to open the file. This leverages MS's big investment over the years on optimizing this stuff. Maybe you can do this on the Mac somehow.
Also, check out Apache's mod_auth_ldap. It is said to support "Complex authorization policies can be implemented by representing the policy with LDAP filters."
I don't know what your app does that it doesn't use some kind of database for stuff. Good for you for not taking the easy way out! Here's where a flat text file with JSON can go a long way.
It seems what you're describing is an Access Control List (ACL) to accompany authentication, since you're going beyond 'groups' to specific actions within that group. To create an ACL without a database separate from your authentication means, I'd suggest taking a look at the Zend Framework for PHP, specifically the ACL module.
In your AD settings, assign users to groups (you mention "managers", you'd likely have "users", "administrators", possibly some department-specific groups, and a generic "public" if a user is not part of a group). The Zend ACL module allows you to define "resources" (correlating to page names in your example), and 'actions' within those resources. These are then saved in the session as an object that can be referred to to determine if a user has access. For example:
<?php
$acl = new Zend_Acl();
$acl->addRole(new Zend_Acl_Role('public'));
$acl->addRole(new Zend_Acl_Role('users'));
$acl->addRole(new Zend_Acl_Role('manager'), 'users');
$acl->add(new Zend_Acl_Resource('about')); // Public 'about us' page
$acl->add(new Zend_Acl_Resource('personnel_payroll')); // Payroll page from original post
$acl->allow('users', null, 'view'); // 'users' can view all pages
$acl->allow('public', 'about', 'view'); // 'public' can only view about page
$acl->allow('managers', 'personnel_payroll', 'edit'); // 'managers' can edit the personnel_payroll page, and can view it since they inherit permissions of the 'users' group
// Query the ACL:
echo $acl->isAllowed('public', 'personnel_payroll', 'view') ? "allowed" : "denied"; // denied
echo $acl->isAllowed('users', 'personnel_payroll', 'view') ? "allowed" : "denied"; // allowed
echo $acl->isAllowed('users', 'personnel_payroll', 'edit') ? "allowed" : "denied"; // denied
echo $acl->isAllowed('managers', 'personnel_payroll', 'edit') ? "allowed" : "denied"; // allowed
?>
The benefit to separating the ACL from the AD would be that as the code changes (and what "actions" are possible within the various areas), granting access to them is in the same location, rather than having to administrate the AD server to make the change. And you're using an existing (stable) framework so you don't have to reinvent the wheel with your own isAuthorized function.