Because permissions are indexed, with the right incantation you can also query
by permissions. First you need to create a hash of the permission using the
role and capability, similar to the xdmp.permission constructor:
// JavaScript
xdmp.add64(
xdmp.mul64(
xdmp.add64(
xdmp.mul64(roleID, 5), xdmp.hash64(capability)
), 5
), xdmp.hash64('permission()')
);
Then use that hash to create a cts.termQuery (or in XQuery cts:term-query).
cts.termQuery is an undocumented query that matches the low-level terms that
make up the indexes.
You can use a cts.termQuery just like, or along with, any other cts.query. For
example,
cts.uris(null, null, cts.termQuery(hash));
The example below allows you to specify one or more role IDs and it will
calculate the cross-product of roles and capabilities to build a query that
will match any document with any permission that uses those roles. (The
minimized blob at the top is just helper functions.)
Justin
'use strict';
/** {@link
https://gist.github.com/jmakeig/0a331823ad9a458167f6#file-apply-as-9-sjs} */
function applyAs(fct,options,thisArg){return function(){const
f=()=>{return[fct.call(thisArg,...arguments)]};options=options||{};if('string'===typeof
options.database){options.database=xdmp.database(options.database)}if(options.user){options.userId=xdmp.user(options.user);delete
options.user}if(fct.transactionMode&&!(options.transactionMode)){options.transactionMode=fct.transactionMode}return
fn.head(xdmp.invokeFunction(f,options)).pop();}};
/** {@link
https://gist.github.com/jmakeig/0a331823ad9a458167f6#file-hof-mapper-sjs} */
function map(fct,mapper){const ident=item=>item;mapper=mapper||ident;return
function*_map(){const itr=fct.apply(null,arguments);if('string'===typeof
itr||!(itr[Symbol.iterator])){yield itr}else{for(const item of itr){yield
mapper(item)}}}};
const sec = require('/MarkLogic/security');
/**
* Generate hashes of permission terms for the cross product of roles and
capabilities (read,
* update, insert, execute). Use `cts.termQuery(hash)` to match documents by
their terms.
*
* @param {string|Iterable.<string>} [roleIDs] - One or more role IDs.
Defaults to all roles.
* @returns {GeneratorFunction} - A generator that yields
permission term hashes for the
* cross-product of roles and
capabilities
*/
function* getPermissionTerms(roleIDs) {
const capabilities = ['read', 'update', 'insert', 'execute'];
/** @function */
const getRoleIDs = map(applyAs(sec.getRoleIds, { database:
xdmp.securityDatabase() }), fn.data);
function permHash(roleID, capability) {
return xdmp.add64(
xdmp.mul64(
xdmp.add64(
xdmp.mul64(roleID, 5), xdmp.hash64(capability)
), 5
), xdmp.hash64('permission()')
);
}
for(const roleID of roleIDs || getRoleIDs()) {
for(const capability of capabilities) {
yield permHash(roleID, capability);
}
}
}
const query = cts.orQuery(
[...getPermissionTerms(/* Array of roleIDs here to limit to specific roles
*/)]
.map(term => cts.termQuery(term))
);
// URIs of the documents that have the supplied permissions
cts.uris(null, null, query);
> On Dec 8, 2016, at 6:15 PM, Will Thompson <[email protected]> wrote:
>
> I got a script working. I suspect there are faster/better ways to do this,
> but for anyone who may need it in the future, this will resolve any orphaned
> permissions. For a very large data set, you would probably need to batch this:
>
> xquery version "1.0-ml";
>
> let $uris := cts:uris((), 'limit=30000')
> let $permissions-map := map:new((
> $uris ! map:entry(., xdmp:document-get-permissions(.))
> ))
> let $orphaned-map :=
> xdmp:eval('
> xquery version "1.0-ml";
> import module namespace sec="http://marklogic.com/xdmp/security" at
> "/MarkLogic/security.xqy";
> declare variable $PERMISSIONS external;
> map:new(
> for $uri in map:keys($PERMISSIONS)
> let $orphaned :=
> for $p in map:get($PERMISSIONS, $uri)
> return try {
> let $name := sec:get-role-names($p/sec:role-id)
> return ()
> }
> catch ($e) {
> if ($e/error:code = "SEC-ROLEDNE")
> then $p
> else xdmp:rethrow()
> }
> where (exists($orphaned))
> return map:entry($uri, $orphaned)
> )
> ',
> (xs:QName('PERMISSIONS'), $permissions-map),
> <options xmlns="xdmp:eval">
> <database>{xdmp:security-database()}</database>
> </options>)
> for $o in map:keys($orphaned-map)
> let $permissions := map:get($orphaned-map, $o)
> return xdmp:document-remove-permissions($o, $permissions)
>
> -W
>
>> On Dec 8, 2016, at 6:10 PM, Will Thompson <[email protected]> wrote:
>>
>> Hi Chris,
>>
>> That's entirely plausible and even likely. Do you know of an easy way to
>> remove orphaned permissions? If there's not a shortcut, I could probably
>> build a script to do it, but it seems like it might be messy: walk through
>> every document in the db, try to lookup each doc's permissions, catch failed
>> ones and delete them?
>>
>> -Will
>>
>>> On Dec 8, 2016, at 6:01 PM, Christopher Hamlin <[email protected]> wrote:
>>>
>>> Hi,
>>>
>>> This is more of a guess than a suggestion. Let's call it a suggestive
>>> guess.
>>>
>>> It looks like export-to-archive copies permissions. I'm not sure what
>>> would happen if you had a permission (which has a role-id) and the role
>>> with that id got removed. Maybe the above?
>>>
>>> - Chris
>>>
>>> On Thu, Dec 8, 2016 at 6:39 PM, Will Thompson <[email protected]>
>>> wrote:
>>> I am trying to export data from a Windows machine into an archive to be
>>> imported into a Mac, but MLCP crashes. The error MLCP returns is nearly 250
>>> lines, but this part seemed possibly relevant:
>>>
>>> "...Caused by: com.marklogic.xcc.exceptions.XQueryException: SEC-ROLEDNE:
>>> (err:FOER0000) Role does not exist: sec:role-id = 6626745612256060316
>>> [Session: user=wthompson, cb=#17033682864837852147 [ContentSource:
>>> user=wthompson, cb={none} [provider: address=localhost/127.0.0.1:10003,
>>> pool=4/64]]] [Client: XCC/8.0-1, Server: XDBC/8.0-6]
>>> in /MarkLogic/security.xqy, on line 960..."
>>>
>>> The MLCP command is:
>>>
>>> mlcp.bat export
>>> -host localhost -port 10003 -username wthompson -password *****
>>> -output_type archive -output_file_path /some/output/path -directory_filter
>>> /some/dir/
>>>
>>> This is on ML 8.0-6 with the latest MLCP binaries. Any suggestions?
>>>
>>> -Will
>>> _______________________________________________
>>> General mailing list
>>> [email protected]
>>> Manage your subscription at:
>>> http://developer.marklogic.com/mailman/listinfo/general
>>>
>>> _______________________________________________
>>> General mailing list
>>> [email protected]
>>> Manage your subscription at:
>>> http://developer.marklogic.com/mailman/listinfo/general
>>
>> _______________________________________________
>> General mailing list
>> [email protected]
>> Manage your subscription at:
>> http://developer.marklogic.com/mailman/listinfo/general
>
> _______________________________________________
> General mailing list
> [email protected]
> Manage your subscription at:
> http://developer.marklogic.com/mailman/listinfo/general
_______________________________________________
General mailing list
[email protected]
Manage your subscription at:
http://developer.marklogic.com/mailman/listinfo/general