Welcome Guest, Not a member yet? Register   Sign In
HTTP header-based login?
#1

[eluser]Phil Sturgeon[/eluser]
Anyone have experience with forcing login's through HTTP headers (either Basic or Digest)?

I have got Basic working through the browser but cannot get it working through cURL.

I cannot get Digest working at all.

If anyone can post examples of working Digest auth code within CodeIgniter, and perhaps the accompanying cURL login code that would be freakin marvellous.

This is one little bit I'm stuck on before I can finish off and wrap up all the REST work I have been doing with CodeIgniter.
#2

[eluser]Yorick Peterse[/eluser]
I've been looking at Basic, Digest and OAuth. It seems that OAuth is the best you can get, but there's almost no information on how to implement it.

I've tried Digest auth as well, but for some reason it wasn't working as well (probably my fault). Currently my basic, and useless authentication (as it doesn't checks if the username and password combination is correct) looks as the following :

Code:
<php
// Basic authentication, for now
    if(!isset($_SERVER['PHP_AUTH_USER'])) {
        // Send the headers
        header('WWW-Authenticate: Basic realm="Flork API"');
        header('HTTP/1.0 401 Unauthorized');
        
        // Send the reponse in case the user hit cancel
        $this->sendResponse('401','','text/html');
        exit;
    }
    else {
        // Call the function
        $data = $this->model_api->getData($table,$field,$value,$format);
        echo $data;
    }
?&gt;
#3

[eluser]Phil Sturgeon[/eluser]
See the problem im getting is that PHP_AUTH_USER is never set when run over cURL even when using the suggest params.

Basic jut about works over a normal request but not over cURL. Digest doesnt work for shit. This is using the examples found in the php.net manual. Yay...

Also, I dont really think OAuth can be compared here as its really not the same as Basic and Digest. They are HTTP standard protocols, OAuth is something totally different.
#4

[eluser]Yorick Peterse[/eluser]
[quote author="Phil Sturgeon" date="1244511891"]
Also, I dont really think OAuth can be compared here as its really not the same as Basic and Digest. They are HTTP standard protocols, OAuth is something totally different.[/quote]

Yes it's different, but it's a way of authorizing the connection Wink
#5

[eluser]Phil Sturgeon[/eluser]
Anyhow, this one is still ongoing. How in the heck do I get a Digest system A) working on normal browsing request and B) working over curl.

The API contains this code in a controller method (as a test for now).

Code:
function basicauth_get()
    {
        $username = null;
        $password = null;
        
        // mod_php
        if (isset($_SERVER['PHP_AUTH_USER']))
        {
            $username = $_SERVER['PHP_AUTH_USER'];
            $password = $_SERVER['PHP_AUTH_PW'];
        }
        
        // most other servers
        elseif (isset($_SERVER['HTTP_AUTHENTICATION']))
        {
            if (strpos(strtolower($_SERVER['HTTP_AUTHENTICATION']),'basic')===0)
                list($username,$password) = explode(':',base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
        }
        
        if (is_null($username))
        {
            header('WWW-Authenticate: Basic realm="My Realm"');
            header('HTTP/1.1 401 Unauthorized');
            echo 'Text to send if user hits Cancel button';
            return;
            
        }
        
        else
        {
            echo "<p>Hello {$username}.</p>";
            echo "<p>You entered {$password} as your password.</p>";
        }
        
    }

If I access this over cURL using the following code then it works fine (for basic).

Code:
function auth_test()
    {
          $responce = $this->curl->simple_get('http://USER:PASS@localhost/codeigniter/index.php/example_api/basicauth');
        
        echo $this->curl->debug();
    }

However if I try to use the proper login method then it fails with a 401.

Code:
function auth_test()
    {
          $this->curl->http_login('USER', 'PASS', 'basic');
        $responce = $this->curl->simple_get('http://localhost/codeigniter/index.php/example_api/basicauth');
        
        echo $this->curl->debug();
    }

The $this->curl->http_login() function is...

Code:
public function http_login($username = '', $password = '', $type = 'any')
    {
        $this->option(CURLOPT_HTTPAUTH, constant('CURLAUTH_'.strtoupper($type) ));
        $this->option(CURLOPT_USERPWD, $username.':'.$password);
        return $this;
    }

This will default to using CURLAUTH_ANY which supports basic, digest and several other crazy types, or it can be passes a specific type. This SHOULD work fine according to PHP examples, but just doesn't seem to... Erf.
#6

[eluser]Yorick Peterse[/eluser]
[quote author="Phil Sturgeon" date="1244556643"]

The $this->curl->http_login() function is...

Code:
public function http_login($username = '', $password = '', $type = 'any')
    {
        $this->option(CURLOPT_HTTPAUTH, constant('CURLAUTH_'.strtoupper($type) ));
        $this->option(CURLOPT_USERPWD, $username.':'.$password);
        return $this;
    }

[/quote]

Does the following work ? I don't think it makes a difference but it's worth a try :

Code:
$this->option(CURLOPT_USERPWD, "$username:$password");

The only other thing I can think of is that it might be a bug related to your cURL wrapper for CI, try using regular curl, perhaps that will work.
#7

[eluser]Phil Sturgeon[/eluser]
Yeah I went down that road in the end and seemed to get it working using basic cURL and then finally with my cURL wrapper.

Code:
function auth_test()
    {
     $location="http://localhost/codeigniter/index.php/example_api/basicauth";
     $username = 'USER';
     $password = 'PASSWORD2';
        
         if(TRUE)
          {
              //$this->curl->http_login('USER', 'PASS');
              
              $this->curl->create($location);
              $this->curl->option(CURLOPT_RETURNTRANSFER,1);
              $this->curl->option(CURLOPT_USERPWD,"$username:$password");
            $responce = $this->curl->execute($location);
            
            echo $this->curl->debug();
          }
        
        else
        {
        
          $ch = curl_init ();
          curl_setopt($ch,CURLOPT_URL,$location);
          curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
          curl_setopt($ch,CURLOPT_USERPWD,"$username:$password");
        
          $result = curl_exec ($ch);
          print $result;
          curl_close($ch);
        }
    }

Both methods there seem to work fine for Basic auth so far.

Not entirely sure what the bloody difference was between create, option, execute and simple_get as they do the same damn thing!

I will get this working if it kills me... which it might.
#8

[eluser]Phil Sturgeon[/eluser]
DUMBASS!

simple_get() runs create() first, which was wiping out the options set with http_login. FFS I have spent hours on this... :red:
#9

[eluser]Phil Sturgeon[/eluser]
Implementing basic and auth into REST_Controller now. :-)
#10

[eluser]Phil Sturgeon[/eluser]
Ok so Basic auth now integrates with the REST_controller perfectly via a config file where you set realm, logins and authentication type.

However, the Digest is being a little more tricky. Keeps asking for password over and over. Anyone got any ideas?

From REST_Controller.php

Code:
// SECURITY FUNCTIONS ---------------------------------------------------------
    
    private function _checkLogin($username = '', $password = NULL)
    {
        if(empty($username))
        {
            return FALSE;
        }
        
        $valid_logins =& $this->config->item('rest_valid_logins');
        
        if(!array_key_exists($username, $valid_logins))
        {
            return FALSE;
        }
        
        // If actually NULL (not empty string) then do not check it
        if($password !== NULL)
        {
            if($valid_logins[$username] != $password)
            {
                return FALSE;
            }
        }
        
        return TRUE;
    }
    
    private function _prepareBasicAuth()
    {
        $username = NULL;
        $password = NULL;
        
        // mod_php
        if (isset($_SERVER['PHP_AUTH_USER']))
        {
            $username = $_SERVER['PHP_AUTH_USER'];
            $password = $_SERVER['PHP_AUTH_PW'];
        }
        
        // most other servers
        elseif (isset($_SERVER['HTTP_AUTHENTICATION']))
        {
            if (strpos(strtolower($_SERVER['HTTP_AUTHENTICATION']),'basic')===0)
            {
                list($username,$password) = explode(':',base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
            }  
        }
        
        if ( !$this->_checkLogin($username, $password) )
        {
            $this->_forceLogin();
        }
        
    }
    
    private function _prepareDigestAuth()
    {
        $digest = NULL;
        
        // mod_php
        if (isset($_SERVER['PHP_AUTH_DIGEST']))
        {
            $digest = $_SERVER['PHP_AUTH_DIGEST'];
        }
        
         // most other servers
        elseif (isset($_SERVER['HTTP_AUTHENTICATION']))
        {
            if (strpos(strtolower($_SERVER['HTTP_AUTHENTICATION']),'digest')===0)
            {
                $digest = substr($_SERVER['HTTP_AUTHORIZATION'], 7);
            }
        }
        
        // If there was no digest, show login
        if (empty($digest))
        {
            $this->_forceLogin();
        }
        
        preg_match_all('@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', $digest, $matches, PREG_SET_ORDER);
        
        $digest_parts = array();
        foreach($matches as $match)
        {
            $digest_parts[$match[1]] = $match[2];
        }
        unset($matches);
        
        if ( !$this->_checkLogin($digest_parts['username']) )
        {
            $this->_forceLogin();
        }
        
        $valid_logins =& $this->config->item('rest_valid_logins');
        $valid_pass = $valid_logins[$digest_parts['username']];
        
        // Based on all the info we gathered we can figure out what the response should be
        $A1 = md5(sprintf("%:%:%", $digest_parts['username'], $this->config->item('rest_realm'), $valid_pass));
        $A2 = md5(sprintf("%:%", $this->method, $digest_parts['uri']));
        
        $validResponse = md5(sprintf("%:%:%:%:%:%", $A1, $digest_parts['nonce'], $digest_parts['nc'], $digest_parts['cnonce'], $digest_parts['qop'], $A2));
        
        if ($digest_parts['response']!=$validResponse)
        {
            $this->_forceLogin();
        }

    }
    
    private function _forceLogin()
    {
        if($this->config->item('rest_login') == 'basic')
        {
            header('WWW-Authenticate: Basic realm="'.$this->config->item('rest_realm').'"');
        }
        
        elseif($this->config->item('rest_login') == 'digest')
        {
            header('WWW-Authenticate: Digest realm="' . $this->config->item('rest_realm') . '",qop="auth",nonce="' . uniqid() . '",opaque="' . md5($this->config->item('rest_realm')) . '"');
        }
        
        header('HTTP/1.0 401 Unauthorized');
        echo 'Text to send if user hits Cancel button';
        die();
    }


config/rest.php
Code:
&lt;?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/*
|--------------------------------------------------------------------------
| REST Login
|--------------------------------------------------------------------------
|
| Is login required and if so, which type of login?
|
|    '' = no login required, 'basic' = unsecure login, 'digest' = more secure login
|
*/
$config['rest_login'] = 'digest';

/*
|--------------------------------------------------------------------------
| REST Realm
|--------------------------------------------------------------------------
|
| Name for the password protected REST API displayed on login dialogs
|
|    E.g: My Secret REST API
|
*/
$config['rest_realm'] = 'REST API';

/*
|--------------------------------------------------------------------------
| REST Login usernames
|--------------------------------------------------------------------------
|
| Is login required
|
|    '' = no login required, 'basic' = unsecure login, 'digest' = more secure login
|
*/
$config['rest_valid_logins'] = array('user' => 'password');


/* End of file config.php */
/* Location: ./system/application/config/rest.php */




Theme © iAndrew 2016 - Forum software by © MyBB