Alfresco as Extranet

In a couple of projects I’ve worked on we’ve been using Alfresco as an extranet – that’s to say we’ve given external people access to our Alfresco instance so that we can collaborate by sharing documents and using the other site functions like discussion lists and wikis.

We’ve also had these Alfresco instances integrated into a wider single sign on system.

We want people to be able to self register into the SSO system, for a number of reasons.

This has lead to a couple of problems.

Firstly we don’t want somebody to be able to self register and then log into Alfresco and collect our user list by doing a people search.
Secondly we’d like to be able to restrict who can log into Alfresco but give a helpful message if they’ve authenticated successfully.
Thirdly we want to restrict site creation.

Restricting site creation

I’ll cover this first because it’s quite straightforward and documented elsewhere.

There are two parts to the problem:
1) Blocking access to the api
2) Removing the menu option in the UI.

Part 1 can be done by modifying the appropriate bean from public-services-security-context.xml
Part 2 will depend on your version of Alfresco and is adequately covered elsewhere.

Restricting access to the user list

This has come up a few times
e.g.
http://forums.alfresco.com/forum/end-user-discussions/alfresco-share/how-restrict-people-search-share-40-05022012-1720
http://forums.alfresco.com/forum/end-user-discussions/alfresco-share/restricting-people-find-01072009-0935

It’s even in the To Do section on the wiki
http://wiki.alfresco.com/wiki/Security_and_Authentication#To_Do

Simple approach

The simplest approach is to change the permissions on /sys:system/sys:people
You can do this by finding the nodeRef using the Node Browser and going to: share/page/manage-permissions?nodeRef=xxxx

You’ll need to create a group of all your users and give them read permission, replacing the EVERYONE permission.

You could get carried away with this by changing the permissions on individual users but that’s not a great idea.

More complex approach

A more complex approach is to use ACLs in a similar fashion to the approach used to block site creation however this does require some custom code and still isn’t perfect.

There are some changes required to make this work nicely above and beyond creating the custom ACL code

In org.alfresco.repo.jscript.People.getPeopleImpl if getPeopleImplSearch is used then
1) it’s not using PersonService.getPeople
2) if it’s using FTS and afterwards PersonService.getPerson throws a AccessDeniedException then it will cause an error (which in the case of an exception will fall through thereby giving the desired result but not in a good way as the more complex search capabilities will be lost)
This, I think, would be a relatively simple change although I’m not sure whether to catch an exception or use the getPersonOrNull method and ignore the null – I’m going with the later
e.g.

// FTS
  List personRefs = getPeopleImplSearch(filter, pagingRequest, sortBy, sortAsc);

  if (personRefs != null)
  {
    persons = new ArrayList(personRefs.size());
    for (NodeRef personRef : personRefs)
    {
      Person p = personService.getPersonOrNull(personRef);
      if (p != null) {
        persons.add(p);
      }
    }
  }

The usernamePropertiesDecorator bean (org.cggh.repo.jscript.app.CustomUsernamePropertyDecorator) will throw an exception if the access to the person bean is denied – this will have a major impact so we need to replace this with a custom implementation that swallows the exception and outputs something sensible instead.

I’ve logged an issue to get these fixes made.

Oddities that don’t appear break things

The user profile page /share/page/user/xxxx/profile will show your own profile if you try and access a profile that you don’t have access for – strange but relatively harmless
The relevant exceptions are:
org.alfresco.repo.subscriptions.SubscriptionServiceImpl.getUserNodeRef(SubscriptionServiceImpl.java:449)
org.alfresco.repo.audit.AuditMethodInterceptor.invoke(AuditMethodInterceptor.java:161)
org.alfresco.repo.jscript.People.getCapabilities(People.java:1208)

There are numerous places where the user name will be shown instead of the actual name if permission is denied to access the actual person record, i.e. it’s not using the usernamePropertiesDecorator, this appears to be done via Alfresco.util.userProfileLink. While far from ideal this isn’t too bad as this information will only be shown if you have access to a node when you don’t have access to the creator/modifier information e.g. a shared document.

Other approaches

It looks like there are a few ways to go about doing this…

The forum posts listed discuss(sketchily!) modifying the client side java script and the webscripts

At the lowest level you could modify the PersonService and change the way that the database is queried but that seems too low level

config/alfresco/ibatis/alfresco-SqlMapConfig.xml defines queries
config/alfresco/ibatis/org.hibernate.dialect.Dialect/query-people-common-SqlMap.xml defines alfresco.query.people
which is used in
org.alfresco.repo.security.person.GetPeopleCannedQuery
which in turn is used by
org.alfresco.repo.security.person.PersonServiceImpl

Restricting access

As this seems to have come up a few times as well…

I’m trying to work out if it’s possible to disable some external users.

My scenario is that I have SSO and LDAP enabled but I only want users who are members of a site to be able to access Share – ideally I’d like to be able to send other users to a static page where they be shown some information. At the moment if you attempt to access a page for which you don’t have access,e.g. share/page/console/admin-console you will go to the Share log in page (which you wouldn’t otherwise see)

I still want all the users sync’ed so using a filter to restrict the LDAP sync isn’t an option.
I only want to restrict access to Alfresco so fully disabling the account isn’t an option.

It’s relatively easy to identify the users and apply the cm:personDisabled aspect but this doesn’t appear to do anything.
See this issue.

I think the reason that the aspect doesn’t work is that the isAuthenticationMutable will return false and therefore the aspect is not being checked.

I can see the idea of not changing the sync’ed users – otherwise a full resync will lose changes
I can also see not wanting to allow updates to LDAP although the case for that is perhaps weaker

However given that it’s possible to edit profiles under these circumstances, e.g. for telephone number, wouldn’t it make more sense for the cm:personDisabled to be treated along with the Alfresco specific attributes and therefore editable rather than with the LDAP specific attributes and therefore not editable?
Actually applicable is probably a better word rather than editable as it’s possible to apply the aspect programmatically – it just doesn’t do anything.

I did think about checking some field in LDAP but I don’t think that would work without getting into custom schemas (not a terrible idea but not a great one either)

So going back to my earlier requirement to show a page to users who don’t have the requisite permission I came up with the following approach:

  • Use a cron based action to add all site users to a group all_site_users
  • Use evaluators to check if user is a member of all_site_users and if not then:
    1. Hide the title bar and top menu
    2. Hide dashboard dashlets
    3. Show a page of text

http://blogs.alfresco.com/wp/developer/2011/07/27/how-to-hide-content-on-an-existing-alfresco-share-page/