Set A Role To User Programmatically without RBAC? - yii

I don't use RBAC to validate users. I wouldn't mind using it if it's possible, but I don't think it is. Reason being, I use a REST API to validate users. I have this in my authenticate() function:
$API = new API();
$user = $API->getAccountDetailsByEmail($this->username);
if($user->password !== md5($this->password) ) {
// Validated
}
I want the user to also be assigned a role at this step. Which is why I tried the following below the above:
$this->setState('roles', 'admin');
But this doesn't work at all. I still get:
Error 403: You are not authorized to perform this action.
When I go to the page I am trying to make admin accessible. How do I programmatically set a user as an admin?
Am I missing something, or is there an easy way to assign a role to a user that was authenticated?

The CAccessControlFilter relies on the CWebUser::checkAccess() function. This function is called with the name of the role as a parameter. If you do not want RBAC then the easiest you could do is write your own CWebUser derived class and implement your own checkAccess.
You can activate this class in your config file by adding the "user" component:
'components'=> array
(
'user' => array
(
'class' => 'MyWebUser',
),
),
You could for example set a list of roles in the users' session and have the function check if the user has that role. Although I would advise against using the session to store roles (the database is beter) using setState is definitely a bad idea. IIRC this sets a cookie on the user side and a bit of an inventive user could figure out how to abuse this.

If your action rules are
array('allow',
'actions'=>array(
'myAction',
),
'users'=>array('#'),
'roles'=>array('admin'),
),
Then change them to:
array('allow',
'actions'=>array(
'myAction',
),
'users'=>array('#'),
'expression'=>'$user->getState("roles")=="admin"',
),
The roles parameter for action rules is for use ONLY with RBAC. So you need to do your validation differently if you aren't using RBAC.
If that isn't your issue, then please provide more details about what you are trying and what your access rules look like.

Related

Problems adding items with contact references when authenticated as an app

I'm trying to add an Item, where one of the fields is of type contact (user), to Podio.
I do not have the contact profile_id, only the name, so I need to search the contact to get the profile_id before adding.
The problem is that the /contact/ resources are inaccessible since I'm using app authentication.
The error is: "Authentication as app is not allowed for this method"
What is the recommended way to do this?
Thanks.
As I can see, the tricky part here is that you have just a name of the user. So you need to search this name first.
To be able to search you should be authenticated not as an app, but as a user with appropriate rights. I believe this is because search functions a rate-limited per user. You may authenticate on client side, server side or just by entering user's email and password (see documentation here).
Then, when authenticated, just use search functions with the parameter "ref_type": "profile" to look for the user name within space, organisation or globally. Example for PHP-client:
$attributes = array(
"query" => "John Doe",
"ref_type" => "profile"
);
$results = PodioSearchResult::space( $space_id, $attributes ); // search in space
$results = PodioSearchResult::org( $org_id, $attributes ); // search in organisation
$results = PodioSearchResult::search( $attributes ); // search globally
Functions above will return an array of the most relative results found. There you can get a user id and other user info.
Note that technically several different users may have the same name, so there might be more that one result found. It will be up to you to choose one of them somehow.

Authentication in liferay pages

We are having a portlet on a liferay page. We want to put up up a permission on every action method that is performed. For example on page A we have landed an XYZ portlet. Now we want that whenever there is any action performed form this portlet, we want to check that if the user is having a role to perform this action or not.
It wont be a good approach to put up the code in Action method of the portlet cause we are having approximately 20 such pages and portlets.
Can we have some sort of filter or so, so that each action request is checked if the user is having the access to the content or not.
Thank you...
My idea.
Use a filter to intercept all request
You can add a filter to the Liferay Servlet to check every request.
For that you can use a hook-plugin.
Look at this :
http://www.liferay.com/fr/documentation/liferay-portal/6.1/development/-/ai/other-hooks
http://connect-sam.com/2012/06/creating-servlet-filter-hook-in-liferay-6-1-to-restrict-access-based-on-ip-location/
Issue with filter is that you can't access ThemeDisplay or use PortalUtil.getUser(request).
So you must use work around like that :
private User _getUser(HttpServletRequest request) throws Exception {
HttpSession session = request.getSession();
User user = PortalUtil.getUser(request);
if (user != null) {
return user;
}
String userIdString = (String) session.getAttribute("j_username");
String password = (String) session.getAttribute("j_password");
if ((userIdString != null) && (password != null)) {
long userId = GetterUtil.getLong(userIdString);
user = UserLocalServiceUtil.getUser(userId);
}
return user;
}
Filtering the request
To filter the request you must get :
page id (Layout id in Liferay)
portlet id
portlet lifecycle
One more time using a filter is a pain because you can get the ThemeDisplay. These params are easy to get (with real object instancee) with ThemeDisplay.
So you must get this as parameter in the request.
final String portletId = ParamUtil.get((HttpServletRequest) servletRequest, "p_p_id", "");
final String layoutId = ParamUtil.get((HttpServletRequest) servletRequest, "plid", "");
final String portletLifecycle = ParamUtil.get((HttpServletRequest) servletRequest, "p_p_lifecycle", "");
Lifecycle details :
portletLifecycle is a int and the meaning of value is :
0 : RENDER
1 : ACTION (the one that interests you)
2 : RESOURCE
I think that with this data you can be able to define if user can or cannot make the action.
You can get user roles from the user.
You can get the current page and portlet linked to the request.
And you can know if the request is an action request.
Good luck with Liferay.
You can add freely configurable permissions to Liferay, see the Developer Guide for detailed information. My first guess on this would be that these affect "model resources", e.g. the data that your portlet is dealing with, rather than portlet-resources, e.g. permissions on the individual portlet itself. Think of portlet-permissions as permissions that are defined by Liferay, model-resources as permissions where you can come up with your own vocabulary on the actions, e.g. "UPDATE_ADDRESS" etc.
These permissions will typically be tied to roles, which are granted to users/usergroups/etc.
Based on this variability, it depends on the nature of your permissions if you can write a filter to generically check permissions, or if it depends on more than the individual action call.
If you determine that there is a generic solution, look up PortletFilters, they behave just like ServletFilters. These can easily provide a home for permission checks.
It's quite hard to cover this topic in such a short answer, I hope to have given enough resources for you to continue your quest.
You can abuse some existing portlet permission like "Add to Page" and set it to roles that should call the action.
And by the rendering and action phases validate "has the user necessary permission".
Or you can create new permission and configure it by portlet-configuration. This way is cleaner, but difficulty.

yii ACL for different user roles

This question may be basic and has been asked before, but I couldn't find it.
I'm using Yii and I get trouble when differentiating users with action's access.
I have a table called tbl_user, with fields like username, password, and role. When a user login, the system will set the loginAs state with his/her role, for example:
$role = "Super User"; //assume we get this role by querying the tbl_user
Yii::app()->user->setState("loginAs", $role)
In a controller, there are 4 actions, actionIndex, actionCreate, actionUpdate, and actionDelete. If a super user logins, these 4 action will be available. But if another user with different role logins, for example "administrator", all but actionDelete will be available. I tried this:
public function accessRules()
{
return array(
array('allow',
'actions'=>array('index','create','update','delete'),
'expression'=>'Yii::app()->user->getState("loginAs")=="Super User"'
),
array('allow',
'actions'=>array('index','create','update'),
'expression'=>'Yii::app()->user->getState("loginAs")=="Administrator"',
),
);
}
EDITED
The code above doesn't work. When I login as Administrator, I get error 403 for all 4 actions. Administrator should be able to access all except "delete". Is there another way for this? Any help will be appreciated.
From http://www.yiiframework.com/doc/guide/1.1/en/topics.auth
The access rules are evaluated one by one in the order they are
specified. The first rule that matches the current pattern (e.g.
username, roles, client IP, address) determines the authorization
result. If this rule is an allow rule, the action can be executed; if
it is a deny rule, the action cannot be executed; if none of the rules
matches the context, the action can still be executed.
So you should combine all the roles that can execute an action in a single expression i.e.
array('allow',
'actions'=>array('index','create','update'),
'expression'=>'in_array(Yii::app()->user->getState("loginAs"),array("Super User","Administrator",...))'
),
array('allow',
'actions'=>array('delete'),
'expression'=>'Yii::app()->user->getState("loginAs")=="Super User"'
),
Also if you follow the link above, you'll see how to implement RBAC in Yii. This can reduce your code to something like
array('allow',
'actions'=>array('index','create','update'),
'roles'=>array("Super User","Administrator"),
),
Also make sure that accessControl is enabled in you controller filter
public function filters()
{
// ...
return array('accessControl',);
}

Laravel 4 authentication not working

I have a Laravel 4 app in which I have set up one user. In my login route I'm calling Auth::attempt with the email and password but it always comes back as false. I definitely have the password correct and the correct hash in the database as Hash::check returns true.
I think it may be due to using email as the login field instead of username, but I can't see any setting for that. This question implied you could add an option to config/auth.php but it didn't work. This question says to use username as the array key, but then I get SQL error because it tries to select on a username field in the database.
Do I need to add something to the User model to specify the username field? Here is my login route:
Route::post('login', function() {
// data from login form
$credentials = array(
'email' => Input::get('email'),
'password' => Input::get('password')
);
$auth = Hash::check(Input::get('password'), Hash::make('mypass'));
var_dump($auth); // this is TRUE
// login was good
$auth = Auth::attempt($credentials);
var_dump($auth); // this is FALSE
});
I found the problem. As suggested by Jason in the comment above, I had modified the models/User.php file and removed some functions that I didn't realise were necessary.
The getAuthIdentifier() and getAuthPassword() methods must be included in the User model for authentication!
In app/config/app.php make sure you have the 'key' set. This made me pull my hair out. Everything will apear to work, password seems hashed in the DB, but it will always return false until you set this key and re-hash your password into the DB.
"php artisan key:generate"
Had the same problem and made me sweat for hours. Definitively check your User.php model and make sure you have not overwritten the default one. Thanks Jason!

SimpleMembership updating the "isconfirmed" flag

My Users table (the one that I created) has the following columns:
UserId,UserName,FirstName,LastName,DOB
After I ran this command
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "Users", "UserId", "UserName", autoCreateTables: true);
it created the required simple membership tables for me.
How would I go about "UnConfirming" an user or setting the "IsConfirmed" flag to false in the webpages_Membership using the new SimpleMembership API?
(Earlier, before going to simplemembership using the "Membership" class I could update an user using the api call : Membership.UpdateUser( user );)
I can't answer your question directly since I couldn't figure out a way to 'unconfirm' an account either. What I ended up doing, however, may help whoever finds this question.
I basically use Roles as a gatekeeper. Whenever I create a new account I add that user to a "User" role:
Roles.AddUserToRole(newUser.Username, "User");
I use the Authorize attribute to restrict access to my controllers (and use [AllowAnonymous] for actions that I want to be public -- like RegisterUser, for example). Then, inside each action I add a method to restrict access to only users that are in the "User" role.
if (!Roles.IsUserInRole(role))
{
throw new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.Unauthorized));
}
NOTE: I'm using Web API, but if you're using MVC you should have a much easier time. Instead of manually checking if a user is in a role in each action you can just use the authorize attribute:
[Authorize(Roles = "User")]
When I want to "UnConfirm" a user I just remove them from the "User" role.
Roles.RemoveUserFromRole(user.Username, "User");
This way if a user comes crawling back I can just reactivate their account by adding them back as a User.
What I ended up doing was updating that table directly via a SQL query. Not sure if thats the recommended way of doing it, but that seemed to work for me.
(Thanks for your suggestion too).
Look at this blog post on adding email confirmation to SimpleMembership registration process, which covers how the confirmation process works. The cliff notes are that when you create a new user you set the flag that you want to use confirmation like this.
string confirmationToken =
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { Email = model.Email }, true);
When you do this the CreateUserAndAccount method returns a unique token that you can put in an email with a link so the user can confirm that they gave you a valid email address. When they click on the link it passes the token in the URL and the controller action can then confirm the token like this.
[AllowAnonymous]
public ActionResult RegisterConfirmation(string Id)
{
if (WebSecurity.ConfirmAccount(Id))
{
return RedirectToAction("ConfirmationSuccess");
}
return RedirectToAction("ConfirmationFailure");
}
The ConfirmAccount method checks if there is an uncomfirmed token that matches in the database and if there is it sets the isConfirmed flag to true. The user will not be able to logon until this is set to true.
set requireConfirmationToken to be true: (The 4th value shown below)
WebSecurity.CreateUserAndAccount(viewModel.UserName, viewModel.Password, null, true);
Source
http://www.w3schools.com/aspnet/met_websecurity_createuserandaccount.asp