Marklogic Data Rest Encryption
Marklogic Data Rest Encryption
Marklogic Data Rest Encryption
Security Guide
1
MarkLogic 10
May, 2017
Table of Contents
Security Guide
When you create systems that store and retrieve data, it is important to protect the data from
unauthorized use, disclosure, modification or destruction. Ensuring that users have the proper
authority to see the data, load new data, or update existing data is an important aspect of
application development. Do all users need the same level of access to the data and to the
functions provided by your applications? Are there subsets of users that need access to privileged
functions? Are some documents restricted to certain classes of users? The answers to questions
like these help provide the basis for the security requirements for your application.
MarkLogic Server includes a powerful and flexible role-based security model to protect your data
according to your application security requirements. There is always a trade-off between security
and usability. When a system has no security, then it is open to malicious or unmalicious
unauthorized access. When a system is too tightly secured, it might become difficult to use
successfully. Before implementing your application security model, it is important to understand
the core concepts and features in the MarkLogic Server security model. This chapter introduces
the MarkLogic Server security model and includes the following sections:
• Licensing
• Security Overview
• Terminology
1.1 Licensing
Some MarkLogic Server security features require an Advanced Security License in addition to the
regular license. The Advanced Security License option is required when using:
• Compartment Security
• Redaction
• An external Key Management System (KMS) or keystore with encryption at rest
• Authorization
• Administration
Authentication by username and password is only part of the story. You might grant access to
users based on something other than identity, something such as the originating IP address for the
requests. Restricting access based on something other than the identity of the user is generally
referred to as access control.
1.2.2 Authorization
Authorization provides the mechanism to control document access, XQuery and JavaScript code
execution, and document creation. For an authenticated user, authorization determines what you
are allowed to do. For example, authorization is what allows the user named Melanie to read and
update a document, allows the user named Roger to only read the document, and prevents the user
named Hal from knowing the document exists at all. In MarkLogic Server, authorization is used
to protect documents stored in a database and to protect the execution of XQuery or JavaScript
code. For details on authorization in MarkLogic Server, see “Protecting Documents” on page 22
and “Protecting XQuery and JavaScript Functions With Privileges” on page 110.
1.2.3 Administration
Administration is the process of defining, configuring, and managing the security objects, such as
users, roles, privileges, and permissions that implement your security policies. For details on
security administration procedures in MarkLogic Server, see “Security Administration” on
page 15 and the Administrator’s Guide.
• Security Administration
Other Roles
Privileges
Roles
Document
Permissions
Users
There are two types of privileges: URI privileges and execute privileges. URI privileges are used
to control the creation of documents with certain URIs. Execute privileges are used to protect the
execution of functions in XQuery or JavaScript code.
Note: For execute privileges’ type, you may achieve finer granularity access control over
configuration and various administration abilities through defining granular
privileges. For information on granular privileges, see “Granular Privileges” on
page 113.
Privileges are assigned to zero or more roles, roles are assigned to zero or more other roles, and
users are assigned to zero or more roles. A privilege is like a door and, when the door is locked,
you need to have the key to the door in order to open it. If the door is unlocked (no privileges),
then you can walk right through. The keys to the doors are distributed to users through roles; that
is, if a user inherits a privilege through the set of roles to which she is assigned, then she has the
keys to unlock those inherited privileges.
Permissions are used to protect documents. Permissions are assigned to documents, either at load
time or as a separate administrative action. Each permission is a combination of a role and a
capability (read, insert, update, node-update, execute).
Permission
Capability
Role (read, insert,
update, node-update,
or execute)
Users assigned the role corresponding to the permission have the ability to perform the capability.
You can set any number of permissions on a document.
Capabilities represent actions that can be performed. There are four capabilities in MarkLogic
Server:
• read
• insert
• update
• node-update
• execute
Users inherit the sum of the privileges and permissions from their roles.
For more details on how roles work in MarkLogic Server, see “Role-Based Security Model” on
page 17. For more details on privileges and permissions, see “Protecting Documents” on page 22.
Element level security can be used in addition to and along with existing document level security
and compartment security. For more information about element level security, see “Element Level
Security” on page 40.
The following figure shows that many databases can be configured to use the same security
database for authentication and authorization.
Database 1
Security Database
Database 2 (contains user data,
privilege data, role
data)
Database n
The security database is accessed to authenticate users and to control access to documents. For
details on authentication, the security database, and ways to administer objects in the security
database, see “Authenticating Users” on page 31 and “Administering Security” on page 267.
There may be circumstances in which a cluster is configured with more than one Security
database, such as when using database replication. When multiple Security databases are used,
there should be an equal number of Admin servers with different ports, one for each Security
database. Each Security database can then be upgraded by its respective Admin Interface.
The name of the Security database used by the Admin Interface is shown in the upper right corner
of the Security Configuration page.
• Admin Interface
• REST Management API
• XQuery and JavaScript server-side security administration functions
For details on administering security, see “Administering Security” on page 267.
1.4 Terminology
This section defines the following terms, which are used throughout the security documentation:
• User
• Role
• Execute Privilege
• URI Privilege
• Permission
• Amp
1.4.1 User
A user is a named entity used to authenticate a request to an HTTP, WebDAV, ODBC, or XDBC
server. For details on users, see “Authenticating Users” on page 31.
1.4.2 Role
A role is a named entity that provides authorization privileges and permissions to other roles or to
users. You can assign roles to other roles (which can in turn include assignments to other roles,
and so on). Roles are the fundamental building blocks that you use to implement your security
policies. For details on roles, see “Role-Based Security Model” on page 17.
1.4.5 Permission
A permission provides a role with the capability to perform certain actions (read, insert, update,
node-update, execute) on a document or a collection. Permissions consist of a role and a
capability. Permissions are assigned to documents and collections. For details on permissions, see
“Protecting Documents” on page 22.
1.4.6 Amp
An amp provides a user with the additional authorization to execute a specific function by
temporarily giving the user additional roles. For details on amps, see “Temporarily Increasing
Privileges with Amps” on page 112.
MarkLogic Server uses a role-based security model. Each security entity is associated with a role.
This chapter describes the role-based security model and includes the following sections:
• Understanding Roles
For more details on execute privileges, see “Protecting XQuery and JavaScript Functions With
Privileges” on page 110.
For more details on how URI privileges interact with document creation, see “Protecting
Documents” on page 22.
• read
• insert
• update
• node-update
• execute
Users gain the authority to perform these capabilities on a document if they are assigned a role to
which a permission is associated.
For more details on how permissions interact with documents, see “Document Permissions” on
page 23.
For more details on how default permissions interact with document creation, see “Default
Permissions” on page 26.
Use the Admin Interface to display the set of privileges and default permissions for a given user;
do not try and calculate it yourself as it can easily get fairly complex when a system has many
roles. To display a user’s security settings, use Admin Interface > Security > User > Describe. You
need to select a specific user to see the Describe tab.
Document1
Priv1
Permissions Capability is
one of:
Capability:
Role1 read
update
Role3 insert
Role1 Capability:
update
Priv2 Role3 node-update
insert execute
Capability:
Role2
read
Role2
XQuery Function
xdmp:security-assert(
"Priv1", "$execute") User1
Priv1 needed to
execute this function
Notice how all of the arrows point into the roles; that is because the roles are the center of all
security administration in MarkLogic Server. In this diagram, User1 is part of Role2, and Role2
inherits Role3. Therefore, even though User1 has only been assigned Role2, User1 possesses all of
the privileges and permissions from both Role2 and Role3. Following the arrows pointing into
Role2 and Role3, you can see that the user possesses Priv1 and Priv2 based on the privileges
assigned to these roles and insert and read capabilities based on the permissions applied to
Document1.
Because User1 possesses Priv1 (based on role inheritance), User1 is able to execute code
protected with a xdmp:security-assert("Priv1", "execute") call; users who do not have the
Priv1 privilege can not execute such code.
MarkLogic Server also has a built-in role named security. Users who are part of the security
role have execute privileges to perform security-related tasks on the system using the functions in
the security.xqy Library Module.
The security role does not have access to the Admin Interface. To access the Admin Interface, a
user must have the admin role. The security role provides the privileges to execute functions in
the security.xqy module, which has functions to perform actions such as creating users, creating
roles, and so on. For details on managing security objects programmatically, see Creating and
Configuring Roles and Users and User Maintenance Operations in the Scripting Administrative Tasks
Guide.
To begin, create two roles in MarkLogic Server named engineering and sales respectively.
The engineering role needs to be able to make widgets. You can create an execute privilege with
the name make-widget, and action URI http://widget.com/make-widget to represent that
privilege. The sales role needs to sell widgets,so you create an execute privilege with the name
sell-widget and action URI http://widget.com/sell-widget to represent that privilege.
Note: Names for execute privileges are used only as display identifiers in the Admin
Interface. The action URIs are used within XQuery or JavaScript code to identify
the privilege.
Ron is an engineer in your company so you create a user for Ron and assign the engineering role
to the newly created user. Emily is an account representative so you create a user for Emily and
assign her the sales role.
In your XQuery code, use the xdmp:security-assert function to ensure that only engineers make
widgets and only account representatives sell widgets (if you are using JavaScript, you can
similary call xdmp.securityAssert in your JavaScript function to protect the code). For example:
If Ron is logged into the application and executes the make-widget() function,
xdmp:security-assert("http://widget.com/make-widget", "execute") succeeds since Ron is of
the engineering role which has the execute privilege to make widgets.
If Emily attempts to execute the make-widget function, the xdmp:security-assert function call
throws an exception. You can catch the exception and handle it with a try/catch in the code. If
the exception is not caught, the transaction that called this function is rolled back.
Some functions are common to several protected actions. You can protect such a function with a
single xdmp:security-assert call by providing the appropriate action URIs in a list. For example,
if a user needs to execute the count-widgets function when making or selling widgets, you might
protect the function as follows:
If there is a function that requires more than one privilege before it can be performed, place the
xdmp:security-assert calls sequentially. For example, if you need to be a manager in the sales
department to give discounts when selling the widgets, you can protect the function as follows:
The MarkLogic Server security model has a set of tools you can use to control access to
documents. These authorization tools control creating, inserting into, updating, and reading
documents in a database. This chapter describes those tools and includes the following sections:
• Creating Documents
• Document Permissions
• Default Permissions
• Example—Using Permissions
For example, the screenshot below shows a URI privilege with /widget.com/sales/ as the
protected URI. Any URI with /widget.com/sales/ as the prefix is protected. Users must be part of
the sales role to create documents with URIs beginning with this prefix. In this example, you
need this URI privilege (or a privilege with at least as much authority) to create a document with
the URI /widget.com/sales/my_process.xml.
• any-uri
• unprotected-uri
The any-uri privilege provides the authority to create a document with any URI in the database,
even if the URI is protected with a URI privilege. The unprotected-uri privilege provides the
authority to create a document at any URI in the database except for URIs that are protected with
a URI privilege.
• Read
• Update
• Node-Update
• Insert
• Execute
3.2.1.1 Read
The read capability provides the authority to see the content in the document. Being able to see
the content does not allow you to modify the document.
3.2.1.2 Update
The update capability provides the authority to modify content in the document or delete the
document. However, update does not provide the authority to read the document. Reading the
document requires the read capability. Users with update capability, but not read capability, can
call the xdmp:document-delete and xdmp:document-insert functions successfully. However, node
update functions, such as xdmp:node-replace, xdmp:node-delete, and xdmp:node-insert-after,
cannot be called successfully. Node update functions require a node from the document as a
parameter. If a user cannot read the document, he cannot access the node in the document and
supply it as a parameter.
There is a way to get around the issue with node update functions. The update capability provides
the authority to change the permissions on a document. Therefore, you can use the
xdmp:document-add-permissions function to add a new permission to the document with read
capability for a given role. A user withboth read and update capabilities can call node update
functions succesfully.
3.2.1.3 Node-Update
The node-update capability provides a subset of the update capability, enabling permission to
update nodes within a document. The node-update capability offers finer control of updates when
combined with element level security. The node-update capability covers xdmp:node-replace and
xdmp:node-delete and can also be used in built-ins on properties, including
xdmp:document-add-properties, xdmp:document-set-property, xdmp:document-set-properties
and xdmp:document-remove-properties. Note that if a role has the update capability, it
automatically includes the node-update capability as well.
3.2.1.4 Insert
The insert capability provides a subset of the update capability. The insert capability provides
the authority to add new content to the document. The insert capability by itself does not allow a
user to change existing content or remove an existing document (for example, calls to
xdmp:document-insert and xdmp:document-delete on an existing document fail). Furthermore,
you need read capability on the document to perform actions that use any of the node insert
functions (xdmp:node-insert-before, xdmp:node-insert-after, xdmp:node-insert-child), as
explained above in the description for update. Therefore, a permission with an insert capability
must be paired with a permission with a read capability to be useful.
3.2.1.5 Execute
The execute capability provides the authority to execute application code contained in that
document, if the document is stored in a database which is configured as a modules database.
Users without permissions for the execute capability on a stored module, are not able to execute
that module.
• Explicitly set and remove permissions on a document using the following functions:
• xdmp:document-add-permissions
• xdmp:document-set-permissions
• xdmp:document-remove-permissions
• Implicitly set permissions when the document is created based on the default permissions
of the user who creates the documents. Permissions are applied to a document at document
creation time based on the default permissions of the user who creates the document.
For examples of setting permissions on documents, see “Example—Using Permissions” on
page 26.
For more information about permissions on collections, see Collections and Security in the Search
Developer’s Guide.
If users are creating documents in a database, it is important to configure default permissions for
the roles assigned to that user. Without default permissions, it is easy to create documents that no
users (except those with the admin role) can read, update, or delete.
Suppose that Ron, of the engineering role, is given the task to create a document to describe new
features that will be added to the next version of the widget. Once the document is created, other
users with the engineering role contribute to the document and add the features they are working
on. Ian, of the engineering-manager role, decides that users of the engineering role should only
be allowed to read and add to the document. This enables Ian to control the process of removing
or changing features in the document. To implement this security model, the document should be
created with read and insert permissions for the engineering role, and read and update
permissions for the engineering-manager role.
...
xdmp:document-insert("/widget.com/engineering/features/2017-q1.xml",
<new-features>
<feature>
<name>blue whistle</name>
<assigned-to>Ron</assigned-to>
...
</feature>
...
</new-features>,
(xdmp:permission("engineering", "read"),
xdmp:permission("engineering", "insert"),
xdmp:permission("engineering-manager", "read"),
xdmp:permission("engineering-manager", "update"),
xdmp:permission("engineering-manager", "node-update"))
...
If you specify permissions to the function call explicitly, as shown above, those permissions
override any default permission settings associated with the user (through user settings and role
inheritance).
Default permission settings that apply to a user, either through a role or through the user
definition, are important if you are loading documents using a WebDAV client. When you drag
and drop files into a WebDAV folder, the permissions are automatically set based on the default
permissions of the user logged into the WebDAV client. For more information about WebDAV
servers, see WebDAV Servers in the Administrator’s Guide.
The following screenshot shows a portion of the Admin Interface for the engineering role. It
shows read and insert capabilities being added to the engineering role’s default permissions.
A user’s set of default permissions is additive; it is the aggregate of the default permissions for all
of the user’s role(s) as well as for the user himself. Below is another screenshot of a portion of a
User configuration screen for Ron. It shows read and update capabilities being added to the
engineering-manager role as Ron’s default permissions at the user level.
Note: Ron has the engineering role and does not have the engineering-manager role. A
user does not need to have a certain role in order to specify that role in its default
permission set.
You can also use a hybrid of the two methods described above. Assume that read and insert
capabilities for the engineering role are specified as default permissions for the engineering role
as shown in the first screenshot. However, update and read capabilities are not specified for the
engineering-manager at the user or engineering role level.
Further assume that the following code snippet is executed by Ron. It achieves the desired
objective of giving the engineering-manager role read, update, and node-update capabilities on
the document, and the engineering role read and insert capabilities.
...
xdmp:document-insert("/widget.com/engineering/features/2017-q1.xml",
<new-features>
<feature>
<name>blue whistle</name>
<assigned-to>Ron</assigned-to>
...
</feature>
...
</new-features>,
(xdmp:default-permissions(),
xdmp:permission("engineering-manager", "read")
xdmp:permission("engineering-manager", "update"))
xdmp:permission("engineering-manager", "node-update"))
...
The xdmp:default-permissions function returns Ron’s default permissions (from the role level in
this example) of read and insert capabilities for the engineering role. The read, update, and
node-update capabilities for the engineering-manager role are then added explicitly as function
parameters.
Suppose that Ian, of the engineering-manager role, decides to give users of the sales role read
permission on the document. (He wisely withholds update or insert capability or there will surely
be an explosion of features!) The code snippet below shows how to add permissions to a
document after it has been created.
...
xdmp:document-add-permissions(
"/widget.com/engineering/features/2017-q1.xml",
xdmp:permission("sales", "read"))
...
The update capability is needed to add permissions to a document, and the node-update capability
is needed to update a portion of a document (or node). Therefore, the code snippet only succeed if
it is executed by Ian, or another user of the engineering-manager role. This prevents Ron from
giving Emily, his buddy in sales, insert capability on the document.
But what if the Emily is now the person in sales assigned to the project? Ian has the node-update
capability, so he can call xdmp:node-replace and xdmp:node-delete to modify nodes in a
document. Ian changes the “assigned-to” element in the document using xdmp:node-update.
...
xdmp:node-update("/widget.com/engineering/features/2017-q1.xml",
<new-features>
<feature>
<name>blue whistle</name>
<assigned-to>Emily</assigned-to>
...
</feature>
...
</new-features>,
Changing default permissions for a role or a user does not affect the permissions associated with
existing documents. To change permissions on existing documents, you need to use the
permission update functions. See the documentation for the MarkLogic Built-In Functions in
MarkLogic XQuery and XSLT Function Reference for more details.
MarkLogic Server authenticates users when they access an application. This chapter describes
users and the available authentication schemes, and includes the following sections:
• Users
• Types of Authentication
4.1 Users
A user in MarkLogic Server is the basis for authenticating requests to a MarkLogic application
server. Users are assigned to roles. Roles carry security attributes, such as privileges and default
permissions. Permissions assigned to documents pair a role with a capability, therefore roles are
central to document permissions. Users derive authorization to perform actions from their roles.
You configure users in the Admin Interface, where you assign a user a name, a password, a set of
roles, and a set of default permissions. To see the security attributes associated with a given user,
click on the User:username link in the Admin Interface screen for the given user. For details on
configuring users in the Admin Interface, see the “Security Administration” chapter in the
Administrator’s Guide.
During the initial installation of MarkLogic Server, two users are created. One of the users is an
authorized administrator who has the admin role. During the installation, you are prompted to
specify the username and password for this user. The other user is a user named nobody, which is
created with no roles assigned and is given a password which is randomly generated. For details
about installing MarkLogic Server, see the Installation Guide.
• Basic
• Digest
• Digest-Basic
• Certificate
• Application Level
• Kerberos Ticket
• SAML
4.2.1 Basic
Basic authentication is the typical authentication scheme for web applications. When a user
accesses an application page, she is prompted for a username and password. In basic mode, the
password is obfuscated but not encrypted.
4.2.2 Digest
Digest authentication works the same way as basic, but offers encryption of passwords sent over
the network. When a user accesses an application page, she is prompted for a username and
password.
Note: If you change an App Server from basic to digest authentication, it invalidates all
passwords in the security database. You must then reenter the passwords in the
Admin Interface. Alternatively, you can migrate to digest-basic mode initially,
then switch to digest-only mode once all users have accessed the server at least
once. The first time the user accesses the server after changing from basic to
digest-basic scheme, the server computes the digest password by extracting the
relevant information from the credentials supplied in basic mode.
4.2.3 Digest-Basic
The digest-basic authentication scheme uses the more secure digest scheme whenever possible,
but reverts to basic authentication when needed. Some older browsers, for example, do not
support digest authentication. The digest-basic scheme is also useful if you previously used basic
authentication, but want to migrate to digest. The first time a user accesses the server after
changing from basic to digest-basic authentication scheme, the server computes the digest
password by extracting the relevant information from the credentials supplied in basic mode.
4.2.5 Certificate
Certificate-based authentication requires internal and external users and HTTPS clients to
authenticate themselves to MarkLogic Server via a client certificate, either in addition to, or rather
than a password.
• MarkLogic Server authenticates an internal user via the common name in a certificate.
• MarkLogic Server authenticates an internal user via the distinguished name in a
certificate, by matching the distinguished name to an external name configured for an
internal user.
• MarkLogic Server authenticates an external LDAP user via a certificate subject name,
with internal authorization.
• MarkLogic Server authenticates an external user via a certificate subject name, with
external authorization. User is entirely defined external to MarkLogic.
• MarkLogic Server authenticates via both a client certificate and a username/password.
This provides a greater level of security by requiring that user provide a client certificate
that matches the specified user.
For details on Certificate-based authentication, see “Certificate-based Authentication” on
page 160.
The default user should have the required privileges to at least read the initial page of the
application. In many application scenarios, the user is then given the opportunity to explicitly log
in to the rest of the application from that page. How much of the application and what data a user
can access before explicitly logging in depends on the application and the roles that the default
user is part of. For an example of this type of configuration, see “Using Custom Login Pages” on
page 280.
4.2.8 SAML
When SAML authentication is used, a client requests a resource from MarkLogic Server with no
security context; MarkLogic redirects the authentication request to an Identity Provider. The
Identity Provider prompts the user to login, if necessary, and sends the authentication request back
to MarkLogic Server (the Service Provider) for validation.
• Identity Provider (IDP) authenticates a subject and provides security assertion to service
provider.
• Service Provider (SP) provides access to the resource for a client. MarkLogic Server is a
Service Provider.
MarkLogic Server sends a redirect to the resource. The client requests the resource again with a
security context. MarkLogic Server then authenticates the user using the information from the
authentication request to grant the user access to the requested resource.
The MarkLogic Server includes an extension to the security model called compartment security.
Compartment security allows you to specify more complex security rules on documents.
This chapter describes compartment security and includes the following sections:
• Example—Compartment Security
For example, if a document has read permission for role1 and read permission for role2, a user
who possesses either role1 or role2 can read that document. If those roles have different
compartments associated with them (for example, compartment1 and compartment2, respectively),
then the permissions are checked using AND semantics for each compartment, as well as OR
semantics for each non-compartmented role. To access the document if role1 and role2 are in
different compartments, a user must possess both role1 and role2 to access the document, as well
as a non-compartmented role that has a corresponding permission on the document.
If any permission on a document has a compartment, then the user must have that compartment in
order to access any of the capabilities, even if the capability is not the one with the compartment.
Access to a document requires a permission in each compartment for which there is a permission
on the document, regardless of the capability of the permission. So if there is a read permission
for a role in compartment1, there must also be an update permission for some role in compartment1
(but not necessarily the same role). If you try to add read, insert, node-update, or execute
permissions that reference a compartmented role to a document for which there is no update
permission with the corresponding compartment, the XDMP-MUSTHAVEUPDATE exception is thrown.
You cannot modify an existing role to use a compartment. To add a compartment to a role, you
must delete the role and re-create it with a compartment. If you do re-create a role, any
permissions you have on documents reference the old role (because they use the role ID, not the
role name). So if you want those document permissions to use the new role, you need to update
those documents with new permissions that reference the new role.
To set up the compartment security for this scenario, you create the necessary roles, users, and
documents with the example permissions. You will need access to both MarkLogic Admin
Interface and Query Console.
To run through the example, perform the steps in each of the following sections:
• Create Roles
• Create Users
• Test It Out
1. Create roles named US and Canada and assign each of these roles the country compartment
name. These roles form the country compartment.
2. Create roles named Executive and Employee and assign each of these roles the
job-function compartment name. These roles form the job-function compartment.
3. Create roles named top-secret and unclassified and assign each of these roles the
classification compartment name. These roles form the classification compartment.
User Roles
Gary can-read
1. You can use XQuery code similar to the following example to insert the sample
documents into a database of your choice. This code adds a document with a URI of
doc1.xml, containing one <a> element and a set of five permissions.
xdmp:permission("top-secret", "read"),
xdmp:permission("top-secret", "update")))
The doc1.xml document can only be read by Don because the permissions designate all
three compartments and Don is the only user with a role in all three of the necessary
compartmented roles Executive, US, and top-secret, plus the basic can-read role.
2. Create the rest of the sample documents changing the sample code as needed. You need to
change the document URI and the text to correspond to doc2.xml, doc3.xml, doc4.xml, and
doc5.xml and modify the permissions for each document as suggested in the table in
“Create the Documents and Add Permissions” on page 38.
For simplicity, this sample query uses xdmp:eval and xdmp:user to execute a query in the context
of each different user. Modify the document URI and the user name to verify the permissions until
you understand how the compartment security logic works. If you added the roles, users, and
documents as described in this scenario, the query results should match the table in “Create the
Documents and Add Permissions” on page 38.
xdmp:eval('fn:doc("/doc1.xml")', (),
<options xmlns="xdmp:eval">
<user-id>{xdmp:user("Don")}</user-id>
</options>)
MarkLogic Server includes element level security, an addition to the security model that allows
you to specify more complex security rules on specific elements in documents. The feature also
can be applied to JSON properties in a document. Using element level security, parts of a
document may be concealed from users who do not have the appropriate roles to view them.
Users without appropriate permissions cannot view the secured element or JSON property using
XPath expressions or queries. Element level security can conceal the XML element (along with
properties and attributes) or JSON property so that it does not appear in any searches, query plans,
or indexes, unless accessed by a user with a role included in query rolesets.
Element level security protects elements or JSON properties in a document using a protected path,
where the path to an element or property within the document is protected so that only roles
belonging to a specific query roleset can view the contents of that element or property. Only users
with specific roles that match the specific query roleset can view the elements or properties
protected by element level security. You can set protection with element level security to conceal
a document’s sensitive contents in real time, and also control which contents can be viewed and/or
updated by other users.
Note: See “Interactions with Other MarkLogic Features” on page 105 for details about
using element level security with SQL and semantic queries.
The protected paths are in the form of XPath expressions (not fields) that specify that an XML
element or JSON property is part of a protected path. You will need to install or upgrade to
MarkLogic 9.0-1 or later to use element level security.
This chapter describes element level security and includes the following topics:
Element level security uses query rolesets to determine which elements will appear in query
results. If a query roleset does not exist with the associated role that has permissions on the path,
the role cannot view the contents of that path.
Note: A user with admin privileges can access documents with protected elements by
using fn:doc to retrieve documents (instead of using a query). To see protected
elements as part of query results, however, a user needs the appropriate role(s).
Description: For a MarkLogic application used by a department, certain parts of documents may
be hidden so that only users with the correct role may view or update those parts of the document.
Users without the proper role will not be able to see the element concealed by the protected path.
To set up the element level security for this scenario, you will follow these steps:
• Run the Example Queries - Query the documents as different users to see the different
results
• Additional Examples - More query examples using XQuery and Server-Side JavaScript
3. On the Role Configuration page, enter the information for the first role:
role name: els-role-1
description: els role 1
5. Repeat these steps to create the second role (els-role-2, els role 2)
See Roles in the Administrator’s Guide for details about creating roles.
3. On the User Configuration page, enter the information for the first user:
user name: els-user-1
description: ELS user 1
password: <password>
Add this user to the first role that you created (els-role-1):
1. Scroll down the User Configuration page until you see the els-role-1 role you just
created.
2. Click the box next to els-role-1 to assign the role to the user.
Repeat these steps to create a second user and third user (els-user-2, ELS user 2, els-user-3, ELS
user 3). Assign roles to the users as shown. ELS user 3 will not have an assigned role.
Note: Admin users must be added to a role in order to view the results of a query on
protected paths that involve concealed elements.
xdmp:document-insert("test1.xml",
<root>
<bar baz="1" attr="test">abc</bar>
<bar baz="2">def</bar>
<bar attr="test1">ghi</bar>
</root>,
(xdmp:permission("els-role-1", "read"), xdmp:permission("els-role-2",
"read"), xdmp:permission("els-role-1", "update"),
xdmp:permission("els-role-2", "update")))
,
xdmp:document-insert("test2.xml",
<root>
<reg expr="this is a string">1</reg>
<reg>2</reg>
</root>,
(xdmp:permission("els-role-1", "read"), xdmp:permission("els-role-2",
"read"), xdmp:permission("els-role-1", "update"),
xdmp:permission("els-role-2", "update")))
,
xdmp:document-insert("test1.json", object-node {
"foo" : 1, "bar" : "2", "baz" : object-node
{"bar" : array-node {3,4}, "test" : 5}
},
(xdmp:permission("els-role-1", "read"), xdmp:permission("els-role-2",
"read"), xdmp:permission("els-role-1", "update"),
xdmp:permission("els-role-2", "update")))
The code example adds permissions to the documents for els-role-1 and els-role-2 while
inserting them into the database.
To start, check for any existing protected paths using this query in the Query Console:
fn:collection("http://marklogic.com/xdmp/protected-paths")
This will return an empty sequence if there are no protected paths. If there are protected paths,
information about those protected paths will be displayed, including the path ID, the path
expression, the permissions, and roles associated with that path.
Using the Admin UI, add protected paths with permissions for els-user-2. To add the protected
path from the Admin UI:
3. Enter the path expression for the first path (/root/bar[@baz=1]),with read permissions for
els-role-2.
4. Click ok when you are done. Since there are no namespaces in these examples, the prefix
and namespace are not required for the protected path.
For examples using namespaces and prefixes as part of a protected path, see “Namespaces as Part
of a Protected Path” on page 70.
Repeat this for two additional protected paths, “test” and “/root/reg[fn:matches(@expr,
'is')]”.
The three protected paths with read permissions for els-role-2 are:
/root/bar[@baz=1]
test
/root/reg[fn:matches(@expr, 'is')]
Alternatively, you can add these protected paths with the Query Console. Use this code to add
these protected paths with permissions for els-user-2 to the Security database:
sec:protect-path("/root/bar[@baz=1]", (),
(xdmp:permission("els-role-2", "read"))),
sec:protect-path("test", (), (xdmp:permission("els-role-2", "read"))),
sec:protect-path("/root/reg[fn:matches(@expr, 'is')]", (),
(xdmp:permission("els-role-2", "read")))
Now add query rolesets for these documents. In the Query Console, run this code to add query
rolesets for els-user-2:
In most cases you will want to use the helper functions (xdmp:database-node-query-rolesets and
xdmp:node-query-rolesets) to create query rolesets. The helper function automatically created
the query rolesets based on the protected paths you have set. See “Helper Functions for Query
Rolesets” on page 82 for more information. To understand more about query rolesets, see “Query
Rolesets” on page 75.
You can also can add query rolesets manually with XQuery in the Query Console if you only have
a few query rolesets to add. Use this code, checking to be sure you are running it against the
Security database:
Note: Adding query rolesets does not trigger reindexing, since it is only used by queries.
Check for query rolesets in the Security database using the Query Console:
fn:collection("http://marklogic.com/xdmp/query-rolesets")
=>
Returns details about query rolesets in the Security database.
fn:collection("http://marklogic.com/xdmp/protected-paths")
=>
Returns details about protected paths in the Security database.
The els-role-2 can now see the elements in these paths, but the els-user-1 cannot:
test
/root/bar[@baz=1]
/root/reg[fn:matches(@expr, 'is')]
Note: These examples assume that you have access permissions for both the MarkLogic
Admin Interface and the Query Console.
xdmp:eval(
'cts:search(fn:doc(), cts:word-query("def"), "unfiltered"),
"-----------------------------------------------------",
cts:search(fn:doc(), cts:element-attribute-word-query(xs:QName("bar"),
xs:QName("attr"), "test"), "unfiltered"),
"----------------------------------------------------",
cts:search(fn:doc(), cts:json-property-value-query("bar", "2")),
"-----------------------------------------------------",
cts:search(fn:doc(), cts:element-attribute-word-query(xs:QName("reg"),
xs:QName("expr"), "is"), "unfiltered")',
(),
<options xmlns="xdmp:eval">
<user-id>{xdmp:user("els-user-1")}</user-id>
</options>
)
=>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<bar baz="2">def</bar>
<bar attr="test1">ghi</bar>
</root>
-----------------------------------------------------
----------------------------------------------------
{
"foo": 1,
"bar": "2",
"baz": {
"bar": [
3,
4
]
}
}
-----------------------------------------------------
Notice that in the first query, all of the documents are returned, but the elements with protected
paths are missing from the content:
In the second query, the document does not show up at all because the query is searching on a
protected path that els-user-1 is not allowed to see (protected path “/root/bar[@baz=1]”).
Note: If you are getting different results, check to see that you have set up your user roles
correctly and added the query rolesets to the Security database.
Now, modify the query to use the context of the els-user-2 and run the queries again:
xdmp:eval(
'cts:search(fn:doc(), cts:word-query("def"), "unfiltered"),
"-----------------------------------------------------",
cts:search(fn:doc(), cts:element-attribute-word-query(xs:QName("bar"),
xs:QName("attr"), "test1"), "unfiltered"),
"----------------------------------------------------",
cts:search(fn:doc(), cts:json-property-value-query("bar", "2")),
"-----------------------------------------------------",
cts:search(fn:doc(), cts:element-attribute-word-query(xs:QName("reg"),
xs:QName("expr"), "is"), "unfiltered")',
(),
<options xmlns="xdmp:eval">
<user-id>{xdmp:user("els-user-2")}</user-id>
</options>
)
=>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<bar baz="1" attr="test">abc</bar>
<bar baz="2">def</bar>
<bar attr="test1">ghi</bar>
</root>
-----------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<root>
<bar baz="1" attr="test">abc</bar>
<bar baz="2">def</bar>
<bar attr="test1">ghi</bar>
</root>
----------------------------------------------------
{
"foo": 1,
"bar": "2",
"baz": {
"bar": [
3,
4
],
"test": 5
}
}
-----------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<root>
<reg expr="this is a string">1</reg>
<reg>2</reg>
</root>
This time all of the documents are returned, along with the protected elements. Notice that the one
document is returned twice; two different queries find the same document.
Run the query one more time using the xdmp:eval pattern as els-user-3 and notice that none of
the documents are returned because els-user-3 does not have the basic permissions to read the
documents.
xdmp:eval(
'cts:search(fn:doc(), cts:word-query("def"), "unfiltered"),
"-----------------------------------------------------",
cts:search(fn:doc(), cts:element-attribute-word-query(xs:QName("bar"),
xs:QName("attr"), "test1"), "unfiltered"),
"----------------------------------------------------",
cts:search(fn:doc(), cts:json-property-value-query("bar", "2")),
"-----------------------------------------------------",
cts:search(fn:doc(), cts:element-attribute-word-query(xs:QName("reg"),
xs:QName("expr"), "is"), "unfiltered")',
(),
<options xmlns="xdmp:eval">
<user-id>{xdmp:user("els-user-3")}</user-id>
</options>
)
=>
-----------------------------------------------------
-----------------------------------------------------
-----------------------------------------------------
Because els-user-3 does not have document level permissions, no documents are returned. You
can use document level permissions along with element level security for additional security. See
“Combining Document and Element Level Permissions” on page 91 for more information.
Now unprotect the paths and run the previous query again without the protected paths to see
difference in output. First unprotect the paths:
sec:unprotect-path("/root/bar[@baz=1]", ()),
sec:unprotect-path("test", ()),
sec:unprotect-path("/root/reg[fn:matches(@expr, 'is')]", ())
Note: Adding or unprotecting protected paths will trigger reindexing. After unprotecting
elements, you must wait for reindexing to finish.
Unprotecting the paths does not remove them from the database. You will still see the protected
paths in the Admin UI or when you run
fn:collection("http://marklogic.com/xdmp/protected-paths") against the Security database.
But you will be able to see the whole document once the protected paths are unprotected, if you
have document permissions for the document. See “Unprotecting or Removing Paths” on page 71
for more details.
Look through the code examples and run the queries using the xdmp:eval pattern to change users.
Run the queries in the context of the different users to better understand how the element level
security logic works.
Notice that all of the documents are returned, but the elements with protected paths are missing
from the content:
In the second query, the document does not show up at all because the query is searching on a
protected path that els-user-1 is not allowed to see (protected path “test”).
Note: If you are getting different results, check to see that you have set up your user roles
correctly and added the query rolesets to the Security database.
Now, modify the query to use the context of the els-user-2 and run the queries again:
This time all of the documents are returned, along with the protected elements. Notice that the one
document is returned twice; two different queries will find the same document.
Run the query one more time using the xdmp:eval pattern as els-user-3 and notice that none of
the documents are returned because els-user-3 does not have the basic permissions to read the
documents.
Because els-user-3 does not have document level permissions, no documents are returned. You
can use document level permissions along with element level security for additional security. See
“Combining Document and Element Level Permissions” on page 91 for more information.
Now unprotect the paths and run the previous query again without the protected paths to see
difference in output. Unprotect the paths :
security.unprotectPath('/root/bar[@baz=1]', []);
security.unprotectPath('test', []);
security.unprotectPath('/root/reg[fn:matches(@expr, "is")]', []);
Unprotecting the paths does not remove them from the database. You will still see the protected
paths in the Admin UI or when you run
fn:collection("http://marklogic.com/xdmp/protected-paths") against the Security database.
But if you are els-role-1 or els-role-2, you will be able to see the whole document once the
protected paths are unprotected, if you have document permissions for the document (i.e.
els-role-1 and els-role-2, but not els-role-3). See “Unprotecting or Removing Paths” on
page 71 for more details.
Look through the code examples and run the queries using the xdmp.eval pattern. Run the queries
in the context of the different users to better understand how the element level security logic
works.
These examples make use of the users and roles set up in the earlier example. (See
“Example—Element Level Security” on page 41 for details.) The first example shows hierarchies
of permissions (top-secret, secret, and unclassified) in a document. The second example shows a
slightly different way of protecting content with attributes. The example queries can be done in
using XQuery or JavaScript.
xdmp:document-insert(
"hierarchy.xml", <root>
<title>Title of the Document</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of the document contents
<secret>Only role having "secret" can read this
<top-secret>Only role having "top-secret" can read this
</top-secret>
</secret>
</executive-summary>
<content>Contents of document
<top-secret>Only role with "top-secret" can read this
<secret>Only role with "secret" can read this</secret>
</top-secret>
Unclassified content
</content>
</root>,
(xdmp:permission("els-role-1", "read"), xdmp:permission("els-role-2",
"read"),
xdmp:permission("els-role-1", "update"), xdmp:permission("els-role-2",
"update")))
Add protected paths with permissions for roles to the Security database:
=>
Returns two numbers representing the protected paths
Test this example in the context of the different els-users. This first query uses the context of
els-user-1:
xdmp:eval('fn:doc("hierarchy.xml")',(),
<options xmlns="xdmp:eval">
<user-id>{xdmp:user("els-user-1")}</user-id>
</options>
)
=>
<root>
<title>Title of the Document
</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of contents
</executive-summary>
<content>Contents of document
<top-secret>Only role with "top-secret" can read this</top-secret>
Unclassified content</content>
</root>
The “top-secret” role (els-user-1) cannot see the elements marked with “secret”, only those that
have no protected paths or marked with the protected path for “top-secret”. Next, run the query in
the context of els-user-2:
xdmp:eval('fn:doc("hierarchy.xml")',(),
<options xmlns="xdmp:eval">
<user-id>{xdmp:user("els-user-2")}</user-id>
</options>
)
=>
<root>
<title>Title of the Document</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of contents
<secret>Only role having "secret" can read
this</secret></executive-summary>
<content>Contents of document
Unclassified content</content>
</root>
Notice that even though in the original document there is an element “secret” within the
“top-secret” contents of the document, it is a child of the “top-secret” element and therefore
hidden to users without the “top-secret” role.
The els-user-1 (“top-secret”) cannot see the “secret” content unless you add the els-role-2 to
els-user-1. When you add the role, els-user-1 will be able to see both the “secret” and
“top-secret” elements.
If you run the query as els-user-3, the query returns an empty sequence. The els-user-3 from
the previous query does not have permission to even see the document.
(: unprotect the protected paths -> run against the Security database
:)
sec:unprotect-path("secret", ()),
sec:unprotect-path("top-secret", ())
Note: Adding or unprotecting protected paths will trigger reindexing. After unprotecting
elements, you must wait for reindexing to finish.
Create a new role els-role-3 and add els-user-3 to the role. See “Create Roles” on page 42 and
“Create Users and Assign Roles” on page 42 for details.
xdmp:document-insert(
"attributes.xml", <root>
<title>Document Title</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of contents
<info attr="EU">Only role with "EU" attribute can read this summary
</info>
<info attr="UK">Only role with "UK" attribute can read this summary
</info>
<info attr="US">Only role with "US" attribute can read this summary
</info>
</executive-summary>
<content>Contents of document
Unclassified content
<notes>
<info attr="EU">Only role with "EU" attribute can read this
content</info>
<info attr="UK">Only role with "UK" attribute can read this
content</info>
<info attr="US">Only role with "US" attribute can read this
content</info>
</notes>
</content>
</root>,
(xdmp:permission("els-role-1", "read"), xdmp:permission("els-role-2",
"read"), xdmp:permission("els-role-3", "read"),
xdmp:permission("els-role-1", "update"), xdmp:permission("els-role-2",
"update"), xdmp:permission("els-role-3", "update")))
Add the new protected paths with permissions for roles to the Security database:
(: add new protected paths -> run against the Security database :)
Notice that the protected paths include attributes in the document elements. Also note that
els-role-3 has permissions for two protected paths (@attr, ‘UK’ and @attr, ‘EU’).
Run this next query, similar to the previous queries, this time looking for the attributes.xml
document. First query in the context of els-user-1 who has a role that can see the “US” attribute:
xdmp:eval('fn:doc("attributes.xml")',(),
<options xmlns="xdmp:eval">
<user-id>{xdmp:user("els-user-1")}</user-id>
</options>
)
=>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>Document Title</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of contents
<info attr="US">Only role having "US" attribute can read this
summary</info>
</executive-summary>
<content>Contents of document
Unclassified content
<notes>
<info attr="US">Only role having "US" attribute can read this content
</info>
</notes>
</content>
</root>
Next modify the query to run in the context of els-user-2, who has a role that can see the “UK”
attribute:
xdmp:eval('fn:doc("attributes.xml")',(),
<options xmlns="xdmp:eval">
<user-id>{xdmp:user("els-user-2")}</user-id>
</options>
)
=>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>Document Title</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of contents
<info attr="UK">Only role having "UK" attribute can read this summary
</info>
</executive-summary>
<content>Contents of document
Unclassified content
<notes>
<info attr="UK">Only role having "UK" attribute can read this
content</info>
</notes>
</content>
</root>
xdmp:eval('fn:doc("attributes.xml")',(),
<options xmlns="xdmp:eval">
<user-id>{xdmp:user("els-user-3")}</user-id>
</options>
)
=>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>Document Title</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of contents
<info attr="EU">Only role having "EU" attribute can read this summary
</info>
<info attr="UK">Only role having "UK" attribute can read this summary
</info>
</executive-summary>
<content>Contents of document
Unclassified content
<notes>
<info attr="EU">Only role having "EU" attribute can read this content
</info>
<info attr="UK">Only role having "UK" attribute can read this content
</info>
</notes>
</content>
</root>
The els-user-3 has protected path permissions on both elements with the “EU” info attribute and
the elements with the “UK” info attribute, so the els-user-3 can see both elements. If you are
getting different results, check to be sure that you created an els-role-3 and added the
els-user-3 to that role.
Note: If you run the query in the context of the admin user, you will be able to see the
entire document because the query is using fn:doc.
Use this JavaScript code to insert this document (with permissions) into the Documents database:
declareUpdate();
var perms = [xdmp.permission("els-role-1", "read"),
xdmp.permission("els-role-2", "read"),
xdmp.permission("els-role-1", "update"), xdmp.permission("els-role-2",
"update")
];
xdmp.documentInsert(
"hierarchy.xml", xdmp.unquote(`
<root>
<title>Title of the Document</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of the document contents
<secret>Only role having "secret" can read this
<top-secret>Only role having "top-secret" can read this
</top-secret>
</secret>
</executive-summary>
<content>Contents of document
<top-secret>Only role with "top-secret" can read this
<secret>Only role with "secret" can read this</secret>
</top-secret>
Unclassified content
</content>
</root>
`), {permissions: perms})
Add protected paths with permissions for roles to the Security database:
declareUpdate();
var security = require('/MarkLogic/security.xqy');
Test this example in the context of the different els-users. This query uses the context of
els-user-1:
xdmp.eval("fn.doc('hierarchy.xml')", null,
{
"userId" : xdmp.user("els-user-1")
})
=>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>Title of the Document</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of the document contents
</executive-summary>
<content>Contents of document
Unclassified content
</content>
</root>
The “top-secret” role (els-user-1) cannot see the elements marked with “secret”, only those that
have no protected paths or marked with the protected path for “top-secret”. Next, run the query in
the context of els-user-2:
xdmp.eval("fn.doc('hierarchy.xml')", null,
{
"userId" : xdmp.user("els-user-2")
})
=>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>Title of the Document</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of the document contents
Unclassified content
</content>
</root>
Notice that even though in the original document, there is an element “secret” within the
“top-secret” contents of the document, it is a child of the “top-secret” element and therefore
hidden to users without the “top-secret” role.
The els-user-1 (“top-secret”) cannot see the “secret” content unless you add the els-role-2 to
els-user-1. When you add the role, els-user-1 will be able to see both the “secret” and
“top-secret” elements.
If you run the query as els-user-3, the query returns an empty sequence. The els-user-3 from
the previous query does not have permission to even see the document.
declareUpdate();
var security = require('/MarkLogic/security.xqy');
security.unprotectPath('secret', []),
security.unprotectPath('top-secret', [])
Create a new role els-role-3 and add els-user-3 to the role. See “Create Roles” on page 42 and
“Create Users and Assign Roles” on page 42 for details.
// insert document and permissions -> run this against the Documents
database
declareUpdate();
var perms = [xdmp.permission("els-role-1", "read"),
xdmp.permission("els-role-2", "read"),
xdmp.permission("els-role-3", "read"), xdmp.permission("els-role-1",
"update"),
xdmp.permission("els-role-2", "update"), xdmp.permission("els-role-3",
"update")
];
xdmp.documentInsert(
"attributes.xml", xdmp.unquote(`
<root>
<title>Document Title</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of contents
<info attr="EU">Only role with "EU" attribute can read this summary
</info>
<info attr="UK">Only role with "UK" attribute can read this summary
</info>
<info attr="US">Only role with "US" attribute can read this summary
</info>
</executive-summary>
<content>Contents of document
Unclassified content
<notes>
<info attr="EU">Only role with "EU" attribute can read this
content</info>
<info attr="UK">Only role with "UK" attribute can read this
content</info>
<info attr="US">Only role with "US" attribute can read this
content</info>
</notes>
</content>
</root>
`), {permissions: perms})
Add the new protected paths with permissions for roles to the Security database:
// add new protected paths -> run against the Security database
declareUpdate();
var security = require('/MarkLogic/security.xqy');
security.protectPath("//info[fn:matches(@attr, 'US')]",
[],[xdmp.permission("els-role-1","read", "element")]),
security.protectPath("//info[fn:matches(@attr, 'UK')]",
[],[xdmp.permission("els-role-2", "read", "element"),
xdmp.permission("els-role-3", "read", "element")]),
security.protectPath("//info[fn:matches(@attr, 'EU')]", [],
[xdmp.permission("els-role-3", "read", "element")])
=>
Returns one number representing the protected paths
Run the same queries as before, first in the context of els-user-1, who has a role that can see the
“US” attribute:
xdmp.eval("fn.doc('attributes.xml')", null,
{
"userId" : xdmp.user("els-user-1")
});
=>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>Document Title</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of contents
<notes>
<info attr="US">Only role with "US" attribute can read this
content</info>
</notes></content>
</root>
Next modify the query to run in the context of els-user-2,who has a role that can see the “UK”
attribute
xdmp.eval("fn.doc('attributes.xml')", null,
{
"userId" : xdmp.user("els-user-2")
});
=>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>Document Title</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of contents
<notes>
xdmp.eval("fn.doc('attributes.xml')", null,
{
"userId" : xdmp.user("els-user-3")
});
=>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>Document Title</title>
<summary>Summary of document contents</summary>
<executive-summary>Executive summary of contents
The els-user-3 has protected path permissions on both elements with the “EU” info attribute and
the elements with the “UK” info attribute. So that user can see both elements.
Note: If you run the query in the context of the admin user, you will be able to see the
entire document because the query is using fn.doc.
• Set up roles
• Create users and assign roles
• Add or update documents with permissions for users
• Add protected paths for elements in documents, by inserting the protected paths into the
Security database
• Add the query rolesets to the Security database
Configuring the query rolesets is a task for the administrator. There are two helper functions to
help configure query rolesets. The helper function xdmp:database-node-query-rolesets is used
for querying documents already in your database to discover existing query rolesets, while
xdmp:node-query-rolesets is used to query for protected paths in documents as they are being
loaded into the database. See “APIs for Element Level Security” on page 99 for more
information. You can configure element level security using the Admin UI, using XQuery, or by
using REST.
Note: The number of protected paths that you set on a single element may impact
performance. One or two protected paths on an element will have no discernable
impact (less than 5% in our testing), 10 or so protected paths may have some
impact (around 10%), but setting 100 or so protected paths on a single element will
cause severe and noticeable impact on performance.
• Protected Paths
• Query Rolesets
For performance and security reasons, you can only use a subset of XPath for defining protect
paths. For details, see Element Level Security in the XQuery and XSLT Reference Guide.
Note: The read, update, and insert permissions for an element are checked separately.
For instance, if there are permissions for read, but no permissions for update or
insert, there is no control for update or insert on that element. If there are no
permissions on an element, anyone can read that element, given that they have the
proper document level permssions.
For more about update permissions with element level security, see the table in the section
“Document and Element Level Permissions Summary” on page 95.
sec:security-path-namespace($prefix, $namespace-uri)),
(xdmp:permission($role, "read"))
)
For simple cases, you can also specify a namespace as part of a protected path when configuring
protected paths in the Admin UI.
You can also specify a namespace when using the helper functions
xdmp:database-node-query-rolesets and xdmp:node-query-rolesets. See page “Helper
Functions for Query Rolesets” on page 82 for more info.
Removing protected paths is a two step process. First you must unprotect the path, and then you
can remove it.
Note: You must first unprotect a path before removing it to trigger the reindexer. Since
query rolesets changes don’t require reindexing, there is no need for the separate
step of unprotecting before removing a query roleset.
1. Navigate to Protected Path Configuration by clicking Security and then Protected Paths in
the left tree menu.
3. On the Protected Path Configuration page there are two buttons; an unprotect button and a
delete button (greyed out).
When you have unprotected the protected paths, you’ll see the protected paths on the Summary
page, but no permissions are associated with the paths.
To remove a path, you will need to first unprotect the path. See “Unprotecting or Removing
Paths” on page 71
1. After unprotecting the path, go back to the Protected Path Configuration page. Notice that
the delete button is now available and the unprotect button is greyed out.
The deleted path no longer appears on the Summary page of protected paths.
Note: Adding, unprotecting, or changing permissions for protected paths will trigger
reindexing of the relevant databases. Having too many unprotected paths for your
database can affect performance. Best practice is to delete unprotected paths when
you no longer need them. Be sure to let the reindexing triggered by unprotecting
finish before you delete the paths.
In this example, an insurance company has a schema that groups policy information to control
access to the information, making it easier to protect client information and policy information by
role (US Read, ID_Read, Compliance, and Risk):
"policy": {
"access": "US Read",
"client": {
"access": "ID_Read",
"name": "Paul",
"address": "999 Broadway St",
"phone": "323-344-1555",
"country": "US",
"ssn4digits": "5664"
}
,
"clientSSN": {
"access": "Compliance",
"ssn": "999-999-5664"
}
,
"clientIncome": {
"access": "Risk",
"income": "44,4444"
}
,
"info": {
"access": "Risk",
"propertyType": "Home",
"premium": 432,
"assetValue": 750000,
"currency": "Dollar"
}
}
Different users would be able to see different parts of the data: the Call Center might have the
ID_Read role, the Financial Risk Researcher might have the Risk role, and a Compliance Admin
might have the ID_Read, Risk, and Compliance roles. Each of these would all need to have the US
Read role as well.
If you don’t have control of the schema and your document data is in various formats, you can
leverage Entity Services as a way to improve performance. You can use entity services to create
an entity that groups multiple elements under a single node and then use a single protected path on
that node. See Introduction to Entity Services in the Entity Services Developer’s Guide for
information about creating an entity that links to the source document and protecting both.
Let’s use an example. Say you have a protected path defined as the following:
sec:protect-path("/root/bar[@baz=1]", (),
(xdmp:permission("els-role-2", "read")))
<root>
<bar baz=1>Hello</bar>
</root>
When MarkLogic parses the document, it sees that the word “Hello” is inside the element <bar>
that matches the protected path definition (since bar is under root and has an attribute baz=1). So
instead of simply putting the term “Hello” into the universal index, it combines the term “Hello”
and the permission information in the protected path (in this case, basically the role name
“els-role-2”) into one term and puts this new term into the universal index.
Suppose then you run a search with a query cts:word-query("Hello") with a user that has the
els-role-2 role. The query must know this new term to find the document. The query already
knows the word “Hello” but how would it know the permission information in the protected path?
This is where the query rolesets are used. You configure query rolesets (with just els-role-2 in
this example) and then the query compares that query roleset with the caller’s role. If the caller’s
role “matches” the query rolesets, the query will combine that information with the word “Hello”
to generate the term, which matches the term put into the universal index by MarkLogic.
Query rolesets are made up of roles. There can be any number of roles in a roleset, as long as there
are no duplicates. There can be multiple query rolesets in a database.
Query rolesets are required for element level security to work. You may ask why not just get the
query rolesets information automatically from the protected paths when you configure
sec:protect-path to avoid the manual configuration of query rolesets. For this simple example
this seems practical, but in the real world it is not uncommon to have multiple protected paths that
match the same node or element. Some use cases will have 1000s of protected paths but only 100s
of query rolesets. The indexer side of MarkLogic often needs to combine multiple query rolesets
to create the term.
There is no way for the query side to derive that information from the protected path
configuration, since whether a node element matches a protected path is based on the “value” of
the node. And the query side doesn’t know the value of a node. There is no way for the query side
to know what subsets of all the configured protected paths need to be taken into consideration
when creating the query term. Since enumerating all possible combinations of the roles used in all
protected paths is not practical, MarkLogic leaves query rolesets configuration (creating and
inserting the query rolesets into the Security database) to the adminstrator.
<root>
<content>Contents of document
<top-secret>Only role with "top-secret" can read this
<secret>Only role with "secret" can read this</secret>
</top-secret>
Unclassified content
</content>
</root>
A user with permissions on only the protected path for “secret” can’t see “secret” content unless
the user also had permissions for the protected path for “top-secret” because the “secret” node is a
child of the “top-secret” parent node.
<root>
<foo a=1 b=2 c=3>Hello</foo>
</root>
It is possible to define three different protected paths that all match the foo element, overlapping
each other:
MarkLogic will still create just one term for “Hello”, which is the combination of the word and
the query rolesets ((“els-role-1”),(“els-role-2”),(“els-role-3”)).
Note: In MarkLogic 9.0-2 query rolesets have been simplified and optimized. Existing
documents with query rolesets configured in 9.0-1 will still be protected in 9.0-2.
To take advantage of the optimization however, you need to reindex your
documents and regenerate your query rolesets using the helper functions (“APIs
for Element Level Security” on page 99). It is highly recommended that you
reindex any protected documents already in your database and regenerate your
query rolesets, since documents may be reindexed by another operation, which
may cause a mismatch between the documents and the query rolesets. See
“Algorithm That Determines Which Query Rolesets to Use” on page 101 for
examples and more details.
If you only have one protected path that matches foo in the above example but with three roles,
like this:
sec:protect-path("//foo", (), (
xdmp:permission("els-role-1", "read"),
xdmp:permission("els-role-2", "read"),
xdmp:permission("els-role-3", "read")))
let $roleset1 :=
sec:query-roleset(("els-role-1","els-role-2","els-role-3"))
return
sec:add-query-rolesets(sec:query-rolesets($roleset1))
When you are starting to configure and use element level security, the two query rolesets helper
functions, xdmp:database-node-query-rolesets and xdmp:node-query-rolesets can simplify the
process of setting up your query rolesets. These functions can be used for configuring query
rolesets either for documents in the database, or for documents during ingestion. See “Helper
Functions for Query Rolesets” on page 82 for more information.
A protected path set is an optional string that represents the name of a set is associated with a
protected path. A path that has no “set name” can be seen as a “degenerated form” of a set. The
diagram below shows how permissions from paths in the same set are ORed, while permissions
between sets are ANDed.
The set information (the name) is simply a “tag” on the protected path definition, not a separate
document in the Security database.
Using protected paths, MarkLogic element level security allows multiple protected paths covering
the same element with an AND relationship among their permissions. This models a multiple
security markings (for example @classification and @releasableTo) situation well. For the
element above, two protected paths may be defined:
Note that the value of @releasableTo is a list of country codes, with each mapping to a role. A
user with any of the “country roles” is allowed to read the element. The challenge is that a list can
contain an arbitrary combination of country codes (total 200+). The above approach would
require a user to define one protected path for each of the possible combinations, which may lead
to a very large number of protected paths.
Note: Note that defining the following protected paths won’t satisfy the requirement
because the permissions among the paths are ANDed, not ORed.
The following example shows the benefit of the path set concept more clearly. Consider the
following elements to be protected:
Without using protected path sets, the following protected paths would need to be defined to
protect the elements above:
With protected path sets, only these protected paths are needed:
The total number of protected paths required for the @releasableTo attribute is reduced from 7 to
3 using the SetReleasableTo protected path set.
In real world systems, the total number of possible country codes for these examples are more
than 200, which leads to millions of possible combinations. So with protected path sets, the
number of required protected paths can be reduced from millions to just a couple of hundred for
the @releasableTo use case.
For xdmp:database-node-query-rolesets, the built-in returns a sequence of query rolesets that are
required for proper querying of any given database nodes where element level security is in place
on a document already in the database.
=>
<query-rolesets xml:lang="zxx"
xmlns="http://marklogic.com/xdmp/security">
<query-roleset>
<role-id>12006351629398052509
</role-id>
</query-roleset>
</query-rolesets>
To find the name of this role ID, use this query in the Query Console:
sec:get-role-names((12006351629398052509))
=>
<sec:role-name
xmlns:sec="http://marklogic.com/xdmp/security">els-role-2</sec:role-
name>
The unconfigured option for xdmp:database-node-query-rolesets will return only those query
rolesets that are not configured, meaning these query rolesets are not in the Security database yet
(you have not configured them yet). The all option returns all query rolesets, even if they are
already configured.
You can find existing or yet-to-be-configured query rolesets for documents being loaded into the
database using xdmp:node-query-rolesets. This built-in returns a sequence of query rolesets that
are required for proper querying with element level security if the node is inserted into the
database with the given document-insert options. This built-in also comes with the unconfigured
option and the all option, and works the same as the xdmp:database-node-query-rolesets
built-in.
A typical workflow would call this function and add each query rolesets through the
sec:add-query-rolesets function before inserting the document into the database, so that the
document can be correctly queried with element level security as soon as the document is
inserted.
xdmp:node-query-rolesets(
"/example.xml",
<foo>aaa</foo>,
<options xmlns="xdmp:document-insert">
<permissions>
{xdmp:permission("role1","read"),xdmp:permission("role2","read")}
</permissions>
</options>)
To run this built-in you need to have the security role privileges.
element sec:permission {
$p/*,
sec:get-role-names($p/sec:role-id)
}
};
You will only be able to see the protected paths for elements that you as the user would have
permission to see. For example if you had role1 and the protected path was associated with role2,
role1 would not be able to see those paths.
3. Enter the information for the protected path: the path expression, the prefix and
namespace, and the role name and capabilities for the permissions.
3. Add the roles (els-role-1 and els-role-2) for the query roleset, separated by commas.
• Set up roles
• Create users and assign roles
• Insert documents with permissions
• Add the query rolesets to the Security database
• Add protected paths for elements in documents, by inserting the protected paths into the
Security database
For example:
To manually set up just a few query rolesets, use the sec:add-query-rolesets command using
XQuery.
(: add a few query rolesets => run against the Security database :)
For example:
This example uses a second parameter to set a protected path on the example path namespace.
GET:/manage/v2/security/properties
This returns:
<security-properties xmlns="http://marklogic.com/manage">
<query-rolesets>
<query-roleset>
<role>432432534053458236326</role>
<role>454643243253405823326</role>
</query-roleset>
<query-roleset>
<role>124325333458236346123</role>
<role>124233432432534058213</role>
</query-roleset>
</query-rolesets>
</security-properties>
This returns:
{
"queryRoleset": [
[
432232321212123100000,
432432534053458200000
],
[
124325333458236346123,
124233432432534058213
]
]
}
Note: The REST Management APIs will accept both role names and role IDs in
configuring query rolesets with PUT.
The following are example payloads for POST or PUT calls for managing query rolesets.
JSON Example
{
"role-name": ["manage-admin","rest-writer"]
}
XML Example
<query-roleset-properties
xmlns="http://marklogic.com/manage/query-roleset/properties">
<query-roleset>
<role-name>rest-reader</role-name>
</query-roleset>
</query-roleset-properties>
This returns:
<security-properties xmlns="http://marklogic.com/manage">
<protected-paths>
<protect-path>
<path-namespaces>
<path-namespace>
<prefix>ml</prefix>
<namespace-uri>marklogic.com</namespace-uri>
</path-namespace>
</path-namespaces>
<path-expression>/ml:foo/ml:bar</path-expression>
<permissions>
<permission>
<role-name>user1</role-name>
<capability>read</capability>
</permission>
</permissions>
</protected-path>
</protect-paths>
</security-properties>
This returns:
"protected-path": [
{
"path-namespace": [
{
"prefix" : "ml",
"namespace-uri": "marklogic.com"
}
]
"path-expression": "/some/path",
"permissions": [
{
"role-name": "user1",
"capability": "read"
}
]
}
]
}
Note: When DELETE is used, a force=true url param will force deletion of “in use”
protected paths.
Note: To specify an options element namespace in a JSON REST payload, you will need
to define an options-ns key to set the namespace.
Note: At the element level, the update and node-update capabilities are equivalent.
• The indexing of protected elements and whether index keys are combined with query
rolesets
• Whether protected embedded triples are indexed
During indexing, the element level security of every node in the document is compared to the
document’s protection. For a given node in the document, the permissions on every matching
protected path are compared to the document’s permissions. When all matching protected paths
are determined to be weaker than the document’s protection, the element’s protection is
considered to be weaker. In this case, the query rolesets for the matching protected paths are not
used when indexing the current node. An embedded triple with weaker protection on all of its
nodes (subject, predicate and object), is extracted.
How is the element level protection determined to be weaker? In the absence of compartment
security, a higher number of roles implies weaker permission because it means more accessibility.
More roles in this case doesn’t mean the total number of roles. It means that one set of roles is a
superset of the other. The smaller set (the subset) is considered stronger because it is more
restrictive. Roles are OR’ed by default. If the document is permitted to be accessed by more roles
than the element (the element is more restrictive because there are more limitations on access),
then the element security is considered to be stronger than the document security. In such a case,
the element security is given higher precedence and the element is protected (i.e. the element is
more restrictive). The fewer the number of contained or embedded roles, the more restrictive the
permissions.
In situations where neither is stronger or it is unclear whether the document security or element
security is stronger, the element level is always considered stronger. Only “Read” capability is
checked when comparing the document’s permissions to the element’s permissions.
Note that there is no “flattening” of roles (inheritance of permissions) with element level security.
Using the helper functions, described in “APIs for Element Level Security” on page 99 can
facilitate both discovering existing query rolesets and applying them as part of ingestion.
Note that in example 1, element level protection is more restrictive that the document level
protection. With compartment security, it’s more complicated. The security level that has the most
compartments wins, because more compartments means that access is more restrictive.
When element security is weaker than the document security, MarkLogic will index the content
based on the document level security. MarkLogic lets the document level security protect it.
If the element is considered stronger, then content won’t be visible without the correct query
rolesets. If the element is weaker, then MarkLogic will return the element as part of a query (with
the correct document level permissions).
Note that node-update, just like insert, can be seen as a subset of update, meaning that if a role
has the update capability, it automatically gets the node-update capability as well.
If you have the update capability at the document level, you can call xdmp:document-insert,
xdmp:document-delete, and all node-update functions. When you have the update capability at the
document level, the element level security for update will not be checked, it is effectively “turned
off”. If you have the node-update capability, you can only call all node-update functions for that
node.
You can also protect document property nodes with element level security. With the
node-update/insert capability, you can call xdmp:document-add-properties,
xdmp:document-remove-properties, xdmp:document-set-property, or
xdmp:document-set-properties. See “Document and Element Level Permissions Summary” on
page 95 for details.
Note: At the element level, the update and node-update capabilities are equivalent.
<root>
<foo>hello</foo>
<bar>World</bar>
</root>
There are two roles; role1 with both read and update permissions on the <foo> node, and role2
with read and node-insert permissionson the <root> node:
sec:protect-path("//foo", (), (
xdmp:permission("role1", "read"),("role1", "update"),"role2", "read"))
sec:protect-path("//root", (), (
xdmp:permission("role1", "read"),("role2", "read"),("role2",
"insert"))
The insert and update permissions check the ancestors of a node as well. See “Document and
Element Level Permissions Summary” on page 95 for details.
=>
<root>
<baz>Greetings</baz>
<foo>hello</foo>
<bar>World</bar>
</root>
xdmp:node-replace(doc("/example.xml")/root/foo,<foo>Hello</foo>));
doc("/example.xml");
fn:doc("/example.xml")
=>
<root>
<baz>Greetings</baz>
<foo>Hello</foo>
<bar>World</bar>
</root>
If you are using a user to other than role1 do these same operations, a permission denied
exception will be thrown.
* The properties root is the root of the properties node of a document, not the individual properties
contained in the properties node. The properties root is the first line in this diagram:
<prop:properties xmlns:prop="http://marklogic.com/xdmp/property">
<prop1>. . .</prop1>
<prop2>. . .</prop2>
.
.
.
<propN>. . .</propN>
</prop:properties>
See “Interactions With Compartment Security” on page 103 for more about combining element
level security with compartment security.
<foo>
<bar>
</foo>
For this example role1 has both read and update permissions on the <foo> node, and update
permissions on the <bar> node, but no read permissions on the <bar> node:
It is assumed for these examples that all of the query rolesets are already configured correctly.
xdmp:node-replace(doc("/example.xml")/foo,
<foo><baz>Hello</baz></foo>);
The query will succeed, because role1 has update permissions on /foo.
xdmp:node-replace(doc("/example.xml")/foo/bar, <baz>Hello</baz>);
The expression /foo/bar will return an empty sequence because role1 cannot read the bar
element. Hence the node-replace call will effectively be a no-op, because xdmp:node-replace
was asked to replace nothing with something.
<foo>
<bar>
You have two roles; role1 with both read and update permissions on the <foo> node, and role2
with read permissions on the <bar> node:
Note: At the element level, the update and node-update functions are equivalent.
The protected paths for this document would look like this:
sec:protect-path("//foo", (), (
xdmp:permission("els-role-1", "read"),("role1", "node-update"))
sec:protect-path("//foo/bar", (), (
xdmp:permission("role2", "read"))
With these protected paths, role1 cannot read the <bar> node. But because role1 has update
permissions on the parent node (<foo>), role1 can overwrite the <bar> node, even though it cannot
read it.
To prevent this, add node-update permissions to the <bar> node. The permissions would now look
like this:
The presence of the “node-update” permission on the <bar> node prevents role1 from being able
to update and overwrite the <bar> node (the child node of the <foo> node).
This happens because node permissions are checked separately; first there’s a check for protected
paths for read. Then there is a check for protected paths for update. If no update is found for
/foo/bar, then role1 is allowed to update <bar>. If there is a protected path for updating <bar>,
then role1 is not allowed to update <bar>.
<foo>
<bar>
<baz>
At the element level, there are these permissions for protected paths:
In this example:
• role1 cannot update (or override) <bar> because at the element level role2 has <bar>
protected path permissions
• role3 can override everything because at the document level it has update capability, but
can only read <baz> which has no protected paths.
• XQuery APIs
• sec:protect-path
• sec:unprotect-path
• sec:remove-path
• sec:path-set-permissions
• sec:path-add-permissions
• sec:path-get-permissions
• sec:path-remove-permissions
• sec:query-rolesets-collection
• sec:security-path-namespace
• sec:query-roleset
• sec:query-rolesets
• sec:query-rolesets-id
• sec:add-query-rolesets
• sec:remove-query-rolesets
• sec:protected-paths-collection
With the appropriate permissions, protected path content can be modified using these node update
APIs:
• xdmp:node-replace
• xdmp:node-delete
• xdmp:node-insert-after
• xdmp:node-insert-before
• xdmp:node-insert-child
These two helper functions can be used to search for protected paths:
• xdmp:node-query-rolesets
• xdmp:database-node-query-rolesets
GET:/manage/v2/protected-paths
POST:/manage/v2/protected-paths
GET:/manage/v2/protected-paths/{id|name}
DELETE:/manage/v2/protected-paths/{id|name}
GET:/manage/v2/protected-paths/{id}/properties
PUT:/manage/v2/protected-paths/{id}/properties
GET:/manage/v2/query-rolesets
POST:/manage/v2/query-rolesets
GET:/manage/v2/query-rolesets/{id|name}
DELETE:/manage/v2/query-rolesets/{id|name}
GET:/manage/v2/query-rolesets/{id|name}/properties
PUT:/manage/v2/query-rolesets/{id|name}/properties
Note: A child node will still inherit its parent’s query rolesets.
In MarkLogic 9.0-2, the set of query rolesets for a given node (after inheritance from ancestors)
will be “compacted” based on the “weaker” permissions definined in “Document Level Security
and Indexing” on page 91. If a query roleset in the set is “weaker” than any other query rolesets in
the set, that “weaker” roleset will be “removed”.
For example:
Document:
<foo>Hello<bar>World</bar>,</foo>
Protected Paths:
In MarkLogic 9.0-1, the query rolesets for the “bar” node is ((role-1, role-2), (role-1)), but in
9.0-2 it is simplified (“compacted”) to ((role-1)).
Note: If any query roleset in the above set is “weaker” than the document level
permissions, it will be omitted too.
Document:
<foo><bar>Hello</bar></foo>
Protected Paths:
In 9.0-1, the query rolesets for the “bar” node is ((role-1, role-2), (role-3)), but in 9.0-2 it is
simplified (“compacted”) to ((role-3)) because (role-1, role-2) is “weaker” than the document
level permissions.
A compartment is a name associated with a role. The compartment name is used as an additional
check when determining a user’s authority to access, modify, or create documents. If
compartment security is not used, permissions are checked using OR semantics. For example, if a
document has read permissions for role1 and read permissions for role2, without compartment
security, a user who has either role1 or role2 can read that document.
If any permission on a document has a compartment, then the user must have that compartment in
order to access any of the capabilities, even if the capability is not the one with the compartment.
Access to a document requires a permission in each compartment for which there is a permission
on the document, regardless of the capability of the permission. So if there is read permission for
role compartment1, there must also be an update permission for some role in compartment1 (but not
necessarily the same role).
If compartment security is used, then the permissions are checked using AND semantics for each
compartment. If the document has compartment permissions for both compartment1 and
compartment2, a role must be associated with both compartments to view the document. If two
roles have different compartments associated with them (for example compartment1 and
compartment2) , a user must have role1 and role2 access the document.
This is in addition to checking the OR semantics for each non-compartmented role, as well as a
non-compartmented role that has a corresponding permission on the document. If compartment
security is used along with element level security, a user must have both the appropriate
compartment security and the appropriate role to view protected content.
Because element level security follows the same role based authorization model, compartment
security checks are be done in the same way at the element level. The only difference is that when
calculating “compartments needed” at the element level, only those permissions with the
capability being requested (for example “read”) are checked.
With these permissions set on the document, a user with both role1 and role0 cannot perform a
read operation. This is because one of the permissions mentions role2, even though it is not for
read. In fact, with these permissions at the document level, no one (except for admin) would be
able to read the document.
If the above permissions are set for an element, a user with both role1 and role0 will be able to
read the element, because element level security checks read, update, and insert permissions
separately, based on the operation requested.
Note: Permission checks at the document and element levels are performed
independently.
• If an element is protected by more compartments than the document’s, the element level
protection is considered stronger.
• Within the same compartment, if the element is protected for fewer roles, the element
level protection is stronger.
• There are situations where the weaker/stronger protection cannot be clearly determined. In
this case, element level security is always considered to be stronger.
See “Node Update and Document Permissions Expanded” on page 97 and “Combination Security
Example” on page 92 for more about security protection and indexing. For more information
about compartment security, see “Compartment Security” on page 35.
Query operations that rely on the triple index (such as SPARQL, SQL, the new version of
MarkLogic ODBC, and the Optic API) are supported by element level security. Element-level
security can be leveraged by semantic graphs and SQL. In semantics, individual triples can be
protected. In SQL, this allows you to enable column-level security by protecting specific columns
in a Template (TDE). See “Node Update and Document Permissions Expanded” on page 97 for
details.
• Lexicon Calls
• Fragmentation
• Reverse Indexes
• SPARQL
• mlcp
• XCC
• Bitemporal
• Others
• Rolling Upgrades
6.14.2 Fragmentation
The indexer in MarkLogic doesn’t know the full path when working on child fragments of a
parent document, because the indexer indexes the child fragments first before it indexes the
parent. Because of this element level security and fragmentation don’t work well together,
although fragmentation will still work on documents that don’t have any protected elements.
Any new document with matching fragmentation and protected elements will be rejected. Either
an XDMP-PARENTLINK or an XDMP-FRAGMENTPROTECTEDPATH error will be thrown. When element level
security and fragmentation both apply simultaneously to an existing document (already in the
database), a reindexing error will be thrown, causing reindexing to stop. User must either
remove/fix the matching element level security path or the matching fragmentation element.
For example, if a protected path that ends with baz is added (/foo/bar/baz) and if a fragment root
is configured for baz, any document containing node baz (even under a different path /A/B/C/baz)
will error out with XDMP-PARENTLINK when the document is inserted or reindexed.
6.14.6 SPARQL
If a sem:triple is inside an element that is concealed for any role and the element level security is
stronger than the document security, it will not be put into the triple index. If the triple itself or its
subject, predicate, or object is protected, it will not be put into the triple index, unless the
document security is stronger than the element level security protection. In some scenarios, where
the document’s security is stronger than the element security on a triple, the protected triple will
be added to the triple index. This is because the document’s security already covers the protected
element. The information will be protected at the document level. See “Node Update and
Document Permissions Expanded” on page 97 for details.
There is a two pass rule matching approach; first the rule matching runs against the full version of
the document, then for each matching rule, a second match test is performed using the version of
the document that the target user of the rule is allowed to see.
Now, a rule that matches “hello” will not trigger the action if the target user cannot see “hello”
due to element level security protection. Using element level security, MarkLogic Server will
deliver a redacted version of the document, based on element level security configuration of
protected paths and the user’s role.
Note: When using element level security with Alerting and QBFR, if a query contains a
“NOT” clause, you may see false negatives. What this means is documents might
not be replicated when the alerting rule contains a cts:not-query due to the false
negatives.
6.14.8 mlcp
When you use mlcp to ingest files from MarkLogic 9 or later to another MarkLogic 9 or later
instance, the protected paths and node-update permissions will be preserved.
If you use mlcp to export a database archive that includes documents with the node-update
permission, and then import the archive into MarkLogic 8.0-6 or earlier, the behavior is
undefined. If you import the archive in MarkLogic 8.0-7 or a later version of MarkLogic 8, the
node-update permission is silently discarded.
Similarly, if you use mlcp to copy documents from MarkLogic 9 or later to MarkLogic 8.0-6 or
earlier, the behavior is undefined. If your copy destination is MarkLogic 8.0-7 or a later version of
MarkLogic 8, the node-update permission is silently discarded.
6.14.9 XCC
If you use XCC to insert a document with the node-update permission into MarkLogic 8.0-6 or
earlier, the behavior is undefined.
If you use XCC to insert a document with the node-update permission into MarkLogic 8.0-7 or a
later version of MarkLogic 8, the node-update permission is silently discarded.
6.14.10 Bitemporal
Do not protect system axis for bitemporal queries when using element level security.
6.14.11 Others
A key concept to support cts queries with element level security is query rolesets. A query roleset
is simply a list of roles. When indexing, MarkLogic takes query roleset information into
consideration and essentially “partitions” indexes based on query rolesets. All queries (except for
composite ones like and-query) will look into indexes for different query rolesets based on the
caller’s role and logically “OR” the results. See “Query Rolesets” on page 75 for more about
query rolesets.
There are special rules for cts queries, phrase breaks, field values, geo element pairs, auditing and
term-queries when the elements involved are protected.
• cts queries - Positions are always calculated based on the original (full) document, prior to
any concealing. This implies that the distances calculated based on indexes will be larger
than what appears in the concealed document.
• Phrase breaks - When indexing, any element that is protected is considered a phrase break.
Consider the this example:
<foo>1<bar>2 3</bar>4</foo>.
If “bar” is protected by any protected path, then it is considered a phrase break regardless
whether a phrase through is defined on it. So in the example, “2 3” is still a phrase, but
“1 2” or “3 4” is not. “1 4” is not a phrase either.
• Fields - For an XML document, field values or field range values are sometimes
calculated by concatenating elements included in the field. If those elements don’t have
the same rolesets (permissions), concatenating can cause leaking of information.
MarkLogic server will treat this as a misconfiguration and log a warning. The query result
on such a field is undefined.
• Geo element pair with inconsistent permissions - Similar to the field case above, if
permissions on the two elements (or JSON properties) of the geo pair are not consistent
(or either of the two elements has different permissions from the parent node), MarkLogic
server will treat it as a misconfiguration and log a warning. The query result is undefined
in this case.
• Auditing -
a. For the “document-read” event, if the node involved has any element concealed, the
string “concealed” will be reported in the event. Here is an example:
b. When a node or properties update built-in call is rejected due to the lack of
element-level permissions, the “no-permission” event will be reported. This is very
similar to how the event is used when such a call is rejected due to the lack of
document-level permissions.
• term-query - Element level security won’t prevent a “malicious” user from getting a term
key through xdmp:plan from a different MarkLogic deployment, then passing that to a
cts:term-query to find out information she is not supposed to see on the current
MarkLogic deployment. The solution is to add a new execute privilege “term-query” to
“protect” cts:term-query. For backward compatibility, this privilege will only be checked
when element level security is in use (i.e., when at least one protected path is configured).
Execute privileges provide authorization control for executing XQuery and JavaScript functions.
MarkLogic provides three ways to protect XQuery functions:
7.2 Protecting Your XQuery and JavaScript Code with Execute Privileges
To protect the execution of an individual XQuery or JavaScript function that you have written,
you can use an execute privilege. When a function is protected with an execute privilege, a user
must have that specific privilege to run the protected XQuery or JavaScript function.
Note: Execute privileges operate at the function level. To protect an entire XQuery or
JavaScript document that is stored in a modules database, you can use execute
permissions. For details, see “Document Permissions” on page 23.
For example, to create an execute privilege to control the access to an XQuery function called
display-salary, use the following steps:
3. Assign a role to the privilege. You may want to create a specific role for this privilege
depending on your security requirements.
For example, a user may need a count of all the documents in the database in order to create a
report. If the user does not have read permissions on all the documents in the database, queries run
by the user do not “see” all the documents in the database. If you want anyone to be able to know
how many documents are in the database, regardless of whether they have permissions to see
those documents, you can create a function named document-count() and use an amp on the
function to elevate the user to a role with read permission for all documents. When the user
executes the amped function, she temporarily has the necessary read permissions that enable the
function to complete accurately. The administrator has in effect decided that, in the context of that
document-count() function, it is safe to let anyone execute it.
Amps are security objects and you use the Admin Interface or Management API to create them.
Amps are specific to a single function in a library module, which you specify by URI and local
name when creating the amp. You can only amp a function that resides in a library module that is
stored in a trusted directory on the filesystem, such as in the Modules directory
(<install_dir>/Modules), or in the modules database configured for the server in which the
function is executed. The recommended best practice is to put your library module code into the
modules database. You cannot amp functions in XQuery modules or JavaScript modules stored in
other locations. For example, you cannot amp a function in a module installed under the
filesystem root of an HTTP server, and you cannot amp functions that reside in a main module.
Functions must reside in the Modules database or in the Modules directory because these locations
are trusted. Allowing amped functions from under a server root or from functions submitted by a
client could compromise security. For details on creating amps, see the “Security Administration”
chapter of the Administrator’s Guide.
For an example that uses an amp, see “Access Control Based on Client IP Address” on page 281.
For details on amps in JavaScript modules, see Amps and the module.amp Function in the JavaScript
Reference Guide.
Granular privileges extend MarkLogic Server security model by allowing finer granularity access
control over configuration and various administration abilities. Granular privileges is a subtype
of execute privileges type. The purposes of granular privileges are:
• Allow different applications to coexist in a single cluster, with some users having
authority over some parts of the cluster and other users having authority over other parts
of the cluster.
• Support separation of concerns between different administrative users, constraining
control to just the layers they are concerned with.
This chapter describes granular privileges and includes the following sections:
• Categories of Granularity
For example, the following privilege allows a user to restart any forest:
http://marklogic.com/xdmp/privileges/xdmp-forest-restart
Granular privileges allow more fine-grained approach to execute privileges. When assigning
privileges to roles, you may not only specify a privilege to perform a specific action but also
identify a specific resource to which this privilege applies.
For example, you may allow a user to restart a specific forest by assigning one of the following
privileges to this user’s role:
http://marklogic.com/xdmp/privileges/xdmp-forest-restart/forest/forest-ID
http://marklogic.com/xdmp/privileges/xdmp-forest-restart/database/database-ID
where forest-ID is the forest identifier and database-ID is the identifier of the database using the
forest.
You can create an appropriate fine-grained privilege, assign it to some role, and assign that role to
a user. Then the user will be able to restart the specified forest, or forests in the specified database.
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/assignments.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/calendars.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/clusters.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/countries.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/databases.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/groups.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/hosts.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/languages.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/mimetypes.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/security.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/server.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/tokenizer.xml
http://marklogic.com/xdmp/privileges/xdmp-read-cluster-config-file/user-languages.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/assignments.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/calendars.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/clusters.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/countries.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/databases.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/groups.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/hosts.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/languages.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/mimetypes.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/security.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/server.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/tokenizer.xml
http://marklogic.com/xdmp/privileges/xdmp-write-cluster-config-file/user-languages.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/assignments.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/calendars.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/clusters.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/countries.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/databases.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/groups.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/hosts.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/languages.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/mimetypes.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/security.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/server.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/tokenizer.xml
http://marklogic.com/xdmp/privileges/xdmp-delete-cluster-config-file/user-languages.xml
http://marklogic.com/xdmp/privileges/admin/database
http://marklogic.com/xdmp/privileges/admin/forest
http://marklogic.com/xdmp/privileges/admin/host
http://marklogic.com/xdmp/privileges/admin/app-server
http://marklogic.com/xdmp/privileges/admin/app-server-security
http://marklogic.com/xdmp/privileges/admin/group
http://marklogic.com/xdmp/privileges/admin/group-security
http://marklogic.com/xdmp/privileges/admin/cluster
http://marklogic.com/xdmp/privileges/admin/mimetypes
Note: Privileges of this category are pre-defined and included with every installation of
MarkLogic Server. You can view them in the Execute Privileges Summary page of
the Admin Interface (see instructions in Viewing an Execute Privilege section of the
Administrator’s Guide).
http://marklogic.com/xdmp/privileges/admin/database/database-ID
http://marklogic.com/xdmp/privileges/admin/forest/forest-ID
http://marklogic.com/xdmp/privileges/admin/host/host-ID
http://marklogic.com/xdmp/privileges/admin/app-server/server-ID
http://marklogic.com/xdmp/privileges/admin/app-server-security/server-ID
http://marklogic.com/xdmp/privileges/admin/group/group-ID
http://marklogic.com/xdmp/privileges/admin/group-security/group-ID
http://marklogic.com/xdmp/privileges/admin/cluster/cluster-ID
http://marklogic.com/xdmp/privileges/admin/database/forests
http://marklogic.com/xdmp/privileges/admin/database/backup
http://marklogic.com/xdmp/privileges/admin/database/index
http://marklogic.com/xdmp/privileges/admin/database/replication
http://marklogic.com/xdmp/privileges/admin/database/forest-backup
http://marklogic.com/xdmp/privileges/admin/forest/backup
http://marklogic.com/xdmp/privileges/admin/group/scheduled-task
http://marklogic.com/xdmp/privileges/admin/database/forests/database-ID
http://marklogic.com/xdmp/privileges/admin/database/backup/database-ID
http://marklogic.com/xdmp/privileges/admin/database/index/database-ID
http://marklogic.com/xdmp/privileges/admin/database/index/database-name
http://marklogic.com/xdmp/privileges/admin/database/replication/database-ID
http://marklogic.com/xdmp/privileges/admin/database/forest-backup/database-ID
http://marklogic.com/xdmp/privileges/admin/forest/backup/forest-ID
http://marklogic.com/xdmp/privileges/admin/group/scheduled-task/group-ID
http://marklogic.com/xdmp/privileges/admin/database/index
http://marklogic.com/xdmp/privileges/admin/database/index/database-ID
http://marklogic.com/xdmp/privileges/admin/database/index/database-name
Property Description
Property Description
Property Description
Property Description
For example, to create a granular privilege that grants a user an ability to administer a specific
aspect (for example, backup) of a set of resources (for example, forests), perform the following
steps:
3. Assign the privilege to the desired role or roles. You may want to create a specific role for
this privilege depending on your security requirements.
The following screenshot depicts the New Execute Privilege page with these parameters:
Note: You cannot create a granular privilege that grants a user the ability to administer a
specific resource (such as a forest with the specified identifier) in the manner
described here because resource identifiers are not exposed in the Admin Interface.
To create a granular privilege of this type (for example,
http://marklogic.com/xdmp/privileges/admin/forest/forest-ID), you need to
use the functions of the XQuery API security module, as described in the
following section Configure Granular Privileges via the XQuery API Security Module.
8.3.2 Configure Granular Privileges via the XQuery API Security Module
You can use the XQuery API security module to create and assign granular privileges. The
following sections describe this in detail:
sec:create-privilege(
$privilege-name as xs:string,
$action as xs:string,
$kind as xs:string,
$role-names as xs:string*
) as xs:unsignedLong
To assign an existing granular privilege to an additional role, use the following function of the
XQuery API security module:
sec:privilege-set-roles(
$action as xs:string,
$kind as xs:string,
$role-names as xs:string*
) as empty-sequence()
$$server-id(server-name,
$$group-id(group-name))
{
"privilege-name": "finalDbName-index-editor",
"action":
"http://marklogic.com/xdmp/privileges/admin/database/index/$$database-
id(FinalDbName)",
"role": ["firstEditorRole","secondEditorRole"],
"kind": "execute"
}
sec:privilege-set-roles(
"http://marklogic.com/xdmp/privileges/admin/database/index",
"execute",
("admin","role1")
)
Example 2: Create a privilege to perform any operations on database db1 for role2
Create a privilege to perform any operations on database db1 for role2 as follows (note the use of
function xdmp:database("db1") to convert from the database name to the database identifier):
sec:create-privilege(
"admin-database-db1",
fn:concat("http://marklogic.com/xdmp/privileges/admin/database/",
xdmp:database("db1")),
"execute",
"role2"
)
Example 3: Create a privilege to perform index operations on database db1 for role3
Create a privilege to perform index operations on database db1 for role3 as follows (note the use
of function xdmp:database("db1") to convert from the database name to the database identifier):
sec:create-privilege(
"admin-database-db1",
fn:concat("http://marklogic.com/xdmp/privileges/admin/database/inde
x/", xdmp:database("db1")),
"execute",
"role3"
)
1. Using the Admin Interface, create databases db1 and db2. For details on creating
databases, see Creating a New Database section of the Administrator’s Guide.
2. Using the Admin Interface, create roles role1, role2, and role3. For details on creating
roles, see Creating a Role section of the Administrator’s Guide.
3. Using the Admin Interface, create users user1, user2, and user3 with roles role1, role2,
and role3 correspondingly. For details on creating users and assigning roles to them, see
Creating a User section of the Administrator’s Guide.
4. Create and assign granular privileges to roles role1, role2, and role3 as described in
Example 1, Example 2, and Example 3 correspondingly of the previous section Configure
Granular Privileges via the XQuery API Security Module.
As the result, you will have the users with roles and privileges as described in the following table:
Execute the following XQuery code to add a range index to database db1:
Execute the following XQuery code to add a range index to database db2:
$rangespec)
return admin:save-configuration($config)
Execute the following XQuery code to add a backup for database db1:
• The user user1 successfully adds indexes to both databases db1 and db2, but fails to add
backup to database db1, because the user’s role1 has granular privilege
http://marklogic.com/xdmp/privileges/admin/database/index that allows to add
indexes to any database but does not allow other operations on databases.
• The user user2 successfully adds both the index and backup to database db1, but fails to
add index to database db2, because the user’s role2 has granular privilege
http://marklogic.com/xdmp/privileges/admin/database/db1_identifier that allows this
user to perform any operation on database db1 but does not allow operations on other
databases.
• The user user3 successfully adds index to database db1, but fails to add index to database
db2 and to add backup to database db1, because the user’s role3 has granular privilege
http://marklogic.com/xdmp/privileges/admin/database/index/db1_identifier that
allows to add indexes to database db1 but does not allow any other operation on database
db1 and does not allow any operation on other databases.
http://marklogic.com/xdmp/privileges/admin/create-user-privilege/DOMAIN/PRIVILEGE-PATH/
Note that the PRIVILEGE-PATH can contain more than one slash (“/”) and must end with a slash.
For example, given a user with a role that has the following privilege:
http://marklogic.com/xdmp/privileges/admin/create-user-privilege/acme.com/publishing/
• http://acme.com/publishing/
• http://acme.com/publishing/updates/
• http://acme.com/publishing/updates/weekly/
This user can also create roles that use these privileges, as long as the role name is unique to the
entire system, including someone else’s set of roles.
As another example, if you only want this user to be able to publish weekly updates, you would
assign them a role with the following privilege:
http://marklogic.com/xdmp/privileges/admin/create-user-privilege/acme.com/publishing/u
pdates/weekly/
Data Hub securityAdmin An administrator; can create roles based on the Flow
Security Developer, Flow Operator, Endpoint Developer, and
Admin Endpoint Operator roles.
Endpoint endpointOperator Represents the operator who can access the endpoints.
Operator
ODBC User odbcUser Represents the user that has access to the analytics stack
that has an ODBC server.
Security SEC-ADMIN Can configure VPC, assign roles, and add users to the
Administrator pre-configured roles. This role is mapped to the AD
group.
• A securityAdmin user cannot delete or modify privileges for these or any other pre-built
roles, and these pre-built roles cannot inherit privileges.
• When a securityAdmin user creates a DHaaS custom role, that role initially has no pre-
built roles associated with it.
• Custom roles in DHaaS can inherit functionality from the pre-built DHaaS roles, from
other DHaaS custom roles, or they can be created to have no inheritance, but you cannot
assign any privileges to DHaaS custom roles.
• DHaaS custom roles cannot inherit privileges from any other (non-DHaaS) pre-built
MarkLogic roles.
• You can change the external name for a DHaaS custom role, but the internal name stays
constant.
This chapter describes SSL support in the MarkLogic Server, and includes the following sections:
• Understanding SSL
This chapter describes how to use the Admin Interface to configure SSL on App Servers. For
details on how to configure SSL programmatically, see Enabling SSL on an App Server in the
Scripting Administrative Tasks Guide.
A browser and App Server create a secure HTTPS connection by using a handshaking procedure.
When browser connects to an SSL-enabled App Server, the App Server sends back its
identification in the form of a digital certificate that contains the server name, the trusted
certificate authority, and the server's public encryption key. The browser uses the server's public
encryption key from the digital certificate to encrypt a random number and sends the result to the
server. From the random number, both the browser and App Server generate a session key. The
session key is used for the rest of the session to encrypt/decrypt all transmissions between the
browser and App Server, enabling them to verify that the data didn't change in route.
The end result of the handshaking procedure described above is that only the server is
authenticated. The client can trust the server, but the client remains unauthenticated. MarkLogic
Server supports mutual authentication, in which the client also holds a digital certificate that it
sends to the server. When mutual authentication is enabled, both the client and the server are
authenticated and mutually trusted.
MarkLogic Server uses OpenSSL to implement the Secure Sockets Layer (SSL v3) and Transport
Layer Security (TLS v1) protocols.
The following are the definitions for the SSL terms used in this chapter:
• A certificate request is a request data structure containing a subset of the information that
will ultimately end up in the certificate. A certificate request is sent to a certificate
authority for certification.
• A key is a piece of information that determines the output of a cipher. SSL/TLS
communications begin with a public/private key pair that allow the client and server to
securely agree on a session key. The public/private key pair is also used to validate the
identity of the server and can optionally be used to verify the identity of the client.
• A certificate template is a MarkLogic construct that is used to generate certificate requests
for the various hosts in a cluster. The template defines the name of the certificate, a
description, and identity information about the owner of the certificate.
• A cipher is an algorithm for encrypting information so that it's only readable by someone
with a key. A cipher can be either symmetric and asymmetric. Symmetric ciphers use the
same key for both encryption and decryption. Asymmetric ciphers use a public and private
key.
Note: Signed certificates are imported via the Certificate Templates import page, as
described in “Importing a Signed Certificate into MarkLogic Server” on page 154.
Certificate Authority certificates are imported via the Certificate Authorities
import page, as described in “CA Certificate (User Cert Signer) Import from
Admin Interface” on page 161.
Note: Certificate templates, requests, and the resulting signed certificates are only valid
within a single cluster.
3. Click the Create tab. The Create Certificate Template page will display:
4. In the Template Name field, enter a shorthand name for this certificate template.
MarkLogic Server will use this name to refer to this template on display screens in the
Admin Interface.
6. Enter the name of your company or organization in the Organization Name field.
7. You can optionally fill in subject information, such as your country, state, locale, and
email address. Country Name must be two characters, such as US, UK, DE, FR, ES, etc.
8. When you have finished filling in the fields, click OK. MarkLogic Server automatically
generates a Self-Signed Certificate Authority, which in turn automatically creates a signed
certificate from the certificate template for each host. For details on how to view the
Certificate Authority and signed certificate, see “Viewing Trusted Certificate Authorities”
on page 156.
2. Click the group in which you want to define the HTTP server (for example, Default).
4. Either create a new server by clicking on one of the Create server_type tabs or select an
existing server from the left tree menu.
The SSL fields are located at the bottom of the server specification page.
5. In the SSL Certificate Template field, select the certificate template you created in
“Creating a Certificate Template” on page 133. Selecting a certificate template implicitly
enables SSL for the App Server.
6. (Optional) The SSL Hostname field should only be filled in when a proxy or load balancer
is used to represent multiple servers. In this case, you can specify an SSL hostname here
and all instances of the application server will identify themselves as that host.
7. (Optional) In the SSL Ciphers field, you can either use the default (ALL:!LOW:@STRENGTH)
or one or more of the SSL ciphers defined in http://www.openssl.org/docs/apps/
ciphers.html.
8. (Optional) If you want SSL to require clients to provide a certificate, select True for SSL
Require Client Certificate. Then select Show under SSL Client Certificate Authorities and
which certificate authority is to be used to sign client certificates for the server.
9. (Optional) Set SSL Client Issuer Authority Verification to True to ensure that the App
Server will accept client certificates only signed directly by a selected CA from the SSL
Client Certificate Authorities list. A setting of False enables the App Server to accept
client certificates that have a parent CA that is indirectly signed by one or more ancestor
CAs selected in the Admin Interface (same as prior to MarkLogic 9.0-8).
To enable WebDAV clients to access an SSL-enabled App Server, you must follow the procedure
described in “Importing a Self-Signed Certificate Authority into Windows” on page 144.
To enable a single browser to access the SSL-enabled App Server, you can create a security
exception for the self-signed certificate in your browser, as described in the following sections:
If you need to enable a number of browsers to access the SSL-enabled App Server, you might
want each browser to import the self-signed certificate authority for the certificate template. Once
this is done, all certificates signed by the certificate authority will be trusted by the browser, so
you can distribute new certificates without requiring each browser to create new security
exceptions. The following sections describe how to import the self-signed MarkLogic certificate
authority:
https://gordon-1:8000/
Note: Remember to start your URL with HTTPS, rather than HTTP. Otherwise, the
browser will return an error.
2. The server responds with a “There is a problem with this website’s security certificate”
notification similar to:
https://gordon-1:8000/
Note: Remember to start your URL with HTTPS, rather than HTTP. Otherwise, the
browser will return an error.
2. The server responds with a “Your connection is not private” notification similar to:
3. Click on “Advanced.”
https://gordon-1:8000/
Note: Remember to start your URL with HTTPS, rather than HTTP. Otherwise, the
browser will return an error.
2. The server responds with an “Your connect is not secure” notification similar to:
Note: If you see another type of error message, see “What to do if you don’t get an ‘Or
you can add an exception’ Prompt” on page 142.
4. In the Add Security Exception page, click Permanently store this exception and click
Confirm Security Exception.
6. The server then prompts you for a username and password before connecting you to the
server.
9.4.3.1 What to do if you don’t get an ‘Or you can add an exception’
Prompt
When using Mozilla Firefox, you may encounter an error message that does not allow you the
option to add an exception for the self-signed certificate. This type of error looks like:
6. Enter the URL, including the host and port, to the SSL-enabled server in the Location
field.
4. Click the certificate template name on the left tree menu. The Configure certificate
template page will display.
5. Click the Status tab to display the certificate template Status page.
6. Click on Import.
7. In the “Do you want to open or save this file?” window, click Open.
9. In the Certificate Import Wizard window, select “Place all certificates in the following
store” and click Browse.
10. In the Select Certificate Store window, select “Trusted Root Certification Authorities” and
click OK.
12. On the Completing the Certificate Import Wizard page, select “Certificate Store Selected
by User” and click Finish
14. When you see “The import was successful prompt,” click OK.
You should now be able to access the SSL-enabled server from your Internet Explorer browser or
WebDAV client.
4. Click the certificate template name on the left tree menu. The Configure certificate
template page will display.
5. Click the Status tab to display the certificate template Status page.
6. Click on Import.
7. Select “Trust this CA to identify web sites” in the “Downloading Certificate” window and
click OK:
You should now be able to access the SSL-enabled server from your Mozilla Firefox browser.
Note: You must first assign the certificate template to an App Server, as described in
“Enabling SSL for an App Server” on page 135, before you can generate a
certificate request.
3. Click the certificate template name on the left tree menu. The Configure certificate
template page will display.
4. Click the Request tab. The Generate Certificate Request page will display:
5. Select either “All” or “Only those that are needed for missing, expired, self-signed, or out
of date certificates that are not already pending,” then click OK.
6. The certificate template Status page will display. Click on Download to download the
certificate request to your file system.
7. If the file does not already have a ‘zip’ extension, rename the file by replacing the ‘xqy’
extension with ‘zip’.
8. Send the zip file containing the certificate requests to a Certificate Authority, such as
Verisign.
Once signed, you can forward the signed certificate to any MarkLogic user, who can then import
the signed certificate into their MarkLogic host, as described in “Importing a Signed Certificate
into MarkLogic Server” on page 154.
For example, to request and sign a certificate from the mycert template created in “Creating a
Certificate Template” on page 133, do the following:
let $req :=
pki:generate-certificate-request(
pki:get-template-by-name("mcert")/pki:template-id,
"ServerName", (), ())
let $cert :=
pki:authority-sign-host-certificate-request(
xdmp:credential-id("acme-ca"),
xdmp:x509-request-extract($req),
fn:current-dateTime(),
fn:current-dateTime() + xs:dayTimeDuration("P365D"))
return xdmp:x509-certificate-extract($cert)
Note: Because the signed certificate is from a trusted certification authority, browsers are
already configured to trust the certificate.
3. Click the certificate template name on the left tree menu. The Configure certificate
template page will display.
4. Click the Import tab. The Import Certificates page will display:
5. Click on Choose File to locate the PEM file(s) containing the signed certificate(s) and
select OK. Zip files can be uploaded directly without the need to unzip them.
Alternatively, you can paste an individual certificate(s) into the text area.
6. We now allow users to import certificates signed by something besides a downloaded CSR
from MarkLogic. To do this, the user also needs to import the private key of the certificate.
The user can only input one certificate at a time if doing this.
The Certificate Authority page provides detailed information on the CA, a list of revoked
certificates, the option to manually revoke a certificate by ID, and the ability to delete the CA
from the server.
3. The Certificate Authority Summary page displays the list of trusted CAs:
You can use the pki:insert-certificate-revocation-list function to import a CRL into the
Security database. certificate authorities typically allow the CRL to be downloaded via HTTP.
The document URL in the database is derived from the URL passed in to the function, so
Inserting a newer CRL retrieved from the same URL will replace the previous one in the database.
For example, the following script imports a PEM- or DER-encoded CRL from Verisign into the
Security database:
return
pki:insert-certificate-revocation-list(
$URI,
xdmp:document-get($URI)/binary() )
Note: If next publication date of the CRL is earlier than the current time, you will recieve
the following message in the error log: loadCertificateRevocationLists: Most
recent CRL for issuer=<issuer_name> is expired.
Certificate-based user authentication allows users to log into MarkLogic Server without being
required to enter user name/password. Certificate-based user authentication configuration can be
achieved using either internal user or external name based user configurations.
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 7 (0x7)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, ST=CA, L=San Carlos, O=MarkLogic Corp.,
OU=Engineering, CN=MarkLogic DemoCA
Validity
Not Before: Jul 11 02:58:24 2017 GMT
Not After : Aug 27 02:58:24 2019 GMT
Subject: C=US, ST=CA, L=San Carlos, O=MarkLogic Corp.,
OU=Engineering, CN=demoUser1
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
.....................
Exponent: 65537 (0x10001)
Signature Algorithm: sha1WithRSAEncryption
Install a CA certificate used to sign the demoUser1 certificate in the Admin Interface, as follows.
3. Click the Import tab and import a certificate, such as the one shown in the example below.
Example CA certificate:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 9774683164744115905 (0x87a6a68cc29066c1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=CA, L=San Carlos, O=MarkLogic Corp.,
OU=Engineering, CN=MarkLogic DemoCA
Validity
Not Before: Jul 11 02:53:18 2017 GMT
Note: If using Query Console, make sure this query is executed against the Security
database.
pki:insert-trusted-certificates(
xdmp:document-get("/OurCertificateLocation/DemoLabCA.pem",
<options xmlns="xdmp:document-get">
<format>text</format>
</options>)
)
After creating a certificate template, link the template with the App Server and enable SSL on the
App Server.
4. In the user name field, enter the user name as it appears in the CN value of the certificate
Subject field (demoUser1 in the example shown in “User Certificate Example” on
page 160)
5. In the App Server configuration page, set Authentication to Certificate and set Internal
Security to true. Unless you want to have the user authenticated as an external user as
well, set External Securities to none.
6. In the App Server configuration page, scroll down to the bottom and select show in the SSL
Client Certificate Authorities section.
7. Select the CA created in “CA Certificate (User Cert Signer) Import from Admin
Interface” on page 161 to sign the client/user certificate.
Once configured, demoUser1 is now able to access the App Server with a browser that has the user
certificate installed, as described in “Certificate Template & Template CA import into Client
(Browser/SSL Client)” on page 163.
Note: You will also need to assign the necessary roles to demoUser1 to access the needed
MarkLogic resources.
5. In the External Name field, enter the entire Subject field from the example shown in “User
Certificate Example” on page 160.
8. Click the Create tab at the top of the External Security Summary window:
9. In the New External Security object window, name the External Security object and select
Certificate for Authentication.
10. Scroll down to the bottom of the External Security object configuration page and select
show in the SSL Client Certificate Authorities section.
11. Select the CA certificate you configured in “CA Certificate (User Cert Signer) Import
from Admin Interface” on page 161.
12. Return to the App Server configuration page and select the External Security object you
just created from the External Securities pull-down menu.
Secure credentials enable a security administrator to manage credentials, making them available
to less privileged users for authentication to other systems without giving them access to the
credentials themselves.
Secure credentials consist of a PEM encoded x509 certificate and private key and/or a username
and password. Secure credentials are stored as secure documents in the Security database on
MarkLogic Server, with passwords and private keys encrypted. A user references a credential by
name and access is granted if the permissions stored within the credential document permit the
access to the user. There is no way for a user to get access to the unencrypted credentials.
Secure credentials allow you to control which users have access to specific resources. A secure
credential controls what URIs it may be used for, the type of authentication (e.g. digest), whether
the credential can be used to sign other certificates, and the user role(s) needed to access the
resource.
• Creating a Secure Credential with PEM Encoded Public and Private Keys
1. In the Admin Interface, click the Security icon in the left tree menu.
3. Click the Create tab at the top of the Secure Credentials window:
4. In the New Credential window, enter the name of the credential. You can optionally
specify a description, the name of the user and password to use to access the resource.
5. Leave the credential certificate and credential private key fields empty. Set credential
signing to false.
6. In the target uri pattern field, enter the URIs of the MarkLogic App Servers this credential
is to protect, starting with https. Select the authorization used by the target App Servers.
In the credential permissions menu, select which roles and permissions are required for a
user to access the App Servers using this credential.
11.2 Creating a Secure Credential with PEM Encoded Public and Private
Keys
You can skip this procedure if you have obtained a signed Certificate Authority (CA) from a
trusted third party. In this case, you can paste the credential and private key into the Secure
Credentials window described above in “Creating a Secure Credential with Username and
Password” on page 170.
Generating a secure credential that includes PEM encoded public and private keys is a two-step
procedure that is best done in code:
pki:create-authority(
"acme-ca", "Acme Certificate Authority",
element x509:subject {
element x509:countryName {"US"},
element x509:stateOrProvinceName {"California"},
element x509:localityName {"San Carlos"},
element x509:organizationName {"Acme Inc."},
element x509:organizationalUnitName {"Engineering"},
element x509:commonName {"Acme CA"},
element x509:emailAddress {"ca@acme.com"}
},
fn:current-dateTime(),
fn:current-dateTime() + xs:dayTimeDuration("P365D"),
(xdmp:permission("admin","read")))
For example, to create a secure credential, named acme-cred, from the acme-ca CA that includes
PEM encoded public and private keys, a username and password, and that enables access to the
target, https://MLserver:8010/.*, do the following:
let $tmp :=
pki:authority-create-client-certificate(
xdmp:credential-id("acme-ca"),
element x509:subject {
element x509:countryName {"US"},
element x509:stateOrProvinceName {"California"},
element x509:localityName {"San Carlos"},
element x509:organizationName {"Acme Inc."},
element x509:organizationalUnitName {"Engineering"},
element x509:commonName {"Elmer Fudd"},
element x509:emailAddress {"elmer.fudd@acme.com"}
},
fn:current-dateTime(),
fn:current-dateTime() + xs:dayTimeDuration("P365D"))
return sec:create-credential(
"acme-cred", "A credential with user/password and certificate",
"admin", "admin", $cert, $privkey,
fn:false(),
sec:uri-credential-target("https://MLserver:8010/.*", "digest"),
xdmp:permission("admin","read"))
To create a secure credential, named simple-cred, that uses only a username and password, do the
following:
sec:create-credential(
"simple-cred", "A simple credential without a certificate",
"admin", "admin", (), (),
fn:false(),
sec:uri-credential-target("https://MLserver:8010/.*", "digest"),
xdmp:permission("admin","read"))
As described in “Configuring SSL on App Servers” on page 130, MarkLogic App Servers
authenticate clients by means of a host certificate associated with a certificate template. The
following example shows how to create a host certificate using the CA described in “Creating a
Certificate Authority” on page 174 and import it into the myTemplate certificate template. For
details on how to create a certificate template, see “Creating a Certificate Template” on page 133.
let $tmp :=
pki:authority-create-host-certificate(
xdmp:credential-id("acme-ca"),
element x509:subject {
element x509:countryName {"US"},
element x509:stateOrProvinceName {"California"},
element x509:localityName {"San Carlos"},
element x509:organizationName {"Acme Inc."},
element x509:organizationalUnitName {"Engineering"},
element x509:commonName {"MLserver.marklogic.com"},
element x509:emailAddress {"me@marklogic.com"}
},
fn:current-dateTime(),
fn:current-dateTime() + xs:dayTimeDuration("P365D"),
"www.eng.acme.com", "1.2.3.4")
MarkLogic Server allows you to configure MarkLogic Server so that users are authenticated
using an external authentication protocol, such as Lightweight Directory Access Protocol
(LDAP), Kerberos, or certificate. These external agents serve as centralized points of
authentication or repositories for user information from which authorization decisions can be
made.
Note: You can configure MarkLogic Server with multiple external security providers. A
user only needs to authenticate with one of them to gain access.
This chapter describes how to configure MarkLogic Server for external authentication using
LDAP and/or Kerberos. The topics in this chapter are:
• Authentication is the process of verifying user credentials for a named user, usually based
on a username and password. Authentication generally verifies user credentials and
associates a session with the authenticated user. It does not grant any access or authority to
perform any actions on the system. Authentication can be done internally inside
MarkLogic Server, or externally by means of a Kerberos or LDAP server. This chapter
describes how do configure MarkLogic Server for external authentication using either the
Kerberos or LDAP protocol, SAML, or Certificates.
• Authorization is the process of allowing a user to perform some action, such as create,
read, update, or delete a document or execute a program, based on the user's identity.
Authorization defines what an authenticated user is allowed to do on the server. When an
App Server is configured for external authentication, authorization can be done either by
MarkLogic Server or by LDAP.
• Lightweight Directory Access Protocol (LDAP) is an authentication protocol for
accessing server resources over an internet or intranet network. An LDAP server provides
a centralized user database where one password can be used to authenticate a user for
access to multiple servers in the network. LDAP is supported on Active Directory on
Windows Server 2008 and OpenLDAP 2.4 on Linux and other Unix platforms.
• Kerberos is a ticket-based authentication protocol for trusted hosts on untrusted networks.
Kerberos provides users with encrypted tickets that can be used to request access to
particular servers. Because Kerberos uses tickets, both the user and the server can verify
each other's identity and user passwords do not have to pass through the network.
• An External Authentication Configuration Object specifies which authentication protocol
and authorization scheme to use, along with any other parameters necessary for LDAP
authentication. After an external authentication configuration object is created, multiple
App Servers can use the same configuration object.
• A Distinguished Name (DN) is a sequence of Relative Distinguished Names (RDNs),
which are attributes with associated values expressed by the form attribute=value. Each
RDN is separated by a comma in a DN. For example, to identify the user, joe, as having
access to the server MARKLOGIC1.COM, the DN for joe would look like:
UID=joe,CN=Users,DC=MARKLOGIC1,DC=COM
Note: The attributes after UID make up what is known as the Base DN.
• A Principal is a unique identity to which Kerberos can assign tickets. For example, in
Kerberos, a user is a principal that consists of a user name and a server resource, described
as a realm. Each user or service that participates in a Kerberos authentication realm must
have a principal defined in the Kerberos database.
A user principal is defined by the format: username@REALM.NAME. For example, to identify
the user, joe, as having access to the server MARKLOGIC1.COM, the principal might look like:
joe@MARKLOGIC1.COM
• A SAML Entity is an XML document located in the MarkLogic Security database that
serves as the SAML Identity Provider.
Users can be authorized either internally by MarkLogic Server, externally by an LDAP or SAML
server, or both internally and externally.
If the App Server is configured for internal authorization, the user needs to exist in the MarkLogic
Security database where his or her “external name” matches the external user identity registered
with either LDAP, Kerberos or certificate, depending on the selected authentication protocol. For
details on how to map a MarkLogic user to an LDAP Distinguished Name (DN) or a Kerberos
User Principal, see “Assigning an External Name to a User” on page 192.
If the App Server is configured for LDAP authorization, the user does not need to exist in
MarkLogic Server. Instead, the external user is identified by a username with the LDAP server
and the LDAP groups associated with the DN are mapped to MarkLogic roles. MarkLogic Server
then creates a temporary user with a unique and deterministic id and those roles. For details on
how to map a MarkLogic role to an LDAP group, see “Assigning an External Name to a Role” on
page 193.
If the App Server is configured for SAML authorization, the server issues a standard SAML
attribute query to the identity provider to retrieve authorization information. The identity provider
is uniquely identified by its ID, which is combined with an attribute name and value to form an
external name with the necessary privileges.
If the App Server is configured for both internal and external authorization, users that exist in the
MarkLogic Security database are authorized internally by MarkLogic Server. If a user is not a
registered MarkLogic user, then the user must be registered on the LDAP or SAML server.
Note: MarkLogic Server caches negative lookups to avoid overloading the external
Kerberos or LDAP server. Successful logins are also cached. The cache can be
cleared by calling the sec:external-security-clear-cache function.
The following flowchart illustrates the logic used to determine how a MarkLogic user is
authenticated and authorized.
Login
External No Return
Security? Error
No
User Found? Create Temp User
Yes
Return
Password No Return Success
Match? Error
Yes
Return Locate User
Success by External Names
in Security Database
No Return
User Found? Error
Yes
Return
Success
The possible external authorization configurations for accessing MarkLogic Server are shown in
the following table.
3. Click the Create tab at the top of the External Security Summary window:
Field Description
external security name The name used to identify this External Security Configuration
Object.
description The description of this External Authentication Configuration
Object.
authentication The authentication protocol to use: certificate, kerberos, ldap, or
saml. The configuration details for LDAP and SAML are
described below in “LDAP Authentication” on page 186 and
“SAML Authentication” on page 189.
cache timeout The login cache timeout, in seconds. When the timeout period is
exceeded, the LDAP server reauthenticates the user with
MarkLogic Server.
authorization The authorization scheme: internal for authorization by
MarkLogic Server, ldap for authorization by an LDAP server, or
saml for authorization by a SAML server.
Note: The MarkLogic SSL App Server can work with SAN or Wild Card certificates.
However, the MarkLogic LDAP client will not accept or work with a SAN or
Wildcard-based certificate.
Field Description
ldap server uri If authorization is set to ldap, then enter the URI for the LDAP
server. Required if authentication or authorization is ldap.
ldap base If authorization is set to ldap, then enter the base DN for user
lookup. Required if authentication or authorization is ldap.
ldap attribute If authorization is set to ldap, then enter the name of the attribute
used to identify the user on the LDAP server. Required if
authentication or authorization is ldap.
Field Description
ldap default user The LDAP default user. Required if authentication is kerberos and
authorization is ldap or bind method is simple.
ldap memberof attribute The optional ldap attribute for group lookup. If not specified,
memberOf is used for search for the groups of a user.
ldap member attribute The optional ldap attribute for group lookup. If not specified,
member is used for search for the group of a group.
ldap start tls Whether or not to use start TLS request to the LDAP server. Set to
true to use start TLS request. If set to true, the LDAP server URI
should start with ldap:// instead of ldaps://.
ldap certificate The PEM encoded X509 certificate for MarkLogic server to
connect the LDAP server using mutual authentication. Required if
bind method is external. Optional if bind method is MD5 or
simple.
ldap private key The PEM encoded private key corresponding to the certificate.
Required if bind method is external. Optional if bind method is
MD5 or simple.
Field Description
ldap remove domain Whether or not to remove domain before matching with ldap-
attribute.
Field Description
When you have finished configuring MarkLogic Server for external security, click Ok.
The SAML 2.0 specification provides a standard format for describing a SAML entity. The
SAML specification provides for a variety of elements that can be defined in an entity, but only
the AttributeAuthorityDescriptor element is used by MarkLogic. The SAML spec is located at
the URL:
http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf
The SAML entity defines an entityID in the form of a URL. To make use of a SAML entity,
specify its entity ID URL in the “saml entity id” field in the external security configuration, as
described in “Creating an External Authentication Configuration Object” on page 184.
MarkLogic only supports the SAML 2.0 SOAP binding over HTTP. If multiple AttributeService
elements are specified in the entity, one will be chosen at random. This allows support for
multiple hosts in a cluster to be specified when no load balancer is used.
Use the sec:saml-entity-insert function to insert the SAML entity into the MarkLogic Security
database. For example, to insert a SAML entity, identified as http://example.com/example, that
uses an encoded certificate for authorization, enter:
sec:saml-entity-insert(
<md:EntityDescriptor entityID="http://example.com/example">
<md:AttributeAuthorityDescriptor
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIID+TCCAeGgAwIBAgIJAImAkE0o79czMA0GCSqGSIb3DQEBCwUAMDwxEjAQBgNV
BAoMCUFjbWUgSW5jLjEmMCQGA1UEAwwdQWNtZSBJbmMuIE9wZXJhdGlvbnMgRGly
ZWN0b3IwHhcNMTcwMTA5MjE0MDE0WhcNMjcwMTA3MjE0MDE0WjA8MRIwEAYDVQQK
DAlBY21lIEluYy4xJjAkBgNVBAMMHU9wc0RpciBNYW5hZ2VkIENsdXN0ZXIgQWNj
ZXNzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwu4iOujPFrkltDel
XgNl1BO/Xbcu6SEWnGCh3yGMwETqx1PnYDlueRuXIrZAHj8FFoKICJIwsARhcixM
ia2vDH0EkZPFGhb0shf0NEt7glDf1uaUava2x2jNXo5YUuiGDUhES50H3A0HS0Nz
WO0TIMaCu1vCTh5IHnKUnQB2MWrNGeb0I3RxOpqhRp6HarTb1u0mQN1iyiQox+pi
67Wh+eZ1313RTQBv8oavJFKHPT6JQK0rOVDXGDez/VajiUJswFNGZ2MgpVxqCDu3
iA+fdTV3TFp8XGYTPYCQgri5OKC9cGmFXzDgIiXqJLR8iAGbQT8YWsCzTzpYtTVN
JnqN/QIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQDPgcmLCl4kQFp15cfEKuI0QguC
vlCMjaZDDAr86IUDVJkVfm3Ytkw/QswI4ghZkbPuEhRf4SCo37OSR3++sPmMu5MR
gFtsU/UWGm6xXmIrBl/bkK+wmUwrW3DCcZQLZGOTG4o0tXSX+gGlvip5swpBTf5T
BsxJ3Hu479R48fTMIjoJ2gnVvZQ7aqnDqcZkifEskY6E7v431W1GEgccf0EJggnz
eRcTWfReYNy/foKKFuPW5MFYLd6RHOyWxgqJ3Nvroqu6xegVSQYJloJprZhhHx2H
NLZcBNYcgu2RgWNq9Pdjswxn3P1rRjch9YjgzZyjWywQpX+aASpPT2m0ONDYbkWK
V6YZmZbTmDDmwVfR4SK5GB93oxdZ647SfJwVsqN2qyKEDl/P2qwSY1iN851PhXAh
WMEyHfMgPTP22LHyYfQa+ExN5hpD95az+ZBdx+1CTO/9fJmQXvrmD1bNdbpfeKBD
YIv+yyL3UDtKQcMhp8zumt2XYJNAzSMhLkAMe2P7/i+47f5lXiGtrRuDVPyNzddB
VD2cQvB3JvQ7YRmt6BJPFmtuGSlx65d0fN7D3M8I5xtDa3XkmrrivcgOKi7DRSzE
bUu4cwfg7mWFJFDkWNWtIzqeni8658yLuEEgyFBUeW9OVjR2caTUZcSIObD2yvq7
o1oZlzTJxNplg99CCA==
</ds:X509Certificate
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:AttributeService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="https://ML1:8005/SAML2/SOAP/AttributeQuery"/>
</md:AttributeAuthorityDescriptor>
</md:EntityDescriptor>
)
2. Click Users.
3. Select a user or create a new one by clicking the Create tab at the top of the User Summary
window.
4. In the User Configuration window, enter the external name for the user in the field in the
External Name section. You can associate multiple external names with the user by
clicking More External Name.
5. Click OK.
This section describes how to assign one or more external names to a role in the Admin Interface.
You can also use the sec:create-role or sec:role-set-external-names function to assign one or
more external names to a role.
3. Select a role or create a new one by clicking the Create tab at the top of the Role Summary
window.
4. In the Role Configuration window, enter the name of the LDAP group to be associated
with the role in the field in the External Name section. You can associate multiple LDAP
groups with the role by clicking More External Name.
5. Click OK.
2. Click the group in which you want to create or configure the App Server (for example,
Default).
4. Select the Create HTTP tab to create a new App Server, or select an existing App Server
from the Summary page.
5. In the App Server Configuration page, scroll down to the authentication section and set the
fields, as described in the table below.
Field Description
Field Description
external The name of the external authentication configuration object to use. For
security details on how to create an external authentication configuration object,
see “Creating an External Authentication Configuration Object” on
page 184. To set additional external authentication configuration objects,
click on More External Securities and select an additional configuration
object from the pull-down menu.
Note: If you are using the MD5 bind method and Active Directory Domain Services (AD
DS) on a computer that is running Windows Server 2008 or Windows Server 2008
R2, be sure that you have installed the hot fix described in http://
support.microsoft.com/kb/975697.
1. Using Active Directory Domain Services on the Windows server, create a “user” with the
same name as the MarkLogic Server hostname. For example, if the MarkLogic Server is
named mysrvr.marklogic.com, create a user with the name mysrvr.marklogic.com.
2. Create a keytab file with the principal HTTP/hostname using ktpass command of the form:
For example, to create a keytab file for the host named mysrvr.marklogic.com, do the
following:
3. Copy the services.keytab from the Windows server to the MarkLogic data directory on
your MarkLogic Server.
3. Use the ktadd command to generate the services.keytab file for the principal.
For example, to create a services.keytab file for the host named mysrvr.marklogic.com,
do the following:
$ kadmin.local
> addprinc -randkey HTTP/mysrvr.marklogic.com
> ktadd -k services.keytab HTTP/mysrvr.marklogic.com
4. Copy the services.keytab from the Linux Kerberos server to the MarkLogic data
directory on your MarkLogic Server.
For the examples, the certificate presented by the App Server User (demoUser1) is the following.
Click Configure in the left tree menu of the Admin UI, then click Security to expand the options.
Click Certificate Authorities, and then click the Import tab.
Paste this text for the trusted certificate into the field:
D9:45:B9:9A:DC:93:7B:DB:47:07:C6:96:63:57:13:A7:A8:F1:D0:C8
X509v3 Authority Key Identifier:
keyid:D9:45:B9:9A:DC:93:7B:DB:47:07:C6:96:63:57:13:A7:A8:F1:D0:C8
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
Signature Algorithm: sha256WithRSAEncryption
pki:insert-trusted-certificates(
xdmp:document-get("/OurCertificateLocation/DemoLabCA.pem",
<options xmlns="xdmp:document-get">
<format>text</format>
</options>)
)
Be sure that this query is executed against the Security database. (The query is
Import_Trusted_CA.xqy hosted by GitHub.)
1. Create the user demoUser1 with the necessary roles in the MarkLogic Security database
(Internal User).
2. On the AppServer page, set the authentication schema to “Certificate” with Internal
Security to set to “true”. Unless you want to have some users authenticated as an External
User as well, leave External Security object to “none”.
3. The AppServer will also select the CA that will be used to sign Client/User Certificate as
accepted Certificate Authorities (See section CA Certificate earlier for example).
Once configured, accessing the App Server with a browser the has the User Certificate
(demoUser1) installed will be able to log into MarkLogic with the internal demoUser1.
Note: You will also need to assign the necessary roles to the internal user to be able to
access resources as needed.
12.9.5.2 User Certificate Subject Field Value as External Name for Internal
User
Follow these steps to configure certificate-based user authentication for demoUser1 as a
MarkLogic external name for the internal user “newUser1”.
1. Create a user named “newUser1” with the necessary roles in MarkLogic Security database
(Internal User), and configure the User Certificate Subject field as External Name to User.
3. For External Name (Cert Subject field) based linkage to Internal User, the App Server
needs to point to our External Security Object.
On Active Directory, there is a Kerberos user and an LDAP user assigned to an LDAP group:
On MarkLogic Server, the two users and the ldaprole1 role are assigned external names that map
them to the above users and LDAP group.
Kerberos User:
Role:
Authentication Authorization
Name Returned
Protocol Scheme
To use this feature, you must set the following environment variables:
For example, to authenticate xdmp:http-get for Kerberos, your function would look like the
following.
XQuery:
xdmp:http-get("http://atsoi-z620.marklogic.com:8008/ticket.xqy",
<options xmlns="xdmp:http">
<authentication method="negotiate">
</authentication>
</options>)
JavaScript:
xdmp.httpGet("http://atsoi-z620.marklogic.com:8008/ticket.xqy",
{ "authentication": { "method" : "negotiate" } })
For example, to forward the ticket (if the user ticket is forwardable), do the following.
XQuery:
xdmp:http-get(“http://myhost.com:8005/index.xqy”,
<options xmlns="xdmp:http">
<authentication method="negotiate">
</authentication>
<kerberos-ticket-forwarding>{”optional”}
</kerberos-ticket-forwarding>
</options>)
JavaScript:
xdmp:httpGet(“http://myhost.com:8005/index.xqy”,
{
"authentication": {"method" : "negotiate"},
"kerberosTicketForwarding": “optional”
})
XQuery:
xdmp:http-get("http://targethost.marklogic.com/index.html",
<options xmlns="xdmp:http">
<proxy>http://proxy.marklogic.com:8080</proxy>
</options>)
JavaScript:
xdmp.httpGet("http://targethost.marklogic.com/index.html",
{proxy:"http://proxy.marklogic.com:8080"})
MarkLogic Server accesses Kerberos Secured HDFS using the keytab file and principal. To
configure Kerberos authentication to Secured HDFS, set the following environment variables in
your /etc/marklogic.conf file:
Note: When using rolling upgrades, deploy your credential keytab files after the cluster
has been fully upgraded to MarkLogic Server 9. Otherwise the behavior of
accessing secure HDFS will be undefined.
Encryption at rest protects your data on media - which is “data at rest” as opposed to data moving
across a communications channel, otherwise known as “data in motion.” Increasing security risks
and compliance requirements sometimes mandate the use of encryption at rest to prevent
unauthorized access to data on disk.
Note: To use encryption at rest with an external key management system (KMS), an
Advanced Security License key that includes this feature is required. For details on
purchasing a license key for the Advanced Security features, contact your
MarkLogic sales representative. See “Licensing” on page 10 for more information.
Encryption at rest can be configured to encrypt data, log files, and configuration files separately.
Encryption is only applied to newly created files once encryption at rest is enabled, and does not
apply to existing files without further action by the user. For existing data, a merge or re-index
will trigger encryption of data, a configuration change will trigger encryption of configuration
files, and log rotation will initiate log encryption.
This chapter describes encryption at rest security and includes the following sections:
• Licensing
• Example—Encryption at Rest
• Key Management
13.1 Licensing
The use of an external Key Management System (KMS) or keystore with encryption at rest
requires an Advanced Security License, in addition to the regular license. See “Licensing” on
page 10 for more details.
Term Definition
keystore Repository for crytographic keys in the PKCS #11 secured wallet or
any external KMS that is KMIP-server conformant
PKCS #11 One of the Public-Key Cryptography Standards, and also the
programming interface to create and manipulate cryptographic
tokens. See the OASIS PKCS TC for details
MKEK Master Key Encryption Key, resides in the keystore, and is used to
generate the CKEK, which is enveloped (encrypted) with the
MKEK
CKEK Cluster Key Encryption Key, resides in the keystore and is used to
encrypt the data (CDKEK), configuration(CCKEK), and log
CLKEK) encryption keys
CDKEK Cluster Data Key Encryption Key, used to directly encrypt (wrap)
the object key encryption keys (OKEY) for stands, forest journals,
and large files
CLKEK Cluster Log Key Encryption Key, used to encrypt (wrap) the object
key encryption keys (OKEY) for log files
Term Definition
BKEK Backup Key Encryption Key, used to encrypt backups, both full and
incremental. The BKEK is a locally generated backup KEK, that is
used to encrypt all files in the backup. The BKEK is encrypted with
the CDKEY and the BDKEY.
Key strength The size of key in bits. Usually the more bits, the stronger the key
and more difficult to break; for example 128-bits, 256 bits, or
512-bits, and so on
Key rotation The process of aging out and replacing encryption keys over time
• User data - data ingested into MarkLogic databases, along with derived data such as
indexes, user dictionaries, journals, backups, and so on
• Configuration files - all configuration files generated by MarkLogic (for example,
whenever a change is made to the configuration file)
• Log files - all log files generated by MarkLogic, such as error logs, access logs, service
dumps, server error logs, logs for each application server, and the task server logs
Note: There are both MarkLogic Application Server logs and MarkLogic Server logs;
both types of logs will be encrypted as part of log encryption.
These types of data can each be encrypted separately. You can configure encryption for databases
individually, or at the cluster level. Encryption at rest is “off” by default. To use encryption at rest,
you need to configure and enable encryption for your database(s), configuration files, and/or log
files.
Encryption at rest provides data confidentiality, but not authentication of identity or access control
(permissions). See “Authenticating Users” on page 31 and “Protecting Documents” on page 22
for information about authentication and other forms of security in MarkLogic Server.
Warning If you cannot access your PKCS #11 secured wallet (or external KMS if you are
using one), or lose your encryption keys, you will not be able to decrypt any of
your encrypted data. There is no “mechanism” to recover the encrypted data. We
recommend that you backup your encryption keys in a secure location. See
“Backup and Restore” on page 255 for more details.
The MarkLogic embedded wallet uses a standard PKCS #11 protocol, using the PKCS #11 APIs.
The wallet or another KMS, must be available during the MarkLogic startup process (or be
bootstrapped from MarkLogic during start-up). You can also use any KMIP-compliant external
keystore with MarkLogic or the native AWS KMS.
To configure an external KMS you will need the following information for your cluster:
• Host name
• Port number
• Client certificate
• Server certificate
If you are using the native AWS KMS, you will not need the Client certificate or the Server
certificate. You will need the other information.
Note: If you plan to use an external key management system, configure the external
KMS first, and then turn on encryption in the MarkLogic server.
You do not need to completely understand the details of the key hierarchy to use the encryption
feature, but this section will help to understand the general concepts involved.
The keystore contains the Master Key Encryption Key (MKEK). The keystore generates the
Cluster Key Encryption Key (CKEK), which is enveloped (encrypted) with or derived from the
Master Key Encryption Key. Both the Master Key Encryption Key and the Cluster Key
Encryption Key reside in the keystore (key management system or KMS). These keys never leave
the keystore and MarkLogic Server has no knowledge or control over these keys. The keys are
referenced from the keystore by their key IDs.
The KMS can be either the internal keystore provided by MarkLogic or an external
KMIP-compliant KMS; the same mechanism is used by both types of keystores. The
configuration happens at the cluster level because there is one keystore configuration per cluster.
The encryption feature is fully compliant with the KMIP standard and the Amazon KMS.
The external KMS provides even higher security. The key IDs are provided by the KMS and
returned through a TLS tunnel after the MarkLogic-generated keys have been sent to the KMS
and wrapped (encrypted). The actual encryption keys never leave the KMS.
There are multiple levels to the key hierarchy, each level wrapping (encrypting) the level below it.
The KMS generates the Cluster Level Data Encryption Keys for data (CDKEK), configuration
files (CCKEK), and log files (CLKEK). The corresponding key (CDKEK, CCKEK, or CLKEY)
is used to encrypt (wrap) all the Object Encryption Keys (OKEY) generated by MarkLogic Server
for each file, so that an encryption key protects each file, no matter what category (data,
configuration files, logs).
The Object Encryption Keys (OKEY) are randomly generated per file (for stands, journals, config
files, and log files, etc.) wrapped (encrypted) with the corresponding keys (CDKEK, CCKEK, or
CLKEK). So an encryption key protects each file within a category (data, configuration files,
logs).
For example, the Master Key Encryption Key (MKEK) wraps (encrypts) the Cluster Key
Encryption Keys (CKEK), which in turn wraps (encrypts) the Data Key Encryption Key
(CDKEK). The Data Key Encryption Key encrypts the Object Encryption Key (OKEY) for a file
such as a stand. The keys at the bottom of the diagram are encrypted as headers in each file,
wrapped (encrypted) with each of the keys above them in the hierarchy. Each of the three
categories of objects (data, configuration files, and logs) has its own key encryption hierarchy.
Database backups are encrypted using a generated backup key (BKEK). This key is then
encrypted with the cluster key (CDKEK). See “Backup and Restore” on page 255 for more
information about backups.
MarkLogic Server generates the Data Key Encryption Key (CDKEK), the Configuration Key
Encryption key (CCKEK) and the Logs Key Encryption Key (CLKEK). The Data Key
Encryption Key is then used to wrap the OKEYs for the database objects (journals, data files,
etc.). These keys are stored in the wallet (internal KMS). The key IDs are generated in the
MarkLogic Server for encryption and decryption by the KMS (the PKCS #11 secured wallet in
this case). The configuration happens at the cluster level because there is one keystore per cluster.
The individual Object Encryption Keys (OKEYs) are then randomly generated and used to
directly encrypt individual files (journals, config files, and log files, etc.). These keys (the
OKEYs) are wrapped (encrypted) with the corresponding KEK for data, config, and logs. A
unique key protects (encrypts) each file. The keys at the object levels are wrapped (encrypted by
the keys above them) for each category.
For example, the Data Key Encryption Key (CDKEK) wraps (encrypts) the Object Encryption
Key (OKEY) for a file such as a journal. The keys at the bottom of the diagram are encrypted
(wrapped) by all the keys above them in the hierarchy, and then placed in the header for each file.
In the case of the embedded KMS, there is only one CDKEK for the entire cluster - all databases
in the cluster will use that key. When using the embedded KMS, it is not possible to use “per
database” keys for encryption.
Database backups are encrypted using the locally generated backup key (BKEK) that is used to
encrypt all of the files in the backup. The BKEK is then encrypted with the cluster data key
(CDKEK) and then encrypted with the cluster key (CKEK). Additionally you could encrypt this
key with the BDKEY and a passphrase. See “Backup and Restore” on page 255 for more
information about backups.
The keystore contains the Master Key Encryption Key (MKEK). The KMS generates or derives
the Cluster Key Encryption Key (CKEK), which is enveloped (encrypted) with the Master Key
Encryption Key. Both the Master Key Encryption Key and the Cluster Key Encryption Key reside
in the KMS keystore. These keys never leave the keystore. MarkLogic Server has no knowledge
or control over these keys. The keys are referenced from the keystore by their key IDs. The actual
encryption keys never leave the KMS.
There are multiple levels to the key hierarchy in this deployment, each level wrapping
(encrypting) the level below it. The KMS generates the cluster level encryption keys for data
(CDKEK), configuration files (CCKEK), and log files (CLKEK). The corresponding KEK is used
is used to encrypt (wrap) all the Object Encryption Keys (OKEY) generated by MarkLogic Server
for each file, so that a unique key protects each file, no matter what category (data, configuration
files, logs). A unique key protects each file within a category (data, configuration files, logs).
The corresponding KEK (for data, config, or logs) is used to encrypt (wrap) all the Object
Encryption Keys (OKEY) generated by MarkLogic Server for each file, so that an encryption key
protects each file, no matter what category (data, configuration files, logs).
For example, the Master Key Encryption Key (MKEK) wraps (encrypts) the Cluster Key
Encryption Keys (CKEK), which in turn wraps (encrypts) the Data Key Encryption Key
(CDKEK), then wraps (encrypts) the Object Encryption Key (OKEY) for a file such as a stand.
The keys at the bottom of the diagram are encrypted (wrapped) by all the keys above them in the
hierarchy, and then placed in the header for each file.
Database backups are encrypted using the BKEK, the locally generated backup KEK, the BKEK
is encrypted with the CDKEK. Then the CDKEY may be encrypted or derived from the cluster
key (CKEK). This last step is outside of the control of MarkLogic. You can also use a password or
passphrase to encrypt and secure your backup. See “Backup and Restore” on page 255 for more
information about backups and the use of a passphrase to secure your backup.
Note: If you plan to use an external key management system, configure the external
KMS first, and then turn on encryption in the MarkLogic server.
Description:.
To set up encryption at rest for this scenario, you will need Admin privileges. You will need
access to both MarkLogic Admin Interface and Query Console.
To run through the example, perform the steps in each of the following sections:
• Encrypt a Database
• Test It Out
Note: The Security database or other databases used by MarkLogic will not be encrypted
by default. Existing data can be encrypted by forcing a merge or a reindex of the
database.
1. Select Databases from the left tree menu in the Admin UI.
3. On the Database Configuration page, next to data encryption, select on from the
drop-down menu. (The other options are default-cluster and off.)
4. Click ok.
If you select default-cluster, encryption for that database will default to whatever encryption
option has been set for the cluster as a whole. If the cluster is set to encrypt data, this database will
be encrypted. If encryption has not been turned on for the cluster, this database will not be
encrypted if default-cluster is selected. See “Cluster Encryption Options” on page 223 for
details.
As you access data in your database, it will be encrypted when it is written back to disk. You can
view the encryption progress on the Database Status page by looking at the Size and Encrypted
Size numbers.
Note: To encrypt the existing data in your database, you will need to re-index your
database. On the Database Configuration page, click the reindex button at the top
of the page (below the “OK” button), and then click ok. You can also force a
merge of the database to encrypt the data.
Encryption of large databases will take some time initially. Updates and changes to the database
will be fairly transparent to the user after initial encryption. The Size and Encrypted Size numbers
will be equal when the encryption process is complete.
=>
on
You can also check the Size and Encrypted Size numbers on the Database Status page. These
numbers will be equal when the encryption process is complete and the entire database is
encrypted.
3. On the Database Configuration page, next to data encryption, select off from the
drop-down menu.
4. Click ok.
To verify that encryption is turned off, run this query in Query Console:
at "/MarkLogic/admin.xqy";
=>
off
To decrypt the existing data in your database, you will need to re-index your database. On the
Database Configuration page, click the reindex button and then click ok.
Note: You can also decrypt the data by forcing a merge on the database to decrypt its
contents. This process may take a while.
When you start up MarkLogic for the first time after installation, the keystore.xml file will be
loaded first. It contains the encryption key IDs. After loading the keystore.xml configuration,
MarkLogic validates connectivity to the KMS (local or external) and the validity of the keys
stored in keystore.xml. Once validated, encryption keys will be loaded and decrypted. Normal
startup then continues. If configuration files are encrypted, the file layer will decrypt them as they
are being loaded, making the encryption transparent to the cluster.
Note: If a node in your cluster is offline for any reason, wait until the host comes back
online to make any changes to your encryption at rest settings. Do not change your
encryption settings while a host is offline.
Default-Cluster On Off
With encryption enabled, files are encrypted as they are ingested into the database, or when those
files are written back to disk. If you want to encrypt existing data in a database either reindex the
database or force a merge on the database. This will take a few minutes depending on the size of
database. See Cluster Encryption Options
Note: Large binary files are only encrypted during initial ingestion into the database. If
you want to encrypt existing large binary files already loaded into MarkLogic
Server prior to turning on encryption, you must reindex the database or force a
merge.
1. To configure database encryption, go to the Admin UI and click Databases in the left
navigation tree.
3. On the Database Configuration page, next to data encryption, select on from the
drop-down menu. (The other options are default-cluster and off.)
Note: The keystore.xml and hsm.cfg files are never be encrypted because they are
configuration for the Keystore. The servers.xml file is not immediately encrypted
until a server (apps server) is updated, a new server is created, or an existing server
is deleted. This is because these actions trigger a restart of the MarkLogic server.
Cluster configuration settings for encryption at rest interact with the encryption settings for
databases. You can separately configure encryption for each database on the Database
Configuration page in the Admin UI or set database encryption to default to the cluster encryption
settings.
Note: The database encryption configuration settings take precedence unless the cluster
Force Encryption option is set. If Force Encryption is on, configuration files and
log files will be encrypted. Please check all database encryption settings to ensure
that they are set correctly.
The following table shows the interaction between the cluster configuration options and the
database configuration options. There are three possible database encryption settings and three
possible cluster encryption settings. The cell where the row and column intersect shows the
outcome of that configuration combination.
Database Encryption
Cluster Encryption Settings
Setting
The Force Encryption option in the Cluster Encryption Settings will force encryption for all of the
databases in the cluster. If the Cluster Encryption Setting is Force Encryption (or Default On), or
the Database Encryption Setting is On, then the database will be encrypted.
1. To configure encryption using the embedded keystore in the Admin UI, click Clusters in
the left navigation tree and click the name of the cluster you want to configure.
2. Click the Keystore tab to configure the keystore for encryption at rest.
3. Use the drop-down menus to configure encryption for data, config files, and/or log files.
Setting Description
data encryption Specifies whether or not encryption is enabled for user data. The options
are:
force — Force encryption for all data in the cluster. The database
configuration cannot overwrite this setting.
config encryption Specifies whether or not encryption is enabled for configuration files
logs encryption Specifies whether or not encryption is enabled for log files.
kms type Specifies whether the KMS is internal to MarkLogic or an external KMS
Beneath these options on the Edit Keystore Configuration page, there are two tabs for
specifying further options for either the Internal KMS or the External KMS. For the
Internal KMS there are these options:
Setting Description
backup option The internal KMS is automatically included in backups unless you
change the default setting of “include” to “exclude”.
internal data The UUID that identifies the encryption key from the internal KMS that
encryption key id is to be used to encrypt data files.
internal config The UUID that identifies the encryption key from the internal KMS that
encryption id is to be used to encrypt config files.
internal logs The UUID that identifies the encryption key from the internal KMS that
encryption id is to be used to encrypt log files.
Note: Adding or changing any encryption information will require a restart of all of the
hosts in the cluster.
1. Click Clusters in the left navigation tree and click the name of the cluster that has the
KMS keystore with password that you want to change.
2. Click the Keystore tab to open the Edit Keystore Configuration page. Click the change
password button on the Edit Keystore Configuration page. This opens the Change Internal
KMS Password page.
3. Enter the current password in the first field, then enter the new password in the second
field. Confirm the new password by entering it again in the third field.
Note: This process will only work on a clean data directory with a first time install.
1. The PKCS#11 devices must not be initialized and no PIN should be set, MarkLogic will
initialize it and set a PIN.
For example, to set the encryption for log files at cluster level:
To see whether encryption is turned on for log files, you can run this XQuery in the Query
Console:
GET:/manage/v2/databases/{id|name}/properties
This command gets the current properties of the Documents database, including the encryption
status and encryption key ID in JSON format:
Returns
{"database-name":"Documents", "forest":["Documents"],
"security-database":"Security", "schema-database":"Schemas",
"triggers-database":"Triggers", "enabled":true,
"data-encryption":"off", "encryption-key-id":"",
Returns
<database-properties xmlns="http://marklogic.com/manage">
<database-name>Documents</database-name>
<forests>
<forest>Documents</forest>
</forests>
<security-database>Security</security-database>
<schema-database>Schemas</schema-database>
<triggers-database>Triggers</triggers-database>
<enabled>true</enabled>
<data-encryption>on</data-encryption>
<encryption-key-id/>
...
</database-properties>
GET:/manage/v2/security/properties
This command returns the current encryption status, along with other properties including
encryption key ID, for localhost in JSON format:
Returns:
{"keystore":{"data-encryption":"default-off",
"data-encryption-key-id":"091fd9a0-f090-4c7e-91ca-fedfe21dbfef",
"config-encryption":"off", "config-encryption-key-id":"",
"logs-encryption":"off", "logs-encryption-key-id":"",
"host-name":"LOCALHOST", "port":9056}}
Here is the same version of the command, this time returning XML:
Returns:
<security-properties
xsi:schemaLocation="http://marklogic.com/manage/security/properties
manage-security-properties.xsd"
xmlns="http://marklogic.com/manage/security/properties"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<keystore>
<data-encryption>default-off</data-encryption>
<data-encryption-key-id>8d0b07d8-b655-4408-affd-e49a2ece0af3
</data-encryption-key-id>
<config-encryption>off</config-encryption>
<config-encryption-key-id/>
<logs-encryption>off</logs-encryption>
<logs-encryption-key-id/>
<host-name>LOCALHOST</host-name>
<port>9056</port>
</keystore>
</security-properties>
POST:/manage/v2/security/properties
This command sets the protected path for //d with read permissions for manage-user:
<protected-path-properties
xmlns="http://marklogic.com/manage/protected-path/properties">
<path-expression>//d</path-expression>
<path-namspaces/>
<permissions>
<permission>
<role-name>manage-user</role-name>
<capability>read</capability>
</permission>
</permissions>
</protected-path-properties>
{
"path-expression": "//e",
"path-namespace": [],
"permission": [{
"role-name": ["manage-user"],
"capability": "read"
}]
}
PUT:/manage/v2/databases/{id|name}/properties
POST manage/v2/security?
operation=export-wallet&filename=/my/test..wallet&password=test
<export-wallet-operation xmlns="http://marklogic.com/manage/security">
<operation>export-wallet</operation>
<filename>/tmp/mywallet.txt</filename>
<password>mypassword</nassword>
</export-wallet-operation>
POST manage/v2/security
{"operation":"export-wallet","filename":"/my/test.wallet","password":"
test"}
{
"operation":"export-wallet",
"filename":"/tmp/mywallet.tmp",
"password":"mypassword"
}
Note: The export wallet operation saves the wallet to a directory on the server on which
MarkLogic is running. Similarly, the import wallet operation imports from the
filesystem on which MarkLogic is running.
POST manage/v2/security?
operation=import-wallet&filename=/my/test.wallet&password=test
<import-wallet-operation xmlns="http://marklogic.com/manage/security">
<operation>import-wallet</operation>
<filename>/tmp/mywallet.txt</filename>
<password>mypassword</password>
</import-wallet-operation>
POST manage/v2/security
{"operation":"import-wallet","filename":"/my/test.wallet","password":"
test"}
{
"operation":"import-wallet",
"filename":"/tmp/mywallet.tmp",
"password":"mypassword"
}
Note: MarkLogic will only import keys generated by the embedded MarkLogic KMS.
Note: By default the keystore passphrase is set to the admin password. We strongly
recommend that you set a new, different passphrase before turning on encryption.
Using a separate passphrase for admin and the keystore helps support the strong
security principle called “Separation of Duties”.
If you believe that an encryption key has been compromised, you should force a merge or start a
re-index of your data to change/update the encryption keys. See “Key Rotation” on page 233 for
more about updating encryption keys.
• Key Rotation
There are two steps to key rotation. First, rotating the KEK keys (using AES 256 symmetric
encryption) used to envelope the object file encryption keys, and second, re-encrypting the object
file encryption keys (also using AES 256 symmetric encryption).
After calling the built-in function to rotate encryption keys, all new data will be written to disk
using the new key encryption key. Old data will be migrated as it is re-written to disk. If you wish
to force re-encryption using the new key, you can either force a merge or re-index the forest.
At the local, host level, you can manually rotate the data keys, configuration keys, and the logs
keys (CDKEK, CCKEK, CLKEK) using these APIs:
• admin:cluster-rotate-config-encryption-key-id
• admin:cluster-rotate-data-encryption-key-id
• admin:cluster-rotate-logs-encryption-key-id
Note: These key rotation functions are only available for the MarkLogic internal KMS
(the PKCS #11 secured wallet) and not for any keys that are managed by an
external KMS.
At the cluster level, to manually rotate the cluster-level keys use these APIs:
• admin:group-get-rotate-audit-files
• admin:group-get-rotate-log-files
• admin:group-set-rotate-audit-files
• admin:group-set-rotate-log-files
Note: When you are using an external KMS, MarkLogic does not have access to the
envelope key, it only has access to the key ID, and asks for the KMS to open the
envelope.
The internal KMS (the PKCS #11 secured wallet) follows these steps for fast key rotation:
2. MarkLogic requests a new data encryption key (CDKEK, CCKEK, CLKEK - the
cluster-level encryption keys) from the internal KMS.
3. Only the fast rotation keys are re-encrypted with the new data encryption keys (CDKEK,
CCKEK, CLKEK).
1. The external KMS creates new KEK key (CDKEK, CCKEK, CLKEK - the cluster-level
encryption keys).
2. User updates the UUIDs in MarkLogic. See “Set Up an External KMIP KMS with
MarkLogic Encryption” on page 249 for UUID details.
Note: Expired keys can be used for decryption, but not encryption. Expired keys may be
needed for decrypting backups.
xdmp:keystore-export("Unique passphrase",
"/backups/MarkLogic.wallet.bak")
=>
true
xdmp:keystore-import("Unique passphrase",
"/backups/MarkLogic.wallet.bak")
=> true
Key encryption keys can only be imported from MarkLogic exported files. Imported keys can
only be used for decryption. The import requires the passphrase that was provided at the time of
the export.
Warning If a duplicate key is supplied during the import, the import will be rejected.
Duplicate keys can be caused by importing the keystore twice.
Note: The use of an external Key Management System (KMS) or keystore with
encryption at rest, requires an Advanced Security License, in addition to the
regular MarkLogic license.
When using an external KMS, usually there is a security administrator role separate from the
MarkLogic administrator. The security administrator would be the role setting up and configuring
the external keystore. The MarkLogic administrator can also perform this task, but for greater
security it is recommended that the separate security administrator configure the KMS.
This section covers setting up MarkLogic encryption for use with an external key management
system from the MarkLogic Admin UI on the MarkLogic host. You don’t need to have
MarkLogic encryption turned on for your cluster while you are setting up and configuring the
external key management system.
Note: If you plan to use an external key management system, we recommend that you
configure the external keystore first, and then turn on encryption in the MarkLogic
server.
The installation process for the external keystore will vary depending on the type of external
KMIP-compliant KMS you plan to use. A security administrator must configure the external
keystore using the administration set up tools that come with the external KMS. This section
provides a high-level overview of the process from the MarkLogic Server point of view.
To set up the AWS key management system, first set up your AWS instance. See Getting Started
with MarkLogic Server on AWS and Overview of MarkLogic Server on AWS in the MarkLogic Server on
Amazon Web Services (AWS) Guide for details.
The AWS KMS keys (data, config, and log encryption keys) needed to encrypt and decrypt data
must be configured in MarkLogic before using encryption.
You cannot use the master key and roles from the MarkLogic KMS to access the AWS KMS, so
you will need to have a Key Administrator specify access to the AWS KMS keys on a per-key
basis tied to the user’s IAM role. The Key Administrator can specify access using the Encryption
Keys section of the IAM AWS management console. See the next section (AWS KMS on EC2) for
details and the AWS documentation regarding key policies for more information.
Warning If an encryption key stored in the AWS KMS is disabled for any reason, it cannot
be used for encryption or decryption, and MarkLogic loses access to any data
encrypted with the disabled key. Deleting a key will lead to permanent data loss as
deleted keys can never be recovered. Any keys created in the AWS KMS are
cluster management keys and should never be deleted. See
https://docs.aws.amazon.com/kms/latest/developerguide/enabling-keys.html for more
information.
The key policy is tied to the the user’s IAM role. To set up your IAM role and privileges, see
Creating an IAM Role in the MarkLogic Server on Amazon Web Services (AWS) Guide.
Once you have set up your MarkLogic Server (and IAM roles if necessary), follow these steps:
3. In the next screen, pick a region (in the same region as your MarkLogic instance).
4. Create the key following the steps indicated. In the next step, be sure to give each key you
create a descriptive name so that you can tell them apart.
5. In the last step of this process you can preview the key policy you just created. Be sure to
authorize your MarkLogic instance to use the key.
6. Click Previous to go back and make any changes, if necessary. Click Finish when you are
done checking the Key policy you just created.
7. From the AWS IAM Management Console, click Encryption keys in the left navigation
bar again and open the list of encryption keys. Be sure to select the same region from the
drop down that you chose when creating the key to see the correct list.
8. Find the key that you just created. Select and copy the key ID from the list. Repeat the
process for the other keys.
Note: To separate the encryption keys for data, configuration, and log files, we
recommend that you create three separate encryption keys. Give each type of key a
descriptive name (for example ML_data_key) for the type of content it will be
used to encrypt.
9. Open the MarkLogic Admin UI and click on the Keystore tab. Paste the key ID you copied
from AWS into the encryption key id fields in the Edit Keystore Configuration page.
10. Enter the following information to identify the external KMS and the required encryption
keys. Add the appropriate encryption key ID to each field.
Note: We recommend that you create three separate encryption key IDs (one for data,
one for configuration, and one for logs). Give each a descriptive name in order to
help distinguish between them.
Setting Description
host name The host name of the external Key Management Server (KMS).
Setting Description
external data encryption The UUID that identifies the encryption key from the external
key id KMS that is to be used to encrypt data files.
external config The UUID that identifies the encryption key from the external
encryption key id KMS that is to be used to encrypt config files.
external logs encryption The UUID that identifies the encryption key from the external
key id KMS that is to be used to encrypt log files.
For more about IAM roles and privileges, see Creating an IAM Role in the MarkLogic Server on
Amazon Web Services (AWS) Guide. To learn more about using MarkLogic with Amazon Web
Services, see the MarkLogic Server on Amazon Web Services (AWS) Guide.
To use the AWS KMS key to encrypt data that will be stored on AWS S3, specify which key to be
used to encrypt. You can do this using the Admin UI or by using the
admin:group-set-s3-server-side-encryption-kms-key API. To find the S3 encryption key (if it
has already been set) use the admin:group-set-s3-server-side-encryption-kms-key API.
To set the AWS KMS in the MarkLogic Admin UI, navigate to Groups Configuration page. Scroll
down to the S3 protocol configuration field. Select https as the s3 protocol and aws:kms as the s3
server side encryption. Paste the s3 server side encryption kms key into the field.
Starting in MarkLogic 9.0-8, this capability is supported by MarkLogic for AWS. Users can turn
on encryption on EBS volumes on their cluster and also optionally specify a custom key for
volumes. This can be done using MarkLogic CloudFormation templates and Managed Cluster
Feature. See The Managed Cluster Feature and Deploying MarkLogic on EC2 Using CloudFormation in
the MarkLogic Server on Amazon Web Services (AWS) Guide.
If a cluster is created by the MarkLogic CloudFormation template, a same encryption key will be
used to encrypt all EBS volumes in the cluster. If encryption option is specified, all volumes
attached to an instance will apply the same setting. EBS Encryption is only supported by some
EC2 instance types, mostly the new generation. The key that is used to encrypt the volume must
be in the same region.
Note: KMS keys are never transmitted outside of the AWS regions in which they were
created.
To set up the Microsoft Azure Key Vault, first set up your Azure instance. See Getting Started with
MarkLogic Server on Azure and Overview of MarkLogic Server on Azure for details. Keys are governed
by access policies created by the Key Administrator. See the next section (Microsoft Azure Key
Vault) for details and the Azure documentation regarding key policies for more information.
Warning If an encryption key stored in the Azure Key Vault is disabled, it cannot be used
for encryption or decryption, and MarkLogic loses access to any data encrypted
with the disabled key. Deleting a key will lead to permanent data loss as deleted
keys can never be recovered.
On the Review tab, enter your prefered email address and phone number. Review your
information and click Create. This process may take a bit of time. Once the virtual machine has
been created, you can configure the Key Vault.
Create a new Key Vault with name/resource group/location and a new access policy with keys
permissions (decrypt and encrypt) and principle (your newly created VM).
Under Settings navigate to Keys, and generate new keys for data/config/logs encryption. Use
these keys IDs to configure MarkLogic encryption.
Install MarkLogic
Install MarkLogic on the Azure virtual machine. See Set up a Simple Deployment in the MarkLogic
Server on Microsoft® Azure® Guide for details. Once MarkLogic is installed on Azure, start
MarkLogic and navigate to the Admin UI (port 8001).
Note: You may need to stop the firewall from the command line (sudo service
firewalld stop).
Enter the following information to identify the Azure Key Vault and the required encryption key
identifiers. Add the appropriate encryption key ID to each field.
• Set hostname using DNS Name from the Azure Key Vault (without the beginning
“https://” and the ending “/”, and ending with “vault.azure.net”).
• Set port 443
• Copy the encryption key IDs for the Azure Key Vault into the external data encryption
key field, the external config encryption key field, and the external logs encryption key
field.
Click OK to configure encryption.
Note: We recommend that you create three separate encryption key IDs (one for data,
one for configuration, and one for logs). Give each a descriptive name in order to
help distinguish between them.
Setting Description
external data encryption The identifier of the encryption key from the external KMS that
key id is to be used to encrypt data files.
external config The identifier of the encryption key from the external KMS that
encryption key id is to be used to encrypt config files.
external logs encryption The identifier ofthe encryption key from the external KMS that is
key id to be used to encrypt log files.
For more about roles and privileges, see the MarkLogic Server on Microsoft® Azure® Guide.
• kmip-CA.pem - The root/certificate of the CA that signed the certificate request for
MarkLogic.
• kmip-cert.pem - The certificate that was issued to MarkLogic and the one that was signed
by the CA.
• kmip-key.pem - The private key that was generated for MarkLogic and is associated with
the Certificate issued to MarkLogic (kmip-cert). (Optional for some KMS servers.)
These certificates are the Certificate Authority (CA) for the root of the certificate chain for the
kmip-cert.pem. A certificate could be a self-signed root used by an enterprise or an external CA.
Copy these files into the MarkLogic data directory (/var/opt/MarkLogic). The location and name
of these files can be changed by calling the admin functions. See “Admin APIs for Encryption at
Rest” on page 262 for details.
Note: These settings are cluster wide, so each individual host must have a local copy at
the location specified.
For each host specified, there must exist a PEM-encoded Certificate Authority file and
PEM-encoded KMIP certificate file accessible to each node of MarkLogic server.
The pem files are looked up with the user-specified path or default location for the first host. For
subsequent hosts, the file names are expected to be accessible through the original file name
pre-pended by the host’s index in the configuration sequence.
If the first specified KMIP host stops responding, the program will try to connect to each of the
other hosts on the user-specified list in turn until it successfully connects.
If for some reason the programs is unable to connect with a valide KMIP server after multiple
attempts, it will report exception.
If you don’t already have the external KMS configured and running, set up the external KMS
using the appliance’s interface before turning on MarkLogic encryption. The steps in the process
for setting up the external KMS will depend on the type of KMIP-compliant external KMS you
are using.
• The external key management system is set up, running, and provisioned first to use
KMIP 1.2, before you configure MarkLogic encryption.
• To secure communications between the KMS and MarkLogic Server obtain the required
certificates; KMIP TLS certificate, CA of the KMS, private key for the client (optional for
some KMS servers).
The security administrator can enable encryption for user data, configuration files, and/or logs,
either per cluster or per database. You must use the administration tools that come with the
external KMS to set up the external keystore.
Note: The external key management system (KMS) must be available during the
MarkLogic startup process. Access to the external KMS must be granted to all
nodes in the cluster.
1. Set up your external KMS, if not already set up. See “Set Up an External KMIP KMS with
MarkLogic Encryption” on page 249 for details.
2. Get the generated encryption key IDs from the external KMS (for data, config, and logs as
needed). If you are using data encryption, configuration file encryption, and log
encryption, and you want different encryption keys for each, you will need three
encryption key IDs (UUIDs).
3. Click Clusters in the left navigation tree, then click the name of the cluster to configure.
4. Click the Keystore tab, then click the external radio button next to Key Management
System (KMS). Additional fields for setting up the external KMS are displayed.
5. Provide the host name and port number for your external KMS in the appropriate fields.
Note: Replace the existing host name and port and any existing encryption key IDs, with
the information for the external KMS.
6. Add the encryption key IDs (generated by the external KMS) for the types of encryption
you are configuring (data, configuration, and/or logs), to the appropriate fields on the Edit
Keystore Configuration page in the Admin UI.
7. Click ok.
Note: Adding the encryption information will require a restart of all of the hosts in your
cluster.
8. Turn on the types of encryption you wish from Admin UI (data encryption, configuration
file encryption, and/or log file encryption).
When using an external KMS, key encryption keys (KEK) might be rotated according to the
policy set in the KMS. Each time that the keys are rotated in an external KMS, you will have to
update the new KEK IDs (UUIDs - i.e. key encryption keys - KEKs) to MarkLogic. Data will then
start to be encrypted with new KEK ID, as described in “Key Rotation” on page 233. The object
keys (OKEYs) with be enveloped by the external KMS and the new keys as MarkLogic uses the
IDs to request that the OKEY be enveloped with the corresponding KEK ID.
Encryption at rest may be configured using REST, XQuery, or JavaScript APIs. See “APIs for
Encryption at Rest” on page 261 for details.
Customer-provided cluster KEK IDs will be validated against the KMS for
encryption/decryption. If any KEK ID validation fails or MarkLogic cannot connect to the KMS,
there will be no changes to the configuration files.
Even after you have migrated to an external KMS, the PKCS #11 secured wallet will retain and
manage any encryption keys that were generated before the migration to the external keystore.
To migrate from the PKCS #11 secured wallet to an external keystore (KMS) do the following:
1. Important: Before you start the transition to an external KMS, backup the wallet that
contains all of the internal keys.
2. Confirm that the external KMS is running and available. See “Set Up an External KMIP
KMS with MarkLogic Encryption” on page 249 .
3. Enable the desired encryption options from the MarkLogic Admin UI. MarkLogic
encryption will now used the encryption keys supplied by the external KMS.
1. Important: Before you start the transition to an external KMS, backup the wallet that
contains all of the internal keys.
2. Turn off encryption on all categories and force decryption of all encrypted forests by
issuing a merge command.
3. Ensure that all data is un-encrypted, forest status reports encryption size.
Note: Encrypted read-only forests will need to be set to updates-allow all and merge or
they will be inaccessible.
4. Set the configuration back to the internal PKCS #11 KMS and rotate the key encryption
keys. See “Key Rotation” on page 233 for more information.
Warning Moving from an external KMS to the internal KMS will downgrade your overall
security, as the external KMS is more secure than the internal PKCS #11 secured
wallet.
Note: If any forest in the backup has encryption enabled, then the entire backup will be
encrypted.
The encryption keys residing in the PKCS #11 secured wallet (the embedded KMS) will be
exported as part of a full backup by default. This is true whether encryption is configured to use
the internal KMS or an external KMS. Full backups will include this exported copy of the
keystore, encrypted using the embedded KMS passphrase, unless you specify otherwise. See .
Warning If you cannot access your PKCS #11 secured wallet (or external KMS if you are
using one), or lose your encryption keys, you will not be able to decrypt any of
your encrypted data (including backups). There is no workaround to recover the
encrypted data. We recommend that you backup your encryption keys in a secure
location.
Note: By default the keystore passphrase is automatically set to the admin password. We
strongly recommend that you set a new, different passphrase before turning on
encryption.
During an internal keystore backup/restore, data is added to the embedded PKCS #11 secured
wallet; no keys are deleted. The encrypted file containing the keys is named kms.exp. The
exported keystore is not imported during a restore from a backup. If you need to restore the keys,
use the xdmp:keystore-import function. The keystore passphrase will be required to decrypt the
exported keystore file when restoring backups on another MarkLogic instance.
Note: To change the keystore passphrase, the current password or passphrase is required.
1. Import the backup as usual. See Backing Up and Restoring a Database in the Administrator’s
Guide for details.
1. Use the xdmp:keystore-import function to import the keystore. The function requires the
keystore passphrase to decrypt the keystore.
The import process will reject duplicate keys and log a warning that includes the ID of the
rejected keys. Imported keys can only be used for decryption.
2. Import the backup as usual. See Backing Up and Restoring a Database in the Administrator’s
Guide for details.
Note: As long as the current database being restored is encrypted, the restored database
will also be encrypted.
Using this process you can move your encrypted backups from one system to another and restore
them, as long as you have the passphrase and import the keystore into the new system before
restoring the backup. See Backup and Restore Overview in the Administrator’s Guide for more
information about backup and restore procedures.
Warning If you lose the cluster configuration information, you must first manually restore
the keystore before an encrypted backup can be restored.
xdmp:keystore-export("strong passphrase",
"/backups/MarkLogic.wallet.bak")
This function exports all of the encryption keys stored in the MarkLogic embedded KMS (the
PKCS #11 secured wallet) and stores them at the location provided to the function.
Setting the option to exclude prevents the embedded KMS from being included in the backup.
Warning If you set the backup option to exclude and turn off the automatic inclusion of the
keystore, you are responsible for saving keystore (the embedded KMS) to a secure
location. If you cannot access your PKCS #11 secured wallet (or external KMS if
you are using one), or lose your encryption keys, you will not be able to decrypt
any of your encrypted data (including backups).
For example, with this XQuery statement you can backup your Documents database using the
BDKEK:
xdmp:database-backup(xdmp:database-forests(xdmp:database("Documents"))
,????"/backups/Data", fn:true(),
"/backups/JournalArchiving", 15,"bf44aab-3f7a-41d2-a6a5-fc41a0e5e0cf")
xdmp.databaseBackup(xdmp.databaseForests(xdmp.database("Documents")),?
? "/backups/Data", fn:true(),
"/backups/JournalArchiving",
15,"bf44aab-3f7a-41d2-a6a5-fc41a0e5e0cf");
• If the mlecat tool is given access to the MarkLogic data directory and the .pem files.
• If the log files are encrypted with a user-specified logs passphrase and the same logs
passphrase is passed to mlecat with -p option.
Note: The mlecat tool should be run by a user with sufficient OS privileges to access the
PKCS#11 wallet (located by default at /var/opt/MarkLogic). It is suggested that
the user be a member of group running MarkLogic (by default daemon).
If you want to decrypt log files without having access to your KMS, you must set a
logs-encryption-passphrase. To set this passphrase, use the
admin:cluster-set-keystore-logs-encryption-passphrase function. For example:
($config,$passphrase)
return admin:save-configuration($config)
Note: Log file encryption must be enabled for this passphrase to be used.
PATH=$MARKLOGIC_INSTALL_DIR:$MARKLOGIC_INSTALL_DIR/bin:$PATH
For more about setting environment variables on various platforms, see the information about
installation and data directories as part of Installing MarkLogic in the Installation Guide.
To see the command line options for the mlecat tool, invoke mlecat (or mlecat.bat) with no
arguments.
mlecat
==>
mlecat [option] filepath(s)
option:
-i iDIR, iDir is MarkLogic's Install directory, alternatively the
environmental variable
MARKLOGIC_INSTALL_DIR can be used to set this value.
-d dDIR, dDIR is MarkLogic's Data directory, alternatively the
environmental variable
MARKLOGIC_DATA_DIR can be used to set this value
-p PASS, PASS is your logs-encryption-passphrase (if you are using
one);
[-f] filepath(s), one or more file paths (-f can be specified before
each file for explicit file list)
For example:
Defaults for the MarkLogic data and install directories are shown in the following
For more about setting environment variables on various platforms, see the information about
installation and data directories as part of Installing MarkLogic in the Installation Guide.
If you have experienced a complete loss of your host, you will need to do the following:
2. Import the keystore and keys from a backup (using xdmp:keystore-import). See “Export
and Import Encryption Keys” on page 235 for details.
3. Perform a restore from backup as usual. See Backing Up and Restoring a Database in the
Administrator’s Guide for more information.
• xdmp.keystoreStatus
• xdmp.keystoreExport
• xdmp.keystoreImport
• xdmp.filesystemFileEncryptionStatus
• xdmp.databaseEncryptionAtRest
• xdmp.databaseEncryptionKeyId
• xdmp.keystoreValidateExported
• xdmp:keystore-export
• xdmp:keystore-import
• xdmp:filesystem-file-encryption-status
• xdmp:database-encryption-at-rest
• xdmp:database-encryption-key-id
• xdmp:keystore-validate-exported
<xs:complexType name="options">
<xs:sequence>
<xs:element ref="timeout" minOccurs="0"/>
<xs:element ref="data" minOccurs="0"/>
<xs:element ref="headers" minOccurs="0"/>
<xs:element ref="credential-id" minOccurs="0"/>
<xs:element ref="authentication" minOccurs="0"/>
<xs:element ref="client-cert" minOccurs="0"/>
<xs:element ref="client-key" minOccurs="0"/>
<xs:element ref="pass-phrase" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
These server-side XQuery functions work with either the PKCS #11 secured wallet or a
third-party KMIP-compliant keystore:
• admin:cluster-get-config-encryption
• admin:cluster-get-data-encryption
• admin:cluster-get-logs-encryption
• admin:cluster-set-config-encryption
• admin:cluster-set-data-encryption
• admin:cluster-set-logs-encryption
• admin:database-get-data-encryption
• admin:database-set-data-encryption
• admin:cluster-set-keystore-passphrase
• admin:cluster-set-keystore-logs-encryption-passphrase
• admin:cluster-set-keystore-p11-driver-path
• admin:cluster-get-keystore-backup-option
• admin:cluster-get-keystore-wallet-location
The admin:cluster-rotate-xxxx-encryption-key-id APIs are only for use with the embedded
KMS provided by MarkLogic (the PKCS #11 secured wallet). Using these functions with an
external KMS will cause an error.
• admin:cluster-rotate-config-encryption-key-id
• admin:cluster-rotate-data-encryption-key-id
• admin:cluster-rotate-logs-encryption-key-id
• admin:group-get-rotate-audit-files
• admin:group-get-rotate-log-files
• admin:group-set-rotate-audit-files
• admin:group-set-rotate-log-files
These next two APIs are used in transitioning from an internal keystore (the PKCS #11 secured
wallet) to an external KMIP-compliant keystore. If these functions are set to external, MarkLogic
Server will first look for the external keystore to verify the keys.
• admin:cluster-set-keystore-kms-type
• admin:cluster-get-keystore-kms-type
• admin:cluster-get-config-encryption-key-id
• admin:cluster-set-config-encryption-key-id
• admin:cluster-get-data-encryption-key-id
• admin:cluster-set-data-encryption-key-id
• admin:cluster-get-keystore-host-name
• admin:cluster-set-keystore-host-name
• admin:cluster-get-keystore-port
• admin:cluster-set-keystore-port
• admin:cluster-get-logs-encryption-key-id
• admin:cluster-set-logs-encryption-key-id
• admin:cluster-get-keystore-kmip-CA-path
• admin:cluster-set-keystore-kmip-CA-path
• admin:cluster-get-keystore-kmip-certificate-path
• admin:cluster-set-keystore-kmip-certificate-path
• admin:cluster-get-keystore-kmip-key-path
• admin:cluster-set-keystore-kmip-key-path
• admin:database-get-encryption-key-id
• admin:database-set-encryption-key-id
Note: The functions designed to work with a external KMS will return an error if you try
to use them with the PKCS #11 secured wallet (the default built-in KMS).
• Encryption configuration
• Keystore configuration
• Database configuration
• Database status, including database encryption (encrypted size, total size)
• Cluster status
• Forest status
• Security
• Backups, status (encrypted or not)
• Restore (with property for using private key)
The REST Management APIs that are used to query and manage the cluster security properties
include encryption information for database, cluster, and forest.
<security-properties
xmlns="http://marklogic.com/manage/security/properties"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://marklogic.com/manage/security/properties
manage-security-properties.xsd">
<keystore>
<data-encryption>default-off</data-encryption>
<config-encryption>off</config-encryption>
<logs-encryption>off</logs-encryption>
<kms-type>internal</kms-type>
<host-name>localhost</host-name>
<port>9056</port>
<data-encryption-key-id>92ed7360-458a-427e-abad-c6595b192cb7</data-enc
ryption-key-id>
<config-encryption-key-id>8b9a9bdb-7b0e-41eb-9aa6-ed6e8cb23ad5</config
-encryption-key-id>
<logs-encryption-key-id>01c50d02-b43f-46bc-bbe5-6d4111d1180b</logs-enc
ryption-key-id>
</keystore>
</security-properties>
{
"keystore": {
"data-encryption": "default-off",
"config-encryption": "off",
"logs-encryption": "off",
"kms-type": "internal",
"host-name": "localhost",
"port": 9056,
"data-encryption-key-id":
"92ed7360-458a-427e-abad-c6595b192cb7",
"config-encryption-key-id":
"8b9a9bdb-7b0e-41eb-9aa6-ed6e8cb23ad5",
"logs-encryption-key-id":
"01c50d02-b43f-46bc-bbe5-6d4111d1180b"
}
}
Note: During upgrades, the default passphrase for the upgraded system is not set. You
will need to reset the default passphrase after an upgrade.
13.13.2 Telemetry
The telemetry feature is not available for use until the cluster is upgraded to MarkLogic 9.0-1 or
later. See Telemetry in the Monitoring MarkLogic Guide for more about telemetry.
This chapter describes the basic steps to administer security in MarkLogic Server. It does not
provide the detailed procedures for creating users, roles, privileges, and so on. For those
procedures, see the “Security Administration” chapter of the Administrator’s Guide. This chapter
includes the following sections:
The configuration that associates the security database with the database and servers is at the
database level. HTTP, WebDAV, ODBC, and XDBC servers each access a single documents
database, and each database in turn accesses a single security database. Multiple documents
databases can access the same security database. The following figure shows many servers
accessing some shared and some different documents databases, but all accessing the same
security database.
HTTP Server1
Documents
Database1
WebDAV
Server1 Security
Database
XDBC Server1
Documents
Database2
XDBC Server2
Sharing the security database across multiple servers provides a common security configuration.
You can set up different privileges for different databases if that makes sense, but they are all
stored in a common security database. For an example of this type of configuration, see
“Example: Using the Security Database in Different Servers” on page 270.
In addition to storing users, roles, and privileges that you create, the security database also stores
pre-defined privileges and pre-defined roles. These objects control access to privileged activities
in MarkLogic Server. Examples of privileged activities include loading data and accessing URIs.
The security database is initialized during the installation process. For a list of all of the
pre-defined privileges and roles, see the corresponding appendixes in the Administrator’s Guide.
For the procedures for creating, deleting, and modifying security objects, see the Administrator’s
Guide.
The functions in security.xqy must be executed against the security database. You can use these
functions to do a wide variety of things. For example, you can write code to test which collections
a user has access to, and use that information in your code.
For the signatures and descriptions of the functions in security.xqy, see the MarkLogic XQuery
and XSLT Function Reference.
With this configuration, users who are assigned RoleA can access documents in DocumentsA and
users of RoleB can access documents in DocumentsB. Assuming that ExecutePrivilegeA or
ExecutePrivilegeB are appropriately configured as login privileges on every HTTP and XDBC
server that accesses either DocumentsA or DocumentsB, user access to these databases can
conveniently be managed by assigning users the role(s) RoleA and/or RoleB as required.
Admin Interface
Port: 8001
ApplicationA
DocumentsA
Documents Database
HTTP Server
Security
ExecutePrivilegeA-- RoleA
ExecutePrivilegeB -- RoleB
RoleA – UserA1, UserA2…
RoleB – UserB1, UserB2…
ApplicationB
DocumentsB
Security Database
HTTP Server
Documents Database
Note: The Admin Interface at port 8001 is also used to configure all databases, HTTP
servers, hosts, and so on. The connection between the Admin Interface and the
Security database in the diagram simply indicates that the Admin Interface is
storing all security objects—users, roles, and privileges—in Security database.
The steps below outline the process to create the configuration in the above example.
1. Create two document databases: DocumentsA and DocumentsB. Leave the security database
for the document databases as Security (the default setting).
Note: The new execute privileges created using the Admin Interface are stored in the
Security database. The new roles and users created below are also stored in the
Security database.
3. Create two new roles. These roles are used to organize users into groups and to facilitate
granting access to users as a group.
b. Scroll down to the Execute Privileges section and select ExecutePrivilegeA. This
associates ExecutePrivilegeA with RoleA. Any user assigned RoleA is granted
ExecutePrivilegeA.
d. Select ExecutePrivilegeA in the privilege drop down menu. This indicates that
ExecutePrivilegeA is required to access ApplicationA.
c. Repeat the steps for UserB1, selecting RoleB in the roles section.
UserA1 is granted ExecutePrivilegeA by virtue of its role (RoleA) and has login access to
ApplicationA. Because ApplicationA is connected to DocumentsA, UserA1 is able to access
documents in DocumentsA assuming no additional security requirements are implemented
in ApplicationA, or added to documents in DocumentsA. The corresponding is true for
UserB1.
The configuration process is now complete. Additional users can be created by simply repeating
step 5 and selecting the appropriate role. All users assigned RoleA have login access to
ApplicationA and all users assigned RoleB have login access to ApplicationB.
This approach can also be easily extended to handle additional discrete databases and user groups
by creating additional document databases, roles and execute privileges as necessary.
15.0 Auditing
274
Auditing is the monitoring and recording of selected operational actions from both application
users and administrative users. You can audit various kinds of actions related to document access
and updates, configuration changes, administrative actions, code execution, and changes to access
control. You can audit both successful and failed activities. This chapter contains the following
parts:
• MarkLogic Auditing
• Configuring Auditing
• Best Practices
For procedures on setting up auditing as well as a list of audit events, see Auditing Events in the
Administrator’s Guide.
• Enable accountability for actions. These might include actions taken on documents,
changes to configuration settings, administrative actions, changes to the security database,
or system-wide events.
• Deter users or potential intruders from inappropriate actions.
• Investigate suspicious activity.
• Notify an auditor of the actions of an unauthorized user.
• Detect problems with an authorization or access control implementation. For example,
you can design audit policies that you expect to never generate an audit record because the
data is protected in other ways. However, if these policies generate audit records, then you
know the other security controls are not properly implemented.
• Address auditing requirements for regulatory compliance.
Audit records are stored on the local file system of the host on which the event is detected and on
which the Server subsystem is running.
Rotation of the audit logs to different files is configurable by various intervals, and the number of
audit files to keep is also configurable.
For more details and examples of audit event logs, see Auditing Events in the Administrator’s
Guide.
Be selective with auditing and ensure that it meets your business needs. As a general rule, design
your auditing strategy to collect the amount and type of information that you need to meet your
requirements, while ensuring a focus on events that cause the greatest security concerns.
If you enable auditing, develop a monitoring mechanism to use the audit event logs. Such a
system might periodically archive and purge the audit event logs.
This chapter describes the general steps to follow when using security in an application. Because
of the flexibility of the MarkLogic Server security model, there are different ways to implement
similar security policies. These steps are simple guidelines; the actual steps you take depends on
the security policies you need to implement. The following sections are included:
1. Determine the level of granularity with which you need to protect objects in the database.
4. Create roles.
5. Create users.
7. Set default permissions for users, either indirectly through roles or directly through the
users.
9. Load your documents with the appropriate permissions. If needed, change the permissions
of existing documents using the xdmp:document-add-permissions,
xdmp:document-set-permissions, and xdmp:document-remove-permissions functions.
10. Assign access privileges to HTTP, WebDAV, ODBC, and XDBC servers as needed.
This chapter describes some common scenarios for defining security policies in your applications.
The scenarios shown here are by no means exhaustive. There are many possibilities for how to set
up security in your applications. The following sections are included:
1. Using the Admin Interface, specify a modules database in the configuration for the App
Server (HTTP or WebDAV) that controls the execution of your XQuery module.
2. Load the XQuery module into the modules database, using a URI with an .xqy extension,
for example my_module.xqy.
3. Set execute permissions on the XQuery document for a given role. For example, if you
want users with the run_application role to be able to execute an XQuery module with
the URI http://modules/my_module.xqy, run a query similar to the following:
xdmp:document-set-permissions("http://modules/my_module.xqy",
xdmp:permission("run_application", "execute") )
5. Assign the run_application role to the users who can run this application.
Now only users with the run_application role can execute this document.
Note: Because your application could also contain amped functions, this technique can
help restrict access to applications that use amps.
For details on the different authentication schemes, see “Types of Authentication” on page 31.
You can turn off access control for each HTTP or WebDAV server individually by following these
steps using the Admin Interface:
1. Go to the Configure tab for the HTTP server for which you want to turn off access control.
2. Scroll down to the authentication field and choose application-level for the
authentication scheme.
3. Choose a user with the admin role for the default user. For example, you may choose the
admin user you created when you installed MarkLogic.
Note: To assist with identifying users with the admin role, the default user selection field
places (admin) next to admin users.
In this scenario, all users accessing the application server are automatically logged in with a user
that has the admin role. By default, the admin role has the privileges and permissions to perform
any action and access any document in the server. Therefore, security is essentially turned off for
the application. All users have full access to the application and database associated with the
application server.
3. Go to the Configuration tab for all HTTP and WebDAV servers in the system.
5. Leave the privilege field blank since it has no effect in this scenario. This field specifies
the privilege that is needed to log into application server. However, the users are assigned
the admin role and are treated as having all privileges.
In this scenario, all users must authenticate with a username and password. Once they are
authenticated, however, they have full access to all functions and data in the server.
To limit application access to a subset of the users in the security database, perform the following
steps using the Admin Interface:
1. Create an execute privilege named exe-priv-app1 to represent the privilege to access the
App Server.
3. Add role-app1 to the roles of all users in the security database who should have access to
this App Server.
4. In the Configuration page for this App Server, scroll down to the authentication field and
select digest, basic or digest-basic. If you want to use application-level authentication
to achieve the same objective, a custom login page is required. See the next section for
details.
5. Select exe-priv-app1 for the privilege field. Once this is done, only the users who have the
exe-priv-app1 by virtue of their role(s) are able to access this App Server.
Note: If you want any user in the security database to be able to access the application,
leave the privilege field blank.
To configure MarkLogic Server to use a custom login page for an App Server, perform the
following steps using the Admin Interface:
1. Go to the Configuration tab for the HTTP App Server for which you want to create a
custom login page.
3. Choose nobody as the default user. The nobody user is automatically created when
MarkLogic Server is installed. It does not have an associated role and therefore has no
privileges. The nobody user can only access pages and perform functions for which no
privileges are required.
4. Create a custom login page that meets your needs. We refer to this page as login.xqy.
5. Make login.xqy the default page displayed by the application server. Do not require any
privilege to access login.xqy (that is, do not place xdmp:security-assert() in the
beginning of the code for login.xqy. This makes login.xqy accessible by nobody, the
default user specified above, until the actual user logs in with his credentials.
...return
if xdmp:login($username, $password) then
... protected page goes here...
else
... redirect to login page or display error page...
The rest of this example assumes that all valid users can access all the pages and functions
within the application.
Note: If you are using a modules database to store your code, the login.xqy file still
needs to have an execute permission that allows the nobody (or whichever is the
default) user to access the module. For example, you can put an execute
permission paired with the app-user role on the login.xqy module document, and
make sure the nobody user has the app-user role (which it does by default).
8. Add the application-user-role to all users who are allowed to access the application.
9. Add this snippet of code before the code that displays each of the pages in the application,
except for login.xqy:
try
{
xdmp:security-assert("application-privilege","execute")
}
catch($e)
{
xdmp:redirect-response("login.xqy")
}
or
if(not(xdmp:has-privilege("application-privilege","execute")))
then
(
xdmp:redirect-response("login.xqy")
)
else ()
This ensures that only a user who has the application-privilege by virtue of his role can access
these protected pages.
Similar to the previous approach, this method of authentication requires the appropriate security
configuration for users and documents. See “Introduction to Security” on page 10 for background
on the security model.
1. Using the Admin Interface, configure the App Server to use a custom login page:
a. Go to the Configuration tab for the HTTP or WebDAV App Server for which you want
to create a custom login page.
c. For this example, choose nobody as the default user. The nobody user is automatically
created when MarkLogic Server is installed. It does not have an associated role and
hence has no privileges. The nobody user can only access pages and perform functions
for which no privileges are required.
2. Add the following code snippet to the beginning of the default page displayed by the
application, for example, default.xqy.
The try-ip-login function is defined in login-routine.xqy. It is used to determine if the user can
be automatically logged in based on the client IP address. If the user cannot be logged in
automatically, he is redirected to a login page called login.xqy where he has to log in explicitly.
See “Using Custom Login Pages” on page 280 for example code for login.xqy.
3. Define try-ip-login:
a. Create a file named login-routine.xqy and place the file in the Modules directory
within the MarkLogic Server program directory. You create an amp for try-ip-login
in login-routine.xqy in the next code sample. For security reasons, all amped
functions must be located in the specified Modules directory or in the Modules database
for the App Server.
module "http://widget.com"
declare namespace widget ="http://widget.com"
If the user is accessing the application from an approved IP address, try-ip-login logs in the
user with username local-user or site-user as appropriate and returns true. Otherwise,
try-ip-login returns false.
Note: In the code snippet above, the empty sequence () is supplied in place of the actual
passwords for local-user and site-user. The pre-defined xdmp-login execute
privilege grants the right to call xdmp:login without the actual password. This
makes it possible to create deployments in which users can be automatically
logged in without storing user passwords outside the system.
4. Finally, to ensure that the code snippet above is called with the requisite xdmp-login
privilege, configure an amp for try-ip-login:
An amp temporarily assigns additional role(s) to a user only for the execution of the specified
function. The amp above gives any user who is executing try-ip-login() the login-role
temporarily for the execution of the function.
In this example, default.xqy is executed as nobody, the default user for the application. When the
try-ip-login function is called, the nobody user is temporarily amped to the login-role. The
nobody user is temporarily assigned the xdmp:login execute privilege by virtue of the login-role.
This enables nobody to call xdmp:login in try-ip-login for any user without the corresponding
password. Once the login process is completed, the user can access the application with the
permissions and privileges of local-user or site-user as appropriate.
5. The remainder of the example assumes that local-user and site-user can access all the
pages and functions within the application.
d. Add this snippet of code before the code that displays each of the subsequent pages in
the application:
try
{
xdmp:security-assert("application-privilege","execute")
...
}
catch($e)
{
xdmp:redirect-response("login.xqy")
}
or
if(not(xdmp:has-privilege("application-privilege","execute")))
then
(
xdmp:redirect-response("login.xqy")
)
else ()
This ensures that only the user who has the application-privilege by virtue of his role can
access these protected pages.
Reviewing the MarkLogic security model, recall that users do not have permissions, documents
have permissions. And permissions are made up of a role paired with a capability. Additionally,
execute privileges protect code execution and URI privileges protect the creation of documents in
a specific URI namespace. This example shows one way to implement the read-only user and is
devided into the following parts:
• Troubleshooting Tips
2. Create a user named ReadOnly and grant this user the ReadsStuff role.
3. Create a role named WritesStuff and grant this role the ReadsStuff role.
4. Grant the WritesStuff role the any-uri privilege, as well as any execute privileges needed
for your application code.
5. Create a user named LoadsStuff and grant this user the WritesStuff role. When you load
documents, load them as the LoadsStuff user and give each document an update and insert
permission for the WritesStuff role and a read permission for the ReadsStuff role.
Here is sample code to create a set of permissions to do this as on option to either the
xdmp:document-insert function or the xdmp:document-load function:
(xdmp:permission("ReadsStuff", "read"),
xdmp:permission("WritesStuff", "insert"),
xdmp:permission("WritesStuff", "update"))
An alternative to specifying the permissions when you load documents is to assign default
permissions to the LoadsStuff user or the WritesStuff role.
A security system is only as good as its weakest link. This chapter describes some general
principles to think about with an eye toward hardening your entire environment for security, and
contains the following sections:
• Infrastructure Hardening
• Implement Auditing
Complexity verification verifies that each password is complex enough to provide reasonable
protection against intruders who try to break into the system by guessing passwords. This
encourages users to create strong passwords.
Password managment includes things such as password aging and expiration, automatically
locking users out of the application after failed login attempts, and controlling the reuse of old
passwords.
To enforce password complexity programmatically, use the password plugins. For more
information about the plugin framework and to view a sample password plugin, see System Plugin
Framework and Password Plugin Sample in the Application Developer’s Guide.]
• The number of roles that have capabilities to add, change or remove security-related
privileges.
• OS-Level Restrictions
• Network Security
• Port Management
• Physical Access
Another example is the CERT Program, a part of the Software Engineering Institute, a federally
funded research and development center operated by Carnegie Mellon University. This
organization is devoted to ensuring that appropriate technology and systems management
practices are used to resist attacks on networked systems and to limit damage and ensure
continuity of critical services in spite of successful attacks, accidents, or failures. For more
detailed information about CERT visit their website: http://www.cert.org/.
MarkLogic provides technical support according to the terms detailed in your Software License
Agreement or End User License Agreement.
Complete product documentation, the latest product release downloads, and other useful
information is available for all developers at http://developer.marklogic.com. For technical
questions, we encourage you to ask your question on Stack Overflow.
MarkLogic 10
MarkLogic Server Technical Support
20.0 Copyright
999
COPYRIGHT
Copyright © 2020 MarkLogic Corporation. All rights reserved.
This technology is protected by U.S. Patent No. 7,127,469B2, U.S. Patent No. 7,171,404B2, U.S.
Patent No. 7,756,858 B2, and U.S. Patent No 7,962,474 B2, US 8,892,599, and US 8,935,267.
The MarkLogic software is protected by United States and international copyright laws, and
incorporates certain third party libraries and components which are subject to the attributions,
terms, conditions and disclaimers set forth below.
For all copyright notices, including third-party copyright notices, see the Combined Product
Notices for your version of MarkLogic.
MarkLogic 10
MarkLogic Server Copyright