Confluence Filter setting permission in WebPreferences does not work?

Hi there,

I’m working on a POC migrating confluece to xWiki including space-permissions and page-restrictions. For this I’ve “hacked” (I’m not a Java developer) into the org.xwiki.contrib.confluence.filter.internal.input.ConfluenceInputFilterStream extending permission migration functionality. Currently I’m struggling with one thing on the Java-side.

If I generate a Velocity-Script like this - it works:

{{velocity}}
START
#set ($mydoc = $xwiki.getDocument("TESTARGESPACE02.WebPreferences"))
#set ($RightsObjectAdmins = $mydoc.newObject("XWiki.XWikiGlobalRights"))
#set ($result = $RightsObjectAdmins.set("groups", "XWiki.zbg_bedienstete"))
#set ($result = $RightsObjectAdmins.set("levels", "view"))
#set ($result = $RightsObjectAdmins.set("allow", 1))
$mydoc.save()

#set ($RightsObjectAdmins = $mydoc.newObject("XWiki.XWikiGlobalRights"))
#set ($result = $RightsObjectAdmins.set("groups", "XWiki.zbg_studenten"))
#set ($result = $RightsObjectAdmins.set("levels", "view"))
#set ($result = $RightsObjectAdmins.set("allow", 1))
$mydoc.save()
#set ($RightsObjectAdmins = $mydoc.newObject("XWiki.XWikiGlobalRights"))
#set ($result = $RightsObjectAdmins.set("groups", "XWiki.zbg_projektkonten"))
#set ($result = $RightsObjectAdmins.set("levels", "view,edit,comment"))
#set ($result = $RightsObjectAdmins.set("allow", 1))
$mydoc.save()
#set ($RightsObjectAdmins = $mydoc.newObject("XWiki.XWikiGlobalRights"))
#set ($result = $RightsObjectAdmins.set("users", "XWiki.loc_hettegger_ib"))
#set ($result = $RightsObjectAdmins.set("levels", "view"))
#set ($result = $RightsObjectAdmins.set("allow", 1))
$mydoc.save()
#set ($RightsObjectAdmins = $mydoc.newObject("XWiki.XWikiGlobalRights"))
#set ($result = $RightsObjectAdmins.set("users", "XWiki.baerthlein"))
#set ($result = $RightsObjectAdmins.set("levels", "view,edit,comment,admin"))
#set ($result = $RightsObjectAdmins.set("allow", 1))
$mydoc.save()
#set ($RightsObjectAdmins = $mydoc.newObject("XWiki.XWikiGlobalRights"))
#set ($result = $RightsObjectAdmins.set("users", "XWiki.Admin"))
#set ($result = $RightsObjectAdmins.set("levels", "view,comment,edit,admin"))
#set ($result = $RightsObjectAdmins.set("allow", 1))
$mydoc.save()
END
{{/velocity}}  

This will generate a new “WebPreferences” document, where I’m able to inspect the class, object and properties. When I click on “administre page” the formaly “WebPreferences” will be converted into a “Page Administration”-title and I can acces and see all permissions the velocity-script has set.

If I’m trying to do the same thing on the Java-side using a similar code somewhere in “readInternal()”:

                // seems there is no xxx.WebPreferences Document so a NPE is thrown
                // create a new xxx.WebPreferences

                // > WikiDocument
                String webPreferences = "WebPreferences"; // in the context of parent node of this space //spaceKey + ".WebPreferences"; // eg. TESTARGESPACE02.WebPreferences
                FilterEventParameters documentParameters = new FilterEventParameters();
                proxyFilter.beginWikiDocument(webPreferences, documentParameters);

                // now it should be possible to persist global permissions into this WebPreferences-document
                createSpacePermissionsImportScript(spaceId, spaceKey, spacePermissions, proxyFilter);

                // < WikiDocument
                proxyFilter.endWikiDocument(webPreferences, documentParameters);

and somewhere within createSpacePermissionsImportScript()

FilterEventParameters objectProps = new FilterEventParameters();
objectProps.put(WikiObjectFilter.PARAMETER_NUMBER, 0); // each object should have a new number
objectProps.put(WikiObjectFilter.PARAMETER_CLASS_REFERENCE, "XWiki.XWikiGlobalRights");
String globalPermissionDocument = "WebPreferences";
proxyFilter.beginWikiObject(globalPermissionDocument, objectProps);

// permissions object property
proxyFilter.onWikiObjectProperty("levels", "view,edit,comment", new FilterEventParameters());
proxyFilter.onWikiObjectProperty("users", "loc_hetteger_ib", new FilterEventParameters());
proxyFilter.onWikiObjectProperty("allow", 1, new FilterEventParameters());

// persist wiki object
proxyFilter.endWikiObject(globalPermissionDocument, objectProps);

I’m getting the same “WebPreferences” class, object, properties as creating it via Velocity. BUT when I’m clicking on “Administre Page” (parent) I’ll NOT see any permission set - also the permissions seems not to be set (locked in with a user and tested it).

Any idea on that (sorry, I’m still a xWiki rookie).

Regards,
Stefan.

Well, there must be a difference, but I don’t see anything obvious without reproducing, sorry.

One thing you might want to try to compare both versions at a lower level is to add ?xpage=xml at the end of the URL, as in https://tuska.myxwiki.org/xwiki/bin/view/Test/Object/?xpage=xml.

This is not how the name part of an object reference is supposed to look like (in your case, it would be more something like XWiki.XWikiGlobalRights[0]). But it’s not your problem here, since it’s not really taken into account when you indicate the PARAMETER_CLASS_REFERENCE anyway.

Setting a number is not mandatory unless you absolutely want a specific one. If none is provided, the object will get a new one when inserted in the document.

You should use FilterEventParameters.EMPTY to avoid create new objects for this case.

I just noticed confluence/confluence-xml/src/main/java/org/xwiki/contrib/confluence/filter/internal/input/ConfluenceInputFilterStream.java at 4b40a4ed4cf9b3fa54ff2f15ba1d67880b3385e3 · xwiki-contrib/confluence · GitHub which is not a great inspiration, cleaning that up a bit.

Thank you :1st_place_medal:!

The XML diff told me that I’ve forgot to prefix the users and groups with “XWiki.” - I think this was the main error. Also I could successfully optimize the existing code, removing the number (as there is an autoincrement) and using FilterEventParameters.EMPTY (the other codeparts I didn’t touch).

Feels like one big step forward!
Regards,
Stefan.

By the way @baerthlein if the point is to import standard Confluence permissions, it would be great if you could contribute it to GitHub - xwiki-contrib/confluence: Various Atlassian Confluence related tools when you start having something good enough. I’m sure many people would be happy with this kind of feature :wink:

it’s just a dirty PoC code but working for my purposes. I’ve started with code of 9.20.2-SNAPSHOT-26. In the first quess, when I could not set the global space permissions in java, I’ve generated a velocity script as workaround (confluence permission migrator.vm) - later I deleted that code, anyhow…it’s a little bit messy but here are the snippets (just remove the “.txt” extension and compare it with the original versions). Regards, Stefan.ConfluenceXMLPackage.java.txt (58.1 KB)

ConfluenceInputFilterStream.java.txt (77.5 KB)

confluence permission migrator.vm.txt (5.4 KB)

Thanks. In any case, whatever the current status, what is interesting is the work you did to translate Confluence metadata into XWiki rights, which can be very useful to someone that would want to work on that.

sorry :slight_smile:
in xwiki-contrib-confluence\confluence-xml\src\main\java\org\xwiki\contrib\confluence\filter\input\ConfluenceXMLPackage.java I’ve added some code in order to process the Contentpermissions

image

in xwiki-contrib-confluence\confluence-xml\src\main\java\org\xwiki\contrib\confluence\filter\internal\input\ConfluenceInputFilterStream.java I added some code to “readInternal” to convert all those confluence stuff into xWiki-Objects

    private void readInternal(Object filter, ConfluenceFilter proxyFilter) throws FilterException
    {
        // Prepare package
        try {
            this.confluencePackage.read(this.properties.getSource());
        } catch (Exception e) {
            throw new FilterException("Failed to read package", e);
        }

        Map<Long, List<Long>> pages = this.confluencePackage.getPages();

        if (this.properties.isUsersEnabled()) {
            Collection<Long> users = this.confluencePackage.getInternalUsers();
            // TODO get users in new format (this.confluencePackage.getAllUsers())
            Collection<Long> groups = this.confluencePackage.getGroups();

            this.progress.pushLevelProgress(users.size() + groups.size() + pages.size()
                + pages.entrySet().stream().mapToInt(e -> e.getValue().size()).sum(), this);

            sendUsers(users, groups, proxyFilter);
        } else {
            this.progress.pushLevelProgress(
                pages.size() + pages.entrySet().stream().mapToInt(e -> e.getValue().size()).sum(), this);
        }

        // Generate documents events
        for (Map.Entry<Long, List<Long>> entry : pages.entrySet()) {
            long spaceId = entry.getKey();

            ConfluenceProperties spaceProperties;
            try {
                spaceProperties = this.confluencePackage.getSpaceProperties(spaceId);
            } catch (ConfigurationException e) {
                throw new FilterException("Failed to get space properties", e);
            }

            String spaceKey = toEntityName(ConfluenceXMLPackage.getSpaceKey(spaceProperties));
            FilterEventParameters spaceParameters = new FilterEventParameters();

            // **@baerthlein Start**
            Collection<Long> spacePermissions = this.confluencePackage.getSpacePermissions(spaceId);
            //if (this.properties.isUsersEnabled())
            // create groups and users in order to assign spacepermissions later on
            try {
                **sendSpacePermissionUsersAndGroups(spaceId, spacePermissions, proxyFilter);**
            }
            catch (FilterException e) {
                logger.error("Problem creating groups and users from confluence space permissions (space-Id: "+spaceId+")", e);
            }

            // > WikiSpace
            proxyFilter.beginWikiSpace(spaceKey, spaceParameters);

            // Main page
            StringBuilder script = new StringBuilder();
            Long descriptionId = spaceProperties.getLong(ConfluenceXMLPackage.KEY_SPACE_DESCRIPTION, null);
            if (descriptionId != null) {
                this.progress.startStep(this);
                if (this.properties.isIncluded(descriptionId)) {
                    **readPage(descriptionId, spaceKey, filter, proxyFilter, script);**
                }
                this.progress.endStep(this);
            }

            // Other pages
            for (long pageId : entry.getValue()) {
                this.progress.startStep(this);
                if (this.properties.isIncluded(pageId)) {
                    **readPage(pageId, spaceKey, filter, proxyFilter, script);**
                }
                this.progress.endStep(this);
            }

**// workaround building velocity script**
            if (script.length() > 0){
                script.insert(0, "{{velocity}}\n").append("{{/velocity}}\n");
                String filename = this.environment.getTemporaryDirectory().toPath() + "/pagerestriction-script-"+spaceKey+".vm";
                FileOutputStream fileStream = null;
                try {
                    fileStream = new FileOutputStream(filename);
                    fileStream.write(script.toString().getBytes());
                    fileStream.flush();
                    fileStream.close();
                    this.logger.info("Created pagerestriction-script: " + filename);
                } catch (FileNotFoundException e) {
                    logger.error("File not found error writing pagerestriction-script: " + filename, e);
                } catch (IOException e) {
                    logger.error("IO-error writing pagerestriction-script: " + filename, e);
                }
            }

            try {
                // Problems with NPE seems that I'm unable to manipulate a simple xObject???
                //sendSpacePermissions(proxyFilter, spaceId, spacePermissions);

                // seems there is no xxx.WebPreferences Document so a NPE is thrown
                // create a new xxx.WebPreferences

                // > WikiDocument
                **String webPreferences = "WebPreferences";** // in the context of parent node of this space //spaceKey + ".WebPreferences"; // eg. TESTARGESPACE02.WebPreferences
//                FilterEventParameters documentParameters = new FilterEventParameters();
                proxyFilter.beginWikiDocument(webPreferences, FilterEventParameters.EMPTY /*documentParameters*/);

                // now it should be possible to persist global permissions into this WebPreferences-document
                createSpacePermissionsImportScript(spaceId, spaceKey, spacePermissions, proxyFilter);

                // < WikiDocument
                proxyFilter.endWikiDocument(webPreferences, FilterEventParameters.EMPTY /*documentParameters*/);
            }
            catch (FilterException e) {
                logger.error("Error creating spacepermissions-script (space-Id: "+spaceId+") ", e);
            }

            // < WikiSpace
            proxyFilter.endWikiSpace(spaceKey, spaceParameters);
        }

        this.progress.popLevelProgress(this);

        // Cleanup

        try {
            this.confluencePackage.close();
        } catch (IOException e) {
            throw new FilterException("Failed to close package", e);
        }
    }

trying to convert confluence space permissions (there may be falsy code for checking things are existing aso)

  /**
     * Extracts all groups and users from the confluence spacepermissions and if not existing creates them
     * @param spaceId Id of the space containing the permissions
     * @param spacePermissions Collection of spacePermissions (properties)
     * @param proxyFilter Filter doing the input output convertion
     * @throws FilterException if Exception occurs logs them
     */
    private void sendSpacePermissionUsersAndGroups(long spaceId, Collection<Long> spacePermissions, ConfluenceFilter proxyFilter)
            throws FilterException {

        List<String> uniqueUsernames = new ArrayList<>();
        List<String> uniqueGroupnames = new ArrayList<>();
        for (Long spacePermissionId : spacePermissions) {
            this.progress.startStep(this);
            ConfluenceProperties spacePermissionProperties;

            try {
                spacePermissionProperties = this.confluencePackage.getSpacePermissionProperties(spaceId, spacePermissionId);
            } catch (ConfigurationException e) {
                throw new FilterException("Failed to get space-permission properties for space-Id: "+ spaceId +" and permission-Id: "+spacePermissionId, e);
            }

            // Seems that 1 Permission is always assign to 1 group our 1 user
            String groupName = spacePermissionProperties.getString(ConfluenceXMLPackage.SPACEPERMISSION_GROUP, "");
            String useSubject = spacePermissionProperties.getString(ConfluenceXMLPackage.SPACEPERMISSION_USER, "");
            String anonymous = spacePermissionProperties.getString(ConfluenceXMLPackage.SPACEPERMISSION_ANONYMOUS, "");
            if (StringUtils.isNoneEmpty(groupName)){

                if (uniqueGroupnames.contains(groupName))
                    continue;

                if (isExistingGroup(groupName)){
                    uniqueGroupnames.add(groupName);
                    continue;
                }

                sendSpacePermissionGroups(proxyFilter, uniqueGroupnames, groupName);
                uniqueGroupnames.add(groupName);
                logger.info("Created group: " + groupName + " from spacerpermissions.");
            }
            else if (StringUtils.isNoneEmpty(useSubject)) {

                try {
                    ConfluenceProperties userImplProperties = this.confluencePackage.getUserImplProperties(useSubject);
                    String lowerName = userImplProperties.getString(ConfluenceXMLPackage.USERIMPL_LOWERNAME, "");
                    String xWikiUsername = lowerName;
                    if (this.properties.isConvertToXWiki()) {
                        if (lowerName.equals("admin")) {
                            xWikiUsername = "Admin";
                        }
                    }

                    if (uniqueUsernames.contains(lowerName))
                        continue;

                    if (isExistingUser(xWikiUsername)){
                        uniqueUsernames.add(lowerName);
                        continue;
                    }

                    sendSpacePermissionUsers(proxyFilter, userImplProperties, lowerName);
                    uniqueUsernames.add(lowerName);
                    logger.info("Created user: " + lowerName + " from spacerpermissions.");
                }
                catch (ConfigurationException e) {
                    throw new FilterException("Failed to get UserImpl properties for user-key: "+ useSubject, e);
                }
            }
            // Anonymous won't be migrated
            else if (StringUtils.isNoneEmpty(anonymous)) {
                continue;
            }

            this.progress.endStep(this);
        }
    }

the creationg of groups and users - I’m not sure if it would be sufficient if I create only the permissions or it there also have to be groups and users as well (anyhow, could reuse this code for a later user-sync script…)

    /**
     * Creates groups if it does not exists
     * @param proxyFilter Filter doing input/output convertion
     * @param uniqueGroupnames Collection checking for unique groupnames (beeing extracted from the confluence space permissions)
     * @param groupname current groupname
     * @return true = group exists, false = group does not exist
     * @throws FilterException Convertion Error
     */
    private boolean sendSpacePermissionGroups(ConfluenceFilter proxyFilter, List<String> uniqueGroupnames, String groupname) throws FilterException {

        // only create unique, not existing groups
        if (uniqueGroupnames.contains(groupname) ||
                StringUtils.isEmpty(groupname) ||
                documentAccessBridge.exists(XWiki.SYSTEM_SPACE + "." + groupname)) {// check if group / document / pagereference exists
            this.progress.endStep(this);
            return true;
        }

        uniqueGroupnames.add(groupname);
        FilterEventParameters groupParameters = new FilterEventParameters();
        // > Group
        proxyFilter.beginGroupContainer(groupname, groupParameters);
        // < Group
        proxyFilter.endGroupContainer(groupname, groupParameters);
        return false;
    }

create user

    /**
     * Creates user if not existing
     *
     * @param proxyFilter        Filter doing the iput / output convertion
     * @param userImplProperties Internal confluence user-Id (GDPR obfuscated)
     * @param lowerName         lower username
     * @throws FilterException convertion error
     */
    private void sendSpacePermissionUsers(ConfluenceFilter proxyFilter, ConfluenceProperties userImplProperties, String lowerName) throws FilterException {
        String email = userImplProperties.getString(ConfluenceXMLPackage.USERIMPL_EMAIL, "");
        FilterEventParameters userParameters = new FilterEventParameters();
        userParameters.put(UserFilter.PARAMETER_FIRSTNAME, lowerName);
        userParameters.put(UserFilter.PARAMETER_LASTNAME, lowerName);
        userParameters.put(UserFilter.PARAMETER_EMAIL, email);
        userParameters.put(UserFilter.PARAMETER_ACTIVE,true); // all users should be activated per default
        // TODO: no idea how to import/convert the password, probably salted with the Confluence instance id

        // > User
        proxyFilter.beginUser(lowerName, userParameters);

        // < User
        proxyFilter.endUser(lowerName, userParameters);
    }

for the pagerestrictions i’ve used some ugly code wihtout refactoring, anyhow it comes done to probably this snippets

/**
     * Reads the confluence pagepermissions and assignes "view" or "edit" (= view, edit, comment, delete) to users and
     * groups like set in the space-export (if users or groups do not exist, they won't be created - xWiki permissions
     * will work as soon as the users and groups have been created).
     * <strong>The xWiki-Permissions are set via the document's XWiki.XWikiRights class and are visible in the edit object mode,
     * they won't shine up in the page-permissions for some reasons (perhaps index problem)?</strong>
     *
     * @param pageProperties Currents Pageproperties
     * @param proxyFilter    valid confluence filter
     * @param script         the internally created Velocity script
     * @throws FilterException Error during reading or setting pageproperties / document
     */
    private void readPageRestrictions(ConfluenceProperties pageProperties, ConfluenceFilter proxyFilter, StringBuilder script) throws FilterException {
        String objectName = getObjectName(pageProperties); // eg. ITInfo.WebHome
        Map<String, String> userPermissions = new HashMap<>();
        Map<String, String> groupPermissions = new HashMap<>();

        // confluence content permission set - should be max size = 2 (1x view + 1x edit)
        for (Object commentIdStringObject : pageProperties.getList(ConfluenceXMLPackage.CONTENT_PERMISSION_SETS)) {
            long contentPermissionSetId = Long.parseLong((String) commentIdStringObject);
            ConfluenceProperties contentPermissionSetProps;
            try {
                contentPermissionSetProps = this.confluencePackage.getObjectProperties(contentPermissionSetId);
            } catch (ConfigurationException e) {
                throw new FilterException("Failed to get contentpermissionsets properties for: " +contentPermissionSetId, e);
            }

            // within every view- or edit-set there are the permissions stored and assigned to user and groups
            // each permission is assigned to only 1 user or 1 group
            final List<Object> contentPermissions = contentPermissionSetProps.getList(ConfluenceXMLPackage.CONTENT_PERMISSIONS);
            for (Object permissionIdStringObject : contentPermissions) {
                long permissionId = Long.parseLong((String) permissionIdStringObject);
                try {
                    final ConfluenceProperties contentPermissionProperty = this.confluencePackage.getObjectProperties(permissionId);
                    final String userSubject = contentPermissionProperty.getString("userSubject");
                    String username = "";
                    if (StringUtils.isNoneEmpty(userSubject)) {
                        final ConfluenceProperties userImplProperties;
                        // look up ConfluenceUserImpl in order to get username aso
                        try {
                            userImplProperties = this.confluencePackage.getUserImplProperties(userSubject);
                        }
                        catch (ConfigurationException e) {
                            throw new FilterException("Failed to get UserImpl properties for user-key: "+ userSubject, e);
                        }
                        username = userImplProperties.getString(ConfluenceXMLPackage.USERIMPL_LOWERNAME, "");
                        // admin should be skipped as we can't restrict an admin...?
                        if (this.properties.isConvertToXWiki()) {
                            if (username.equals("admin")) {
                                username = "Admin";
                            }
                        }
                    }
                    final String groupName = contentPermissionProperty.getString("groupName");
                    final String type = contentPermissionProperty.getString("type"); // view, edit etc
                    // confluence stores view and edit-permissions additionally, means user x can have view and edit-permissions
                    // edit-permission implies view-permission. In order to a view OR a edit permission (NOT both) we want to
                    // replace a view-permission if an edit permission exists for the same user or group
                    replaceViewByEditPermission(userPermissions, username, type);
                    replaceViewByEditPermission(groupPermissions, groupName, type);

                } catch (ConfigurationException e) {
                    logger.error("Failed getting content permissions for: " + permissionId, e);
                }
            }
        }

        // persist the collected data into xObjects / XWikiRights
        StringBuilder body = new StringBuilder();
        writePageResrticitions(proxyFilter, objectName, userPermissions, true, body);
        writePageResrticitions(proxyFilter, objectName, groupPermissions, false, body);
        if (body.length() > 0)
            script.append("#set ($mydoc = $xwiki.getDocument(\"").append(objectName).append("\"))\n").append(body); // document-ref eg. TESTARGESPACE02.Testseite 3
    }
    /**
     * if user or a group has Edit-Permission replace the View-Permission
     * @param permissions collection containing user or group (key = user or group-name, value = permissiontype)
     * @param userOrGroup name of the user or the group
     * @param permissionType Edit or View
     */
    private void replaceViewByEditPermission(Map<String, String> permissions, String userOrGroup, String permissionType) {
        if (StringUtils.isNoneEmpty(userOrGroup)){
            String value = permissions.get(userOrGroup);
            if (value == null)
                permissions.put(userOrGroup, permissionType);
            else if (value.equals("View") && permissionType.equals("Edit"))
                permissions.replace(userOrGroup, permissionType);
        }
    }

main part - we don’t need the velocity workaround, but I let it still there for some legacy reason (and lazyness)

private void writePageResrticitions(ConfluenceFilter proxyFilter, String objectName, Map<String, String> userPermissions, boolean isUsercollection, StringBuilder body) throws FilterException {
        for (Map.Entry<String, String> entry : userPermissions.entrySet()) {

            // Permission object
            FilterEventParameters restrictionsParameters = new FilterEventParameters();
            restrictionsParameters.put(WikiObjectFilter.PARAMETER_CLASS_REFERENCE, XWiki.SYSTEM_SPACE + ".XWikiRights");
            proxyFilter.beginWikiObject(objectName, restrictionsParameters);

            // permissions object property
            String levels = this.convertConfluencePageRestrictions2xWikiPermission(entry.getValue());
            proxyFilter.onWikiObjectProperty("levels", levels, new FilterEventParameters());
            if (isUsercollection)
                proxyFilter.onWikiObjectProperty("users", XWiki.SYSTEM_SPACE + "." + entry.getKey(), new FilterEventParameters());
            else
                proxyFilter.onWikiObjectProperty("groups", XWiki.SYSTEM_SPACE + "." + entry.getKey(), new FilterEventParameters());
            proxyFilter.onWikiObjectProperty("allow", 1, new FilterEventParameters());

            // persist wiki object
            proxyFilter.endWikiObject(objectName, restrictionsParameters);

            // generating Velocity Script as currently the Pagerestrictiong are getting overwritten by the "Nested Page Migrator" Plugin
            // always create a new Object so the existing (rights) Objects don't get overwritten
            body.append("#set ($rightsObject = $mydoc.newObject(\""+ XWiki.SYSTEM_SPACE + ".XWikiRights"+"\"))\n");
            if (isUsercollection)
                body.append("#set ($result = $rightsObject.set(\"users\", \""+ XWiki.SYSTEM_SPACE + "." + entry.getKey() +"\"))\n");
            else
                body.append("#set ($result = $rightsObject.set(\"groups\", \""+ XWiki.SYSTEM_SPACE + "." + entry.getKey() +"\"))\n");
            body.append("#set ($result = $rightsObject.set(\"levels\", \""+levels+"\"))\n");
            body.append("#set ($result = $rightsObject.set(\"allow\", 1))\n");
            body.append("$mydoc.save()\n");
        }
    }
private String convertConfluencePageRestrictions2xWikiPermission(String pageRestriction){
//     xWiki Permissions
//     view - ability to view pages
//     comment - ability to write page comments
//     edit - ability to edit page content
//     script - control programmatically exactly what users are allowed to do
//     delete - ability to delete pages
//     admin - ability to administer pages or the wiki

//     Confluence Page Restrictions
//     edit
//     view

        String xWikipermission = "";
        if (pageRestriction.equals("View")) {
            xWikipermission = "view";
        }
        else if(pageRestriction.equals("Edit")) {
            xWikipermission = "view,edit,comment,delete";
        }

        return xWikipermission;
    }

hopefully this is the wright code I’m looking at :slight_smile: since there is a little bit of confusion on my hard disk now - but the code seems to work (as reading over it), also the lastedit should tell the truth about the source I found :crossed_fingers:

Regards,
Stefan.

I don’t understand, users and groups are already created. What’s missing is permission handling.

I just recognized that the bold marking does not work when using block quotes (just search for ** in order to get the most important spots)

I’m using the xwiki confluence migration tool and didn’t succeed in importing groups and users which have confluence space permissions, so I “hard coded” this functionality - also I wasn’t sure if I could create permissions without the existing users - nevertheless in the end it seemed to work they way I did it - for my purpose…

I recognized that I didn’t post the confluence space permission-part (only the page restriction) - anyhow you could read it out of the attachments I’ve posted before - here the main parts

    /**
     * users & groups have to be created in order to assign them permissions
     *
     * @param spaceId confluence space id
     * @param spaceKey confluence space key
     * @param spacePermissions confluence space permissions
     * @param proxyFilter confluence filter
     * @throws FilterException filter error
     */
    private void createSpacePermissionsImportScript(long spaceId, String spaceKey, Collection<Long> spacePermissions, ConfluenceFilter proxyFilter) throws FilterException {
        // in order to use few objects, collect oll permissions on user, group base
        Map<String, List<String>> userPermissions = new HashMap<>();
        Map<String, List<String>> groupPermissions = new HashMap<>();
        for (Long spacePermissionId : spacePermissions) {
            ConfluenceProperties spacePermissionProperties;
            try {
                spacePermissionProperties = this.confluencePackage.getSpacePermissionProperties(spaceId, spacePermissionId);
            } catch (ConfigurationException e) {
                throw new FilterException("Failed to get spacepermission properties", e);
            }

            final String group = spacePermissionProperties.getString("group");
            final String permission = spacePermissionProperties.getString("type");
            final String xWikiPermission = convertConfluenceSpacepermission2xWikiPermission(permission);
            final String user = spacePermissionProperties.getString("userSubject");
            if (StringUtils.isEmpty(xWikiPermission))
                continue;

            if (StringUtils.isNoneEmpty(group)){
                addPermissionIfNotExists(groupPermissions, group, xWikiPermission);
            }
            else if (StringUtils.isNoneEmpty(user)) {

                final ConfluenceProperties userImplProperties;
                // look up ConfluenceUserImpl in order to get username aso
                try {
                    userImplProperties = this.confluencePackage.getUserImplProperties(user);
                }
                catch (ConfigurationException e) {
                    throw new FilterException("Failed to get UserImpl properties for user-key: "+ user, e);
                }
                String lowerName = userImplProperties.getString(ConfluenceXMLPackage.USERIMPL_LOWERNAME, "");
                if (this.properties.isConvertToXWiki()) {
                    if (lowerName.equals("admin")) {
                        lowerName = "Admin";
                    }
                }

                addPermissionIfNotExists(userPermissions, lowerName, xWikiPermission);
            }
        }

        String globalPermissionDocument = "WebPreferences"; //spaceKey + ".WebPreferences"; // eg. TESTARGESPACE02.WebPreferences
        **writeSpacePermissions(proxyFilter, groupPermissions, globalPermissionDocument, false);**
**        writeSpacePermissions(proxyFilter, userPermissions, globalPermissionDocument, true);**

/*        {{/velocity}}
        #set ($mydoc = $xwiki.getDocument("TESTARGESPACE02.WebPreferences"))
        #set ($RightsObjectAdmins = $mydoc.newObject("XWiki.XWikiGlobalRights"))
        ## #set ($result = $RightsObjectAdmins.set("groups", "XWiki.zbg_bedienstete"))
        #set ($result = $RightsObjectAdmins.set("levels", "view,comment,edit,delete"))
        #set ($result = $RightsObjectAdmins.set("users", "XWiki.baerthlein,XWiki.loc_hettegger_ib"))
        #set ($result = $RightsObjectAdmins.set("allow", 1))
        $mydoc.save()
        {{/velocity}}*/

/*        StringBuilder body = new StringBuilder();
        for (Map.Entry<String, List<String>> set : groupPermissions.entrySet()) {
            // always create a new Object so the existing (rights) Objects don't get overwritten
            body.append("#set ($RightsObjectAdmins = $mydoc.newObject(\"XWiki.XWikiGlobalRights\"))\n");
            body.append("#set ($result = $RightsObjectAdmins.set(\"groups\", \"XWiki."+set.getKey()+"\"))\n");
            String levels = String.join(",", set.getValue());
            body.append("#set ($result = $RightsObjectAdmins.set(\"levels\", \""+levels+"\"))\n");
            body.append("#set ($result = $RightsObjectAdmins.set(\"allow\", 1))\n");
            body.append("$mydoc.save()\n");
        }

        for (Map.Entry<String, List<String>> set : userPermissions.entrySet()) {
            // always create a new Object so the existing (rights) Objects don't get overwritten
            body.append("#set ($RightsObjectAdmins = $mydoc.newObject(\"XWiki.XWikiGlobalRights\"))\n");
            body.append("#set ($result = $RightsObjectAdmins.set(\"users\", \"XWiki."+set.getKey()+"\"))\n");
            String levels = String.join(",", set.getValue());
            body.append("#set ($result = $RightsObjectAdmins.set(\"levels\", \""+levels+"\"))\n");
            body.append("#set ($result = $RightsObjectAdmins.set(\"allow\", 1))\n");
            body.append("$mydoc.save()\n");
        }

        // todo: spaceKey == xWiki - Webhome / name ?
        StringBuilder header = new StringBuilder("{{velocity}}\n");
        header.append("#set ($mydoc = $xwiki.getDocument(\""+spaceKey+".WebPreferences\"))\n");
        StringBuilder footer = new StringBuilder("{{/velocity}}\n");
        String script = header.toString() + body.toString() + footer.toString();

        String filename = this.environment.getTemporaryDirectory().toPath() + "/spacepermission-script-"+spaceKey+".vm";
        FileOutputStream fileStream = null;
        try {
            fileStream = new FileOutputStream(filename);
            fileStream.write(script.getBytes());
            fileStream.flush();
            fileStream.close();
            this.logger.info("Created spacepermissions-script: " + filename);
        } catch (FileNotFoundException e) {
            logger.error("File not found error writing spacepermission-script: " + filename, e);
        } catch (IOException e) {
            logger.error("IO-error writing spacepermission-script: " + filename, e);
        }*/

    }

and the

    private static void writeSpacePermissions(ConfluenceFilter proxyFilter, Map<String, List<String>> groupPermissions, String globalPermissionDocument, boolean isUserCollection) throws FilterException {
        for (Map.Entry<String, List<String>> set : groupPermissions.entrySet()) {
            // Permission object
            FilterEventParameters objectProps = new FilterEventParameters();
            objectProps.put(WikiObjectFilter.PARAMETER_CLASS_REFERENCE, XWiki.SYSTEM_SPACE + ".XWikiGlobalRights");
            proxyFilter.beginWikiObject(globalPermissionDocument, objectProps);

            // permissions object property
            String levels = String.join(",", set.getValue());
            proxyFilter.onWikiObjectProperty("levels", levels, new FilterEventParameters());
            if (isUserCollection)
                proxyFilter.onWikiObjectProperty("users", set.getKey(), new FilterEventParameters());
            else
                proxyFilter.onWikiObjectProperty("groups", set.getKey(), new FilterEventParameters());
            proxyFilter.onWikiObjectProperty("allow", 1, new FilterEventParameters());

            // persist wiki object
            proxyFilter.endWikiObject(globalPermissionDocument, objectProps);
        }
    }

hope that makes it a little bit clearer?
regards, Stefan.

Strange, maybe it’s yet another type of user/group. I did not check the details of your code yet but what the current version of the filter support are objects of types InternalUser, ConfluenceUserImpl, InternalGroup and HibernateMembership (see https://github.com/xwiki-contrib/confluence/blob/master/confluence-xml/src/main/java/org/xwiki/contrib/confluence/filter/input/ConfluenceXMLPackage.java#L735).

@baerthlein Hello!

I’m studying how I could migrate Confluence rights to XWiki. I may be interested in reusing your code. Would you agree if we reuse this code under LGPL 2.1+ to integrate it in the relevant projects? (GitHub - xwiki-contrib/confluence: Various Atlassian Confluence related tools, GitHub - xwikisas/application-confluence-migrator: Migrates content from Confluence to XWiki, GitHub - xwikisas/application-confluence-migrator-pro). If so, do you allow us to create commits under your name as the author or the Co author of the commits? Do you happen to have your code committed in git repositories?

Note that I’m not promising to integrate your work, I’m in early investigation phase.

In the meantime, thank you for sharing this work, that’s very nice and helps a lot!

hi @rjakse,

yes sure you can reuse the code for what ever purpose you’re using it. I’m fine with that - as I unfortunately don’t have any time (for now), I’m quite happy if I can contribute to the community (indirectly) :grinning:.

good luck!
Regards, Stefan.

Nice, thanks!