Montag, 17. Februar 2014

Alfresco Share - remove Create Site Link from new header bar (4.2.e)

The header menu bar in Alfresco Share changed in 4.2.d to a completely new design. With the new design, there also comes a new way for customization and since I have not found an instruction to remove the "Create Site" menu entry for non admin users, I decided to document that here.
This instruction will ONLY work from 4.2.e and I only tested in on 4.2.e. There are some good blog entries why it is not working on 4.2.d, so I will not discuss that here anymore.

I will not create an own JAR file for that customization, but do all in the shared directory. Perhaps I will provide a JAR file too, if I have some time which is quite rare.

1. Create a share module
create file shared/classes/alfresco/web-extension/site-data/extension/remove-create-site-extension.xml
<extension>
 <modules>
  <module>
   <id>Remove create site menu option for non admin users</id>
   <version>1.0</version>
   <customizations>
    <customization>
     <targetPackageRoot>org.alfresco.share.header</targetPackageRoot>
     <sourcePackageRoot>ingen.header</sourcePackageRoot>
    </customization>
    <customization>
     <targetPackageRoot>org.alfresco.components.dashlets</targetPackageRoot>
     <sourcePackageRoot>ingen.dashlets</sourcePackageRoot>
    </customization>
   </customizations>
  </module>
 </modules>
</extension>
2. customize header webscript
create file shared/classes/alfresco/web-extension/site-webscripts/ingen/header/share-header.get.js
//Find the "Sites" menu...
var sitesMenu = widgetUtils.findObject(model.jsonModel, "id", "HEADER_SITES_MENU");

if (sitesMenu != null) {
 if (!user.isAdmin) {
  sitesMenu.config.showCreateSite = false;
 }
}
3. the 'my sites' dashlet
create file shared/classes/alfresco/web-extension/site-webscripts/ingen/dashlets/my-sites.get.js
if (!user.isAdmin) {
 model.showCreateSite = false;
}
4. don't forget the dynamic-welcome dashlet
Thanks Douglas for remembering me about the dynamic-welcome dashlet and the create site link in there. To remove that link create file shared/classes/alfresco/web-extension/site-webscripts/ingen/dashlets/dynamic-welcome.get.js
if (args.dashboardType == "user" && !user.isAdmin) {
 model.columns[1].actionMsg = null;
 model.columns[1].actionHref = null;
}
5. restart alfresco share
6. activate module

Now everything should be fine. But don't forget to restrict the service calls too - especially if you want to be sure that any left link, direct call and alternative frontend (mobile, ...) are save too ;)

Sonntag, 16. Februar 2014

Alfresco Share - disable site creation for non admin user

It's quite a common use case to restrict site creation in Alfresco Share to admin users only.

There are some good instructions out there describing how to do that: http://www.chipnick.com/blog/2013/04/09/restrict-site-creation-to-administrators-in-alfresco/ 

Short description:
  • configure permissions (important, otherwise the user can call the link directly or use another interface (like mobile app))
  • remove site creation link in front end

I will concentrate on the permission part in this post only. There will be another post how to remove the link (especially in 4.2.e onwards).

Without RM module just configure the security layer to restrict calls to the createSite Method of the SiteService. You can do that by simply creating a file shared/classes/alfresco/extension/custom-public-services-security-context.xml:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>

<beans>
    
    <!-- ============ -->
    <!-- Site Service -->
    <!-- ============ -->
    
    <bean id="SiteService_security" class="org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor">
        <property name="authenticationManager"><ref bean="authenticationManager"/></property>
        <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
        <property name="afterInvocationManager"><ref bean="afterInvocationManager"/></property>
        <property name="objectDefinitionSource">
            <value>
               org.alfresco.service.cmr.site.SiteService.cleanSitePermissions=ACL_NODE.0.sys:base.ReadProperties
               org.alfresco.service.cmr.site.SiteService.createContainer=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
               org.alfresco.service.cmr.site.SiteService.createSite=ACL_METHOD.ROLE_ADMINISTRATOR
               org.alfresco.service.cmr.site.SiteService.deleteSite=ACL_METHOD.ROLE_ADMINISTRATOR
               org.alfresco.service.cmr.site.SiteService.findSites=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
               org.alfresco.service.cmr.site.SiteService.getContainer=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
               org.alfresco.service.cmr.site.SiteService.listContainers=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
               org.alfresco.service.cmr.site.SiteService.getMembersRole=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.getMembersRoleInfo=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.resolveSite=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.getSite=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
               org.alfresco.service.cmr.site.SiteService.getSiteShortName=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
               org.alfresco.service.cmr.site.SiteService.getSiteGroup=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.getSiteRoleGroup=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.getSiteRoles=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.getSiteRoot=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
               org.alfresco.service.cmr.site.SiteService.hasContainer=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.hasCreateSitePermissions=ACL_METHOD.ROLE_ADMINISTRATOR
               org.alfresco.service.cmr.site.SiteService.hasSite=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.isMember=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.listMembers=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.listMembersInfo=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.listMembersPaged=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.listSites=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
               org.alfresco.service.cmr.site.SiteService.listSitesPaged=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
               org.alfresco.service.cmr.site.SiteService.removeMembership=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.canAddMember=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.setMembership=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.updateSite=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.countAuthoritiesWithRole=ACL_ALLOW
               org.alfresco.service.cmr.site.SiteService.*=ACL_DENY
            </value>
        </property>
    </bean>
 
</beans>
So everything should be fine. BUT NOT if you have installed the records management module (RM).

The RM module adds some own custom security settings (adds a rmEntryVoter voter in file rm-public-services-security-context.xml to the bean accessDecisionManager) which "overrides" the normal security settings and breaks the customization from above.

Customization with RM module:

It's much easier as you might except. Just add a file shared/classes/alfresco/extension/rm-method-security.properties with following content:
rm.methodsecurity.org.alfresco.service.cmr.site.SiteService.createSite=ACL_METHOD.ROLE_ADMINISTRATOR
rm.methodsecurity.org.alfresco.service.cmr.site.SiteService.hasCreateSitePermissions=ACL_METHOD.ROLE_ADMINISTRATOR
I tested that with Alfresco Community 4.2.e and RM version 2.1.0-621.

Credits:
Thanks to Ahmed (Ashex on #alfresco irc channel) for discussing the problem on IRC and for your good instructions on your blog.