App ausführen

Gespeichert von Erik Wegner am/um

Jetzt endlich kann die Node.JS-Anwendung auf SharePoint zugreifen. Alle genutzten Projektdateien sind auch auf GitHub zu finden: https://github.com/ErikWegner/hightrust-sharepoint-node.js

Der Quelltext der Anwendung

var http = require('http');
var jws = require('jws')
var fs = require('fs');

var options = {
	key: fs.readFileSync('../server.key'),
	cert: fs.readFileSync('../server.crt')
};

function base64urlEscape(str) {
	return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
function base64urlEncode(str) {
	return new Buffer(str).toString('base64');
}

var sharepointhostname = process.argv[2]
var clientid = "927e7578-6a96-4120-be36-495a5bbb989b"
var realm = "5df7ebc5-9401-43fe-93e2-86a07f62c2b2" // equals to SharePoint Farm ID
var issuerid = '2a80398d-800e-44b1-ac67-e34b1207114f' + "@" + realm
var audience = '00000003-0000-0ff1-ce00-000000000000/' + sharepointhostname + '@' + realm
var x5t = "+NgPPAV6+Nm+sqGz/WHYxq1Mp8E" // do not include any "=" at the end
var nameid = "s-1-5-21-1482654976-146172710-446466059-3816" // SID of the acting user
var nii = "urn:office:idp:activedirectory"

var dateref = parseInt((new Date()).getTime() / 1000)
var rs256 = '{"typ":"JWT","alg":"RS256","x5t":"' + x5t + '"}'

var actortoken = {
	aud: audience,
	iss: issuerid,
	nameid : clientid + '@' + realm,
	nbf: (dateref - 21600).toString(),
	exp: (dateref + 21600).toString(),
	trustedfordelegation: true
}

var payload = {
	aud: audience,
	iss: clientid + '@' + realm,
	nbf: (dateref - 21600).toString(),
	exp: (dateref + 21600).toString(),
	nameid: nameid,
	nii: nii,
	actortoken: jws.sign(
		{
			header: JSON.parse(rs256),
			payload: JSON.stringify(actortoken),
			privateKey : options.key
		})
}

var authtoken = base64urlEncode(JSON.stringify({"typ":"JWT", "alg":"none"})) + '.' + base64urlEncode(JSON.stringify(payload)) + '.';
authtoken = authtoken.replace(/=/g, '') // my SharePoint does not accept base64 padding

var headers = {
	'Accept': 'application/json;odata=verbose',
	'Authorization' : 'Bearer ' + authtoken
};
var options = {
	host: sharepointhostname,
	port: 80,
	path: "/sites/hightrustdemo/" + '_api/web/lists',
	method: 'GET',
	headers: headers,
	agent: false,
	ciphers: 'RC4',
	secureOptions: require ('constants').SSL_OP_NO_TLSv1_2
};
var listreq = http.get(options, function(listres) {
	listres.setEncoding('utf8');
	var listdata = "";
	listres.on('data', function(data) {
		listdata += data;
	});
	listres.on('end', function() {
		/* console.log("Response headers");
		console.log(JSON.stringify(listres.headers));
		console.log("Request headers");
		console.log(JSON.stringify(headers));
		console.log("Req fin\n\n");*/
		console.log(listdata);
		listdata = JSON.parse(listdata);
		var lists = [];
		if (listdata.d && listdata.d.results) {
			for (var ri in listdata.d.results) {
				var list = listdata.d.results[ri];
				console.log(list.Title);
			}
		}
	});
}).on('error', function(e) {
	console.log("Error " + e.message);
	console.log(JSON.stringify(e));
});

Folgende Anpassungen sind notwendig:

  1. Zeile 6: Pfad zum privaten Teil des Zertifikats
  2. Zeile 18: Die App-Id
  3. Zeile 19: Die SharePoint-Farm-Id
  4. Zeile 20: Die Herausgeber-Guid aus dem PowerShell-Script (RegisterCertificate.ps1)
  5. Zeile 22: Die x5t-Zeichenfolge für das genutzte Zertifikat
  6. Zeile 23: Die SID des zugreifenden Benutzers
  7. Zeile 63: Der Pfad zur Webseitensammlung

Die Ausführung in der Konsole erfordert zuerst die Installation der notwendigen Node-Pakete. Anschließend wird das Script mit dem gewünschten SharePoint-Servernamen aufgerufen:

npm install
npm index.js sharepointserver

Command line execution

Resultat: Eine Liste von Listen

Kommentare

Permalink

Hallo Erik,

vielen Dank für diese ausführliche Anleitung. Ich versuche gerade eine provider hosted App ohne Aspx und ohne TokenHelper.cs zu entwickeln. Deine Lösung würde mir dabei enorm helfen. Gibt es davon auch eine reine Javascript Version? Ich habe in meiner Entwicklungsumgebung leider keine Node.js und es ist leider auch nicht möglich in dieser Umgebung Node.js zu benutzen.

Würde mich auf eine Rückmeldung sehr freuen (nalizadeh@gmx.net)

Vielen Dank!

lg.

Nader

Permalink

Hallo Nader,

verstehe ich dich richtig, dass du wissen möchtest, ob es eine Variante mit clientseitigem JavaScript gibt? Darauf kann ich ganz klar antworten: Jein :-)

Für die clientseitige Kommunikation (also zwischen Browser und SharePoint) gibt es von Microsoft die bekannten Schnittstellen wie JavaScript Object Model und REST.

Wenn du eine provider-hosted App entwickelst, hast du auch einen Provider (sprich Webserver) im Spiel. Dieser kann dann eine bestimmte Sprache (C#, Java, Ruby, Python, PHP, JavaScript, Perl, etc.). Damit dein Server mit dem SharePoint-Server sprechen kann, benötigt er ein Token, dass du entweder (Cloud) per HTTP-Post-Request erhalten kannst oder tatsächlich über selbstgestrickte JavaScript-Ajax-Aufrufe. (On premise) musst du das Token auf Serverseite selbst erstellen (deshalb ja High trust app). Auf der ersten Seite dieses Tutorials findet sich der Verweis auf diesen Blog-Beitrag, der neben JavaScript auch Implementierungen für Java und PHP anzeigt. Beispielhaft ist hier eine Umsetzung für Drupal zu finden.

Am Ende sei noch der Hinweis gestattet: wenn die provider-hosted App läuft, ist es weiterhin möglich, beim Laden der SharePoint-Seite mit dieser provider-hosted App zu interagieren. Dabei wird der Browser veranlasst, ein Script vom Provider zu laden, das sich um Authentifizierung und ggfs. Benutzerschnittstelle (also Anzeige, Schaltflächen, etc.) kümmert. Damit ist für den Benutzer komplett transparent, dass sein Browser sich an der App anmeldet und die Serverseite der App kann mit dem SharePoint Daten austauschen.

Permalink

Hallo Erik

vielen Dank für deine Antwort.

Das bedeuted für High trust Apps das AccessToken kann nur auf dem Server erstellt werden (zb. auf dem Provider)

Aber wie macht denn die Cross-domain Libraries von SharePoint? oder wird dort ebenfalls ein serverseitiger Service aufgerufen?

Mein Problem ist, ich habe kein AppWeb, aber für Cross-domain Libraries brauche ich unbedingt AppWeb. Erstellung von AppWeb durch SharePoint Artefakt wäre zwar möglich aber nicht im Sinne des Erfinders.

Permalink

Der Artikel Nahtlose Provider-hosted-App zeigt, wie eine Integration einer Low-Trust-App ablaufen kann. In Kombination mit dem Wissen für die High-Trust-App lassen sich die Aufrufe so ändern, dass eventuell dein Szenario erreicht wird.

Von den Cross-Domain-Libraries kenne ich gerade nur den clientseitigen Teil, der mit den bereits verlinkten JSOM- und REST-Aufrufen arbeitet.