How does a service app create a session?

cspwcspw's picture

In Drupal 5: My C# application can access my drupal service al. la. Rob's great video. I turn on the session ids for the service, and call the system.connect service to get a sessionID, which I then pass around as the extra parameter in each of my service calls. I authenticate my user, but cannot persist the session state...

I added authentication to my client, and used the user.login service successfully. This returns a user structure. I'd optimistically hoped that the fact that I was passing a session id around and had authenticated would mean that I had a session with an authenticated user that would persist across calls to my services...

In fact, the service runs as an anonymous user every time. I've hacked around trying various things (ensuring my client has a cookie-container in its html, putting the session id into the cookie, etc. and have not yet managed to preserve a session between the initial call to system.connect and the subsequent calls to my methods.

a) When I authenticate successfully, (on the server side) do I have to store the user in the $_SESSION?
b) When another service method is called, what php magic gets back my session and sets my user up correctly?
c) Can I turn off the sessid feature on services, and somehow just use a cookie? (I'm naive enough not to know if it is the client that creates the cookie, or the server that creates the cookie and somehow pushes it back to the client!)

Any suggestions about where to look (I feel like a need quite small slow steps at this stage!) will be most appreciated!

peter

Comments

This is how I got it to work...

cspwcspw's picture

To answer my own questions above. a) NO, it looks after itself, b) every service method must begin with session_start() if you need the session info, user, rights, etc; c) If cookies work you can turn off sessid - let the cookie mechanism keep the id. It also works if it is turned on, but 'off' leads to cleaner code.

Unfortunately, your client has to enable cookies. There appears to be some bad code (a bot-avoidance feature, perhaps a bug around line 80 of session.inc) where the drupal core refuses to persist sessions unless cookies are enabled. This is service unfriendly, and renders the "manage-your-own-sessid" features of the services a bit meaningless in Drupal 5.

The default for the xmlrpc.NET library is to provide a cookie container, but the trick is to populate it properly! When you first issue a system.connect, the HttpResponse returns a Set-Cookie header that your client has to honour. Unfortunately, I can find no hooks in the xmlrpc library to intercept this, and the xmlrpc library itself doesn't honour the request. So I had to hack the library to create a new callback with the raw HttpResponse. Now my client can intercept responses from the server, inspect the headers, and honour the Set-Cookie request if it finds one. (By building a suitable cookie from what was requested, and assigning it to your client's xmlrpc proxy cookie container.)

And then it worked ...

Please help - sessid without cookies?

raspberryman-gdo's picture

Phew, this can get confusing!

I looked at other APIs around the neighborhood, and didn't find any that were reliant on a sessid sent via cookies.

Is there a way to use sessid without needing cookies?

I have a Facebook developer building an app right now, and he is running into lots of problems because of this.

Any insights would be greatly appreciated.

Call system.connect

redben's picture

Edit : Oops ! i read your comment but not the first post, which says it all !

Hi,
I'm using flex and here is what i did to make sessid's work for me :
If you want to start a session and get the session id, you should first call the system service's connect method. It will return a sessid wichi you can store and use for your next calls. I think it is the only method which does not require a sessid (abviously)

Newer XML-RPC.NET library makes this much easier ...

cspwcspw's picture

The new version of the CookComputing XML-RPC.NET package adds two properties that allow you to get at the most recent response headers, and the cookies in the response. So now my previous session workaround becomes trivial, and there is no need to hack into the libraries. I still had one small niggle: that the domain in the cookie was prefixed by a period, which I had to strip off to get things to work:

My few lines of code now look like this (without extra error handling wrapping) ...

                    proxy.login(user, pass);                
                    Cookie ck = cookies[0];
                    if (ck.Domain.StartsWith("."))   ck.Domain = ck.Domain.Substring(1);
                    proxy.CookieContainer.Add(ck);

and I now have a persistent session!

Thanks to Chares Cook for the upgrade to the XML-RPC.NET libraries.

Solution without cookies handling

bricel's picture

here is my solution, using only session IDs (no cookies manipulation required), note that after Login a new session ID is assign, this session ID is the one to use for all the Methods activated afterward.

[XmlRpcMissingMapping(MappingAction.Ignore)]
    public struct DrupalUser
    {
        // Fields
        public string name;
        public string email;
    }
public struct Drupal //Struct defining information to receive from connect and login methods
    {
        public string sessid;
        public DrupalUser user;
    }
public struct Story //struct for node of Story type
    {
        public string title;
        public string name;
    }
[XmlRpcUrl("http://YourDomain/services/xmlrpc")] // Change this if you are not using Clean URL's!
    public interface IServiceSystem : IXmlRpcProxy
    {
        [XmlRpcMethod("system.connect")]
        Drupal Connect();

        [XmlRpcMethod("user.login")]
        Drupal Login(string sessid, string username, string password);
       
        [XmlRpcMethod("node.get")]
        Story NodeGet(string sessid, int nid, object fields);//define the node type I wanna receive
  }
---------------------------------------------------------------------------------------------------------
public connectToSerives()
        {
                IServiceSystem iss = XmlRpcProxyGen.Create<IServiceSystem>();
                Drupal cnct = iss.Connect();  //Connecting - getting first Session ID to use for login
                Drupal lgn = iss.Login(cnct.sessid, "user", "password"); //Getting Second Session to use with Methods

                //get node example
                Object ob = new object();
                Story str = iss.NodeGet(lgn.sessid, 1, ob); //using the Session ID received after the Login Method
        }