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

Support for Element Level Security #846

Open
grtjn opened this issue Sep 22, 2017 · 2 comments
Open

Support for Element Level Security #846

grtjn opened this issue Sep 22, 2017 · 2 comments

Comments

@grtjn
Copy link
Contributor

grtjn commented Sep 22, 2017

Involves creating query rolesets, and protected paths

@grtjn
Copy link
Contributor Author

grtjn commented Sep 22, 2017

I've done things like this in app_specific, but we need a better way of feeding relevant roles and paths to protect:

  alias_method :original_bootstrap,      :bootstrap

  def bootstrap
    original_bootstrap
    bootstrap_els
  end

  def bootstrap_els
    logger.info "Bootstrapping Element Level Security.."
    r = execute_query(
      %Q{
        xquery version "1.0-ml";

        import module namespace sec = "http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy";

        let $app-name := "#{@properties['ml.app-name']}"
        let $role-names := (
          $app-name || "-power-role",
          $app-name || "-customer-A-role",
          $app-name || "-customer-B-role"
        )
        let $role-ids :=
          for $r in $role-names
          return
            xdmp:role($r)
        return (
          let $existing-rolesets :=
            collection(sec:query-rolesets-collection())
              //sec:query-roleset
                [count(sec:role-id[. = $role-ids]) eq count($role-ids)]
          where empty($existing-rolesets)
          return
            let $_ := sec:add-query-rolesets(sec:query-rolesets(sec:query-roleset($role-names)))
            return "Added roleset: ((" || string-join($role-names, ",") || "))",

          let $permissions :=
            for $role-name in $role-names
            return
              xdmp:permission($role-name, "read")
          let $protected-paths := (
            "//ip",
            "//City",
            "//Gender",
            "//TwitterID",
            "//FacebookID",
            "//InstagramID",
            "//WeiboID",
            "//EmailAddress",
            "//StreetAddress",
            "//ZipCode",
            "//TelephoneNumber",
            "//Birthday",
            "//NbOfChilds",
            "//Invoice"
          )
          for $path in $protected-paths 
          let $existing-path :=
            collection(sec:protected-paths-collection())
              [.//sec:path-expression eq $path]
          return
            if (empty($existing-path)) then
              let $_ := sec:protect-path($path, (), $permissions)
              return "Protected path: " || $path
            else
              let $existing-permissions := sec:path-get-permissions($path, ())
              where count($existing-permissions[string(.) = $permissions/string()]) ne count($permissions)
              return
                let $_ := sec:path-add-permissions($path, (), $permissions)
                return "Updated path: " || $path
        )
      },
      { :db_name => "Security" }
    )
    r.body = parse_body r.body
    logger.info ""
    logger.info r.body
    logger.info ""
  end

@grtjn
Copy link
Contributor Author

grtjn commented Sep 22, 2017

Corresponding wipe:

  alias_method :original_wipe,           :wipe

  def wipe_els
    logger.info "Wiping Element Level Security.."
    r = execute_query(
      %Q{
        xquery version "1.0-ml";

        import module namespace sec = "http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy";

        let $app-name := "#{@properties['ml.app-name']}"
        let $role-names := (
          $app-name || "-power-role",
          $app-name || "-customer-A-role",
          $app-name || "-customer-B-role"
        )
        let $role-ids :=
          for $r in $role-names
          return
            xdmp:role($r)
        return (
          for $existing-roleset in
            collection(sec:query-rolesets-collection())
              /sec:query-rolesets
                [sec:role-id = $role-ids]
          return
            let $_ := sec:remove-query-rolesets($existing-roleset)
            return ("Removed roleset: ((" || string-join($existing-roleset/sec:role-id/string(), ",") || "))"),

          let $permissions :=
            for $role-name in $role-names
            return
              xdmp:permission($role-name, "read")
          let $protected-paths := (
            "//ip",
            "//City",
            "//Gender",
            "//TwitterID",
            "//FacebookID",
            "//InstagramID",
            "//WeiboID",
            "//EmailAddress",
            "//StreetAddress",
            "//ZipCode",
            "//TelephoneNumber",
            "//Birthday",
            "//NbOfChilds",
            "//Invoice"
          )
          for $path in $protected-paths
          let $existing-path :=
            collection(sec:protected-paths-collection())
              [//sec:path-expression eq $path]
          return
            if (exists($existing-path)) then
              let $existing-permissions := sec:path-get-permissions($path, ())
              return
                if (count($existing-permissions[string(.) = $permissions/string()]) eq count($permissions)) then
                  let $_ := sec:unprotect-path($path, ())
                  return
                    "Unprotecting path: " || $path (:sec:remove-path($path, ()):)
                else if ($existing-permissions) then
                  let $_ := sec:path-remove-permissions($path, (), $permissions)
                  return
                    "Unprotecting path: " || $path
                else ()
            else ()
        );
        xquery version "1.0-ml";

        import module namespace sec = "http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy";

        for $path in collection(sec:protected-paths-collection())//sec:path-expression
        let $existing-permissions := sec:path-get-permissions($path, ())
        where empty($existing-permissions)
        return
          let $_ := sec:remove-path($path, ())
          return
            "Removing path: " || $path
      },
      { :db_name => "Security" }
    )
    r.body = parse_body r.body
    logger.info ""
    logger.info r.body
    logger.info ""
  end

  def wipe
    wipe_els
    original_wipe
  end

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant