Product DocsMenu

Wiki Late


This C# project represents the API that allows the users to access documents contained in WikiLate. The connector (security provider and connector) uses this API. This API is the same as WikiEarlyAPI, except that the classes WikiGroup and WikiUser are not used. This API is made up of three classes:

WikiSession Class
This class is the entry-point of the API.  To access the documents, it is important to first login. The constructor of this class receives a username and password. If the login information entered is not valid, the constructor throws an exception. Once successfully authenticated, methods in this class can be called to access the documents.
WikiDocument Class
This class represents a Wiki document.
WikiDocAttachment Class
This class represents an attachment to a Wiki document.Term1


As for the WikiEarly class, it contains the crawling logic. In this section, we focus only on the differences.  All the explanations are not repeated here (see Wiki Early).

The PerformInitialize() and Update() methods are identical.

In the Run() method, there is only one difference: the two calls to AddACLs() are absent because in late-binding, ACLs are not added to the documents during crawling. The rights to access a document are checked at query-time. That is the purpose of the Authorize() method in SecurityProvider.cs.

WikiLateCrawler.Crawler.Run() Method:

protected override void Run()
  Context.LogCrawlerMessage("Crawling WikiLate documents...");

  // Validate the value of the parameter 'Uri'.
  string uriParam = Context.GetConfigValue(URI_PARAM_NAME);
  int markerPos = uriParam.IndexOf(PATHNAME_MARKER_IN_URI);
  if (markerPos == -1 || uriParam.IndexOf(PATHNAME_MARKER_IN_URI, markerPos + 1) != -1) {
     throw new Exception(INVALID_URI_PARAM);

  // Index the documents.
  WikiSession wikiSession = new WikiSession(m_Repository, Context.UserName, Context.UserPassword);
  foreach (WikiDocument wikiDoc in wikiSession.ListDocuments()) {
   using (Document document = new Document(Context)) {
     try {
       // Fill the document's info.
       document.Uri = Context.GetConfigValue(URI_PARAM_NAME).Replace(PATHNAME_MARKER_IN_URI, wikiDoc.PathName);
       document.Data = wikiDoc.Content;

       // Transfer the document's attachments.
       foreach (WikiDocAttachment attachment in wikiDoc.DocAttachments) {
         Document attachmentDoc = new Document(Context);
         try {
           attachmentDoc.Uri = Context.GetConfigValue(URI_PARAM_NAME).Replace(PATHNAME_MARKER_IN_URI, attachment.PathName);
           attachmentDoc.Data = attachment.Content;
           attachmentDoc = null;
         } finally {
           if (attachmentDoc != null) {
             attachmentDoc = null;

       // Give the document to the indexer.
   } catch (ThreadAbortException) {
     // Let go.
   } catch (Exception e) {
     Context.LogCrawlerErrorMessage(e.Message, document.Uri);


As for the WikiEarly class, it contains the security logic. This section only focuses on the differences. All the explanations are not repeated here (see Wiki Early).

The Initialize() method creates a new instance of Repository, the class that contains the code shared by WikiEarly and WikiLate. The path to the repository is obtained by calling GetConfigValue("RepositoryPath").  Contrary to WikiEarly, there is not a member WikiSession in this class because ACLs are not added during crawling. Because no groups or users are passed to CES, there is no need to expand Wiki groups.

WikiLateCrawler.SecurityProvider.Initialize() Method:

public  override  InitializeError Initialize()
   m_Repository =  new  Repository(GetConfigValue("RepositoryPath"));
   return  ErrorOk;

The Login() and ValidateSession() methods are identical and required for WikiEarly as well as WikiLate. For WikiEarly, these two methods are required as this sample assumes there is no mapping between Wiki and Windows users.

The most interesting part of this class is the Authorize() method. It is the center piece of late-binding: p_UserName and p_SessionData identify the user; p_SessionsData contains the same BLOB returned by Login() and passed to ValidateSession(); p_Uris contains the documents which the method has to determine if the user can access. The result (i.e. the array of Booleans) is returned in p_OutAuthorizations.

At the beginning of the method, a WikiSession is created using the user’s login. Then in the loop, for each document, the code tries to access the document by calling GetDocument() on the newly created user session. The document is returned only if the user has the appropriate permissions to access it. That is how impersonation is accomplished with WikiLateAPI. The success/failure is stored as a Boolean in p_OutAuthorizations.

WikiLateCrawler.SecurityProvider.Authorize() Method:

public override AuthorizeError Authorize(string p_UserName,
  byte[] p_SessionData,
  string[] p_Uris,
  out bool[] p_OutAuthorizations)
 AuthorizeError retErr;
 PropTree sessionData = (p_SessionData != null ? PropTree.Parse(p_SessionData) : new PropTree());
 CNLAssert.Check(p_UserName == sessionData.GetStringValue("u"));
 try {
   WikiSession wikiSession = new WikiSession(m_Repository, p_UserName, sessionData.GetStringValue("p"));

   // No exception thrown, then login is valid.
   string templateUri = GetConfigValue(Crawler.URI_PARAM_NAME);
   int markerPos = templateUri.IndexOf(Crawler.PATHNAME_MARKER_IN_URI);
   p_OutAuthorizations = new bool[p_Uris.Length];
   if (markerPos != -1) {
     int nbCharsAfter = templateUri.Length - (markerPos + Crawler.PATHNAME_MARKER_IN_URI.Length);
     for (int uriNo = 0; uriNo < p_Uris.Length; ++uriNo) {
       // Extract the document's pathname from the URI.
       string docName = p_Uris[uriNo].Substring(markerPos, p_Uris[uriNo].Length - markerPos - nbCharsAfter);
       // Check if the user can access the document and store the result in 'p_OutAuthorizations[]'.
       p_OutAuthorizations[uriNo] = (wikiSession.GetDocument(docName) != null);
   retErr = ErrorOk;
 } catch (Exception e) {
   // Login NOT valid.
   p_OutAuthorizations = null;
   retErr = ErrorUnknownFailure(e.Message);

 return retErr;