There's been a significant improvement to SAML with AEM 6.1 that is worth mentioning: Multiple OSGi configurations.

The problem

If you've gone through my AEM ADFS SAML tutorial, you know that SAML works tremendously well for author integrations. On 6.0, having a single OSGi configuration ties you to a single SAML IDP per AEM instance. In the case of ADFS, this meant not being able to use multiple URLs for SAML authentication.

The solution

By having multiple OSGi configurations in 6.1, you are no longer forced to choose a site or AEM instance to support. You can mix and match sites, AEM instances (author, publish, dispatch), and content nodes. This gives you complete control over how you trigger and accept SAML assertions.

Something to remember

Authentication in AEM is handled by the resource being requested. This means a parent resource SAML entry will override any sibling resource.

Bad OSGi SAML Paths:


In this case, having a root node authentication handler will completely override any authentication handler declared for a child node. This can be frustrating if you want to have all publish requests hit one IDP and have site-1's requests hit another IDP. With clever apache rewrites you can work around this limitation.

A better scenario would be handle authentication at a sibling level:

Good OSGi SAML Paths:


In this scenario, site one is not a child of site two, and thus can have a different authentication handler / IDP / return URL.


I was looking for a concise way to work with users and groups in Sling. Because, "everything is content," it's easy to use Sling's REST API to create a user like any other node, but things get a little dicey when you want a bit more flexibility. Enter the Jackrabbit API...

private void createAuthorGroupAndUser(ResourceResolver resolver) {
  try {
    Session session = resolver.adaptTo(Session.class);
    if (session != null && session instanceof JackrabbitSession) {
      // Get our User Manager
      UserManager userManager = ((JackrabbitSession) session).getUserManager();
      ValueFactory valueFactory = session.getValueFactory();

      // Create the Authors group if it doesn't exist already.
      Authorizable authors = userManager.getAuthorizable("authors");
      if (authors == null) {
        authors = userManager.createGroup("authors");
        authors.setProperty("displayName", valueFactory.createValue("Authors"));
      // Create the default author if it doesn't already exist.
      Authorizable author = userManager.getAuthorizable("author");
      if(author == null) {
        author = userManager.createUser("author", "letMeIn");
        author.setProperty("displayName", valueFactory.createValue("Default Author"));
      // Add author member to authors group
      ((Group) authors).addMember(author);
      // Save our session;
  } catch (RepositoryException e) {
      LOGGER.error("Could not get the session", e);

More Reading

Jackrabbit Wiki - User Management

Jackrabbit API -


Trace AEM Bundle Issues

August, 28 2015

There comes a point where you need to triage why a bundle isn't behaving as you would expect. The simplest way I've found is to setup a logger. A logger has many advantages over tailing logs/error.log...

  • You can target a specific bundle. No need to grep.
  • You can leave the generic logger on something less frequent like 'Information'.
  • This is likely what you'll be sending if you end up talking to Adobe support.

On to setting up a logger for a specific bundle...

  1. Open Console: http://localhost:4502/system/console/configMgr
  2. Find the bundle PID you want to trace. In our case, we want to trace com.adobe.granite.auth.saml
  3. Add a new Logger entry at "Apache Sling Logging Logger"
    • Set the Log Level: Trace
    • Set the Log File Location: logs/saml-error.log
    • Specify your Bundle PID: com.adobe.granite.auth.saml
  4. Go tail it via terminal: tail -f logs/saml-error.log

Bundle Trace 1 Bundle Trace 3

Update to SVG Component

August, 24 2015

The SVG component has been updated with a contribution from Gabriel Walt. The HTML has been cleaned up and simplified.

Go get latest from here.