When service authentication starts it saves a copy of $orginal_user and $old_state so that the authentication can change these as required without affecting the remainder of the program.
This essentially gives us a push authentication situation. I think we also need a pop authentication call after the service call has been executed so that the auth plugin can cleanup (if desired) the state that was awarded. This would be very useful in my situation where service authentication is always given to a semi-privileged user, the service is executed and now i want to remove this user privileges again.
This kind of happens anyway with the check that if drupal_save_session fails then revert back to the other originally saved user, it would just be better if the plugin could influence this.
Thanks,
Jamie
Comment | File | Size | Author |
---|---|---|---|
#82 | services-1240074-presave-session-refactoring-2.patch | 3.55 KB | mradcliffe |
#63 | services-1240074-presave-session-refactoring.patch | 3.52 KB | ygerasimov |
#62 | api.txt | 896 bytes | tormu |
#56 | session_restore-1240074-54-services-6.x-3.x-dev.patch | 2.38 KB | klokie |
#54 | session_restore-1240074-54.patch | 1.97 KB | emorency |
Comments
Comment #1
marcingy CreditAttribution: marcingy commentedWhere exactly are you looking to have to this new hook? Immediately before
The idea seems sensible on my part.
Comment #2
jamielennox CreditAttribution: jamielennox commentedWell as a quick example see patch.
It's not perfect, calling services_auth_invoke twice means rebuilding everything twice. Also i'm not really sure how this should relate to $orig_user and $old_state, what is the point in reverting the user only when
if (drupal_save_session($user) === FALSE)
??Comment #3
marcingy CreditAttribution: marcingy commentedI don't understand why you are calling the authenication twice, your auth method should be dealing with what ever is required to perform authenication.
And then the deauthenticate_call simply needs to do
The deauthenticate_call should only be reversing what the initail authenticate_call did
Comment #4
jamielennox CreditAttribution: jamielennox commentedSorry, i think that i worded my comment #2 badly. I just meant that every time you call services_auth_invoke you recall the hooks and you could optimise that. I'm not really sure what the standard approach to that is.
But you are right, the patch will still only have you call 'autheticate_call' and 'deauthenticate_call' once each.
Still why do we revert the user to the original user only if a session save fails?
Comment #5
marcingy CreditAttribution: marcingy commentedAh adding caching for auth methods would make senese but that would be seperate patch in my opinion.
The check is because a custom auth method might be utilising a different user and could have reset drupal_save_session to true to be honest it shouldn't have $user being passed in if I'm honest..
Comment #6
voxpelli CreditAttribution: voxpelli commentedI'm not really understanding the use case here?
Eg. Services OAuth sets the logged in user to that of the OAuth token which Services resets to the request's original user (by default just an anonymous) when the Services call is done.
Why is that cleanup not enough? Are your auth mechanism setting more global variables than just the user? If so - why?
Comment #7
ygerasimov CreditAttribution: ygerasimov commentedHere is use case from user perspective:
1. I am happy new to services user set up rest endpoint with all enabled node resource
2. I create a node
3. I try open in my browser /node and see my newly created node
4. I go back to the site but I see that I am logged off. I start thinking what I have done wrong :(
Shall we take care about this user experience and take logged in user back?
I think yes.
Moving this issue to bug category.
Comment #8
jamielennox CreditAttribution: jamielennox commentedIn which case i'm not sure what is happening then because my tests are showing that the $user is not being unset. In my auth method at the moment i am just
$user = user_load(1);
, yes thats bad but i'm just testing things at the moment.Now every time i make a services call i get a new entry in the session table. I don't want to log user 1 off if they are logged in, and i don't want to share the session (though there are probably use cases that do). I think whatever is in services tearing down the user is not functioning correctly because it does not log it off.
I also question having the user reset in services.runtime rather than another call to the module. Shouldn't the module be unsetting the user and saving its session etc if it is appropriate to that module? This is not a question of OAuth but other modules and for me i want my service call to be stateless.
Comment #9
voxpelli CreditAttribution: voxpelli commentedSeems to be a bit of confusion here as to what Services is actually trying to do - I will try to describe what it's meant to do overall:
Seems like @ygerasimov are suggesting that Services on purpose logs user out when an API is accessed - it does not. It's meant to restore the original session after each request - if that's not the case then that's a bug - we're only interested in enabling "sandboxing" of the user object during the duration of a Services call and there's good security reasons for doing that. Enabling the session auth module should make Services authentication behave like it did prior to the security fix - if that's not true then that's a abug as well.
@jumentous - that you get a new row in the session table seems like a bug. The only session we're touching is the one Drupal might be already using when the Services call is started. We deactivate it during the duration of the session call and then restores it. How that can cause your user 1 to be logged out seems very weird.
@jumentous - services.runtime is the right place as we want all API calls to be anonymous unless the endpoint has been specifically configured otherwise - this is to avoid similar CSRF-vulnerabilities that Drupal core solves through form tokens.
And lastly: Of course Services and the REST Server should be stateless - the REST Server was designed to be stateless - any case where Services isn't stateless is a bug (of course with the session auth exempt as sessions by nature isn't stateless).
Comment #10
ygerasimov CreditAttribution: ygerasimov commented@voxpelli thank you very very much for this detailed explanation. I think we should grab it to some wiki documentation page.
Then what I described in #7 is a bug that should be fixed.
Comment #11
jamielennox CreditAttribution: jamielennox commentedOk, thanks for the explanation.
Given that i now see how and why the user is reset by services i don't have a specific need for the deauthenticate hook - though i don't see it as a bad idea.
My tests show that every call to services ends up with a new entry in sessions table for the anonymous user which is a result of the way that the user is backed up and restored.
Using the information here: http://drupal.org/node/218104 we can change services.runtime.inc according to the attached patch and this problem is solved.
Comment #12
marcingy CreditAttribution: marcingy commented@jumentous thanks for the patch above that code looks much tidier :)
Comment #13
voxpelli CreditAttribution: voxpelli commentedThat's the guide we followed as well when we did the initial code - I do however think that your change will break the login method on the user resource and thus break session authentication. Can someone test? If I'm wrong then please return to RTBC.
Comment #14
mradcliffeRe #9, would you be able to explain what changes I would need to make to work with the new Services runtime model?
- Flash application downloaded and invoked from Drupal site with session id.
- Flash application makes web services call with session id and other variables back to site via custom Services request, which returns custom auth token (can't use oauth model here).
- User can still use web site without being logged out.
As of now, as soon as that auth call is made the user is logged out, and thus any further requests are invalid because it's access denied.
How can I prevent the session from being destroyed?
Edit: sorry, the patch above will work in my case.
Comment #15
kylebrowning CreditAttribution: kylebrowning commentedBumping this to major as we need it for release.
Comment #16
ygerasimov CreditAttribution: ygerasimov commentedSorry gents, I got really confused. The test case I did in #7 is invalid, as browser received different cookies (for anonymous user) and then of course when it tries to open admin page, I got access denied. It has nothing to do with Services module.
I am not sure if I understand the question right on this issue. What user's session should/or should not be destroyed? Original user or user that we authenticate and act on behalf?
I have applied patch from #11 and it breaks tests on user. It happens because we destroy session after user has been logged in using drupal core auth mechanism with cookies.
@mradcliffe, @jumentous could you please come once online on IRC and explain this issue in details? Also I would like to write automatic test for this bug, so we need some guidance about your custom authentication you have problems with.
Comment #17
ygerasimov CreditAttribution: ygerasimov commentedChanging status as we need more info about this issue to reproduce.
Comment #18
mradcliffeI finally created a test module that illustrates this (attached).
If your curl call passes in the same session cookie, then that session is destroyed. I couldn't reproduce this until I passed in that session cookie. If the call to the web service does not include it, then it's fine. In my use case, however, a flash app. is doing this and is necessary to keep session as it will load up private filesystem assets.
Comment #19
jamielennox CreditAttribution: jamielennox commentedSorry for the late reply i've been away.
I had a look back into this and my issue may not actually be services fault (but it sounds different to mradcliffe's).
Today i downloaded the -dev of ctools, services, features and created the simple module eauth to do authentication.
On a fresh site whenever i do an xmlrpc query the number of entries in my sessions table increases. However when i look in the blobs as to what is being saved in sessions it is:
messages|a:1:{s:5:"error";a:2:{i:0;s:288:"Warning: array_flip(): Can only flip STRING and INTEGER values! in DrupalDefaultEntityController->load() (line 178 of /home/jamie/public_html/eauth/includes/entity.inc).";i:1;s:292:"Warning: array_flip(): Can only flip STRING and INTEGER values! in DrupalDefaultEntityController->cacheGet() (line 354 of /home/jamie/public_html/eauth/includes/entity.inc).";}}
so while there is a bug i don't know where and i don't have a backtrace of the above message to know what is causing the error. When using the patch in #11 (no longer applies cleanly but c&p) the error no longer occurs and the session count remains the same.
I'm attaching my very basic auth plugin, a feature with my xmlrpc service, and a python script that calls the xmlrpc service. You still need to create a node id 1, and modify the script to point to your site.
Comment #20
mradcliffeChanging issue title to be a bit more informative on the issue queue.
Comment #21
mradcliffeThese modified patches from jumentous *should* work. The original_user should NOT be anonymous in the test, but for some reason the conditional is failing.
As we can see in the test, we log in as one user so there is no way that we can be anonymous when we make user login request again. It doesn't make any sense. Debugging Services is so frustrating sometimes.
Is there something else going on? Is SimpleTest the problem here and not the actual code?
I really need help to get this committed because this bug is preventing me from updating Services at all.
Comment #23
kylebrowning CreditAttribution: kylebrowning commentedHeres an updated patch, but as you can see, it needs work.
Comment #25
kylebrowning CreditAttribution: kylebrowning commentedheres a new patch.
Comment #26
kylebrowning CreditAttribution: kylebrowning commentedwe've added a test, and rolled back a certain commit that we believed was causing this issue.
Please reopen if you experience this issue again.
Comment #27
rypit CreditAttribution: rypit commentedIf I am understanding this correctly, it seems like the bug is still in the latest dev release.
Following these steps results in the active user being logged out:
This is without using any authentication services. Is this desired behavior? How would one go about ensuring that the session of the active user isn't destroyed? Maybe only calls to authentication-type methods should mess about with the active user?
Please feel free to change this back to fixed if I am misunderstanding something here.
Comment #28
marcingy CreditAttribution: marcingy commentedPlease provide a simple test to recreate this.
Comment #29
rypit CreditAttribution: rypit commentedI'm just starting working with the testing module, and I'm not immediately sure how to demonstrate this problem through that interface at the moment -- but you can easily reproduce the problem by:
Note -- when manually applying the patch in #25 to services.runtime.inc -- the problem is resolved.
Comment #30
kylebrowning CreditAttribution: kylebrowning commentedWEll, using the latest dev release of Services, I cannot reproduce this issue.
I copied and pasted your code for jQuery and was unable to see this as an issue.
I still think the patch in #25 should be committed though, but I haunt written a test to prove that is an issue.
Comment #31
marcingy CreditAttribution: marcingy commentedWe don't actually seem to have a bug so moving to a task.
Comment #32
rypit CreditAttribution: rypit commentedI just checked out the latest version of 7.x-3.x and am still experiencing the issue with a fresh install and minimal configuration. That is: checked out services, added spyc, enabled a rest server with a node resource. I do not have any authentication modules enabled. I was still logged out by pasting the JavaScript into my console -- ie making a typical resource request. Perhaps I am missing a step in my configuration.
I was working on a simpletest to recreate this issue, but it seems like it doesn't occur when testing takes place within the sandbox of the testing class(es). When I replaced the typical means with a drupal_http_request however, my active user (not test the user) was logged out while running the test. I'm not confident that is the desired result for the test (the user running the test should ideally not be affected by such a thing), so more work would be required to figure out why this is happening (and I'm still becoming familiar with the simpletest framework).
Comment #33
kylebrowning CreditAttribution: kylebrowning commentedRypit if you enable session authentication does it fix the issue?
Like i said, i think #25 is still a valid task. Ill try and write a test tomorrow if I don't get any more real work tickets :P
Comment #34
rypit CreditAttribution: rypit commentedkylebrowning -- enabling session authentication does seem to fix the issue. I've been trying to write a test but haven't had much luck... I'm not sure if servicesGet ever ends up running through services_controller_execute, but that's where the issue seems to be (as you've pointed out).
Comment #35
mradcliffeYou need to make sure you include the same php session in the tes. Please see my testsvc module in #19 for an example. I have not been able to test this using that
Comment #36
joachim CreditAttribution: joachim commentedI'm seeing this bug in 6.x-3.1:
- create a service that has the node resource, without session authentication
- go to myendpoint/node/xx
- reload another site page: I am logged out.
Comment #37
marcingy CreditAttribution: marcingy commentedPlease provide a simpletest that recreates this bug without a simple test this is not going anywhere because the implication of this change affect security massively, and to be honest the use case in #36 is not really a normal use case given that you are doing everything in the same context. The old broswer in 2.x used to do strange things as well in certain cases, so moving back to a task until we have a real world situation that is actually a 'bug'.
Comment #38
joachim CreditAttribution: joachim commentedSee #7.
This is a pain for a user using and exploring this module's capabilities.
Comment #39
marcingy CreditAttribution: marcingy commentedPlease do not change the category.....
Comment #40
kylebrowning CreditAttribution: kylebrowning commentedhave you tried the patch in #25?
Comment #41
joachim CreditAttribution: joachim commentedI did, but it doesn't apply on 6.x-3.x.
> Please do not change the category.....
Sorry but how on earth is this not a bug?
Comment #42
kylebrowning CreditAttribution: kylebrowning commentedIts not a bug because its slightly intended functionality of the anonymous usage of services wen you do not have session authentication enabled.
Enable sessions authentication and this shouldn't be an issue.
It is however rather annoying that thishapens when you are logged in, and I believe the patch in #25 fixes it.
Comment #43
joachim CreditAttribution: joachim commentedSounds like we disagree about the definition of what a bug is.
> It is however rather annoying
This makes it a bug.
Even if the *design* of an application is 'the application should smack the user in the face when they activate it', if the user doesn't *like* being smacked in the face and finds it unpleasant, then that is a *bug*.
Comment #44
kylebrowning CreditAttribution: kylebrowning commentedI disagree, this ticket could technically be closed as, works as designed.
Comment #45
sreynen CreditAttribution: sreynen commentedAs someone who just spent a long time thinking I was doing something wrong before discovering this issue, I'm in the bug camp. I've read a good deal of documentation and didn't see any mention that I should expect to see my session deleted when making GET requests. So if this isn't a code bug, I'd suggest it's at least a documentation bug.
I'm still not sure how to avoid the problem. There's a few references in this thread to enabling session authentication. How exactly do I do that? I don't see any option to enable that on any of the services configuration screens I've found, nor any module I might enable that seems to match that description.
Comment #46
sreynen CreditAttribution: sreynen commentedFound it! For anyone else looking: "session authentication" is a checkbox on the endpoint edit screen.
Comment #47
mradcliffe@kylebrowning's patch from #25 did work for me. I have re-rolled it.
I will try to re-roll for Drupal 6.
Comment #48
mradcliffeHere's a 6.x version of the same patch (untested).
Comment #49
marcingy CreditAttribution: marcingy commentedI have real concerns about this line of code being removed
as it means that services calls are no longer running in a 'sandbox'
Comment #50
mradcliffeI think the one thing missing from kyle's approach was addressed in jumentous' patch with the saving and restoring of the old_state. Here's one that combines the two.
Comment #52
kylebrowning CreditAttribution: kylebrowning commentedEither the tests are wrong, or the patch is bad :(
Comment #53
mradcliffeI think it's the same issue that was causing the past patches from jumentous to fail (my comments in #21). It has been so long since I had a chance to work on this.
Comment #54
emorency CreditAttribution: emorency commentedI've taken the patch from #50 and created a patch that I can apply with git apply. It is a proper git patch.
Comment #55
magnusk CreditAttribution: magnusk commentedI tried patch from #54 with the REST server -- it doesn't work with POST to user/login followed by resource GETs by an authenticated user (the authenticated session is not recognized; anonymous access is rejected). If I change the end of the patch as follows (leaving $user alone in case of a user login) it does work:
Also, why call
drupal_save_session($user);
and notdrupal_save_session(TRUE);
?Comment #56
klokie CreditAttribution: klokie commentedHi, I've been having this same issue (as in #7) with a site that uses Services for D6. I managed to backport the patch in #54 to Services=6.x-3.x-dev and resolve the problem. I haven't done that before, but I hope it helps someone.
Comment #57
kent_drupal CreditAttribution: kent_drupal commented@Klokie,
This patch isn't working for me. The user gets logged in successfully but if I send "Logout" right after login, I get below error:
"readyState":4,"responseText":"[\"User is not logged in.\"]","status":406,"statusText":"Not Acceptable: User is not logged in."}
am I missing something? I will appreciate any inputs on this.
FYI, I tried this patch on latest 6.3 dev version (18th Jul 2012), fresh install, clear cache.
Comment #58
kent_drupal CreditAttribution: kent_drupal commentedComment #59
joachim CreditAttribution: joachim commentedI'd love to push this patch forward as this bug is the bane of when working with Services.
However, I don't follow what's being done:
What does that callback mean? (Also, should probably be != not <>, which isn't used anywhere in Drupal AFAIK.)
Nothing happens when the callback is that. Why?
Code and comment don't seem to agree. We don't care, and yet we're saving a value?
As pointed out above, it makes no sense to pass $user in here. This function takes a boolean parameter. If the intention is to pass TRUE in if there's a user account, that should be made explicit with (bool) $user, or (bool) $user->uid if what counts is whether it's an anon user or not.
Comment #60
kylebrowning CreditAttribution: kylebrowning commentedThings may have changed in Drupal 7 when this patch was done but ill explain a bit about whats happening.
Basically when any method happens besides resource login, we dont want to change the user state, thats wy its checking that.
Your other comments on the code are correct.
Comment #61
kylebrowning CreditAttribution: kylebrowning commentedThis should be resolved in 7.x and 6.x
Comment #62
tormu CreditAttribution: tormu commentedI'm not seeing this as fixed in the newest stable release.
I've got the server set up to only output nodes, and anonymous users have the permission to view content. When the session authentication is not checked and I make a request for the node via REST server, I get logged out if the request is made while being logged in.
Making the same request as a anonymous user works as expected and I get the content.
If I put the session authentication on, everything works as before, but I don't get logged out when making the request as a logged user.
Drupal version 7.19, exported server configuration attached, happy to provide any more debug information needed. Debug info shows that the logout is done during the services_controller_execute() (between watchdog('services', 'Passed arguments.... and watchdog('services', 'Called arguments...
Comment #63
ygerasimov CreditAttribution: ygerasimov commentedI also find current state not quite right.
We should preserve session and global $user for every call beside login and logout.
Attached patch does some refactoring plus restoring user and session in case exception is caught during runtime.
Lets take a look at tests check.
Comment #65
ygerasimov CreditAttribution: ygerasimov commentedComment #66
ygerasimov CreditAttribution: ygerasimov commented#63: services-1240074-presave-session-refactoring.patch queued for re-testing.
Comment #68
ygerasimov CreditAttribution: ygerasimov commented#63: services-1240074-presave-session-refactoring.patch queued for re-testing.
Comment #70
mradcliffeIt's trying to apply the ptach to tag 7.x-3.3, instead of branch 7.x-3.x. I was confused as well for a moment.
Comment #71
mradcliffe#63: services-1240074-presave-session-refactoring.patch queued for re-testing.
Comment #72
ygerasimov CreditAttribution: ygerasimov commented@mradcliffe well done! This is why bot was not able to apply the patch. I did it against 7.x-3.x-dev and not 3.3. Now it is green and I would like to know everyone's opinion about it.
Comment #73
adnasa CreditAttribution: adnasa commentedI don't if my findings was beyond the scope of this issue, as I understood it you guys were trying to resolve this when using the resource of node
but I'm currently testing out Services 7.x-3.3 on a fresh install of Drupal
without any patch applied.
Using node resource with endpoint/node/[nid]
This works fine, I'm not logged out.
Changed resource. Using now user resource with endpoint/user/[uid]
I get
["Access denied for user anonymous"]
and as I was user-1 I got logged out.Was I approaching this the wrong way?
Comment #74
adnasa CreditAttribution: adnasa commentedComment #75
adnasa CreditAttribution: adnasa commentedSorry about my previous comment, guys
I totally configured my installation wrong.
Comment #76
citricguy CreditAttribution: citricguy commentedWhat did you have to reconfigure to solve this?
Comment #77
citricguy CreditAttribution: citricguy commentedTo followup, when I check the "Session authentication" box at http://bestlocalreviews.com/admin/structure/services/list/ I am no longer forced to log out.
Comment #78
marcingy CreditAttribution: marcingy commented@ygerasimov I have read over this patch a few times and what is there makes sense to me. I wanted to give it a number of visits just because of what this code does.
Comment #79
kylebrowning CreditAttribution: kylebrowning commentedLove it.
Comment #80
mradcliffe#63: services-1240074-presave-session-refactoring.patch queued for re-testing.
Comment #82
mradcliffeRe-roll with new services.runtime.inc location.
Comment #83
marcingy CreditAttribution: marcingy commentedAs its just a re-roll :)
Comment #84
joachim CreditAttribution: joachim commentedAs a follow-up, there's at least one place where this module's tests have had to work around this bug:
Comment #85
ygerasimov CreditAttribution: ygerasimov commentedThank you very much for reroll. I have committed patch #82.