accessing user credentials/permissions - symfony1

Is there an easy way to get a credential/permission for a particular user?
I've seen the hasCredential() method, but I'd like to dynamically check any user, not just the current user.
I know I can use sfContext::getInstance()->getUser(); to get the current user object, but is there a way to load in any user and get his/her credentials?
Thanks

It kind of depends on the "store" you're using. In Symfony the current user (the one provided with sfContext::getInstance()->getUser()) is more an abstraction of the session.
So the most used plugin for authentication, sfDoctrineGuard, has controllers (sfGuardAuth) which handle things like a a signin form, and once succesful, it will populate the sfUser accordingly.
So, if you want to check for the permissions of a user, you will have to check the underlying store. If you're using sfDoctrineGuard, you can retrieve a User model through sfGuardUserTable::getInstance()->find(...). On the sfGuardUser, you can call the hasPermission($name) function to check.

If you are using sfGuardPlugin or sfDoctrineGuardPlugin you can get all user permissions by calling getAllPermissions() inside actions with:
$this->getUser()->getGuardUser()->getAllPermissions();
or inside models with:
sfContext::getInstance()->getUser()->getGuardUser()->getAllPermissions();
either way you have to call getGuardUser.

if you are using the sfGuardPlugin, you have the sf_guard_user, sf_guard_permission and sf_guard_group tables in your databse. So you can query that tables to obtain the permission of an specific user doing something like:
$c = new Criteria();
$c->add('username',$specificName);
$userPeer = new sfGuardUserPeer();
$user = $userPeer->doSelect($c);
$credentials = $user->getPermissions();
that way in $credentials you'll have an array of all the permissions (permissions are the credentials in sfGuardPlugin) of the selected user.
Good luck

Related

Rails 5 access profile data anywhere in session without querying database each time

I've a user profile (with name, logo, about_me) which is created after user creation(using Devise). Profile table uses user_id as Primary key.
Now I want that whenever the user creates/updates a post, while filling in form some details are taken from profile, so profile data or #profile be available in post form as I cannot expose my model in form.
To set post.myname attribute in create and #update I'm doing this:
#myprofile = Profile.find_by_user_id(current_user)
write_attribute(:myname, #myprofile.name)
I read from various sources but what's the best solution of the 4 given and if anyone can back with easy code as I do not want to do something extensive? Thanks in advance.
1)Form Hidden fields - Like get the profile data as above in hash in #edit and then pass through form and access fields in #update but that way we will pass each field separately. Can one #myprofile be passed?
2)Session - I feel if profile data is stored in a session and someone updates profile then updated data won't be available in that session.So not sure if it is plausible.
3)Caching - easy way to do that?
4)polymorphic profile---tried it but I didnot get relevant example. I was stuck with what to put as profileable id and type and how to use them in the code.
If your Profile and User models have a one-to-one relationship with each other, the simplest solution is to remove the Profile model altogether and move its fields into the User model.
Devise already queries the database to obtain the current_user object. So, your example would like this:
write_attribute(:myname, current_user.name)
Which wouldn't hit the database (after Devise has retrieved the current_user object).
If you're forced to keep the Profile model, in looking at your four scenarios ...
You could use a session variable. Something like:
session[:profile_name] ||= #myprofile.name
This would go in a controller action.
The trick here is that you will want to redefine the each relevant session variable if the profile gets updated. And because you don't have access to the session in the model, you'd be best to perform that action in the controller. So, not pretty, but it could work.
You could also use low-level caching, and save the profile relationship on the user. In general, you could have a method like this in your user model:
def profile_cached
Rails.cache.fetch(['Profile', profile.id]) do
profile
end
end
Here, too, you will have to know when to expire the cache. The benefit of this approach is that you can put this code in the model, which means you can hook its expiration in a callback.
Read more about this in Caching with Rails.
I would avoid hidden fields and I'm not sure how a polymorphic relationship would solve you not hitting the database. So, #2 and #3 are options, but if you can combine the two models into one, that should simplify it.

Rails Security - Enforcing ownership at the model level

I recently coded up a 'friend' capability with my website. The way it works is if a user wants to 'friend' another user, sending a request creates a user_connection record with the original user set at the user_id and the requested user set as the contact_id. If the other user accepts the request, then another user_connection record will be made, with the user_id and contact_id reversed. If both user_connections exist, then the two users are considered friends. This currently gives each user access to any buildings shared between the two users.
I was wondering if there was some way I could enforce my user_connection model to make sure that whoever is creating the record gets set as the user_id. Otherwise it seems that someone could spoof the user_connection create request to make themself a contact of whomever they want, and then could spoof building shares using the same methodology. Are there any built in methods to prevent this?
My first thought was to have an initializer that always set the user_id to the current_user's id, but it appears that current_user is outside of the context of the model.
Don't allow user_id to be provided as a parameter, using strong params.
So, you could create the relation like that:
#friendship = current_user.friendships.new(contact_id: other_user.id)
Also make sure you provide the correct condition for current_user.
That's it... user_id is implied but never provided.

How can I find a devise user by it's session id?

Given session["session_id"] is it possible to find the logged in User to which that session belongs to?
At least on my system (rails 3.2, devise 2.0.4), you can do it like this:
session is:
{"session_id"=>"be02f27d504672bab3408a0ccf5c1db5", "_csrf_token"=>"DKaCNX3/DMloaCHbVSNq33NJjYIg51X0z/p2T1VRzfY=", "warden.user.user.key"=>["User", [3], "$2a$10$5HFWNuz5p6fT3Z4ZvJfQq."]}
session["warden.user.user.key"][1][0], then is 3.
So, I'd find it as:
User.find(session["warden.user.user.key"][1][0])
I'm not sure what you are trying to accomplish but will try to answer
If you want only the User from the current session, a simple way would be to store his id on session, for example:
def login(username, pass)
# do the usual authentication stuff and get user
if logedin
session[:user_id] = user.id
end
end
Then get the current user would be something like
current_user =User.find(session[:user_id])
If what you want is finding all the users that are currently logged in, I think you need to config your app to save session at DB, because predefined is that session data is store in cookies in the browser. For more information on this check this answer
How to track online users in Rails?
EDIT: Just noticed you are using devise so the first way is actually there for you. You just need to call current_user method at any controller.
For the second way check this answer "Who's Online" using Devise in Rails
And i might add this, as i was trying to do it the other way, if you are using ActiveRecord session_store you can find all stored sessions of a user like so:
ActiveRecord::SessionStore::Session.select{ |s| s.data["warden.user.user.key"] && s.data["warden.user.user.key"][0][0] == user_id }

How to create a "backdoor" for administrator, to be able to log in as anohter user and see information?

I am creating an online survey tool.
As an administrator, i would like to see what the users have answered and also be able to answer on their behalf. The system get's a users answers and other information based on his/her username, when they are logged in, using the built in membership provider.
There are currently three roles: Administrator, Moderator and Respondent
If i would like to show my administrator a list of users,
how would it be possible to create a "backdoor" for the administrator, so that he can "log" in as the user, see the users answers etc ? (Just like the user would be able to if he was logged in to his own account).
When answering and retrieving quyestions, the system is bound to `User.Identity.Name
My suggestion on how to solve this:
Currently, when i want to retrive a users answers i use the following code:
Firma_ID = db.Firma.Single(x => x.CVR_nummer == User.Identity.Name).firma_id;
var answers = db.Tabelform_Answers.Where(x => x.question_id == model.Question_ID && x.respondent == Firma_ID);
This is because i have a table named Firma, that has a column referencing to a users Name, called CVR_Nummer. I then retrieve all the records in the Tabelform_Answers table, that match question_id and Firma_ID (A users answers for a specific question).
Instead of using `Firma_ID = db.Firma.Single(x => x.CVR_nummer == User.Identity.Name).firma_id;
to retrive the Firma_ID of a given user, i could store it in the Session upon Login. When i want to view a specific users Answers as Administrator, i would then just change Firma_ID in the Session. Changing Firma_ID in the Session would only be allowed through a controller which has the following code:
[Authorize(Roles = "Administrator")]
Also, i would set the Session timeout to be the same as the Authentication timeout.
Can somebody tell me which pros and cons of this solution? Are there any other ways of storing a "global" variable for a Session? (Firma_ID)?
Thanks
If you only need to log in as your users, I went for a ticket-method.
I have a special login-page that can take a ticket-id. This ticket is created in the admin-gui when the admin wants to log in as another user. The login-page checks the ticket in the database, logs in the wanted user, and then deletes/marks the ticket as used. As an added security, a ticket is only valid for 10 seconds after creation.
Another option is to make answers from users available from the admin-gui...
also you can do in your log-in script override
so you have at present something like
if user name and password match string then user is logged in and based on this you get user permissions
instead have admin page,
where you can select user and then you can apply permissions of the user instead of admin.

Steps to create my own authentication system, need some guidance

I want to learn how to create my own authentication system, please provide some guidance if am doing this wrong.
I will create a Module in my /lib folder /lib/auth.rb
I will require this module in my ApplicationController.
when a user enters their email + password, I will call a method that will do a lookup in the user's table for a user with the same email, I will then compare the passwords. (i'll add encryption with salt later).
If the user entered the correct credentials, I will create a row in the Sessions table, and then write the session GUID to a cookie.
Now whenever I need to check if the user is logged in, or I need the user object, I will check if the cookie exists, if it does, I will lookup the session table for a row with the same guid, if it exists, I will return the session row and then load the User object.
I realize there are many suggestions one can give, but in a nutshell does this sound like a workable solution?
Now to make this usable, I will have to make some helper methods in my ApplicationController right?
How will I access the current_user from within my views?
P.S I know of other authentication systems, I just want to learn how to create my own.
The basic logic you're following is correct. Of course you can always expand on this with features that you need. For instance, you'll need helper methods for things like "logged_in?" and "current_user". Also, you might want to add session expiry, or session retention as a "remember me" feature.
Go for it, you won't learn authentication systems better than building your own then figuring what's wrong with it.
You should really check out the authlogic gem on github.
http://github.com/binarylogic/authlogic
It also has great instructions on how to set up your users.
After Faisal said what I would say, I only give you answer to the last part of your question:
"How will I access the current_user from within my views?"
try something like this:
class User < ...
def self.current=(u)
#current = u
end
def self.current
#current
end
end
In your views (or any part of your code) you can call User.current. Your controller has to assign a validated user to User.current. Your filters can react to "if User.current.nil?" and so on.
If you want to be thread safe, you may use a thread variable instead of #current:
Thread.current[:current_user] = u

Resources