Tag: Best Practices

Secure your Alfresco server

One of the services that Metaversant provides is called a Health Check, which is exactly like it sounds: We review clients’ Alfresco installations from bottom to top and make recommendations for improvement.

A surprisingly large number of those assessments consistently show that people are not doing enough to secure their environment. In the past, I might have added, “especially for those with an externally-facing server” but, honestly, at this point, you really ought to be treating the entire network as an untrusted, hostile environment, even if it is behind a firewall.

First, let’s start with the bare minimum. These will be obvious to many of you, but believe me, they are not universally applied.

Change the default admin password to a random string

Most everyone changes the admin password, but many people make poor choices as to what that password is. Do what you should be doing with your personal passwords: Change the admin password to a randomized string.

Once you change it, don’t share it in clear-text email or text messages. Use PGP to encrypt emails that include secrets. If you must use a mobile device to share secrets use Signal.

Secure your server traffic with HTTPS

If you aren’t going to encrypt the traffic to your server then you might as well skip all of the advice in this entire post and treat your repository as public information. If that sounds like a bad idea, then you must encrypt your traffic to prevent passwords from being exposed in clear text.

The wonderful service, Let’s Encrypt, makes quality SSL certificates available to everyone for free. Yes, you have to renew them more often than paid certificates but you can automate that fairly easily with EFF’s certbot. In fact, once you establish the web proxy in front of Tomcat, securing your traffic with Let’s Encrypt is as easy as running the certbot script if you have a public-facing server.

Do not run Alfresco as root

If someone does compromise Alfresco you want to limit the damage they can do. If Alfresco is running as root, they can wreck havoc on your server.

I often see Alfresco running as root on installations where someone has simply stood up a server, switched to root, and then run the installer. When you install as root, the Alfresco service will be set up to run as root. If you later try to run as a non-root user, the alfresco.sh script might complain. You can fix this by editing the script. But you can avoid the problem altogether by installing as a non-root user in the first place.

Sometimes Alfresco will be set up to run as a non-root user and then someone will unknowingly start the server as root. When this happens you have to stop the server, recursively fix all of the permissions on the files that root touched, and then restart as the non-root user.

Disable unused protocols

This one is about reducing your attack surface. One of the nice things about Alfresco is the wide number of options you have for getting information in and out of the repository. That’s great, but if you aren’t using, for example, FTP, then why leave FTP enabled? That’s a potential place an attacker could find a toehold. Purposefully review each of the protocols that Alfresco supports and disable those that are not being used.

Re-generate the Solr certificate

Alfresco and Solr are separate web applications. Regardless of whether or not these web apps are running in the same Tomcat server, different Tomcat servers, or even different machines, they use HTTP to communicate with each other. The communication between Solr and Alfresco is encrypted, by default. The Solr web application is secured using certificate-based client authentication. But, by default, the certificate Solr uses for both encryption and authentication is the one that Alfresco generated and shipped with the product. This means that, by default, if someone can get to your Solr port they can search your entire repository because the public has easy access to that Alfresco-generated, default client certificate.

To fix this, either make sure no one can hit the Solr port (8443, by default) or re-generate the certificate. Or both. For more info on how to re-generate the Solr certificate, see the docs.

Stay current

I see an alarmingly high number of people running ancient versions of Alfresco. Often this is because the effort to upgrade can be fairly intense, especially if there are a lot of customizations to deal with. Like any significant piece of software, there have been a number of vulnerabilities discovered and resolved in Alfresco over the years. Staying on an old release could put your installation at risk.

Those are certainly the most common security issues I come across. I would consider these to be the minimum set of best practices.

Recently, I’ve had an increase in the number of clients asking about adding Two-Factor Authentication to Alfresco Share. There are a few options for doing this:

  1. Loftux offers a module that implements two-factor authentication using Authy. There is a cost associated both with the Loftux add-on and the Authy service.
  2. Contezza offers an add-on that uses Google Authenticator. In this case, the add-on has a cost but Google Authenticator is free. Google Authenticator may not be the right choice for everyone, though.
  3. There are also community projects that have done some work in this area, including a very old add-on that works with Yubikeys. Yubikeys are pretty cool, but the obvious drawback is that you have to distribute and manage the physical keys to your users.

Finally, no discussion of Alfresco and security would be complete without mentioning my friend and former colleague, Toni Blyx. The guy knows his stuff. His “Security Best Practices” presentation from Alfresco Summit 2014 is an important read.

Photo Credit: “Vintage Bank Vault” by Brook Ward, CC BY-NC 2.0

5 rules you must follow on every Alfresco project

I know that people are often thrown into an Alfresco project having never worked with it before. And I know that the platform is broad and the learning curve is steep. But there are some rules you simply have to follow when you make customizations or you could be creating a costly mess.

The single most important one is to use the extension mechanism. Let me convince you why it’s so important, then I’ll list the rest of the top five rules you must follow when customizing Alfresco.

All-too-often, people jump right in to hacking the files that are part of the distributed WARs. I see examples of it in the forums and other community channels and I see it in client projects. Not every once-in-a-while. All. Of. The. Time.

If you’ve stumbled on to this blog post because you are embarking on your first Alfresco project, let this be the one thing you take to heart: The extension mechanism is not optional. You must use it. If you ignore this advice and begin making changes to the files shipped with Alfresco you are entering a world of pain.

The extension points in Alfresco allow you to change just about every aspect of Alfresco Share and the underlying repository without touching a single file shipped with the product. And you can do so in a way that can be repeated as you move from environment to environment or when you need to re-apply your customizations after an upgrade.

“But I am too busy,” you say. “This needs to be done yesterday!”, you say. “I know JavaScript. I’m just going to make some tweaks to these components and that’s it. What’s the big deal?”

Has your Saturday Morning Self ever been really angry at things your Friday Night Self did without giving much consideration to the consequences? That’s what you’re doing when you start making changes to those files directly. Yes, it works, but you’ll be sorry eventually.

As soon as you change one of those files you’ve made it difficult or impossible to reliably set up the same software given a clean WAR. This makes it hard to:

  • Migrate your code, because it is hard to tell what’s changed across the many nooks and crannies of the Alfresco and Share WARs.
  • Determine whether problems you are seeing are Alfresco bugs or your bugs, because you can’t easily remove your customizations to get back to a vanilla distribution.
  • Perform upgrades, because you can’t simply drop in the new WARs and re-apply your customizations.

People ask for best practices around customizing Alfresco. Using the extension mechanism isn’t a “best practice”–it’s a rule. It’s like saying “Don’t cross the foul line” is a “best practice” when bowling. It’s not a best practice, it’s a rule.

So, to repeat, the first rule that you have to abide by is:

  1. Use the extension mechanism. Don’t touch a single file that was shipped inside alfresco.war or share.war. If you think you need to make a customization that requires you to do that I can almost guarantee you are doing it wrong. The official docs explain how to develop extensions.

Rounding out the top five:

  1. Get your own content model. Don’t add to Alfresco’s out-of-the-box content model XML or the examples that ship with the product. And don’t just copy-and-paste other models you find in tutorials. Those are just examples, people!
  2. Get your own namespace. Stay out of Alfresco’s namespace altogether. Don’t put your own web scripts in the existing Alfresco web script package structure. Don’t put your Java classes in Alfresco’s package structure. It’s called a “namespace”. It’s for your name and it keeps your stuff separate from everyone else’s.
  3. Package your customizations as an AMP. Change the structure of the AMP if you want–the tool allows that–but use an AMP. Seriously, I know there are problems with AMPs, but this is what we’re all using these days in the Alfresco world. Ideally you’ll have one for your “repo” tier changes and one for your “share” tier changes. An AMP gives you a nice little bundle you can hand to an Alfresco administrator and simply say, “Apply this AMP” and they’ll know exactly what to do with it.
  4. Create a repeatable build for your project. I don’t care what you use to do this, just use something, anything, to automate your build. If a blindfolded monkey can’t produce a working AMP from your source code you’re not done setting up your project yet. It’s frustrating that this has to be called out, because it should be as natural to a developer as breathing, but, alas, it does.

The Alfresco Maven SDK can really help you with all of these. If you use it to bootstrap your project, and then only make changes to the files in your project, you’re there. If you need help getting started with the Alfresco Maven SDK, read this.

These are the rules. They are non-negotiable. The rest of your code can be on the front page of The Daily WTF but if you stick to these rules at a minimum, you, your team, and everyone that comes after you will lead a much less stressful existence.

You might also be interested in my presentation, “What Every Developer Should Know About Alfresco“. And take a look at the lightning talk Peter Monks gave at last year’s Alfresco Summit which covers advice for building Alfresco modules.

 

Alfresco Best Practices Masters Class shaping up for Fall Meet-ups

Peter Monks (Alfresco), Russ Danner (Rivet Logic), and I have been working on compiling course content for the “Alfresco Best Practices” Masters Class that will be given at the Alfresco Community Meet-Ups around the world this Fall. I’m a bit worried, though. If you’ll forgive the somewhat graphic mixed metaphor, the three of us have done this huge brain dump and now we’re stirring it together in the hopes that we can firehose the audience and have some of it stick. There’s just a lot of stuff to cover in very little time. (I’m sure between now and then we’ll get it to be less of a hose down. And, whatever we don’t get to in the session will be made available online for your reference).

Our plan for the talk is to cover the material in the same conceptual order that your implementation will go through. We’ll start by understanding the most common business use cases for Alfresco. Then we’ll talk about the pieces of Alfresco that you have to work with, and sort of line those up against the common use cases. From there, we’ll dive in to best practices for each of the pieces, roughly in order that you’d touch them (start with content modeling, move to writing code, then deployment, then keeping everything running). We’re going to share best practices on extensions, UI customizations, WCM, Surf, backup/restore procedures, and on and on.

Hopefully, regardless of where you are in your implementation, you’ll be able to come away with at least a handful of tips, tricks, or things to avoid that will make your project more successful.

Russ will deliver the material in Washington, D.C. and I’m taking Atlanta and L.A. I’ll also be in D.C. to steal ideas from Russ’ delivery that I can pass off as my own. Toni de la Fuente will be giving the talk in Madrid (and translating the deck into Spanish). I’m not sure who’s delivering the material at the other European events.

In any case, I’m looking forward to it. If you’ll be attending any of the North American meet-ups, be sure to say hi.

Keeping your Alfresco web scripts DRY

One of my teammates thoroughly drenched our under-the-desk development server with a giant cup of coffee once. Somehow, disaster was avoided, although the client’s carpet had a nice coffee-stain outline of the server’s footprint long after the app rolled out which afforded the rest of us endless opportunities to mercilessly haze the clumsy coder.

Keeping your Alfresco web scripts DRY is actually not about making your developers use spill-proof travel mugs, or better yet, virtual machines. DRY is a coding philosophy or principle that stands for Don’t Repeat Yourself. There are all kinds of resources available that go into more detail, and the principle is more broad than simply avoiding duplicate code, but that’s what I want to focus on here.

There are three techniques you should be using to avoid repeating yourself when writing web scripts: web script configuration, JavaScript libraries accessed via import, and FreeMarker macros accessed via import.

Web Script Configuration

Added in 3.0, a web script configuration file is an XML file that contains arbitrary settings for your web script. It’s accessible from both your controller and your view. Building on the hello world web script from the Alfresco Developer Guide, you could add a configuration script named “helloworld.get.config.xml” that contained:


<properties>
<title>Hello World</title>
</properties>

You could then access the “title” element from a JavaScript controller using the built-in E4X library:

var s = new XML(config.script);
logger.log(s.title);

And, you could also grab the title from the FreeMarker view:

<title>${config.script["properties"]["title"]}</title>

The web script configuration lets you separate your configuration from your controller logic. And because you can get to it from both the controller and the view, you don’t have to stick configuration info into your model.

This example showed a script-specific configuration, but global configuration is also possible. See the Alfresco Wiki Page on Web Scripts for more details.

JavaScript Import

If your web script controllers are written in JavaScript, at some point you will find yourself writing JavaScript functions that you’d like to share across multiple web scripts. A common example is logic that builds a query string, executes the query, and returns the results. You don’t want to repeat the code that does that across multiple controllers. That’s what the import statement is for.

The syntax is easy:

<import resource="classpath:alfresco/extension/scripts/status.js">

This needs to be the first line of your JavaScript controller file. This example shows a JavaScript library being imported from the classpath, but you can also import from the repository by name or by node reference. See the Alfresco JavaScript API Wiki Page for more details.

FreeMarker Import

Of the three this is the one I see ignored most often. Let’s take the Optaros-developed microblogging component for Share. Its basic data entity is called a “Status” object. So web scripts on the repository tier return JSON that might have a single Status object or a list of Status objects. That’s two different web scripts and two different views, but the difference between a list of objects and a single object is really just the list-related wrapper–in both cases, the individual Status object JSON is identical. I’ve seen people simply copy-and-paste the FreeMarker from the single-object template to the list template and then just wrap that with the list markup. That’s bad. If you ever change how a Status object is structured, you’ve got to change it in (at least) two places. (Or it’ll be someone that comes after you that has to do it which makes it even worse. If you aren’t following the analogy, your redundant code is the coffee stain).

Instead of duplicating the logic, use a FreeMarker import and define a macro that formats the object. Then you can call the macro any time you need your object formatted. Here’s how it works for Status.

A FreeMarker file called “status.lib.ftl” contains the macros that format Status objects. It lives with the rest of the web script files and looks like this:


<#assign datetimeformat="EEE, dd MMM yyyy HH:mm:ss zzz">
<#--
Renders a status node as a JSON object
-->
<#macro statusJSON status>
<#escape x as jsonUtils.encodeJSONString(x)>
{
"siteId" : "${status.properties["optStatus:siteId"]!''}",
"user" : "${status.properties["optStatus:user"]!''}",
"message" : "${status.properties["optStatus:message"]!''}",
"prefix" : "${status.properties["optStatus:prefix"]!''}",
"mood" : "${status.properties["optStatus:mood"]!''}",
"complete" : ${(status.properties["optStatus:complete"]!'false')?string},
"created" : "${status.properties["cm:created"]?string(datetimeformat)}",
"modified" : "${status.properties["cm:modified"]?string(datetimeformat)}"
}
</#escape>
</#macro>
<#--
Renders a status node as HTML
-->
<#macro statusHTML status>
SiteID: ${status.properties["optStatus:siteId"]!''}<br />
User: ${status.properties["optStatus:user"]!''}<br />
Message: ${status.properties["optStatus:message"]!''}<br />
Prefix: ${status.properties["optStatus:prefix"]!''}<br />
Mood: ${status.properties["optStatus:mood"]!''}<br />
Complete: ${(status.properties["optStatus:complete"]!'false')?string}<br />
Created: ${status.properties["cm:created"]?string(datetimeformat)}<br />
Modified: ${status.properties["cm:modified"]?string(datetimeformat)}<br />
</#macro>

There’s one macro for JSON and another for HTML. It still bothers me that the same basic structure is repeated, but at least they are both in the same file and it feels better knowing that this is the one and only place where the data structure for a Status object is defined.

The FreeMarker that returns Status objects as JSON resides in status.get.json.ftl and looks like this:

<#import "status.lib.ftl" as statusLib/>
{
"items" : [
<#list results as result>
<@statusLib.statusJSON status=result />
<#if result_has_next>,</#if>
</#list>
]
}

You can see the import statement followed by the JSON that sets up the list, and then the call to the FreeMarker macro to format each Status object in the list.

When someone posts a new Status, the new Status object is returned. Rather than repeat the JSON structure for a Status object, the status.post.json.ftl view simply calls the same macro that got called from the GET:

<#import "status.lib.ftl" as statusLib/>
{
"status" : <@statusLib.statusJSON status=result />
}

Now if the data structure for a Status object ever needs to change, it only has to be changed in one place.

Don’t Repeat Yourself

Take a look at your web scripts. Eliminate your duplicate code. And keep a lid on your mocha frappuccino.