diff --git a/authentication.php b/authentication.php new file mode 100644 index 0000000..a7398ec --- /dev/null +++ b/authentication.php @@ -0,0 +1,293 @@ + */ + +require_once ("domframework/auth.php"); +require_once ("domframework/authparams.php"); +require_once ("domframework/authsession.php"); +require_once ("domframework/ratelimit.php"); +require_once ("domframework/ratelimitfile.php"); + +/** All the authentication protocol */ +class authentication +{ + /** The email of the authenticated/nonauthenticated user */ + //private $email = "anonymous"; + + /** The debug of the authentication methods */ + public $debug = 0; + + /** The route object */ + private $route; + + /** Number of authentication maximum by minute */ + public $ratelimitAuth = 3; + /** Directory to store the ratelimit files */ + public $ratelimitDir = "/tmp"; + + /** The rest authentication methods. Can be http, session, post. + Attention : session case = CSRF ! */ + public $restMethods = array ("http"); + /** The html authentication methods. Can be http, session, post */ + public $htmlMethods = array ("session"); + /** The authentication methods. Can be ldap, sympa...*/ + public $authMethods = array (); + /** The authentication servers configuration + array ("authXXXX"=>array ( + array ("ldapserver"=>"ldaps://annuaire.grenoble.cnrs.fr", + "ldapport"=>636, + "ldaptimeout"=>5, + "ldapauth"=>"uid=annuaire,ou=people,dc=grenoble,dc=cnrs,dc=fr", + "ldappwd"=>";authANNUAIRE2013", + "ldapbase"=>"", + "ldapfilter"=>"(mail=%s)", + "ldapfield"=>"mail", + "ldapfiltersearch"=>"(objectClass=inetOrgPerson)" + ), + ), + );*/ + public $authServers = array (); + + public function __construct ($route) + { + $this->route = $route; + } + +/* public function email () + { + return $this->email; + }*/ + + /** Disconnect the user */ + public function logout () + { + if ($this->debug) echo "
LOGOUT\n";
+    $authsession = new authsession ();
+    $param = $authsession->getdetails ();
+    if ($this->debug) echo "Logout for '".$param["email"]."'\n";
+    trigger_error ("Logout for '".$param["email"]."'", E_USER_NOTICE);
+    $authsession->logout ();
+    unset ($_SESSION["domframework"]["authentication"]);
+    $_SESSION["domframework"]["authentication"]["message"] =
+       _("You have been logged out");
+    if ($this->debug) echo "Redirect to authentication page";
+    if ($this->debug) $this->route->debug = $this->debug;
+    $this->route->redirect ("/authentication", "");
+  }
+
+  /** Display the login page */
+  public function pageHTML ($url = "")
+  {
+    // If the user is already connected, redirect to the main page of the site
+    $auth = new auth ();
+    $pre = new authparams (array ("session"));
+    if (isset ($_SESSION["domframework"]["authentication"]["message"]))
+      $message = $_SESSION["domframework"]["authentication"]["message"];
+    else
+      $message = "";
+    unset ($_SESSION["domframework"]["authentication"]["message"]);
+    $alreadyAuth = false;
+    if ($pre->email !== "anonymous")
+      $alreadyAuth = $pre->email;
+    echo $auth->pageHTML ($this->route->baseURL(), $message, $url,
+                          $alreadyAuth);
+  }
+
+  /** Check the authentication page */
+  public function verifAuthLoginPage ($url = "")
+  {
+    // rate-limit the connections
+    $ratelimiter = new ratelimitfile ();
+    // 3 connections by minutes
+    $ratelimiter->maxEntries = $this->ratelimitAuth;
+    $ratelimiter->storageDir = $this->ratelimitDir;
+    if (isset ($_SERVER["HTTP_X_FORWARDED_FOR"]))
+      $ipClient = $_SERVER["HTTP_X_FORWARDED_FOR"];
+    else
+      $ipClient = $_SERVER["REMOTE_ADDR"];
+    if ($ratelimiter->set ("loggin-$ipClient") === false)
+    {
+      trigger_error ("Ratelimiting for $ipClient", E_USER_WARNING);
+      $_SESSION["domframework"]["authentication"]["message"] =
+        _("Too much connections");
+      if ($url === "")
+      {
+        $this->route->redirect ("/authentication", "");
+      }
+      else
+      {
+        $this->route->redirect ("/authentication/$url", "");
+      }
+    }
+    $authparams = new authparams (array ("post"));
+    $res = $this->verifAuth ($authparams->email, $authparams->password);
+    if (! is_array ($res))
+    {
+      // Authentication error
+      // Redirect to login page after logout
+      trigger_error ("Logging error for '$authparams->email' (HTML) : $res",
+                     E_USER_WARNING);
+      $authsession = new authsession ();
+      $authsession->logout ();
+      $baseURL = $this->route->baseURL ();
+      $_SESSION["domframework"]["authentication"]["message"] = $res;
+      // Check the provided URL before using it
+      if ($url === "")
+      {
+        $this->route->redirect ("/authentication", "");
+      }
+      else
+      {
+        $this->route->redirect ("/authentication/$url", "");
+      }
+    }
+    // Login OK : save in SESSION and go to main page
+    trigger_error ("Logging in for '$authparams->email'", E_USER_NOTICE);
+    $session = new authsession ();
+    $session-> savedatas ($authparams->email, $authparams->password,
+                          $res["lastname"], $res["firstname"]);
+    if ($url === "")
+      $this->route->redirect ("/", "");
+    else
+      $this->route->redirect ("/$url", "");
+  }
+
+  /** Check all the REST API */
+  public function verifAuthREST ()
+  {
+    $authparams = new authparams ($this->restMethods);
+    $res = array ("email"=>"anonymous", "password"=>"anonymous");
+    if ($authparams->email !== "anonymous" &&
+        $authparams->password !== "anonymous")
+    {
+      if ($this->debug)
+        echo "verifAuth ($authparams->email, $authparams->password)\n";
+      $res = $this->verifAuth ($authparams->email, $authparams->password);
+    }
+    if (! is_array ($res))
+    {
+      trigger_error ("Logging error for '$authparams->email' (REST) : $res",
+                     E_USER_WARNING);
+      // Authentication error
+      // TODO : header 401 ? Block previously in the framework auth process
+      exit;
+    }
+    return $res;
+  }
+
+  /** Check all the others pages of the site */
+  public function verifAuthHTML ()
+  {
+    if ($this->debug) echo "verifAuthHTML() : ";
+    $authparams = new authparams ($this->htmlMethods);
+    // Don't ask to the provider if anonymous is known
+    if ($authparams->email === "anonymous" || $authparams->email === null)
+    {
+      if ($this->debug) echo "Anonymous\n";
+      return array ("email"=>"anonymous", "lastname"=>"Anonymous",
+                    "firstname"=>"", "password"=>"");
+    }
+    if ($this->debug)
+      echo "verifAuth ($authparams->email, $authparams->password)\n";
+    $res = $this->verifAuth ($authparams->email, $authparams->password);
+    if (! is_array ($res))
+    {
+      // Authentication error
+      if ($this->debug) echo "Previous session not found";
+      $msg = _("Previous session not found");
+      $_SESSION["domframework"]["authentication"]["message"] = $msg;
+      trigger_error ("Previous session not found for '$authparams->email'",
+                     E_USER_WARNING);
+      $url = $this->route->requestURL();
+      $this->route->redirect ("/authentication/$url");
+    }
+    return $res;
+  }
+
+  /** Do the real authentication process on all the providers defined in the
+      properties of the class.
+      @return an array containing the user datas if the authentication is
+              correct,
+              an exception if noting is found */
+  private function verifAuth ($email, $password)
+  {
+    if (isset ($_SESSION["domframework"]["authentication"]["lastcheck"]) &&
+        $_SESSION["domframework"]["authentication"]["lastcheck"] + 180 <
+          time ())
+    {
+      // Test the authentication each 3 minutes if there is a session, else
+      // return the previous values
+      return $_SESSION["domframework"]["authentication"]["authcache"];
+    }
+    
+    foreach ($this->authMethods as $method)
+    {
+      $classname = "auth$method";
+      require_once ("domframework/$classname.php");
+
+      // If only one server is defined, the parameters can directely be pushed
+      // to the classname
+      if (! is_array ($this->authServers[$classname]))
+      {
+        $this->authServers[$classname] = array ($this->authServers[$classname]);
+      }
+      foreach ($this->authServers[$classname] as $key=>$serversParam)
+      {
+        if ($this->debug)
+          echo "Test auth server $method # $classname # $key\n";
+        $authmethod = new $classname ();
+        foreach ($serversParam as $param=>$value)
+        {
+          $authmethod->$param = $value;
+        }
+        $authmethod->connect ();
+        try
+        {
+          $authmethod->authentication ($email, $password);
+          $_SESSION["domframework"]["authentication"]["authcache"] =
+            $authmethod->getdetails ();
+          $_SESSION["domframework"]["authentication"]["lastcheck"] = time ();
+          return $authmethod->getdetails ();
+        }
+        catch (Exception $e)
+        {
+          trigger_error ("Authentication error for '$email' : ".
+                        "$classname : ".$e->getMessage(), E_USER_WARNING);
+        }
+      }
+    }
+    trigger_error ("Bad login/password for '$email'", E_USER_WARNING);
+    return _("Bad login/password");
+  }
+
+  /** Add the authentication routes to the routing model */
+  public function routes ()
+  {
+    $authObj = $this;
+    $this->route->get ("authentication/logout", function () use ($authObj)
+    {
+      $authObj->logout ();
+    });
+
+    $this->route->get ("authentication/{url}", function ($url) use ($authObj)
+    {
+      $authObj->pageHTML ($url);
+    });
+
+    $this->route->post ("authentication/{url}", function ($url) use ($authObj)
+    {
+      $authObj->verifAuthLoginPage ($url);
+    });
+
+    $this->route->get ("authentication", function () use ($authObj)
+    {
+      $authObj->pageHTML ();
+    });
+
+    $this->route->post ("authentication", function () use ($authObj)
+    {
+      $authObj->verifAuthLoginPage ();
+    });
+  }
+}