Archive de novembre, 2010

Accéder à Sharepoint avec PHP via SOAP en passant par l’authentification Windows (NTLM)

par Jean-françois JOLY le nov.22, 2010, dans Developpement Web

Alors voilà, j’avais un problème tout simple (enfin il semblait simple) à résoudre : accéder aux données de microsoft sharepoint en utilisant PHP.
Facile me direz vous Sourire : il suffit d’y accéder via SOAP avec un webservice et le tour est joué. C’est exactement l’approche que j’ai utilisé, sauf que voilà, à chaque fois : problème d’authentification.

Je n’ai pourtant pas grand chose d’exceptionnel : Un serveur microsoft sharepoint, relié à active directory en authentification windows classique, du php 5.3 en utilisant le client SOAP natif.
Le code devrait être relativement simple pour se connecter : (le wdsl d’un serveur sharepoint est généralement de la forme http://monserveurmoss/monsite/_vti_bin/Lists.asmx?WSDL)
Ce qui nous donnerait donc dans un monde idéal :

$client = new SoapClient("http://monserveurmoss/monsite/_vti_bin/Lists.asmx?WSDL", 
			array(	'soap_version'   => SOAP_1_2,
				'login'          => "some_name",
				'password'       => "some_password"));
$params = array(
	'listName' =>'{0CD81D15-2793-4C63-BEED-1594788A3030}',
	'viewName'=>'{75B8995C-9148-40AA-924E-991684D20015}';
$rawXMLresponse = $client->GetListItems($params)->GetListItemsResult->any;

Donc là normalement, je devrais me connecter tranquillement à ma liste et la vue associée et récupérer des données sous la forme d’un fichier XML. Sauf que pas du tout … Au lieu de ça j’ai une erreur d’authentification, accès refusé.

Après quelques tests, j’en conclus que ce qui ne marche pas c’est l’authentification windows plus connues sous son petit nom de NTLM Tire la langue. Muni de cette information capitale (NTML), je me relance dans la recherche de solutions …

Et après pas mal de recherches, j’ai fini par trouver une solution qui fonctionne : http://rabaix.net/en/articles/2008/03/13/using-soap-php-with-ntlm-authentication

Comme cette page est sous licence creative commons, je me permets d’en copier le code, car sait on jamais, si la source disparait ce serait bien dommage …

Donc, bien que celà semble surprenant, on dirait que PHP n’implémente pas de base la gestion de l’authentification Windows, se coupant donc de pas mal de webservice sous Windows…

La solution proposée est très sympa car à l’aide de quelques surcharges elle permet d’accéder aux fonctionnalités SOAP natives sans utiliser de solutions ultra compliquées :

Une classe qui permet de surcharger SOAPClient en utilisant CURL :

class NTLMSoapClient extends SoapClient {
	function __doRequest($request, $location, $action, $version) {
		$headers = array(
			'Method: POST',
			'Connection: Keep-Alive',
			'User-Agent: PHP-SOAP-CURL',
			'Content-Type: text/xml; charset=utf-8',
			'SOAPAction: "'.$action.'"',
		);
		$this->__last_request_headers = $headers;
		$ch = curl_init($location);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($ch, CURLOPT_POST, true );
		curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
		curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
		curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
		curl_setopt($ch, CURLOPT_USERPWD, MossParameter::MOSS_USER.':'.MossParameter::MOSS_PASSWORD);
		$response = curl_exec($ch);
		return $response;
	}
	function __getLastRequestHeaders() {
		return implode("\n", $this->__last_request_headers)."\n";
	}
}

 

Une autre classe qui permet de redéfinir un “stream wrapper” :

class NTLMStream {
	private $path;
	private $mode;
	private $options;
	private $opened_path;
	private $buffer;
	private $pos;
	/**
	 * Open the stream 
	 *
	 * @param unknown_type $path
	 * @param unknown_type $mode
	 * @param unknown_type $options
	 * @param unknown_type $opened_path
	 * @return unknown
	 */
	public function stream_open($path, $mode, $options, $opened_path) {
		$this->path = $path;
		$this->mode = $mode;
		$this->options = $options;
		$this->opened_path = $opened_path;
		$this->createBuffer($path);
		return true;
	}
	/**
	 * Close the stream
	 *
	 */
	public function stream_close() {
		curl_close($this->ch);
	}
	/**
	 * Read the stream
	 *
	 * @param int $count number of bytes to read
	 * @return content from pos to count
	 */
	public function stream_read($count) {
		if(strlen($this->buffer) == 0) {
			return false;
		}
		$read = substr($this->buffer,$this->pos, $count);
		$this->pos += $count;
		return $read;
	}
	/**
	 * write the stream
	 *
	 * @param int $count number of bytes to read
	 * @return content from pos to count
	 */
	public function stream_write($data) {
		if(strlen($this->buffer) == 0) {
			return false;
		}
		return true;
	}
	/**
	 *
	 * @return true if eof else false
	 */
	public function stream_eof() {
		if($this->pos > strlen($this->buffer)) {
			return true;
		}
		return false;
	}
	/**
	 * @return int the position of the current read pointer
	 */
	public function stream_tell() {
		return $this->pos;
	}
	/**
	 * Flush stream data
	 */
	public function stream_flush() {
		$this->buffer = null;
		$this->pos = null;
	}
	/**
	 * Stat the file, return only the size of the buffer
	 *
	 * @return array stat information
	 */
	public function stream_stat() {
		$this->createBuffer($this->path);
		$stat = array(
			'size' => strlen($this->buffer),
		);
		return $stat;
	}
	/**
	 * Stat the url, return only the size of the buffer
	 *
	 * @return array stat information
	 */
	public function url_stat($path, $flags) {
		$this->createBuffer($path);
		$stat = array(
			'size' => strlen($this->buffer),
		);
 
		return $stat;
	}
	/**
	 * Create the buffer by requesting the url through cURL
	 *
	 * @param unknown_type $path
	 */
	private function createBuffer($path) {
		if($this->buffer) {
			return;
		}
		$this->ch = curl_init($path);
		curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($this->ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
		curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
		curl_setopt($this->ch, CURLOPT_USERPWD, MossParameter::MOSS_USER.':'.MossParameter::MOSS_PASSWORD);
		$this->buffer = curl_exec($this->ch);
		$this->pos = 0;
	}
}

Bon j’ai juste fait une petite variation par rapport à l’original en utilisant une classe de constante MossParameter, histoire de ne pas dupliquer le paramétrage user/password.

Une fois ces deux classes faites, il suffit d’accéder à sharepoint très facilement de cette manière :

stream_wrapper_unregister('http');
stream_wrapper_register('http', 'NTLMStream') or die("Failed to register protocol");
$client = new NTLMSoapClient("http://monserveurmoss/monsite/_vti_bin/Lists.asmx?WSDL", 
			array(	'soap_version'   => SOAP_1_2));
$params = array(
	'listName' =>'{0CD81D15-2793-4C63-BEED-1594788A3030}',
	'viewName'=>'{75B8995C-9148-40AA-924E-991684D20015}';
$rawXMLresponse = $client->GetListItems($params)->GetListItemsResult->any;
stream_wrapper_restore('http');

 

Et voilà le tour est joué, plus de problème d’authentification SOAP entre PHP et Windows.

Autre petite précision pour ceux qui se demandent comment obtenir les uid des list et des view de sharepoint : il y a un outil très pratique (Stramit SharePoint 2007 Caml Viewer ) que vous trouverez ici : http://www.codeplex.com/wikipage?ProjectName=SPCamlViewer

A la prochaine pour de nouvelle aventure entre php et sharepoint Sourire.

3 Commentaires plus...

Synchroniser, migrer ou “backuper” un serveur SVN de Linux vers Windows

par Jean-françois JOLY le nov.10, 2010, dans Developpement Web

Dans le cadre de mes tests sur l’intégration continue, a un moment j’ai eu besoin de trouver une solution pour dupliquer les données d’un dépôt SVN, tout en conservant l’historique.

Difficulté supplémentaire : le serveur source est sous linux et je n’y connais pas grand chose, le serveur cible pour mes tests est sous Windows (parce que je suis un fan du click click Tire la langue).

1ère étape : Installer SVN sous Windows

Il s’agit de la partie la plus simple, puisque j’ai opté pour la solution de facilité :

VISUALSVN SERVER

http://www.visualsvn.com/

Voilà un petit soft bien sympa qui se propose d’installer SVN ainsi qu’une surcouche graphique pour simplifier l’administration sur les opérations les plus courantes. D’ordinaire installer SVN consiste à installer le serveur SVN, puis généralement apache pour l’accès web, puis créer en ligne de commande les dépôts & Cie. Avec Visual SVN, double click sur l’installeur, suivant, suivant, suivant et bingo. Après il ne reste plus qu’à créer un dépôt avec l’assistant et de la même manière créer un utilisateur. Pas besoin de connaitre la syntaxe ou l’endroit dans lequel doit être mis le fichier qui stocke les mots de passe & Cie.

Maintenant que l’installation est faites, il ne vous reste plus qu’à créer un dépôt (sans structure de base pour la migration). ainsi qu’un utilisateur.

Pour la suite, il peut être intéressant de rajouter le chemin de visualSVN/bin dans le path Windows, afin de pouvoir taper directement des commandes sous DOS si besoin.
Pour cela, rien de plus simple :

image imageimageimage

image

Là, il ne reste plus qu’à redémarrer la session pour prendre en compte ce nouveau chemin et vous êtes prêt pour la phase suivante.

2ème étape : Créer un dépôt synchronisé.

Alors en fait, il existe plusieurs méthodes pour migrer les données de son serveur vers un autre :

  • Faire un dump sur le serveur source puis l’importer sur le serveur de destination  :

    1
    
    svnadmin dump “chemin du repositery a dumper” > “fichier qui contient le dump”
  • Utiliser la HotCopy (Je n’ai pas testé car il parait que ce n’est pas recommandé) :

    svnadmin hotcopy
  • Utiliser la synchronisation (c’est la méthode que je vais utiliser).

Pour moi la méthode la plus simple, la plus pratique et qui peut présenter pas mal d’avantage, c’est la synchronisation. Elle a toutefois un inconvénient : elle est assez lente.

Parmi les avantages : on peut très bien utiliser cette méthode pour effectuer un backup distant synchronisé, ce qui est quand même beaucoup moins barbare que de faire un dump tous les soirs.

Passons à la pratique !

pré requis :

  • L’accès au SVN source (URL + utilisateur autorisé).
  • Un dépôt vide sur le serveur de destination (voir 1ère étape), dans la suite on va considérer que notre projet s’appelle SVN_migration le chemin devrait donc être quelque chose comme : C:\Repositories\SVN_migration.
  • Une console DOS sur le serveur de destination.

Action :

  • Ajouter un fichier vide nommé pre-revprop-change.bat dans le répertoire C:\Repositories\SVN_migration\hock
  • Taper cette commande (sur le serveur de destination) pour initialiser la synchronisation :

    (je pars du principe qu’on se connecte sur un serveur svn via http ou https, mais ça marche aussi avec le protocole svn ou file)

    1
    
    svnsync init file:///C:/Repositories/SVN_migration http://svn.monsite.fr/repository/myproject/

    Remplacer "http://svn.monsite.fr/repository/myproject/" par l’adresse de votre dépôt. Normalement, svn va vous demander les infos de connections, une fois ces infos rentrées.

    Si vous avez correctement ajouté le chemin des binaires SVN, vous pouvez taper la commande n’importe où, sinon il faut se placer dans le répertoire c:\program files\VisualSVN\bin.

    Si vous avez ajouté le fichier bat précédent, vous n’aurez pas d’erreur, autrement il vous signalera que ce fichier est manquant : "svnsync: Repository has not been enabled to accept revision propchanges; ask the administrator to create a pre-revprop-change hook"

    Si tout se passe bien, vous devrier avoir le message : "Copied properties for revision 0."

  • Maintenant que la synchro est initialisée, il n’y a plus qu’à lui dire de se synchroniser complètement :
    1
    
    svnsync sync file:///C:/Repositories/SVN_migration

    Et c’est parti, chaque révision va être synchronisée, vous avez le temps d’aller prendre plusieurs cafés selon la taille du projet et le nombre de branches.

Voilà, vous pouvez bien sur utiliser la même technique pour migrer d’un Windows vers linux ou d’un linux vers linux Tire la langue. Personnellement je trouve cette technique plutôt sympa pour faire des backup sur un un autre serveur au cas ou, puisque une fois la première synchro passée, il n’y a plus qu’à retaper la même commande pour faire des backups réguliers et rapides.

Commentaires fermés :, , , , , plus...

A la recherche de quelque chose ?

Utiliser ce champs pour faire votre recherche :

Vous n'avez pas trouvé votre bonheur ? N'hésitez pas à contacter l'auteur de ce blog ou alors laissez un commentaire sur un post !

Les liens !

Quelques liens intéressants...

Les archives

Tout, classé par ordre chronologique ...