Skip to content
This repository has been archived by the owner on Nov 9, 2022. It is now read-only.

#311 - Adding support for ldap in bootstrap #316

Merged
merged 4 commits into from
Dec 1, 2014
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 197 additions & 12 deletions deploy/lib/xquery/setup.xqy
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ declare variable $common-server-settings :=
<setting>pre-commit-trigger-depth</setting>
<setting>pre-commit-trigger-limit</setting>
<setting>collation</setting>
<setting>authentication</setting>
<setting min-version="7.0-0" if="fn:not(setup:get-appserver-external-security($server-config))" value="setup:get-appserver-internal-security($server-config)">internal-security</setting>
<setting if="fn:not(setup:get-appserver-external-security($server-config))">authentication</setting>
<setting value="setup:get-appserver-privilege($server-config)">privilege</setting>
<setting>concurrent-request-limit</setting>
<setting>log-errors</setting>
Expand Down Expand Up @@ -179,7 +180,7 @@ declare variable $http-server-settings :=
<setting accept-blank="true">url-rewriter</setting>
<setting min-version="6.0-1">rewrite-resolves-globally</setting>
<setting>static-expires</setting>
<setting value="setup:get-appserver-default-user($server-config)">default-user</setting>
<setting if="fn:not(setup:get-appserver-external-security($server-config))" value="setup:get-appserver-default-user($server-config)">default-user</setting>
</settings>
;

Expand Down Expand Up @@ -295,7 +296,8 @@ declare function setup:get-rollback-config()
element sec:privileges
{
map:get($roll-back, "privileges")
}
},
map:get($roll-back, "external-security")
}
};

Expand All @@ -307,6 +309,7 @@ declare function setup:do-setup($import-config as element(configuration)) as ite
setup:create-privileges($import-config),
setup:create-roles($import-config),
setup:create-users($import-config),
setup:create-external-security($import-config),
setup:create-mimetypes($import-config),
setup:create-groups($import-config),
setup:create-forests($import-config),
Expand All @@ -324,6 +327,14 @@ declare function setup:do-setup($import-config as element(configuration)) as ite
}
catch($ex)
{
if ($ex/error:code = "ADMIN-INVALIDAUTHENTICATION") then
fn:concat('&#10;
Either your authentication configuration is invalid or you
are trying to change from external authentication back to internal authentication. There is a bug
in MarkLogic''s Admin API which prevents going from external back to internal.&#10;
See http://docs.marklogic.com/guide/security/external-auth#id_63262 for more information on
configuring external authentication.&#10;&#10;' )
else (),
xdmp:log($ex),
setup:do-wipe(setup:get-rollback-config()),
fn:concat($ex/err:format-string/text(), '&#10;See MarkLogic Server error log for more details.')
Expand All @@ -332,6 +343,7 @@ declare function setup:do-setup($import-config as element(configuration)) as ite

declare function setup:do-wipe($import-config as element(configuration)) as item()*
{
let $_ := xdmp:log(("wiping: ", $import-config))
(: remove scheduled tasks :)
let $admin-config := admin:get-configuration()
let $remove-tasks :=
Expand Down Expand Up @@ -432,7 +444,7 @@ declare function setup:do-wipe($import-config as element(configuration)) as item
else ()',
(xs:QName("amp"), $amp),
<options xmlns="xdmp:eval">
<database>{xdmp:database("Security")}</database>
<database>{$default-security}</database>
</options>)
}
catch($ex)
Expand Down Expand Up @@ -541,7 +553,7 @@ declare function setup:do-wipe($import-config as element(configuration)) as item
sec:remove-user($user)',
(xs:QName("user"), $user),
<options xmlns="xdmp:eval">
<database>{xdmp:database("Security")}</database>
<database>{$default-security}</database>
</options>)
}
catch($ex)
Expand All @@ -562,7 +574,7 @@ declare function setup:do-wipe($import-config as element(configuration)) as item
sec:remove-role($role)',
(xs:QName("role"), $role),
<options xmlns="xdmp:eval">
<database>{xdmp:database("Security")}</database>
<database>{$default-security}</database>
</options>)
}
catch($ex)
Expand All @@ -585,7 +597,7 @@ declare function setup:do-wipe($import-config as element(configuration)) as item
(xs:QName("action"), $priv/sec:action,
xs:QName("kind"), $priv/sec:kind),
<options xmlns="xdmp:eval">
<database>{xdmp:database("Security")}</database>
<database>{$default-security}</database>
</options>)
}
catch($ex)
Expand All @@ -595,6 +607,28 @@ declare function setup:do-wipe($import-config as element(configuration)) as item
xdmp:rethrow()
},

(: remove external security :)
for $es in $import-config/sec:external-securities/sec:external-security
return
try
{
xdmp:eval(
'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy";
declare variable $name as xs:string external;

sec:remove-external-security($name)',
(xs:QName("name"), $es/sec:external-security-name),
<options xmlns="xdmp:eval">
<database>{$default-security}</database>
</options>)
}
catch($ex)
{
if ($ex/error:code = "SEC-EXTERNALSECURITYDNE") then ()
else
xdmp:rethrow()
},

if ($restart-needed) then
"note: restart required"
else ()
Expand Down Expand Up @@ -3294,15 +3328,21 @@ declare function setup:configure-server(
""
else
"[fn:string-length(fn:string(.)) > 0]"
let $min-version as xs:string? := $setting/@min-version
let $version-ok := fn:empty($min-version) or setup:at-least-version($min-version)
let $if :=
if ($setting/@if) then
xdmp:value($setting/@if)
else
fn:true()
let $value :=
if ($setting/@value) then
if ($setting/@value and $if and $version-ok) then
xdmp:value($setting/@value)
else
fn:data(xdmp:value(fn:concat("$server-config/gr:", $setting, $setting-test)))
let $min-version as xs:string? := $setting/@min-version
where (fn:exists($value))
where ($if and fn:exists($value))
return
if (fn:empty($min-version) or setup:at-least-version($min-version)) then
if ($version-ok) then
xdmp:set($admin-config,
xdmp:value(fn:concat("admin:appserver-set-", $setting, "($admin-config, $server-id, $value)")))
else
Expand Down Expand Up @@ -3364,6 +3404,45 @@ declare function setup:configure-server(
else
$admin-config

let $admin-config :=
let $external-security as xs:string? := $server-config/gr:external-security/@name
return
if ($external-security) then
try {
xdmp:eval('
import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy";

declare namespace gr="http://marklogic.com/xdmp/group";

declare variable $admin-config external;
declare variable $server-id external;
declare variable $external-security external;
declare variable $server-config external;

admin:appserver-set-external-security(
$admin-config,
$server-id,
$external-security,
xs:boolean($server-config/gr:internal-security),
fn:string($server-config/gr:authentication))
',
(
xs:QName("admin-config"), $admin-config,
xs:QName("server-id"), $server-id,
xs:QName("external-security"), $external-security,
xs:QName("server-config"), $server-config
))
}
catch($ex) {
if ($ex/error:code = "XDMP-UNDFUN" and fn:not(setup:at-least-version("7.0-0"))) then
(: If we're not using a recent enough version of ML, then the properties are irrelevant. :)
()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get into this block, I think we should throw an error. Otherwise, the resulting config won't match what the user specified.

fn:error(
      xs:QName("VERSION_NOT_SUPPORTED"),
      fn:concat("MarkLogic ", xdmp:version(), " does not support external security. Use 7.0-0 or higher."))

else
xdmp:rethrow()
}
else
$admin-config

let $module-locations := $server-config/gr:module-locations
let $admin-config :=
if ($module-locations/*) then
Expand Down Expand Up @@ -3739,6 +3818,75 @@ declare function setup:validate-privileges(
setup:validation-fail(fn:concat("Missing privilege: ", $privilege-name))
};

declare function setup:create-external-security(
$import-config as element(configuration))
{
let $eval-options :=
<options xmlns="xdmp:eval">
<database>{$default-security}</database>
</options>
for $es in $import-config/sec:external-securities/sec:external-security
return
(: if it exists, don't recreate it :)
if (setup:get-external-securities($es/sec:external-security-name)) then ()
else
(
(: Wrapping this in xdmp:eval because it didn't exist until ML7 :)
try {
xdmp:eval(
'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy";
declare variable $es as element(sec:external-security) external;

sec:create-external-security(
$es/sec:external-security-name,
$es/sec:description,
$es/sec:authentication,
$es/sec:cache-timeout,
$es/sec:authorization,
$es/sec:ldap-server-uri,
$es/sec:ldap-base,
$es/sec:ldap-attribute,
$es/sec:ldap-default-user,
$es/sec:ldap-password)',
(xs:QName("es"), $es),
$eval-options)
}
catch($ex) {
if ($ex/error:code = "XDMP-UNDFUN" and fn:not(setup:at-least-version("7.0-0"))) then
(: If we're not using a recent enough version of ML, then the properties are irrelevant. :)
()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, I think it would be useful to throw a specific error.

else
xdmp:rethrow()
},
setup:add-rollback("external-security", $es)
)
};

declare function setup:validate-external-security(
$import-config as element(configuration))
{
for $es in $import-config/sec:external-securities/sec:external-security
let $es-name as xs:string? := $es/sec:external-security-name
let $match := setup:get-external-securities($es-name)
return
if ($match) then
let $match-elements := $match/*[fn:not(fn:local-name(.) = 'external-security-id')]
let $all-match :=
for $e in $match-elements
let $name := fn:node-name($e)
return
$es/*[fn:node-name(.) = $name] = $e
let $has-mismatch := $all-match = fn:false()
let $c1 := fn:count($es/*)
let $c2 := fn:count($match-elements)
return
if ($c1 ne $c2 or $has-mismatch) then
setup:validation-fail(fn:concat("Mismatched external-security ", $es-name))
else ()
else
setup:validation-fail(fn:concat("Missing external-security ", $es-name))
};

declare function setup:create-roles(
$import-config as element(configuration))
{
Expand Down Expand Up @@ -3898,7 +4046,6 @@ declare function setup:validate-roles(
let $amps as element(sec:amp)* := $role/sec:amps/*
let $match := setup:get-roles(())/sec:role[sec:role-name = $role-name]
return
(: if the role exists, then update it :)
if ($match) then
if ($match/sec:role-name != $role-name or
$match/sec:description != $description or
Expand Down Expand Up @@ -4267,6 +4414,22 @@ declare function setup:get-appserver-default-user($server-config as element()) a
else $default-user
};

declare function setup:get-appserver-internal-security($server-config as element()) as xs:boolean?
{
if (setup:at-least-version("7.0-0")) then
(
fn:data($server-config/gr:internal-security),
fn:not(setup:get-appserver-external-security($server-config)[fn:not(. = "")]),
fn:true()
)[1]
else ()
};

declare function setup:get-appserver-external-security($server-config as element()) as xs:string?
{
fn:data($server-config/gr:external-security/(@name|text()))
};

declare function setup:get-ssl-certificate-template(
$server-config as element())
as xs:unsignedLong
Expand Down Expand Up @@ -4444,6 +4607,27 @@ declare function setup:get-roles($ids as xs:unsignedLong*) as element(sec:roles)
}</roles>
};

declare function setup:get-external-securities($names as xs:string*) as element(sec:external-securities)*
{
let $external-securities :=
xdmp:eval(
'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy";
fn:collection(sec:security-collection())/sec:external-security
',
(),
<options xmlns="xdmp:eval">
<database>{$default-security}</database>
</options>)
return
element sec:external-securities {
if ($names) then
$external-securities[sec:external-security-name = $names]
else
$external-securities
}
};


declare function setup:get-amps($ids as xs:unsignedLong*) as element(sec:amps)? {
let $amps :=
xdmp:eval(
Expand Down Expand Up @@ -4831,6 +5015,7 @@ declare function setup:validate-install($import-config as element(configuration)
{
try
{
setup:validate-external-security($import-config),
setup:validate-privileges($import-config),
setup:validate-roles($import-config),
setup:validate-users($import-config),
Expand Down
23 changes: 23 additions & 0 deletions deploy/sample/ml-config.sample.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@
<url-rewriter>@ml.url-rewriter</url-rewriter>
<error-handler>@ml.error-handler</error-handler>
<rewrite-resolves-globally>@ml.rewrite-resolves-globally</rewrite-resolves-globally>
<!-- for external security use:

<internal-security>false</internal-security>
<external-security name="name-of-your-external-security-config"/>

-->

<!-- <ssl-certificate-template>@ml.ssl-certificate-template</ssl-certificate-template> -->
</http-server>
@ml.test-appserver
Expand Down Expand Up @@ -500,4 +507,20 @@
</mimetype>
-->
</mimetypes>
<!--
<external-securities xmlns="http://marklogic.com/xdmp/security">
<external-security>
<external-security-name>test</external-security-name>
<description>a big test</description>
<authentication>ldap</authentication>
<cache-timeout>300</cache-timeout>
<authorization>ldap</authorization>
<ldap-server-uri>ldap://dc1.mltest1.local:389</ldap-server-uri>
<ldap-base>CN=Users,DC=MLTEST1,DC=LOCAL</ldap-base>
<ldap-attribute>sAMAccountName</ldap-attribute>
<ldap-default-user/>
<ldap-password/>
</external-security>
</external-securities>
-->
</configuration>
15 changes: 14 additions & 1 deletion deploy/test/data/ml5-config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -697,4 +697,17 @@
<format>text</format>
</mimetype>
</mimetypes>
</configuration>
<!-- doesn't work with 5.x -->
<external-security xmlns="http://marklogic.com/xdmp/security">
<external-security-name>test-external</external-security-name>
<description>a big test</description>
<authentication>ldap</authentication>
<cache-timeout>300</cache-timeout>
<authorization>ldap</authorization>
<ldap-server-uri>ldap://dc1.mltest1.local:389</ldap-server-uri>
<ldap-base>CN=Users,DC=MLTEST1,DC=LOCAL</ldap-base>
<ldap-attribute>sAMAccountName</ldap-attribute>
<ldap-default-user/>
<ldap-password/>
</external-security>
</configuration>
Loading