views:

1001

answers:

4

Hello DJango warriors !

I am building a small app as a service in django and now is the time to integrate it on some clients PHP web app.

Our client A from domain www.a.com handles his own authentication for his users and probably use cookies for sessions.

How could i make logged in users from his domain also logged in on my Django app dommain www.b.com/clientA/ ?

I see how i can make them reloggin on my domain and use an authbackend checking credential with domain A but that means the user will have to enter his login/pass twice: on www.a.com and www.b.com.

Accessing cookie from domain www.a.com is impossible for security reasons i think.

How would you handle this ?

+4  A: 

You are correct in assuming cookies from another domain cannot be accessed. However, if it's on a subdomain, you should be able to access the cookies if they're set correctly.

If you absolutely must have them on completely separate domains, it's going to be a bit tricky. If you can't modify the existing PHP code, you can pretty much forget it.

One option would be using OpenID - that may be the simplest way to tackle this, as there are OpenID libraries available for PHP and Python. OpenID would allow you to have a single-sign on like authentiction, and since it's already used on various sites it is proven and works.

Another option is writing a custom single sign-on system.

The basic idea is that when a user arrives at your site, you direct them to a login site. This can be either in the PHP or Python end of things, or separate. Here, the user will sign in, and then the login generates a secret key - this can be a hash, random string, whatever as long as it's not predictable - and the user is redirected back to the main site with the key.

The main site then sees the user has a key, and sends a request to the login site behind the scenes to verify the user's key.

Now the user is logged in at one site. When the user visits the second site, it too redirects the user to the login site. Since the user had already logged in, the login site simply redirects the user back with a new secret key, and the second site verifies it from the login site and now the user is logged in without having to input their credentials another time.

Jani Hartikainen
Most of the client already have their auth schema and won't use openid it's too alien to them. I like you last solution with a third central login site except it requires maybe too much change on the client unless i provide the PHP code for it.
coulix
You can utilize the client's existing PHP auth for the second option. You'll just need to modify it so it can generate the secret and talk to the other site.
Jani Hartikainen
One small question i am not sure about. When the Login Page gives me a secret key i pass it to my page of origin as a GET var. Now i do request with Ajax maybe to the logging page domain asking could you check this key ?. It will answer yes its valid then what ? How do i log the user on my domain ?
coulix
Maybe by making the Login server return the username and the key when the key is valid ?
coulix
Don't do it with Ajax. It needs to be done server-side for it to be safer and reliable. And yes, you can return any data you wish - probably the user's ID or something you can identify them by is a good idea.
Jani Hartikainen
Server side with a https ? but how can i make sure no one can forge a fake acceptation sending random ids ?
coulix
Got it sorry, Thanks ! its server to server, nothing to do with Ajax and client.
coulix
A: 

You can use HTTP redirects back and forth. When the user accesses www.b.com, and no cookie is set, redirect to www.a.com/crosslogin?return_to=URL&challenge=stuff. On a.com, check for the cookie, and if it is set, redirecto to URL?verified=otherstuff.

This would require challenge-response cryptography if you want users to prevent from faking authentication. a.com and b.com would need to setup a shared secret, and stuff is encrypted with that secret. otherstuff is also encrypted with that secret; when decrypted, it gives a tuple (stuff, user). b.com may need to keep a replay cache to make sure that otherstuff can be used only once.

Martin v. Löwis
A: 

I see the following options:

1) Use Open ID as Jani Hartkainen suggested. It could be the best solution.

2) Use one domain via http reverse proxy:

Use reverse http proxy to put both php application and your django application on the same domain. This would give you access to the sessions cookies of your php app.

Once you get the php session id in your django application run a request to the PHP application with the session cookie set to check who is logged in. Unfortunately this may require html scraping or implementing a simple service in PHP application that would return a name of the logged in user. Once you get the logged in user you can authorize it in your django app.

3) PHP session id passed via GET:

Modify the PHP app to add session id as a parameter to links to your django app. For example ask clients to refer to your web site as follows:

<yourwebsite.com>/?client_session_id=<session_id>&client_name=<client_name>

Once you get the session id you can authenticate user as described in point 2.

Piotr Czapla
+1  A: 

Ok, this is how to authenticate a Django user from PHP, or how to "read" a Django password from PHP.

I think OpenID is the best solution but I had to authenticate Django users in a PHP app sharing the same database today and this is how I solved:

<?php

/* Generates crypted hash the same way as Django does */
function get_hexdigest($algorithm, $salt, $raw_password) {
   if (!array_in($algorithm, array('md5', 'sha1'))) {
       return false;
   }
   return $algorithm($salt.$raw_password);
}

/* Checks if password matches the same way Django does */
function check_password($raw_password, $django_password) {
    list($algorithm, $salt, $hsh) = explode('$', $django_password);
    return get_hexdigest($algoritm, $salt, $raw_password) === $hsh;
}

?>

The key is to understand the format in which Django saves the passwords, which is:

[algorithm]$[salt]$[hash]

So for example I had an "admin" user with password "admin" and the password field in the auth_user row was:

sha1$63a11$85a93f217a72212b23fb0d5b95f3856db9575c1a

The algorithm is "sha1", the salt, which was generated randomly is "63a11" and the crypted hash is "85a93f217a72212b23fb0d5b95f3856db9575c1a".

So who do you produce the crypted hash in PHP? You simple concatenate the salt and the raw password and hash it with the algorithm, in this case, sha1:

<?php 

$salt = '63a11';
$pass = 'admin';

echo sha1($salt.$admin); // prints "85a93f217a72212b23fb0d5b95f3856db9575c1a"

?>

That wasn't difficult! I got it by reading the relevant code in the Django sources.

gnrfan