Cloud Connected

Thoughts and Ideas from the Gitana Development Team

Enterprise Access Policies in Gitana 4.0 (Part 2)

In this article, we'll continue our series on Access Policies within Gitana. We'll take a few interesting and more complex examples of how Access Policies may be used to guarantee compliance witih enterprise security requirements.

In the previous article, we left off looking at how you can grant access to content using Access Policies that are defined at either a Platform or Project-level. Platform-scoped policies can be written once and applied across all of your Projects. In this way, you can centrally manage Access Policies that are applied to Projects using regular expressions on the Project ID, title or a custom field.

Alternatively, you can assign them one-by-one to your Projects. Or allow Project Managers to manage their own Access Policies from within their Projects.

Let us extend on this and look at some new Access Policies that do interesting things!

Grant the Consumer Role to Specific Folders

Suppose you have a single Project. You've invited a vendor to the Project and you'd like to allow that vendor's users to be able to view a specific folder and all of its content. Suppose the vendor is ACME Corporation and the path to their resources is /resources/acme.

Let's use the path condition to define an Access Policy that does just this!

{
    "title": "Consumer of Content in Folder /resources/acme",
    "statements": [{
        "action": "grant",
        "roles": ["consumer"],
        "conditions": [{
            "type": "path",
            "config": {
                "path": "/resources/acme(.*)"
            }
        }]
    }]
}

That's it. We assign this Access Policy to the ACME team or group. And by doing so, all members of that team or group will be able to view the /resources/acme folder. It also means that those members will be able to perform full-text searches, GraphQL queries or any other API call within Gitana and read the content contained within that folder.

What if we wanted to define this Access Policy at the platform level and have it apply only to specific Projects? We can borrow the statements from the previous article's Access Policy and combine them here to build a multi-statement Access Policy that runs at the Platform level and can be used across multiple Projects!

{
    "title": "Consumer of Content in Folder /resources/acme",
    "statements": [{
        "action": "grant",
        "roles": ["consumer"],
        "conditions": [{
            "type": "path",
            "config": {
                "path": "/resources/acme(.*)"
            }
        }, {
            "type": "project",
            "config": {
                "property": "has_vendor_resources",
                "value": true
            }
        }]
    }]
}

In this way, this single Access Policy will work across multiple Projects. Specifically, it will work across Projects that have has_vendor_resources set to true.

It's worth noting that you can also limit the grant to the specific folder -without- granting for subfolder elements. For example, if you wanted folks to be able to see the acme folder but -not- see any sub-items, you can change the path to:

"path": "/resources/acme"

You can learn more about the path condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/path.html

Grant Consumer Role to Content on a Specific Branch

Gitana is unique in that it is one of the only content platforms that offers Git-like branches and versioning. Every change that your editorial team makes is captured. And editorial teams are empowered to work in branched workspaces, allowing them to make changes at the same time without stepping on each other's toes!

Your Access Policies can be scoped to work against all branches or against specific branches. The branch condition allows you to scope your Access Policy statements to branches as you please.

Here is an example where the Consumer role is granted to all nodes on the branch named My Workspace.

{
    "title": "Consumer of Content on the 'My Workspace' branch",
    "statements": [{
        "action": "grant",
        "roles": ["consumer"],
        "conditions": [{
            "type": "branch",
            "config": {
                "title": "My Workspace"
            }
        }]
    }]
}

We can also grant by Branch ID or by Branch alias. Here is a statement which uses an $or composite clause to allow for two cases:

{
    "title": "Consumer of Content on Two Branches",
    "statements": [{
        "action": "grant",
        "roles": ["consumer"],
        "conditions": [{
            "type": "or",
            "config": {
                "conditions": [{
                    "type": "branch",
                    "config": {
                        "id": "574118a48a2e68c897ed"
                    }
                }, {
                    "type": "branch",
                    "config": {
                        "alias": "authoring"
                    }
                }]
            }
        }]
    }]
}

Finally, we can also bind the Access Policies to any other property on a Branch (including custom properties) using the property and value options. Suppose our team of editors is kicking off branches left and right for various purposes. We can write our Access Policy to apply to those branches by simply saving them with a custom property. If each Branch had a property purpose with a value of daily_update, we could do something like this:

{
    "title": "Consumer of Content on Daily Update branches",
    "statements": [{
        "action": "grant",
        "roles": ["consumer"],
        "conditions": [{
            "type": "branch",
            "config": {
                "property": "purpose",
                "value": "daily_update"
            }
        }]
    }]
}

We can assign this Access Policy at the Project level to have it apply to all resources within a specific-Project. Or we can define it at the Platform level to have it work across all Projects. If we did that, we'd likely want to introduce additional conditions to selectively decide which Projects the Access Policy should apply to.

You can learn more about the branch condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/branch.html

Grant Consumer Role to Content by Node Type QName

Gitana provides a content modeling facility that lets you define the structure of your content types, content associations and features/aspects using JSON Schema. Everything is compiled at a branch-level, on-the-fly, as you make changes. Compile-time validators run to ensure that your content model is always consistent and valid. The system offers complete support for hierarchical inheritance, property-level overridess and even aspect-oriented feature injection against both content definitions and instances.

Your Access Policies are further able to scope their bindings to specific content definitions in your model. In this way, you can grant or revoke authorities against specific content types, letting you assign permission for teams to work on specific types or lineages of content in one fell swoop.

Suppose you wanted to allow Bill, Tina and Joe the ability to edit Press Releases. Your Press Releases might be implemented as a content type with the type QName of my:press-release. You could use the following Access Policy to grant the Editor authority:

{
    "title": "Editor of Press Releases",
    "statements": [{
        "action": "grant",
        "roles": ["editor"],
        "conditions": [{
            "type": "type-qname",
            "config": {
                "qname": "my:press-release"
            }
        }]
    }]
}

You would then put Bill, Tina and Joe onto a "Press Release Editors" team. Assign this Acccess Policy to the team and away you go!

You can learn more about the type-qname condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/type-qname.html

Grant Consumer Role to Content tagged with a Feature / Aspect

Gitana comes preloaded with a large number of features / aspects that you can use to inject important metadata and important behaviors onto your content instances and content types. Features are aspects that let you define concerns (behaviors / metadata) that you can snap into your content hierarchy from the side.

This provides a valuable tool that works seamlessly alongside hierarchical modeling! It allows you to snap in properties and behaviors that are centrally-managed. This injection effectively comes in from the side, instead of hierarchically, and lets you target any content definition within the tree.

For example, Gitana comes with a feature called f:watermarkable that can be marked onto a node to have that node's image attachment automatically undergo watermarking. That is to say, the node's original image has a watermark applied to it and the resulting image is added to the node as a new attachment.

Suppose you wanted to write a policy that granted Editor rights to all watermarked files. That's now very easy. You can do so like this:

{
    "title": "Editor of Watermarked Files",
    "statements": [{
        "action": "grant",
        "roles": ["editor"],
        "conditions": [{
            "type": "feature",
            "config": {
                "qname": "f:watermarkable"
            }
        }]
    }]
}

That's it. Assign this policy to a user to allow that user to edit all of the nodes with watermarked images in the system!

You can learn more about the feature condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/feature.html

Grant Editor Role to Translators for Localized Content

In Gitana, you use the f:multilingual feature to mark an individual content instance as supporting one or more multilingual translatons. Or, you can mark an entire Content Type within the dictonary so that all content instances of that type (or inherited types) will support multilingual translations.

Multilingual translations are stored within the content graph as associated nodes that contain the localized key/value pairs and the localized binary attachments for a given locale. Each associated node stores the localized data for a single translation. There is also no limit to the number of translations that a multlingual node may support!

You can modify individual translations manually or you can utilize our integrated AI services to automatically produce translated values for your properties. The central node in the graph structure is known as the "master node". You can set things up so that any changes to this master node will cause your localized content automatically translate using these integrated AI services.

Regardless of your approach, it is often the case that organizations will want to delegate either the editing of translations or the approval of automated translations to one or more translation teams. There may be one team of editors whose responsibility it is to manage all localized content. Or you may, for example, have multiple teams where one team is dedicated to Spanish content, another to German content and another to Chinese content.

Access Policies allow you to limit access rights to content based on the locale of the content. You can configure things so that everyone can see each other's content and translations while limiting which teams are specifically responsible for editing or approving the localized translations themselves.

Here is an Access Policy that grants Editor rights to content that has been localized to Spanish (where f:locale = es).

{
    "title": "Editor of Spanish Translations",
    "statements": [{
        "action": "grant",
        "roles": ["editor"],
        "conditions": [{
            "type": "locale",
            "config": {
                "locale": "es"
            }
        }]
    }]
}

And here is an Access Policy that does the same for Chinese (f:locale = zh).

{
    "title": "Editor of Chinese Translations",
    "statements": [{
        "action": "grant",
        "roles": ["editor"],
        "conditions": [{
            "type": "locale",
            "config": {
                "locale": "zh"
            }
        }]
    }]
}

You can learn more about the locale condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/locale.html

Learn More about Access Policies

This article and its predecessor really only scratch the surface regarding what is possible with Access Policies. We hope you've found it interesting! To learn more about Gitana, Access Policies and Content Modeling, please check out:

  • https://gitana.io
  • https://gitana.io/documentation/gitana/4.0/engine/content-models.html
  • https://gitana.io/documentation/gitana/4.0/engine/security/access-policies.html

Enterprise Access Policies in Gitana 4.0 (Part 1)

In this article, we'll take a look at Access Policies -- a powerful, new feature in Gitana 4.0 that allows organizations to set up and guarantee compliance with complex, enterprise-wide security requirements. Access Policies build upon the existing access control facilities provided which include per-object ACLs and broader, team-based ACLs. They extend those capabilities by allowing administrators to express access rights in a broad sweeping and prescriptive manner -- one that allows for customization and rule-based configuration, defining access constraints that span your entire platform, go across projects, across users and across all of your content via centralized and managed policy control documents.

The Access Policy

An Access Policy document is a JSON document that defines one or more conditional statements. Each statement conditionally grants or revokes one or more authorities against a resource. If effect, each statement is a rule that is evaluated for the current user against the given resource and a determination is made of what authorities to bestow.

The basic structure of an Access Policy document looks like this:

{
    "title": "{title}",
    "statements": [{
        "action": "{action}",
        "roles": [],
        "conditions": [{
            "type": "{conditionType},
            "config": {
                ...
            }
        ]}
    }]
}

Access Policies can be assigned to Users, Groups and Teams. By assigning an Access Policy to a Group or a Team, all members of that group or team will receive the grants or revocations prescribed by the Access Policy. This includes sub-groups or principals members with nested memberships.

Finally, Access Policies can be assigned at multiple scopes. A platform-scoped Access Policy will be evaluated universally across all of your Gitana resources (including within Projects). Where as a project-scoped Access Policy is applicable only to the resources of a specific project.

Using scopes, you can centrally manage Access Policies that span the entire organization as well as centrally manage Access Policies that are then assigned project-by-project to fine tune access control rights within any given project. You may also wish to permit Project Administrators to have rights to further extend Access Policies within their individual projects or constrain that very ability, depending on your specific needs.

Access Policies in Practice

We've pulled together a few examples on how Access Policies are most commonly put to use across our customer base. We've also compiled a few simple examples to help demonstrate what Access Policies are all about.

Let's take a look at a few examples, starting with the simplest of cases.

Grant the Consumer Role to Everything

You can write an unconditional Access policy by simply omitting the conditions array.
This Access policy will grant the Consumer role to all resources.

{
    "title": "Consumer of all Resources",
    "statements": [{
        "action": "grant",
        "roles": ["consumer"]
    }]
}

Notes:

  • If this Access Policy were assigned at the Platform scope, it would grant Consumer rights to a principal for everything on the tenant platform.
  • If it were assigned to a specific Project, it would grant Consumer rights to a principal for everything within the project.

This includes the Project itself, the Stack, the Master Branch, any other Branch and all content on all Branches.

Needless to say, this kind of Access Policy isn't typically used. It's provided here as a starting point. Let's see some more!

Grant the Consumer Role to Content Nodes

We can improve on the previous example by constraining the grant to content nodes only. To do so, we can introduce a Condition. Specifically, we'll use the type condition to constrain the statement to apply only to resources of type node.

{
    "title": "Consumer of all Content Nodes",
    "statements": [{
        "action": "grant",
        "roles": ["consumer"],
        "conditions": [{
            "type": "type",
            "config": {
                "type": "node"
            }
        }]
    }]
}

Notes:

  • If this Access Policy were assigned at the Platform scope, it would grant Consumer rights to a principal for all content nodes across all projects on the tenant platform.
  • If it were assigned to a specific Project, it would grant Consumer rights to a principal for all content nodes within that specific project.

You can learn more about the type condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/type.html

Grant the Consumer Role to Content Nodes in specific Projects

Suppose we wanted to apply the previous example at the Platform level but have it only apply to specific projects. We can use the or condition coupled with the project condition to build out the boolean logic for the binding.

Imagine that we have two projects that host content for "level 4" vendors. The first Project might be named FedEx and the second project might be named UPS. We can constrain our Access Policy to those two projects by Title like this:

{
    "title": "Consumer of all Content Nodes for Level 4 Vendor Projects",
    "statements": [{
        "action": "grant",
        "roles": ["consumer"],
        "conditions": [{
            "type": "type",
            "config": {
                "type": "node"
            }
        }, {
            "type": "or",
            "config": {
                "conditions": [{
                    "type": "project",
                    "config": {
                        "title": "FedEx"
                    }
                }, {
                    "type": "project",
                    "config": {
                        "title": "UPS"
                    }
                }]
            }
        }]
    }]
}

Note that the conditions array elements have an implicit and amongst them.

This Access Policy would be assigned at the Platform level and would only evaluate against resources within the FedEx or UPS projects.

Since the titles of Project can potentially change, we could improve this by sle also elect to constrain by ID, like this:

{
    "title": "Consumer of all Content Nodes for Level 4 Vendor Projects",
    "statements": [{
        "action": "grant",
        "roles": ["consumer"],
        "conditions": [{
            "type": "type",
            "config": {
                "type": "node"
            }
        }, {
            "type": "or",
            "config": {
                "conditions": [{
                    "type": "project",
                    "config": {
                        "id": "db247ccd3539f5aa0ef8"
                    }
                }, {
                    "type": "project",
                    "config": {
                        "id": "ada21783fc8761831bbb"
                    }
                }]
            }
        }]
    }]
}

That's not bad. However, we can improve this even further.

Suppose we simply tagged Projects with a property called vendor_level which identified the level of subscription. Then we could just tag the UPS and FedEx projects with vendor_level set to 4.

Now our Access Policy can be simplified:

{
    "title": "Consumer of all Content Nodes for Level 4 Vendor Projects",
    "statements": [{
        "action": "grant",
        "roles": ["consumer"],
        "conditions": [{
            "type": "type",
            "config": {
                "type": "node"
            }
        }, {
            "type": "project",
            "config": {
                "property": "vendor_level",
                "value": 4
            }
        }]
    }]
}

Much better! This Access Policy will automatically be applied to any Projects with the designated vendor_level. This means we can add, remove and update Projects as we wish and the Access Policy system will dynamically apply our provisioned access rights as we go!

It's also worth noting that any and all conditional rules will perform Regular Expression matching whenever textual content is being compared. In the examples above, we used simple text matches. But we could also imagine a more contrived example where we might want this Access Policy to apply to all Projects that start with the letter A. You could adjust the Condition like this:

{
    "type": "project",
    "config": {
        "title": "^A.*"
    }
}

That's it.

You can use RegEx expressions anyplace where text conditions are concerned. Use them for multi-value matches, prefix or suffix matches, partial matches and much more!

You can learn more about the project condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/project.html

You can learn more about the or condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/or.html

You can learn more about the and condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/and.html

More to Come!

In the next article, we'll continue looking at more complex and interesting examples of Access Policies. We'll take a look at revokes and ordering. And we'll cover examples that employ conditions around Branches and further Content properties including locale, path and aspect-injected, nested property paths!

Editorial Flows

Editorial Flows

In Gitana 4.0, we introduced a new feature called Editorial Flows. With Editorial Flows, your editorial teams launch draft workspaces where they work on content items at their own pace. They can write new content, change existing content or delete things in isolation without worrying about how it will affect the main line of content.

They are free to work without worry about stepping on each other's toes. They can make changes to the content graph, upload new files, adjust taxonomies and more! Using instant preview, they can iterate until they get everything just right. And then they can submit their changes for release using scheduled publishing!

In this article, we'll take a closer look at Editorial Flows. We'll do this by looking at how Editorial Flows bring together a number of powerful features from Gitana into a single, draft/publishinig experience. These features are:

  • Branch-Based Workspaces
  • Workflow
  • Collaboration
  • Scheduled Publishing

Let's take a look at how these work together to deliver Editoral Flows!

Branch-Based Workspaces

When you launch an Editorial Flow, Gitana automatically sets up a private workspace for you or your editorial team. This is accomplishing using the Git-like versioning system that powers Gitana. Each editorial flow gets its own Branch!

A Branch is a private workspace that forks off from the main line set of content. You can make any changes you'd like in your brranch and it won't affect users who are looking at content in the main line or in other branches! This provides complete freedom to try out new ideas, experiment, make mistakes and keep going. If you try something and it doesn't work, you can simply toss it out. But if you do produce something interesting, your contributions can be cherry picked and included in the final result.

So take chances. Your branch will track all of your changes and provide you with an instant view of everything you've done. That way, when your work is done, you have a snapshot view of all of the things you've modified -- every property, document, binary attachment and graph relationship. It's all there and instantly previewable by you, you team, your management and anyone else who needs to understand what's been worked on!

Once you're done with your work, you submit it. That's it. The editorial flow will route the work on to the next person. For example, a Manager might need to approve your changes. Or a Publishing Manager might want to merge your changes into a formal, scheduled release that will go out a week from now.

In all of those cases, your specific set of changes (i.e. the work that you've done) is perfectly captured and forwarded on within the business. It contributes, adding value to the final result.

task.png

Workflow

Each Editorial Flow is powered by the Gitana Workflow Engine -- a seamlesslly integrated, business process management engine (BPM) that powers the lifecycle of content within the platform. You can either use one of our pre-built workflow models or you can write your own to implement your exact workflow process needs. Workflow models define lifecycle transition states and they also define collaborators, event handlers, notifications, web hooks and more!

Sometimes you'll have a very simple workflow -- one where you make a change and you just expect it to get merged into the main line. If so, more power to you.

However, at other times, your workflow needs may be more advanced. They may require any editorial changes to be approved by a manager before they are merged. Or they might require scheduling of the resulting changes into a formal release that goes out at a specific time (such as Wednesday morning at 7:00am EST). Workflow models let you capture all of these requirements in a formal document that determines how the workflow executes.

As the workflow proceeds, collaborators receive emails and notifications to let them know when tasks have been assigned to them. Your editorial team simply clicks on a link to jump into Gitana. They can then make their changes and complete the work. It's as simple as that!

The Gitana Workflow engine features a large library of pre-built event handlers and an actions framework that enables your workflow to automatically send emails, fire off web hooks HTTP calls, send notifications, extract content, call out to AI services, tag your content and much more.

As workflows route through their lifecycle changes, reports are instantly generated to reveal bottlenecks and identify opportunities for process improvement. Learn where tasks are lagged or delayed. And find opportunities to improve your editoral flow time to market.

Collaboration

Each Editorial Flow that you launch can be worked on by one person or by many people all at once! You simply invite collaborators into your private workspace and then assign them to teams to grant them roles. You might choose to let some collaborators have READ ONLY rights. Whereas other collaborators might have full rights to EDIT content.

Access Policies allow you to define exactly what each user can do with each type of content in your workspace. Suppose, for example, that you wanted a collaborator to work ONLY on Spanish translations of Press Releases. Or suppose, on the other hadn, that you wanted a different collaborator to only be able to read content within the folder at the path `/customers/acme/marketing'. You can do all of this using Access Policies.

Each workspace tracks all of the changes contributed by you and anyone else you invite. In that sense, it's fair to think of workspaces as units of work. They contain within them the set of changes that the team has ultimately built and has decided to contribute back to the business.

With Editorial Flows, your editorial team can work on many different content tasks at the same time. Your team becomes aware of changes being worked on in one flow versus changes being made in another flow. They can compare these using Visual Compare. These can inspect side-by-side differences to see what document and property-level changes were made that might differ. Finally, they can Cherry Pick from the good ideas that the team has assembled, keeping the elements that yield the highest impact to the final result.

Scheduled Publishing

When an Editoral Flow completes, an agreed upon set of changes will have been produced. This set of changes might go through an approval step (depending on how the workflow is configured). But when all is said and done, the workflow completes and some final result is produced.

In some cases, this final result contain changes to content that are intended to be merged back to the main line... right away. In other cases, the goal might be to have those changes merge at some time in the future. And in still other cases, the goal might be to have those changes merge into a future release that then goes out all at once (at some time in the future).

Gitana supports all off these scenarios. Scheduled Publishing allows your changes to be targeted for a future release date. And Pull Requests make it possible for the content changes to be submitted for consideration by a Publishing Manager for a future release.

For example, you might have 3 changes that are required to go live on Friday. On Monday, you create a 3 Editorial Flows and 1 Release (scheduled for Friday). As the week progresses, you receive Pull Request notifications via email indicating that the Editorial Flows have completed and you now need to decide what to do with the results. You look at each one and you merge them into the Friday release. In this way, the Friday release builds up over time. It accumulates as your editorial teams contribute and those contributes are approved and accepted into the release.

The Gitana Publishing Engine allows you to configure fanned-out Deployment to one or more Deployment Targets. These include CDN endpoints, Amazon S3, IBM Cloud Object Storage, FTP servers, custom HTTP endpoints and even other Gitana environments running in various data centers anywhere in the world.

Upon release, your changes are deployed to to these deployment targets. Differencing allows you to inspect what is live (versus what is in your main line) to spot discrepancies. Finally, snapshots and rollback allow you to scroll your live deployment targets back or forward in time to reflect prior states of deployment in case of an error.

Summary

With Editorial Flows, Gitana 4.0 delivers an extremely powerful facility for quickly producing and publishing content to your live applications, web sites and smart API services running anywhere in the world. Reliably and On-Time. Powered by an enterprise-grade BPM workflow engine, these workflow processes deliver accountability and reportability, letting you track content contributions from inception to delivery.